Oxygen Basic

Programming => Problems & Solutions => Topic started by: Aurel on May 08, 2018, 08:50:19 AM

Title: Construct ?
Post by: Aurel on May 08, 2018, 08:50:19 AM
Hi Charles

is this contruct valid in o2:
it is from C file i would like to translate to o2

Function GetNextChar()
 {
 while ((NextChar = getchar()) = " " )
 }
End Function


Title: Re: Construct ?
Post by: Mike Lobanovsky on May 08, 2018, 12:35:49 PM
Assuming NextChar is a global char variable and getchar() is a C function that gets the next character from stdin,

Sub GetNextChar()
    NextChar = Chr(getchar())
    While NextChar = " "
        NextChar = Chr(getchar())
    Wend
End Sub


The loop runs until the character that getchar() fetches appears any other than a space.
Title: Re: Construct ?
Post by: Aurel on May 08, 2018, 01:02:44 PM
Yes i think in same direction but original C code is as is presented
Title: Re: Construct ?
Post by: Mike Lobanovsky on May 08, 2018, 01:08:53 PM
No, it should have been

while ((NextChar = getchar()) == ' ');  // there's a space in between the single quotes

to be valid in C.
Title: Re: Construct ?
Post by: Charles Pegge on May 08, 2018, 02:17:47 PM
I would do it like this:

Code: [Select]
function GetNextChar() as string
string nextchar
do
  nextchar=getchar()
  if nextchar<>" " then exit do
loop
return nextchar
end function

But I suspect GetChar returns bytes:

Code: [Select]
function GetNextChar() as byte
byte nextchar
do
  nextchar=getchar()
  if nextchar<>32 then exit do
loop
return nextchar
end function

Another construct, recently introduced, compares favourably with C for brevity, without twisting the brain :)

do { nextchar=getchar() } while nextchar=32

Code: [Select]
function GetNextChar() as byte
byte nextchar
do { nextchar=getchar() } while nextchar=32
return nextchar
end function
Title: Re: Construct ?
Post by: Mike Lobanovsky on May 08, 2018, 03:12:26 PM
Ah yes, in fact C language getchar() (lowercase!) returns an int that can be reduced to an unsigned char. NextChar is obviously global in Aurel's C code, and the procedure needs not be dressed as a BASIC function because the rest of his parser is apparently going to use this global NextChar without any special assignment.

So, if we abstract from Aurel's literal while, then one of many possible versions might be

Sub GetNextChar()
    Do
        NextChar = Chr(getchar())
        Break When NextChar <> " " ' 8) :D
    Loop
End Sub


If NextChar is a byte rather than char or string, then just drop Chr() and compare against 32.

[UPD]

Haha yessssss! :D

Another construct, recently introduced, compares favourably with C for brevity ...

do { nextchar=getchar() } while nextchar=32

...

It also compares favorably with every other advanced BASIC (cf. Do [While|Until]/Loop [While|Until]) but has been somehow overlooked in Oxygen's many looping options until now. :)

So,

Sub GetNextChar()
    Do { _ // it probably won't work w/o line continuation
        NextChar = Chr(getchar()) _ // ditto
    } While NextChar = " "
End Sub


is my vote (even if I consider those curly braces and the associated line continuations out of place in a BASIC context) with my note about the NextChar declaration and byte/char/string/32 still holding true.

_____________________________________

(Charles, what about normal BASIC Do [While|Until]/Loop [While|Until] instead of all the existing verbosity?)
Title: Re: Construct ?
Post by: Aurel on May 08, 2018, 08:50:46 PM
Hi guys and thank you both for replys.
This old C code is from old PC Magazine 1993
and i try to translate to o2 ,
I don't have code than just picture of code..so i type  ::)
I ask because i see that this while loop is empty what looks confusing.
And yes NextChar is defined as INT.
More morbid thing i for/loop with construct for  ( ; ; )
what is that ?
for each ..or for any
ok here is i think whole code :

Code: [Select]
'EVAL.C expression evaluator
$ filename "EVALC.exe"
include "rtl32.inc"
#lookahead
'******************************************
' EXPRESSION EVALUATOR - PC Magazine 1993
'******************************************

