Hi Jim,
This is the list of improvements:
BEFORE:
ERROR on line 1: Variable a has not been assigned a value.
AFTER: with quotes - more easy to read
ERROR on line 1: Variable 'a' has not been assigned a value.
print a
BEFORE: variable name is unknown
ERROR on line 1: Variable unknown has not been assigned a value.
AFTER: correct name
ERROR on line 1: Variable 'a' has not been assigned a value.
a=0 print b
BEFORE: wrong name. At line 2 it is b, not a.
ERROR on line 2: Variable a has not been assigned a value.
AFTER: correct variable name (b).
ERROR on line 2: Variable b has not been assigned a value.
dim a(10) print a[1]
BEFORE:
ERROR on line 2: Variable a has not been assigned a value.
AFTER: easy to understand
ERROR on line 2: Element of array 'a' has not been assigned a value.
dim a(1) c=0 d=0 b=a print b[0]
BEFORE: wrong name, wrong varnum
ERROR on line 5: Variable a has not been assigned a value. (variable a!)
AFTER: perfect
ERROR on line 5: Element of array 'b' has not been assigned a value.
if a then print 1
BEFORE: nothing
AFTER:throw error message
ERROR on line 1: Variable 'a' has not been assigned a value.
a="text" a++ a++ print a
BEFORE: Result - incrementation in fact made a concatenation
text11
AFTER: correct behaviour
ERROR on line 2: Unable to convert string to number.
Times in benchmark are measured in a common BASIC256 running program, not just for routine.
sound "x",1000
BEFORE and AFTER messages:
ERROR on line 1: Unable to convert string to number. ERROR on line 1: Unable to convert string to musical note.
a="" print isnumeric(a) a=a-5 print a
BEFORE: isnumeric(a) print value 0 because an empty string is not a number, but why it is treat as 0 in arithmetic operation?
0 #empty string is indeed not a number -5.0 #why is treat as 0?
AFTER: correct behaviour
0 ERROR on line 3: Unable to convert string to number.
call mysub("text")
BEFORE and AFTER messages
ERROR on line 1: No such label mysub. ERROR on line 1: No such SUBROUTINE 'mysub'.
print mysub("text")
BEFORE and AFTER messages:
ERROR on line 1: No such label mysub. ERROR on line 1: No such FUNCTION 'mysub'.
print a/b
will print error: "ERROR on line 1: Division by zero."
but the first error is the most important to debug the problem:
AFTER:
ERROR on line 1: Variable 'b' has not been assigned a value.
dim (a) fill b a fill b
BEFORE: nothing
AFTER: error message
ERROR on line 1: Variable 'b' has not been assigned a value.
a={0,1,2,3,4} dim b(10) redim a(10) fill b[0] print a[9]
BEFORE and AFTER messages
ERROR on line 4: Variable a has not been assigned a value. ERROR on line 3: Element of array 'b' has not been assigned a value.
a=0x80000000 print a print typeof(a) a=-a print a print typeof(a)
BEFORE: wrong output
-2147483648 1 -2147483648 1
AFTER: correct behaviour and output
-2147483648 1 2147483648.0 2
Benchmark: calling an empty subroutine just like
subroutine xxx() end subroutine
dim d(50000) for f=0 to 49999 d[f]=0 next f t=msec for f=0 to 100 dim x=d[] dim x=d[] dim x=d[] dim x=d[] dim x=d[] dim x=d[] dim x=d[] dim x=d[] dim x=d[] dim x=d[] next f print msec-t
BEFORE: 4270ms
AFTER: 1440ms
for f=0 to 100 dim a(1000000) fill 1 dim a(1000000) fill 1 dim a(1000000) fill 1 dim a(1000000) fill 1 dim a(1000000) fill 1 dim a(1000000) fill 1 dim a(1000000) fill 1 dim a(1000000) fill 1 dim a(1000000) fill 1 dim a(1000000) fill 1 next f print msec
BEFORE: 48081ms
AFTER: 19030ms
for f=0 to 1000 a={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1…1,1,1,1} next f print msec
BEFORE: 6800ms
AFTER: 3560ms
BASIC programming language it is in fact a case insensitive language.
A kid should benefit from this advantage.
iscussion BASIC-256 Users
In programming language theory, lazy evaluation is an evaluation strategy which delays the evaluation of an expression until its value is needed or skip it.
Performance increases by avoiding needless calculations, and error conditions in evaluating compound expressions.
Read more: https://en.wikipedia.org/wiki/Short-circuit_evaluation
Implementation:
The old method requests both expr to be evaluated before AND to take action.
expr1 AND expr2
PUSH result expr1 PUSH result expr2 OP_AND
Lazy evaluation will evaluate first expr1 and if it is FALSE then will be no reason to evaluate expr2 because the final result will be FALSE anyway.
Lazy evaluation for AND is like this:
PUSH result expr2 OP_LAZYIFFALSE jmp_address PUSH result expr1 OP_AND jmp_address:
OP_LAZYIFFALSE will pop the bool result from stack of the first expression evaluated (expr1).
If it is false, then push false value on stack and jump after AND statement (final result is false regardless the value of expr2).
If first expression evaluated is true only then it will evaluate the second expression (expr2).
OP_AND will expect now only the result2 on stack because we already know the result of expr1 (true). It will be redundant to push the first result back on stack.
In fact we could skip entirely the OP_AND because the result2 is in fact the result of TRUE AND expr2:
- If expr2==FALSE then "TRUE AND expr2" will be also FALSE.
- If expr2==TRUE then "TRUE AND expr2" will be also TRUE.
I chose to not skip OP_AND because we need to be sure that there is a BOOL value on stack. (In case of FALSE AND "string$" the stack will contain "string$" which is not a BOOL)
The pseudo code is:
PUSH result expr1 (expr1 is evaluated) OP_LAZYIFFALSE { POP result1 from STACK as BOOL IF result1=FALSE THEN PUSH FALSE and JUMP jmp_address } PUSH result expr2 (expr2 is evaluated) OP_AND { ensure result2 from STACK is BOOL } jmp_address: ...
The same thing is happening with OP_OR.
The old method requests both expressions to be evaluated before OR to take action.
expr1 OR expr2
PUSH result expr1 PUSH result expr2 OP_OR
Lazy evaluation will evaluate first expr1 and if it is TRUE, then there will be no reason to evaluate expr2 because the final result will be TRUE anyway.
Lazy evaluation for OR is like this:
PUSH result expr2 OP_LAZYIFTRUE jmp_address PUSH result expr1 OP_OR jmp_address:
OP_LAZYIFTRUE acts just like OP_LAZYIFFALSE, but jumps only if the first expression is true.
The pseudo code is:
PUSH result expr1 (expr1 is evaluated) OP_LAZYIFTRUE { POP result1 from STACK as BOOL IF result1=TRUE THEN PUSH TRUE and JUMP jmp_address } PUSH result expr2 (expr2 is evaluated) OP_OR { ensure result2 from STACK is BOOL } jmp_address: ...
To check the results, I use a code from http://basic256.blogspot.ro/2010/12/rule-30.html
The results are:
Closed graphic window:
1700ms (Short-circuit evaluation)
2750ms (normal run)
Graphic window visible:
2400 ms (Short-circuit evaluation)
3400 ms (normal run)
First we must admit that no programming language is perfect to be taken as a model when it comes to order of operations. Read for example the "Neonatal C" section from https://www.bell-labs.com/usr/dmr/www/chist.html
What we agree for now is that the order of operations of BASIC256 is almost ok.
http://doc.basic256.org/doku.php?id=en:orderofoperators
First thing is to move % Mod operation into the group of [* / \ Multiplication, Division and Integer Division] because it is in fact a division. BASIC256 acts like this; it is just a mistake in help page:
%left '*' '/' B256MOD B256INTDIV
A real issue is with the concatenation symbol ‘; ’(semicolon). It was introduced as an only concatenation operation. It means "stick those things together". The usage is very important for any user:
a=10 b=2 PRINT "A (";a;") divided (/) by B (";b;") = ";a/b
This will print "A (10) divided (/) by B (2) = 5,0
" Which is great. But if you try:
a=10 b=2 PRINT "The sum of two numbers is = ";a+b
... the problem occur by showing this result "The sum of two numbers is = 102". This happen because concatenation symbol ; has the same precedence as + or -. In this case, instead of resolving (a+b) and after that to concatenate all segments separated by ;... it starts to do it from the first place.
%left '-' '+' B256SEMICOLON
B256SEMICOLON should have a lower precedence even lower than bitwise operations because the same thing is happening in this case:
a=1 b=2 PRINT "A | B = ";a|b
Will ouput
ERROR on line 3: Unable to convert string to number.
Also its precedence should be higher than Comparison operators to allow comparison of strings resulted by concatenations:
%left '<' B256LTE '>' B256GTE '=' B256NE %left B256BINARYOR B256AMP %left '-' '+' B256SEMICOLON %left '*' '/' B256MOD B256INTDIV %nonassoc B256UMINUS B256BINARYNOT %left '^'
Become:
%left '<' B256LTE '>' B256GTE '=' B256NE %left B256SEMICOLON %left B256BINARYOR B256AMP %left '-' '+' %left '*' '/' B256MOD B256INTDIV %nonassoc B256UMINUS B256BINARYNOT %left '^'
In mathematics, a percentage is a number or ratio expressed as a fraction of 100. It is denoted using the percent sign, "%". Example 20%, 55%... Percentage calculations are used in almost all calculations made with a pocket calculator.
It is very useful and it is in a human-readable format which is the purpose of BASIC.
Example
vat = price_before_vat * 20%
Example
input "How much do you weigh? (Kg) ", weigh print "You are made of:" print "- Oxygen "; weigh * 65% ;" Kg" print "- Carbon "; weigh * 18.5% ;" Kg" print "- Hydrogen "; weigh * 9.5% ;" Kg" print "- Nitrogen "; weigh * 3.3% ;" Kg" print "- Calcium "; weigh * 1.4% ;" Kg" print "- Phosphorus "; weigh * 1.1% ;" Kg" print "- Other elements "; weigh - weigh * (65+18.5+9.5+3.3+1.4+1.1)% ;" Kg" print "Do you ever think about that?"
Example
input "Sarah is buying a pair of jeans. Enter the original price: ", price input "The percentage discount is: ", percent print "How much will the discount be?" print "Simple: "; price; "$ * "; percent; "% = "; price * percent%; "$"
The implementation is simple, just add:
| expr B256MOD %prec B256UMINUS{ addIntOp(OP_PUSHINT, 100); addOp(OP_DIV); }
Logical operators do not deal with basic elements (numbers/strings) but instead use true/false results obtained from comparisons. They are working with conditions that can be evaluated to a true or false value. So NOT should have a lower precedence, just after the comparison operators, without taking precedence of B256UMINUS.
Example
print 0>10 #print 0 (false) - correct print not (0>10) #print 1 (true) - correct print not 0>10 #print 0 - wrong!
The last example show clear the wrong precedence of NOT. It is equivalent to print not (0) > 10. The fix is simple: to remove B256UMINUS precedence.
| B256NOT expr %prec B256UMINUS { addOp(OP_NOT); } //should be | B256NOT expr { addOp(OP_NOT); }
Logical operators are mainly used to control program flow. Usually, we will find them as part of an if, a while, an until or some other control statement.
The concept of logical operators is simple. They allow a program to make a decision based on multiple conditions. Each operand is considered a condition that can be evaluated to a true or false value. Then the value of the conditions is used to determine the overall value.
IF a=1 and b>0 THEN ...
Most common logical operators in programming languages are:
NOT p (which is an unary negation because it takes only one variable) p AND q - both conditions are true p OR q - at least one condition is true p XOR q - only one condition is true p NOR q - neither p nor q is true / both conditions are false …
(About “NOR” - if you like it as much as I do, then it would be nice to have it into BASIC language.)
http://math.stackexchange.com/questions/128504/boolean-algebra-operation-precedence
About Boolean algebra
There are multiple conventions about syntax, signs and about precedence too in Boolean algebra.
None of those are universally accepted.
In Boolean algebra, as a way of reducing the number of necessary parentheses in complex structures, one may introduce precedence rules. However, not all authors/schools/programming languages/compilers use the same order.
This is a paradox. Because the main goal for precedence rules was reducing the number of parentheses, but now every decent book of programming advise to use parentheses.
Shifting our attention to Boolean algebra, we discover that there are no precedence and associativity rules that are universal. This is particularly true when we start adding more operators (which are nothing but short cut notations for certain combinations of the three fundamental ones). Programming languages, by their nature, HAVE to have well-defined precedence and associativity rules, but they may vary significantly from one language to another. For this reason, it is best to write Boolean expressions with a liberal dose of parentheses.
https://www.allaboutcircuits.com/technical-articles/boolean-basics/
Using precedence in logical operators increase the work required to understand the code. It also request very advanced knowledge from the user. It is hard to understand the developer's intent.
IF a=0 or b=0 and c>0 THEN ...
Let’s keep in mind that BASIC is an acronym for Beginner's All-purpose Symbolic Instruction Code.
BASIC programming language is closer to human languages and further from machine languages. In contrast, assembly languages are considered low-level because they are very close to machine languages.
At least COMODORE BASIC or (the great) ZX SPECTRUM BASIC (as other BASIC’s or other programming languages) use no precedence for logical operators but evaluate expression from left to right, as any users expect to do. It would be strange to be otherwise. Especially as BASIC is suitable for complete beginners (kids).
Logical operators are in fact functions. AND, OR, XOR, NOR are just few functions from the 16 functions that results from using of two variables as input.
http://mathworld.wolfram.com/BooleanFunction.html
https://cs.fit.edu/~wds/classes/adm/Lectures/BooleanFunctions.pdf
http://www.plantation-productions.com/Webster/www.artofasm.com/DOS/pdf/ch02.pdf
There are 2^2n functions for n binary variables.
For 2 variables, n = 2, the number of possible BOOLEAN function is 16.
This is the table for the16 functions of two binary variables x & y.
Each function has a name. But just look at those functions:
#F1 - AND #F6 - XOR #F7 - OR #F8 - NOR #F14 - NAND
Those are the logical operators/functions that we choose before right? So, why should they have precedence? See? In the very background all are the same.
Trying to adopt one precedence variant for logical operators is not a bad thing. The real question is why to do that?
Programming languages are not Boolean algebra.
Even in programming logic gates the order is the same: in the order of connection (in the order they appear), the order you chose to connect.
Play with this: http://www.neuroproductions.be/logic-lab/index.php?id=75114 . It is equivalent to:
IF a OR b AND c XOR d THEN light the bulb
If we want another order, it is logically to use parentheses for that:
http://www.neuroproductions.be/logic-lab/index.php?id=75115
IF a OR (b AND c) XOR d THEN light the bulb
In conclusion, we must not have a precedence for the logical operators as the bitwise operators have no precedence too.
The final and correct order of operations should be:
Respectfully,
Florin Oprea