From 1dd9f61bbc7e8890b5407ba084793817e55fe502 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 10 Mar 2021 12:37:46 +1100 Subject: [PATCH] oceani: updates for new approach to parsing indents. Now that IN is a valid stand-alone token, it makes sense to change the grammar for ocean. We don't need the ':' before an indent if there is some other terminal there. So: while statements do statements doesn't require any ':'. We use the ':' to separate an expression from following statements, in 'if' and 'while' and 'case'. Signed-off-by: NeilBrown --- csrc/oceani-tests.mdc | 54 +++---- csrc/oceani.mdc | 367 ++++++++++++++++++++---------------------- 2 files changed, 204 insertions(+), 217 deletions(-) diff --git a/csrc/oceani-tests.mdc b/csrc/oceani-tests.mdc index 54b08d0..e3739ed 100644 --- a/csrc/oceani-tests.mdc +++ b/csrc/oceani-tests.mdc @@ -163,7 +163,7 @@ Now some contants oceani_tests += "consts" ###### test: consts - const: + const pi ::= 3.141 592 653 four ::= 2 + 2 ; five ::= 10/2 const pie ::= "I like Pie"; @@ -189,12 +189,12 @@ Test merging of variables from multiple cases program: for i:=0; then i=i+1; while i < 5: - switch i + switch i: case 0: num:="zero" case 1: num:="one" case 2: num:="two" case 3: num:="three" - else: num:="many" + else num:="many" print num,", ", print @@ -214,7 +214,7 @@ Now we need to test if/else and some different loops a := 4 if a < 5: print "Success" - else: + else print "Failure" for b:=1; then b=b+b; while b < 100: print '', b, @@ -222,12 +222,12 @@ Now we need to test if/else and some different loops // Newtons method for square root of 2 target ::= 2 guess := target - for: + for count: number = 0 - while: + while current := guess * guess use +(current - target) > 0.000000001 - do: + do guess = (guess + (target / guess) ) / 2 print count, guess count = count + 1 @@ -236,7 +236,7 @@ Now we need to test if/else and some different loops for j:=0; then j = j+3 ; while j < 10: if j != 0 and then 20 / j > 3: print "20 /", j," =", 20 / j - else: + else print "I won't calculate 20 /", j pi ::= 3.1415926535897 if 355/113 == pi or else +(pi - 355/113) < 0.001: @@ -249,7 +249,7 @@ Now we need to test if/else and some different loops then { i = i+1 } while i <= 10: sum = sum + i - else: + else pass print "sum 1..10 is", sum @@ -289,7 +289,7 @@ Here I break it into two parts, keeping the array code separate. */ if A > B: bigger := "yes" - else: + else bigger := "no" print "Is", A, "bigger than", B,"? ", bigger /* If a variable is not used after the 'if', no @@ -298,7 +298,7 @@ Here I break it into two parts, keeping the array code separate. if A > B * 2: double:string = "yes" print A, "is more than twice", B, "?", double - else: + else double := B*2 print "double", B, "is", double @@ -309,15 +309,15 @@ Here I break it into two parts, keeping the array code separate. while a != b: if a < b: b = b - a - else: + else a = a - b print "GCD of", A, "and", B,"is", a else if a <= 0: print a, "is not positive, cannot calculate GCD" - else: + else print b, "is not positive, cannot calculate GCD" - for: + for togo := 10 f1 := 1; f2 := 1 print "Fibonacci:", f1,f2, @@ -331,25 +331,25 @@ Here I break it into two parts, keeping the array code separate. if bbool: print astr ++ " was the str" - else: + else print "I found the str over " ++ astr /* Binary search... */ - for: + for lo:= 0; hi := 100 target := 77 - while: + while mid := (lo + hi) / 2 if mid == target: use Found if mid < target: lo = mid - else: + else hi = mid if hi - lo < 1: use GiveUp use True - do: pass + do pass case Found: print "Yay, I found", target case GiveUp: @@ -545,7 +545,7 @@ Time to test if structure declarations and accesses work correctly. ###### test: structs - struct foo: + struct foo size:[3]number name:string active:Boolean @@ -560,7 +560,7 @@ Time to test if structure declarations and accesses work correctly. case 2: nm:= "peter" case 0: nm:= "bob" case 1: nm:= "jane" - else: nm:= "janine" + else nm:= "janine" info[i].name = nm info[i].size[0] = i*i @@ -710,7 +710,7 @@ various places that `type_err()` are called. ###### test: type_err3 - struct foo: + struct foo a: number b:string = "hello" @@ -722,11 +722,11 @@ various places that `type_err()` are called. print 45 + ( "Hello" ++ "there") c[5] = 1 - while: + while use 1 use True use "Hello" - do: + do print case 1: print "one" case "Hello": print "Hello" @@ -788,10 +788,10 @@ various places that `type_err()` are called. oceani_failing_tests += type_err_const type_err_const1 ###### test: type_err_const - const: + const foo :: number = 45 bar ::= "string" + 56 - const: + const bar ::= "baz" program: foo := 4 @@ -805,7 +805,7 @@ various places that `type_err()` are called. .tmp.code:3:8: info: this is where 'foo' was first declared ###### test: type_err_const1 - const: + const foo : number = 45 bar := "string" program: diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index 0e6cebe..97c1953 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -1004,6 +1004,7 @@ like "if" and the code following it. $void OpenScope -> ${ scope_push(c); }$ + ClosePara -> ${ var_block_close(c, CloseParallel); }$ Each variable records a scope depth and is in one of four states: @@ -1998,7 +1999,7 @@ function will be needed. } ###### top level grammar - DeclareStruct -> struct IDENTIFIER FieldBlock ${ { + DeclareStruct -> struct IDENTIFIER FieldBlock Newlines ${ { struct type *t = add_type(c, $2.txt, &structure_prototype); int cnt = 0; @@ -2017,40 +2018,28 @@ function will be needed. f = f->prev; } } }$ - | DeclareStruct NEWLINE - $void - Newlines -> NEWLINE - | Newlines NEWLINE - Open -> { - | Newlines { - Close -> } - | Newlines } $*fieldlist - FieldBlock -> Open FieldList } ${ $0 = $<2; }$ - | Open SimpleFieldList } ${ $0 = $<2; }$ - | : FieldList ${ $0 = $<2; }$ - - FieldList -> FieldLines ${ $0 = $<1; }$ - | Newlines FieldLines ${ $0 = $<2; }$ - FieldLines -> SimpleFieldListLine ${ $0 = $<1; }$ - | FieldLines SimpleFieldListLine ${ - $2->prev = $<1; - $0 = $<2; + FieldBlock -> { IN OptNL FieldLines OUT OptNL } ${ $0 = $ SimpleFieldList Newlines ${ $0 = $prev = $ SimpleFieldList NEWLINE ${ $0 = $<1; }$ - | SimpleFieldListLine NEWLINE ${ $0 = $<1; }$ - | ERROR NEWLINE ${ tok_err(c, "Syntax error in struct field", &$1); }$ - - SimpleFieldList -> Field ${ $0 = $<1; }$ + SimpleFieldList -> Field ${ $0 = $prev = $<1; - $0 = $<3; + $F->prev = $ IDENTIFIER : Type = Expression ${ { int ok; @@ -2083,7 +2072,7 @@ function will be needed. { int i; - fprintf(f, "struct %.*s:\n", t->name.len, t->name.txt); + fprintf(f, "struct %.*s\n", t->name.len, t->name.txt); for (i = 0; i < t->structure.nfields; i++) { struct field *fl = t->structure.fields + i; @@ -2816,6 +2805,7 @@ precedence is handled better I might be able to discard this. $LEFT + - Eop $LEFT * / % ++ Top $LEFT Uop + $TERM ( ) ###### expression grammar | Expression Eop Expression ${ { @@ -3052,16 +3042,35 @@ is in-place. ###### Binode types Block, +###### expr precedence + $TERM pass + ###### Grammar $*binode - Block -> Open Statementlist Close ${ $0 = $<2; }$ - | Open SimpleStatements } ${ $0 = reorder_bilist($<2); }$ - | : SimpleStatements ${ $0 = reorder_bilist($<2); }$ - | : Statementlist ${ $0 = $<2; }$ - - Statementlist -> ComplexStatements ${ $0 = reorder_bilist($<1); }$ - | Newlines ComplexStatements ${ $0 = reorder_bilist($<2); }$ + Block -> { IN OptNL Statementlist OUT OptNL } ${ $0 = $ OpenScope { IN OptNL Statementlist OUT OptNL } ${ $0 = $ { OpenScope IN OptNL Statementlist OUT OptNL } ${ $0 = $ { IN OptNL Statementlist OUT OptNL } ${ $0 = $ ComplexStatements ${ $0 = reorder_bilist($ ComplexStatements ComplexStatement ${ if ($2 == NULL) { @@ -3085,10 +3094,12 @@ is in-place. }$ $*exec - ComplexStatement -> SimpleStatementLine ${ - $0 = reorder_bilist($<1); + ComplexStatement -> SimpleStatements Newlines ${ + $0 = reorder_bilist($right = $<1; }$ - SimpleStatementLine -> SimpleStatements NEWLINE ${ $0 = $<1; }$ - | SimpleStatements ; NEWLINE ${ $0 = $<1; }$ - | SimpleStatementLine NEWLINE ${ $0 = $<1; }$ - SimpleStatement -> pass ${ $0 = NULL; }$ | ERROR ${ tok_err(c, "Syntax error in statement", &$1); }$ ## SimpleStatement Grammar @@ -3185,6 +3192,9 @@ same solution. ###### Binode types Print, +##### expr precedence + $TERM print , + ###### SimpleStatement Grammar | print ExpressionList ${ @@ -3417,6 +3427,9 @@ function. ###### Binode types Use, +###### expr precedence + $TERM use + ###### SimpleStatement Grammar | use Expression ${ $0 = new_pos(binode, $1); @@ -3565,42 +3578,59 @@ defined. ###### ComplexStatement Grammar | CondStatement ${ $0 = $<1; }$ +###### expr precedence + $TERM for then while do + $TERM else + $TERM switch case + ###### Grammar $*cond_statement - // both ForThen and Whilepart open scopes, and CondSuffix only + // A CondStatement must end with EOL, as does CondSuffix and + // IfSuffix. + // ForPart, ThenPart, SwitchPart, CasePart are non-empty and + // may or may not end with EOL + // WhilePart and IfPart include an appropriate Suffix + + + // Both ForPart and Whilepart open scopes, and CondSuffix only // closes one - so in the first branch here we have another to close. - CondStatement -> ForPart ThenPart WhilePart CondSuffix ${ - $0 = $<4; - $0->forpart = $<1; - $0->thenpart = $<2; - $0->condpart = $3.condpart; $3.condpart = NULL; - $0->dopart = $3.dopart; $3.dopart = NULL; + CondStatement -> ForPart OptNL ThenPart OptNL WhilePart CondSuffix ${ + $0 = $forpart = $thenpart = $condpart = $WP.condpart; $WP.condpart = NULL; + $0->dopart = $WP.dopart; $WP.dopart = NULL; var_block_close(c, CloseSequential); }$ - | ForPart WhilePart CondSuffix ${ - $0 = $<3; - $0->forpart = $<1; - $0->thenpart = NULL; - $0->condpart = $2.condpart; $2.condpart = NULL; - $0->dopart = $2.dopart; $2.dopart = NULL; + | ForPart OptNL WhilePart CondSuffix ${ + $0 = $forpart = $condpart = $WP.condpart; $WP.condpart = NULL; + $0->dopart = $WP.dopart; $WP.dopart = NULL; var_block_close(c, CloseSequential); }$ | WhilePart CondSuffix ${ - $0 = $<2; - $0->condpart = $1.condpart; $1.condpart = NULL; - $0->dopart = $1.dopart; $1.dopart = NULL; + $0 = $condpart = $WP.condpart; $WP.condpart = NULL; + $0->dopart = $WP.dopart; $WP.dopart = NULL; + }$ + | SwitchPart OptNL CasePart CondSuffix ${ + $0 = $condpart = $next = $0->casepart; + $0->casepart = $condpart = $<1; - $2->next = $0->casepart; - $0->casepart = $<2; + | SwitchPart : IN OptNL CasePart CondSuffix OUT Newlines ${ + $0 = $condpart = $next = $0->casepart; + $0->casepart = $condpart = $1.condpart; $1.condpart = NULL; - $0->thenpart = $1.thenpart; $1.thenpart = NULL; + $0 = $condpart = $IP.condpart; $IP.condpart = NULL; + $0->thenpart = $IP.thenpart; $IP.thenpart = NULL; // This is where we close an "if" statement var_block_close(c, CloseSequential); }$ @@ -3611,126 +3641,83 @@ defined. // "for" or "while" statement var_block_close(c, CloseSequential); }$ + | Newlines CasePart CondSuffix ${ + $0 = $next = $0->casepart; + $0->casepart = $next = $0->casepart; - $0->casepart = $<1; + $0 = $next = $0->casepart; + $0->casepart = $ case Expression OpenScope Block ${ - $0 = calloc(1,sizeof(struct casepart)); - $0->value = $<2; - $0->action = $<4; - var_block_close(c, CloseParallel); - }$ - | CasePart NEWLINE ${ $0 = $<1; }$ + IfSuffix -> Newlines ${ $0 = new(cond_statement); }$ + | Newlines ElsePart ${ $0 = $ ${ $0 = new(cond_statement); }$ - | IfSuffix NEWLINE ${ $0 = $<1; }$ - | else OpenScope Block ${ + ElsePart -> else OpenBlock Newlines ${ $0 = new(cond_statement); - $0->elsepart = $<3; - var_block_close(c, CloseElse); - }$ - | else OpenScope SimpleStatements NEWLINE ${ - $0 = new(cond_statement); - $0->elsepart = reorder_bilist($<3); + $0->elsepart = $elsepart = $<3; + $0->elsepart = $ case Expression OpenScope ColonBlock ${ + $0 = calloc(1,sizeof(struct casepart)); + $0->value = $action = $ for OpenScope SimpleStatements ; ${ - $0 = reorder_bilist($<3); + ForPart -> for OpenBlock ${ + $0 = $ then OpenScope SimpleStatements ; ${ - $0 = reorder_bilist($<3); - var_block_close(c, CloseSequential); - }$ - | then OpenScope SimpleStatements NEWLINE ${ - $0 = reorder_bilist($<3); + ThenPart -> then OpenBlock ${ + $0 = $ while OpenScope Block ${ $0 = $<3; }$ - | WhileHead NEWLINE ${ $0 = $<1; }$ $cond_statement // This scope is closed in CondSuffix - WhilePart -> while OpenScope Expression Block ${ - $0.type = Xcond_statement; - $0.condpart = $<3; - $0.dopart = $<4; + WhilePart -> while UseBlock OptNL do Block ${ + $0.condpart = $ if OpenScope Expression OpenScope Block ${ - $0.type = Xcond_statement; - $0.condpart = $<3; - $0.thenpart = $<5; - var_block_close(c, CloseParallel); - }$ - | if OpenScope Expression OpenScope then Block ${ - $0.type = Xcond_statement; - $0.condpart = $<3; - $0.thenpart = $<6; - var_block_close(c, CloseParallel); - }$ - | if OpenScope Expression OpenScope then SimpleStatements ; ${ - $0.type = Xcond_statement; - $0.condpart = $<3; - $0.thenpart = reorder_bilist($<6); - var_block_close(c, CloseParallel); + IfPart -> if UseBlock OptNL then OpenBlock ClosePara ${ + $0.condpart = $ switch OpenScope Expression ${ - $0 = $<3; + $0 = $forpart) { do_indent(indent, "for"); - if (bracket) printf(" {\n"); else printf(":\n"); + if (bracket) printf(" {\n"); else printf("\n"); print_exec(cs->forpart, indent+1, bracket); if (cs->thenpart) { if (bracket) do_indent(indent, "} then {\n"); else - do_indent(indent, "then:\n"); + do_indent(indent, "then\n"); print_exec(cs->thenpart, indent+1, bracket); } if (bracket) do_indent(indent, "}\n"); @@ -3758,12 +3745,12 @@ defined. if (bracket) do_indent(indent, "while {\n"); else - do_indent(indent, "while:\n"); + do_indent(indent, "while\n"); print_exec(cs->condpart, indent+1, bracket); if (bracket) do_indent(indent, "} do {\n"); else - do_indent(indent, "do:\n"); + do_indent(indent, "do\n"); print_exec(cs->dopart, indent+1, bracket); if (bracket) do_indent(indent, "}\n"); @@ -3828,7 +3815,7 @@ defined. if (bracket) printf(" {\n"); else - printf(":\n"); + printf("\n"); print_exec(cs->elsepart, indent+1, bracket); if (bracket) do_indent(indent, "}\n"); @@ -3967,20 +3954,23 @@ various declarations in the parse context. ###### Parser: grammar $void - Ocean -> DeclarationList - | Newlines DeclarationList + Ocean -> OptNL DeclarationList + + OptNL -> + | OptNL NEWLINE + Newlines -> NEWLINE + | Newlines NEWLINE DeclarationList -> Declaration | DeclarationList Declaration - Declaration -> Declaration NEWLINE - | DeclareConstant - | DeclareProgram - | DeclareStruct - | ERROR NEWLINE ${ + Declaration -> ERROR Newlines ${ tok_err(c, "error: unhandled parse error", &$1); }$ + | DeclareConstant + | DeclareProgram + | DeclareStruct ## top level grammar @@ -4009,21 +3999,18 @@ searching through for the Nth constant for decreasing N. ###### top level grammar - DeclareConstant -> const Open ConstList Close - | const Open SimpleConstList } - | const : ConstList - | const SimpleConstList NEWLINE + DeclareConstant -> const { IN OptNL ConstList OUT OptNL } Newlines + | const { SimpleConstList } Newlines + | const IN OptNL ConstList OUT Newlines + | const SimpleConstList Newlines - ConstList -> ConstLines - | Newlines ConstLines - ConstLines -> ConstLines SimpleConstLine + ConstList -> ConstList SimpleConstLine | SimpleConstLine SimpleConstList -> SimpleConstList ; Const | Const | SimpleConstList ; - SimpleConstLine -> SimpleConstList NEWLINE - | SimpleConstLine NEWLINE - | ERROR NEWLINE ${ tok_err(c, "Syntax error in constant", &$1); }$ + SimpleConstLine -> SimpleConstList Newlines + | ERROR Newlines ${ tok_err(c, "Syntax error in constant", &$1); }$ $*type CType -> Type ${ $0 = $<1; }$ @@ -4073,7 +4060,7 @@ searching through for the Nth constant for decreasing N. if (target == -1) { if (i) - printf("const:\n"); + printf("const\n"); target = i; } else { printf(" %.*s :: ", v->name->name.len, v->name->name.txt); @@ -4118,11 +4105,11 @@ analysis is a bit more interesting at this level. } }$ $*binode - Program -> program OpenScope Varlist Block ${ + Program -> program OpenScope Varlist ColonBlock Newlines ${ $0 = new(binode); $0->op = Program; - $0->left = reorder_bilist($<3); - $0->right = $<4; + $0->left = reorder_bilist($right = $scope_stack && !c->parse_error) abort(); }$ @@ -4246,14 +4233,14 @@ things which will likely grow as the languages grows. ###### demo: hello - const: + const pi ::= 3.141_592_6 four ::= 2 + 2 ; five ::= 10/2 const pie ::= "I like Pie"; cake ::= "The cake is" ++ " a lie" - struct fred: + struct fred size:[four]number name:string alive:Boolean @@ -4268,7 +4255,7 @@ things which will likely grow as the languages grows. */ if A > B: bigger := "yes" - else: + else bigger := "no" print "Is", A, "bigger than", B,"? ", bigger /* If a variable is not used after the 'if', no @@ -4277,7 +4264,7 @@ things which will likely grow as the languages grows. if A > B * 2: double:string = "yes" print A, "is more than twice", B, "?", double - else: + else double := B*2 print "double", B, "is", double @@ -4288,15 +4275,15 @@ things which will likely grow as the languages grows. while a != b: if a < b: b = b - a - else: + else a = a - b print "GCD of", A, "and", B,"is", a else if a <= 0: print a, "is not positive, cannot calculate GCD" - else: + else print b, "is not positive, cannot calculate GCD" - for: + for togo := 10 f1 := 1; f2 := 1 print "Fibonacci:", f1,f2, @@ -4309,21 +4296,21 @@ things which will likely grow as the languages grows. print "" /* Binary search... */ - for: + for lo:= 0; hi := 100 target := 77 - while: + while mid := (lo + hi) / 2 if mid == target: use Found if mid < target: lo = mid - else: + else hi = mid if hi - lo < 1: use GiveUp use True - do: pass + do pass case Found: print "Yay, I found", target case GiveUp: -- 2.43.0