def false 0
def true 1

int NextChar
int contin = true

! Factor()     as float
! Expression() as float
! Term()       as float

'************************************************************
'  GetNextChar - Reads chars until a non-space char is found
'************************************************************
Function GetNextChar()
 {
 while ((NextChar = getchar()) = " " )
 }
End Function

'**************************************************************
' Expression - A Recursive routine that evaluates an expression
' EXPRESSION = <EXPRESSION> + TERM | <EXPRESSION> - <TERM>
'**************************************************************

Function Expression() as float
float value
value = Term()

for (;;) {
select NextChar
case " "
GetNextChar()
break
case "+"
GetNextChar()
value = value + Term()
                    continue
case "-"
GetNextChar()
value = value - Term()
                    continue
case else
return value
end select
}

'****************************************************************
' Term - Handles Multiplication and division
' <TERM> = <TERM> * <FACTOR> | <TERM> div <FACTOR> | <FACTOR>
'****************************************************************

Function Term() as float
float value, divisor
value = Factor()
for (;;) {
select NextChar
case " "
GetNextChar()
exit for
case "*"
GetNextChar()
value = value * Factor()
                    continue
case "^"
GetNextChar()
value = value - Factor()
                    continue
case "/"
GetNextChar()
if ((divisor = Factor()) <> 0
   value = value / divisor
else
print " DIVISION BY ZERO !"
Exit Function
end if
                    continue

case else
return value
end select
}
End Function

'*********************************************************
' Factor - Handles numbers,minus signs and parens
' <FACTOR> = <EXPRESSION> | <VARIABLE> | <CONSTANT>
'*********************************************************

Function Factor() as float
float value = 0
int count = 0
int i
int d_point = false

if (( NextChar <= "9") AND (NextChar >= "0"))
while ((NextChar <= "9") AND (NextChar >= "0"))
value = value * 10 + NextChar - "0"
NextChar = getchar()
if (d_point)
count++
if (NextChar = ".")
NextChar = getchar()
d_point = true
end if
end if
wend
for i = 0 To (i < count)
value = value / 10
return value
    next
else
select NextChar
case "-"
GetNextChar()
return -1 * Factor()
case "("
GetNextChar()
value = Expression()
if (NextChar <> ")"
print " MISMATCHED PARENTHES !"
Exit Function
else
NextChar = getchar()
return value
end if
case "."
d_point = true

case else
contin = false
end select

return 0
End Function

'*******************************************************
' Main - Program entry point
'*******************************************************
Title: Re: Construct ?
Post by: Aurel on May 08, 2018, 09:30:45 PM
One more thing
Is exit(0) should be exit function ?
and
break should be exit for ?
right?
Title: Re: Construct ?
Post by: Charles Pegge on May 08, 2018, 10:25:50 PM
Mike,

A few more single-liner variations:

do : nextchar=getchar() : loop while nextchar=32

do : nextchar=getchar() : loop until nextchar<>32

do : nextchar=getchar() : exit when nextchar<>32 : loop

do : nextchar=getchar() : exit if not nextchar=32 : loop


Aurel,

for ( ; ; ) Looks like a do loop

Code: [Select]
do
   ... 'cases with continue do
   exit do 'instead of exit for
loop
 

exit(0) 'could be return 0 its not in your code
Title: Re: Construct ?
Post by: Mike Lobanovsky on May 09, 2018, 01:49:41 AM
Hi Aurel,

Re. C loops

1. In C, "empty" while (........); is used to set up a loop whose entire code can be expressed in between the condition statement parentheses and thus won't need additional code lines in the "body" of the loop proper.

Thus

while ((NextChar = getchar()) == ' ');

means2. Conversely, for (;;) ........ ; is often used to set up a loop in which everything occurs within the loop body rather than in its declaration, e.g.

int i = 0;
for (;;) {
    if (++i == 5) break;
}


whereby the loop is going to break (it means the code will exit from the loop) on its 5th iteration.

3. Summing up, C language "empty" for (;;);, while(1); and do{}while(1); would all mean "loop forever". Exactly which "infinite loop" the programmer is going to use in their code depends entirely on their coding habits.


Re. C sources

No problem, please post the C picture and we will try to turn it into usable O2 code. I suppose you'd also like to use it for parsing a memory string rather than the console buffer, wouldn't you? And no, the code isn't complete as it lacks the executable's main() function or its O2 global level code equivalent. But we can manage to write it ourselves if we know exactly what you're going to parse -- the console's keyboard input buffer or a memory string.
Title: Re: Construct ?
Post by: Mike Lobanovsky on May 09, 2018, 01:57:08 AM
Hi Charles,

A few more single-liner variations:

do : nextchar=getchar() : loop while nextchar=32

do : nextchar=getchar() : loop until nextchar<>32

do : nextchar=getchar() : exit when nextchar<>32 : loop

do : nextchar=getchar() : exit if not nextchar=32 : loop

Wow! That's exactly what I've been after all this time! :D

And I suppose all of them can also be used as multi-liners, can't they? By the looks of them, there's nothing that can cause syntactically unresolvable ambiguity for the compiler even if they would contain other multiply nested loops.
Title: Re: Construct ?
Post by: Charles Pegge on May 09, 2018, 02:48:55 AM
Hi Mike,

I implemented this syntax about 3 months ago. They all use the same nestable blocks system as the prior loops and conditionals in o2tran.bas

Here are some more in multiline format:

http://www.oxygenbasic.org/forum/index.php?topic=1548.0

I also considered extending this syntax for goto and gosub but I am uncertain  it would enhance the language: Do you like your imperatives to come at the beginning of a sentence? :)

gosub xx when a>b
Title: Re: Construct ?
Post by: Mike Lobanovsky on May 09, 2018, 02:59:56 AM
http://www.oxygenbasic.org/forum/index.php?topic=1548.0

Oh, I must have overlooked that thread for some reason among the others, probably due to no follow-up...

Quote
... I am uncertain  it would add clarity to the language:

gosub xx when a>b

Why not? The keyword is already there and looks clear enough syntactically IMO.

Quote
Do you like your imperatives to come at the beginning of a sentence? :)

