duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit a9450f9f284adb643d7424b9a803858847947d16
parent 197fd5e4f114f4b5ea88f605098625adea132a57
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Wed, 15 Jun 2022 20:56:00 -0400

cc: simplify cc/ast's assign parsing

Things get much simpler when you treat assign as it is: just another binop.

Diffstat:
Mfs/cc/ast.fs | 171++++++++++++++++++++++++++++++-------------------------------------------------
Mfs/cc/gen.fs | 33++++++++++++++++-----------------
2 files changed, 80 insertions(+), 124 deletions(-)

diff --git a/fs/cc/ast.fs b/fs/cc/ast.fs @@ -3,47 +3,25 @@ \ An abstract syntax tree, AST, is a hierarchical structure of nodes \ representing the nodes found in a C source file. See tree.fs for structure. -\ Unary operators for expressions -\ ID Sym Name -\ 0 - Negate -\ 1 ~ Complement -\ 2 ! Not - -3 const UOPSCNT -create uopssyms ," -~!?" +\ Unary operators +5 const UOPSCNT +create uopssyms ," -~!&*?" : uopid ( tok -- opid? f ) c@+ 1 = if c@ uopssyms UOPSCNT [c]? dup 0< if drop 0 else 1 then else drop 0 then ; : uopchar ( opid -- c ) UOPSCNT min uopssyms + c@ ; -\ Unary operators for lvalues -\ ID Sym Name -\ 0 & Reference -\ 1 * Dereference -2 const LOPSCNT -create lopssyms ," &*?" - -: lopid ( tok -- opid? f ) - c@+ 1 = if c@ lopssyms LOPSCNT [c]? dup 0< if drop 0 else 1 then - else drop 0 then ; -: lopchar ( opid -- c ) LOPSCNT min lopssyms + c@ ; - \ Binary operators -\ ID Sym Name -\ 0 + Addition -\ 1 - Subtraction -\ 2 * Multiplication -\ 3 / Division - -12 const BOPSCNT +13 const BOPSCNT create BOPTlist 1 c, ," +" 1 c, ," -" 1 c, ," *" 1 c, ," /" 1 c, ," <" 1 c, ," >" 2 c, ," <=" 2 c, ," >=" 2 c, ," ==" 2 c, ," !=" 2 c, ," &&" 2 c, ," ||" + 1 c, ," =" 0 c, \ binary ops precedence. lower means more precedence create bopsprectbl 1 c, 1 c, 0 c, 0 c, 2 c, 2 c, 2 c, 2 c, - 3 c, 3 c, 4 c, 4 c, + 3 c, 3 c, 4 c, 4 c, 5 c, : bopid ( tok -- opid? f ) BOPTlist sfind dup 0< if drop 0 else 1 then ; @@ -61,9 +39,9 @@ create bopsprectbl 1 c, 1 c, 0 c, 0 c, 2 c, 2 c, 2 c, 2 c, 6 const AST_ARGSPECS 7 const AST_LVALUE \ data1=varname 8 const AST_UNARYOP \ data1=uopid -9 const AST_ASSIGN +\ 9 = unused 10 const AST_BINARYOP \ data1=bopid -11 const AST_LVALUEOP \ data1=lopid +\ 11 = unused 12 const AST_IF \ 13 = unused 14 const AST_FUNCALL \ data1=name data2=MAP_FUNCTION @@ -71,7 +49,7 @@ create bopsprectbl 1 c, 1 c, 0 c, 0 c, 2 c, 2 c, 2 c, 2 c, create astidnames 7 c, ," declare" 4 c, ," unit" 8 c, ," function" 6 c, ," return" 8 c, ," constant" 5 c, ," stmts" 4 c, ," args" 6 c, ," lvalue" 7 c, ," unaryop" - 6 c, ," assign" 5 c, ," binop" 6 c, ," lvalop" + 1 c, ," _" 5 c, ," binop" 1 c, ," _" 2 c, ," if" 1 c, ," _" 4 c, ," call" 0 c, @@ -95,10 +73,10 @@ ASTIDCNT wordtbl astdatatbl ( node -- node ) 'w noop ( ArgSpecs ) 'w _s ( LValue ) :w ( UnaryOp ) _[ dup data1 uopchar emit _] ; -'w noop ( Assign ) +'w noop ( unused ) :w ( BinaryOp ) _[ dup data1 boptoken stype _] ; -:w ( LvalueOp ) _[ dup data1 lopchar emit _] ; 'w noop ( Unused ) +'w noop ( If ) 'w noop ( Unused ) 'w _s ( FunCall ) @@ -117,9 +95,8 @@ ASTIDCNT wordtbl astdatatbl ( node -- node ) \ if not 0, next _nextt call will fetch token from here 0 value nexttputback -: _err ( tok -- ) - stype spc> abort" parsing error" ; -: _assert ( tok f -- ) not if _err then ; +: _err ( -- ) abort" parsing error" ; +: _assert ( f -- ) not if _err then ; : _nextt nexttputback ?dup if 0 to nexttputback exit then nextt ?dup not if abort" expecting token!" then ; @@ -139,71 +116,61 @@ ASTIDCNT wordtbl astdatatbl ( node -- node ) \ Parse words -\ Parse a Lvalue wrapped in its unaryops (AST_LVALUEOP) if there are any. -: parseLvalue ( tok -- lvnode ) - dup lopid if ( tok opid ) - nip AST_LVALUEOP createnode swap , ( lopnode ) - _nextt parseLvalue ( lopnode lvnode ) over addnode - else ( tok ) expectIdent AST_LVALUE createnode swap , then ; - -\ parse a constant, variable or function call +\ A factor can be: +\ 1. A constant +\ 2. A Lvalue +\ 3. A unaryop containing a factor +\ 4. A function call : parseFactor ( tok -- node-or-0 ) - dup isIdent? if \ lvalue or FunCall - _nextt ( prevtok newtok ) dup S" (" s= if \ FunCall - drop AST_FUNCALL createnode swap , begin ( node ) - _nextt dup parseFactor ?dup if \ an argument - nip over addnode - _nextt dup S" ," s= if drop else to nexttputback then 0 - else \ not an argument - ')' expectChar 1 then until ( node ) - else \ lvalue - to nexttputback parseLvalue then - else \ Constant - parse if AST_CONSTANT createnode swap , else 0 then + dup uopid if ( tok opid ) + nip AST_UNARYOP createnode swap , ( opnode ) + _nextt parseFactor ?dup _assert over addnode ( opnode ) + else ( tok ) + dup isIdent? if \ lvalue or FunCall + _nextt ( prevtok newtok ) dup S" (" s= if \ FunCall + drop AST_FUNCALL createnode swap , begin ( node ) + _nextt dup parseFactor ?dup if \ an argument + nip over addnode + _nextt dup S" ," s= if drop else to nexttputback then 0 + else \ not an argument + ')' expectChar 1 then until ( node ) + else \ lvalue + to nexttputback AST_LVALUE createnode swap , then + else \ Constant + parse if AST_CONSTANT createnode swap , else 0 then + then then ; -: parseUnaryOp ( tok -- opid? astid? f ) - dup uopid if - nip AST_UNARYOP 1 else lopid if - AST_LVALUEOP 1 else 0 then then ; - -\ An expression can be 3 things: +\ An expression can be 2 things: \ 1. a factor -\ 2. an unaryop containing an expression \ 3. A binaryop containing two expressions. : parseExpression ( tok -- exprnode ) - dup parseUnaryOp if ( tok opid astid ) - createnode ( tok opid node ) swap , nip ( node ) - _nextt parseExpression ( uopnode expr ) - over addnode ( node ) - else ( tok ) \ binaryop or factor - \ tok is expected to be a factor - parseFactor ?dup _assert _nextt ( factor nexttok ) - dup bopid if ( factor tok binop ) - nip ( factor binop ) AST_BINARYOP createnode swap , ( factor node ) - tuck addnode _nextt ( binnode tok ) - \ now, let's consume tokens as long as we have binops coming. - begin ( bn tok ) - parseFactor ?dup _assert _nextt ( bn factor tok ) dup bopid if ( bn fn tok bopid ) - nip AST_BINARYOP createnode swap , ( bn1 fn bn2 ) - \ another binop! who will get fn? bn1 or bn2? the one that has the - \ best precedence! - rot ( fn bn2 bn1 ) over data1 bopprec over data1 bopprec < if - \ bn2 wins. add fn to bn2, add bn2 to bn1, bn2 becomes bn - rot> tuck addnode ( bn1 bn2 ) dup rot addnode ( bn2->bn ) - else \ bn1 wins. add fn to bn1, bn1 to bn2, bn2 becomes bn - rot over addnode ( bn2 bn1 ) over addnode ( bn2->bn ) - then ( bn ) - _nextt 0 ( bn tok 0 ) - else ( bn fn tok ) \ not a binop - \ tok becomes nexttok and we add fn to bn to complete the chain - rot> over addnode swap 1 ( bn tok 1 ) then - until ( bn tok ) - \ bn is not necessarily our result, the root node is. - swap rootnode swap - then \ if not binop we have nothing to do, we're done - ( node tok ) to nexttputback - then ; + \ tok is expected to be a factor + parseFactor ?dup _assert _nextt ( factor nexttok ) + dup bopid if ( factor tok binop ) + nip ( factor binop ) AST_BINARYOP createnode swap , ( factor node ) + tuck addnode _nextt ( binnode tok ) + \ now, let's consume tokens as long as we have binops coming. + begin ( bn tok ) + parseFactor ?dup _assert _nextt ( bn factor tok ) dup bopid if ( bn fn tok bopid ) + nip AST_BINARYOP createnode swap , ( bn1 fn bn2 ) + \ another binop! who will get fn? bn1 or bn2? the one that has the + \ best precedence! + rot ( fn bn2 bn1 ) over data1 bopprec over data1 bopprec < if + \ bn2 wins. add fn to bn2, add bn2 to bn1, bn2 becomes bn + rot> tuck addnode ( bn1 bn2 ) dup rot addnode ( bn2->bn ) + else \ bn1 wins. add fn to bn1, bn1 to bn2, bn2 becomes bn + rot over addnode ( bn2 bn1 ) over addnode ( bn2->bn ) + then ( bn ) + _nextt 0 ( bn tok 0 ) + else ( bn fn tok ) \ not a binop + \ tok becomes nexttok and we add fn to bn to complete the chain + rot> over addnode swap 1 ( bn tok 1 ) then + until ( bn tok ) + \ bn is not necessarily our result, the root node is. + swap rootnode swap + then \ if not binop we have nothing to do, we're done + ( node tok ) to nexttputback ; : parseDeclare ( parentnode -- dnode ) 0 begin ( pnode *lvl ) @@ -213,7 +180,7 @@ ASTIDCNT wordtbl astdatatbl ( node -- node ) : parseDeclarationList ( stmtsnode -- ) parseDeclare _nextt '=' expectChar dup data1 ( dnode name ) - swap parentnode AST_ASSIGN newnode ( name anode ) + swap parentnode AST_BINARYOP newnode ( name anode ) 12 ( = ) , AST_LVALUE newnode ( name lvnode ) swap , parentnode ( anode ) _nextt parseExpression read; ( anode expr ) swap addnode ; @@ -225,16 +192,6 @@ ASTIDCNT wordtbl astdatatbl ( node -- node ) _nextt dup S" )" s= if 2drop exit then ',' expectChar _nextt again ; -\ Parse an assignment statement. It consists of a '=' char with an lvalue on -\ the left and an expression on the right. The left part can have LValue ops -\ applied to it. -: parseAssign ( parent tok -- ) - \ --> assign(lvalue, expr) - swap AST_ASSIGN newnode swap ( anode tok ) - parseLvalue ( anode lvnode ) over addnode ( anode ) - _nextt '=' expectChar ( anode ) - _nextt parseExpression read; ( anode expr ) swap addnode ; - alias noop parseStatements ( funcnode -- ) \ forward declaration create statementnames 6 c, ," return" 2 c, ," if" 0 c, @@ -258,7 +215,7 @@ create statementnames 6 c, ," return" 2 c, ," if" 0 c, dup S" }" s= if 2drop exit then dup statementnames sfind dup 0< if ( snode tok -1 ) drop dup isType? if drop dup parseDeclarationList else ( snode tok ) - over rot> parseAssign then ( snode ) + parseExpression over addnode read; then ( snode ) else ( snode tok idx ) nip statementhandler swap wexec then ( snode ) _nextt again ; current to parseStatements diff --git a/fs/cc/gen.fs b/fs/cc/gen.fs @@ -6,15 +6,12 @@ : _err ( node -- ) printast abort" unexpected node" ; UOPSCNT wordtbl uopgentbl ( -- ) -'w vmneg, ( - ) -'w vmnot, ( ~ ) -'w vmboolnot, ( ! ) - -LOPSCNT wordtbl lopgentbl ( -- ) +:w ( - ) operand?>result vmneg, ; +:w ( ~ ) operand?>result vmnot, ; +:w ( ! ) operand?>result vmboolnot, ; 'w operand>&operand ( & ) 'w operand>[operand] ( * ) -\ In binary Ops, the result is in EAX and the source operand is EBX. BOPSCNT wordtbl bopgentblmiddle ( node -- node ) 'w noop ( + ) 'w noop ( - ) @@ -28,6 +25,7 @@ BOPSCNT wordtbl bopgentblmiddle ( node -- node ) 'w noop ( != ) :w ( && ) vmjz, swap ; :w ( || ) vmjnz, swap ; +'w noop ( = ) BOPSCNT wordtbl bopgentblpost ( -- ) 'w vmadd, ( + ) @@ -42,6 +40,7 @@ BOPSCNT wordtbl bopgentblpost ( -- ) :w ( != ) abort" TODO" ; 'w vmjmp! ( && ) 'w vmjmp! ( || ) +'w noop ( = ) alias noop gennode ( node -- ) \ forward declaration @@ -55,6 +54,14 @@ alias noop gennode ( node -- ) \ forward declaration dup data1 swap getfuncmap ( name funcentry ) findvarinmap ( varentry ) vmap.sfoff ; +\ special binop case +: _assign ( node -- ) + firstchild ?dup not if _err then ( lvnode ) + dup nextsibling ?dup not if _err then ( lvnode exprnode ) + gennode operand?>result \ result=set + gennode \ operand=set + result>operand ; + ASTIDCNT wordtbl gentbl ( node -- ) 'w drop ( Declare ) 'w genchildren ( Unit ) @@ -75,15 +82,9 @@ ASTIDCNT wordtbl gentbl ( node -- ) :w ( LValue ) lvsfoff sf+>operand ; :w ( UnaryOp ) dup genchildren - operand?>result data1 uopgentbl swap wexec ; -:w ( Assign ) - firstchild ?dup not if _err then ( lvnode ) - dup nextsibling ?dup not if _err then ( lvnode exprnode ) - gennode operand?>result \ result=set - gennode \ operand=set - result>operand ; -:w ( BinaryOp ) +'w _err ( unused ) +:w ( BinaryOp ) dup data1 12 = if _assign exit then ( node ) >r r@ childcount 2 = not if abort" binop node with more than 2 children!" then r@ firstchild dup nextsibling swap ( n2 n1 ) @@ -93,9 +94,7 @@ ASTIDCNT wordtbl gentbl ( node -- ) pushresult, gennode operand?>result popresult, else gennode operand?>result then bopgentblpost r> data1 wexec ; -:w ( LValueOp ) - dup firstchild ?dup not if _err then gennode - data1 lopgentbl swap wexec ; +'w _err ( unused ) :w ( If ) firstchild ?dup not if _err then dup gennode ( exprnode ) operand?>result vmjz, swap ( jump_addr exprnode )