Anyway we already have them in some of the loops and in your Do{}While one-liner. :)
Title: Re: Construct ?
Post by: Charles Pegge on May 09, 2018, 03:59:11 AM

Okay, it's only 11 lines. It will be available later today :)
Title: Re: Construct ?
Post by: Aurel on May 10, 2018, 11:47:59 AM
Thanks guys code is let say simple with stupid C constructs
in fact it is recursive descent parser but in some places should be int not string
ok here is image:

so break should break loop like exit while or exit for ..right?
Title: Re: Construct ?
Post by: Mike Lobanovsky on May 10, 2018, 01:26:33 PM
Hi Aurel,

... stupid C constructs ...

They aren't stupid; in fact, they are simply much more flexible than a BASIC'er would ever expect.

Quote
so break should break loop like exit while or exit for ..right?

Yes:

... otherwise break (i.e. stop looping)

................

... the loop is going to break (it means the code will exit from the loop)

ok here is image:

It looks like porting should be pretty straight forward.

Regarding exit(0) (https://msdn.microsoft.com/en-us/library/k9dcesdd.aspx), older C compilers used to return a non-zero program termination code to the system on default upon successful completion even though their main() function was defined as void (i.e. a Sub). To signal a failure, the program was expected to return a zero program termination code via an explicit call to exit(0) anywhere in the program code.

The program termination codes are used for conditional branching in a batch file.


[UPD]

ExprEval.o2bas: Ported to classic BASIC syntax. Works with both console buffer and memory strings. Compiles successfully in JIT and 32-/64-bit static modes.

Code: OxygenBasic
  1. '****************************************
  2. ' EXPRESSION EVALUATOR - PC Magazine 1993
  3. '****************************************
  4.  
  5. #AUTODIM OFF
  6. #LOOKAHEAD
  7.  
  8. $FILENAME "ExprEval.exe"
  9. 'INCLUDE   "rtl32.inc"
  10. 'INCLUDE   "rtl64.inc"
  11. INCLUDE   "Console.inc"
  12.  
  13. INDEXBASE 0
  14.  
  15. DIM AS LONG   idx      = 0
  16. DIM AS LONG   contin   = TRUE
  17. DIM AS BYTE   NextChar
  18. DIM AS STRING Expr // ML: may come from memory, not only from console
  19.  
  20. Main
  21.  
  22. '***********************************************************
  23. '  GetNextChar - Reads chars until a non-space char is found
  24. '***********************************************************
  25. SUB GetNextChar()
  26.         DIM AS BYTE b AT STRPTR Expr
  27.  
  28.         DO
  29.                 NextChar = b[idx]
  30.                 idx++
  31.         LOOP WHILE NextChar AND (NextChar = 32 /*Asc("0")*/) // ML: memory overrun check added
  32. END SUB
  33.  
  34. '**************************************************************
  35. ' Expression - A recursive routine that evaluates an expression
  36. ' EXPRESSION = <EXPRESSION> + TERM | <EXPRESSION> - <TERM>
  37. '**************************************************************
  38. FUNCTION Expression() AS SINGLE
  39.         DIM AS SINGLE value = Term()
  40.  
  41.         DO
  42.                 SELECT NextChar
  43.                         CASE 32 // Asc(" ")
  44.                                 GetNextChar
  45.                         CASE 43 // Asc("+")
  46.                                 GetNextChar
  47.                                 value += Term()
  48.                         CASE 45 // Asc("-")
  49.                                 GetNextChar
  50.                                 value -= Term()
  51.                         CASE ELSE
  52.                                 RETURN value
  53.                 END SELECT
  54.         LOOP
  55. END FUNCTION
  56.  
  57. '************************************************************
  58. ' Term - Handles multiplication and division
  59. ' <TERM> = <TERM> * <FACTOR> | <TERM> div <FACTOR> | <FACTOR>
  60. '************************************************************
  61. FUNCTION Term() AS SINGLE
  62.         DIM AS SINGLE divisor, value = Factor()
  63.  
  64.         DO
  65.                 SELECT NextChar
  66.                         CASE 32 // Asc(" ")
  67.                                 GetNextChar
  68.                         CASE 42 // Asc("*")
  69.                                 GetNextChar
  70.                                 value *= Factor()
  71.                         CASE 94 // Asc("^")
  72.                                 GetNextChar
  73.                                 value = value ^ Factor() // ML: ^= isn't supported in O2
  74.                         CASE 47 // Asc("/")
  75.                                 GetNextChar
  76.                                 divisor = Factor()
  77.                                 IF divisor <> 0 THEN // ML: avoid O2-specific INFinities
  78.                                         value /= divisor
  79.                                 ELSE
  80.                                         PRINT "DIVISION BY ZERO" CR CR "Press any key to exit ..."
  81.                                         WAITKEY
  82.                                         TERMINATE
  83.                                 END IF
  84.                         CASE ELSE
  85.                                 RETURN value
  86.                 END SELECT
  87.         LOOP
  88. END FUNCTION
  89.  
  90. '**************************************************
  91. ' Factor - Handles numbers, minus signs and parens
  92. ' <FACTOR> = <EXPRESSION> | <VARIABLE> | <CONSTANT>
  93. '**************************************************
  94. FUNCTION Factor() AS SINGLE
  95.         DIM AS SINGLE value = 0
  96.         DIM AS LONG i, count = 0, d_point = FALSE
  97.         DIM AS BYTE b AT STRPTR Expr
  98.  
  99.         IF (NextChar <= 57 /*Asc("9")*/) AND (NextChar >= 48 /*Asc("0")*/) THEN
  100.                 WHILE (NextChar <= 57) AND (NextChar >= 48)
  101.                         value *= 10 + NextChar - 48 // Asc("0")
  102.                         NextChar = b[idx]
  103.                         idx++
  104.                         IF d_point THEN count++
  105.                         IF NextChar = 46 /*Asc(".")*/ THEN
  106.                                 NextChar = b[idx]
  107.                                 idx++
  108.                                 d_point = TRUE
  109.                         END IF
  110.                 WEND
  111.                 FOR i = 0 TO i < count
  112.                         value /= 10
  113.                 NEXT
  114.                 RETURN value
  115.         ELSE
  116.                 SELECT NextChar
  117.                         CASE 45 // Asc("-")
  118.                                 GetNextChar
  119.                                 RETURN -1 * Factor()
  120.                         CASE 40 // Asc("(")
  121.                                 GetNextChar
  122.                                 value = Expression()
  123.                                 IF NextChar <> 41 /*Asc(")")*/ THEN
  124.                                         PRINT "MISMATCHED PARENTHESES" CR CR "Press any key to exit ..."
  125.                                         WAITKEY
  126.                                         TERMINATE
  127.                                 ELSE
  128.                                         NextChar = b[idx]
  129.                                         idx++
  130.                                 END IF
  131.                                 RETURN value
  132.                         CASE 46 // Asc(".")
  133.                                 d_point = TRUE
  134.                         CASE ELSE
  135.                                 contin = FALSE
  136.                 END SELECT
  137.         END IF
  138.         RETURN 0
  139. END FUNCTION
  140.  
  141. '***************************
  142. ' Main - Program entry point
  143. '***************************
  144. SUB MAIN()
  145.         DIM AS SINGLE result
  146.  
  147.         SetConsoleTitle "Aurel's Expression Evaluator"
  148.  
  149.         PRINT "Expression must not contain any other symbol but:" CR
  150.         PRINT "'+'      addition" CR "'-'       subtraction" CR
  151.         PRINT "'*'      multiplication" CR "'/' division" CR
  152.         PRINT "'('      left parenthesis" CR "')'       right parenthesis" CR
  153.         PRINT "'.'      decimal point (must be preceded by digit)" CR
  154.         PRINT "'^'      x^y means x to the power of y" CR CR
  155.         PRINT "ENTER EXPRESSION:        "
  156.  
  157.         Expr = INPUT // ML: try e.g. "(1+2)*(6-3)" instead of INPUT
  158.         GetNextChar
  159.         result = Expression()
  160.  
  161.         IF ((NextChar = 13 /*console*/) OR (NextChar = 0 /*memory*/)) AND contin THEN
  162.                 PRINT "RESULT IS:               " STR(result, 3)
  163.         ELSE
  164.                 PRINT "SYNTAX ERROR"
  165.         END IF
  166.         PRINT CR CR "Press any key to exit ..."
  167.         WAITKEY
  168. END SUB

Enjoy! :)
Title: Re: Construct ?
Post by: Charles Pegge on May 11, 2018, 07:04:06 PM
Many thanks, Mike.

May I include this example in the programming languages (projectsC) section?

PS:
I've remembered how to do this condition+assignment combo in o2, not that I would recommend it:

while ((a:=foo())<100)...

Code: [Select]
uses console
int foo(){ static int i : return i++}
int a
while ((a:=foo())<100){print a cr}
wait

Title: Re: Construct ?
Post by: Mike Lobanovsky on May 11, 2018, 09:54:06 PM
Of course, Charles!

I think the PC Mag's Editorial Board wouldn't mind it either since their name is in its proper place in the code.

(Ah yes, I remember seeing a similar piece of code somewhere too now that you've mentioned it. But we already have lots of freedom of expression in Oxygen's looping constructs the way they are, so evidently I didn't pay much attention to yet one more of them. :) )
Title: Re: Construct ?
Post by: Aurel on May 12, 2018, 01:30:05 AM
Fine Mike..fine...  :)

my version will be little bit different  and without console.
Also i have one from Java which is more clear to me.
Title: Re: Construct ?
Post by: Mike Lobanovsky on May 12, 2018, 04:12:14 AM
No problem Aurel, do as you like.

What regards this evaluator, it can get rid of its console input too. The main() function code may include a loop e.g. to read Expr strings from a disk file sequentially line by line. The idx variable used to traverse the Expr string is global and thus can be reset to 0 for each new line in the file in each iteration of such loop. A few minor speedups can also be introduced and whole math/trig functions added. This way the evaluator can be turned into a tiny line-by-line interpreter of math-only input.