duskos

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

commit 72a30850cbf1f59f0fa5f473a411e1f48e041212
parent ca88f0459fc93a4517d1181349113c3ee523fafb
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Sat, 18 Mar 2023 22:50:02 -0400

halcc: introduce the Result structure

I think it's going to end up looking pretty nice...

Diffstat:
Mfs/comp/c/egen.fs | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mfs/comp/c/fgen.fs | 23+++++++++++++++--------
Afs/comp/c/func.fs | 10++++++++++
Afs/comp/c/op.fs | 37+++++++++++++++++++++++++++++++++++++
Mfs/comp/c/type.fs | 6++++++
Mfs/tests/comp/c/cc.fs | 2+-
Mfs/tests/comp/c/test2.c | 5+++++
7 files changed, 141 insertions(+), 21 deletions(-)

diff --git a/fs/comp/c/egen.fs b/fs/comp/c/egen.fs @@ -1,5 +1,8 @@ \ Expression code generation +require /sys/scratch.fs ?f<< /comp/c/tok.fs +?f<< /comp/c/op.fs +?f<< /comp/c/func.fs : _err ( -- ) tokdbg abort" egen error" ; : _assert ( f -- ) not if _err then ; @@ -15,8 +18,28 @@ Arena :new structbind Arena _litarena \ Maximum size in bytes that a single literal can have $400 const MAXLITSZ -alias noop parseExpression ( tok -- ) \ forward declaration -alias noop parseFactor ( tok -- ) \ forward declaration +struct[ Result + 0 const CONST \ Is a constant (value in arg) + 1 const W \ Value in W register + 2 const HALOP \ Value in memory, HAL operand is in arg. + sfield type + sfield arg \ either HAL operand or constant value + + : :new ( arg type -- res ) SZ syspad :allot dup >r !+ ! r> ; + : :const ( n -- res ) CONST :new ; + : :W ( -- res ) 0 W :new ; + : :hal ( operand -- res ) HALOP :new ; + + : :>W ( self -- ) dup bi arg | type case ( self arg ) + CONST of = LIT>W, endof + W of = drop endof + HALOP of = @, endof + _err endcase W swap to type ; + : :hal# ( self -- halop ) dup type HALOP = _assert arg ; +]struct + +alias noop parseExpression ( tok -- res ) \ forward declaration +alias noop parseFactor ( tok -- res ) \ forward declaration \ A factor can be: \ 1. A constant @@ -29,29 +52,61 @@ alias noop parseFactor ( tok -- ) \ forward declaration \ 8. a typecast followed by a factor \ 9. NULL \ 10. sizeof() -: _ ( tok -- operand isconst? ) case ( ) +: _ ( tok -- res ) case ( ) '(' of isChar?^ abort" TODO" endof '"' of isChar?^ MAXLITSZ _litarena :[ here 0 c, ['] ," with-stdin< ccin dup '0' = if drop 1+ 0 c, \ null terminated else ccputback here over - 1- over c! then ( saddr ) - _litarena :] drop ( "a ) 1 endof + _litarena :] drop ( "a ) Result :const endof '{' of isChar?^ abort" TODO" endof S" pspop" of s= abort" TODO" endof - S" NULL" of s= 0 1 endof - S" sizeof" of s= read( nextt parseType _assert typesize 1 read) endof - \ of uopid ( opid ) abort" TODO" endof - of isIdent? abort" TODO" endof \ lvalue, FunCall or macro - r@ parse if 1 else _err then + S" NULL" of s= 0 Result :const endof + S" sizeof" of s= + read( nextt parseType _assert typesize Result :const read) endof + of uopid ( opid ) abort" TODO" endof + of isIdent? \ lvalue, FunCall or macro + r@ findIdent ?dup _assert CType :halop Result :hal ( parsePostfixOp ) endof + r@ parse if Result :const else _err then endcase ; current ' parseFactor realias +: binop doer ' , does> @ ( left right w ) + rot Result :>W swap Result :hal# swap execute Result :W ; +binop _+, +, + +: _=, ( left right ) Result :>W Result :hal# !, Result :W ; + +BOPSCNT wordtbl _tbl ( -- ) +'w _+, 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err +'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err +'w _err 'w _err 'w _=, 'w _err 'w _err 'w _err 'w _err 'w _err +'w _err 'w _err 'w _err 'w _err 'w _err 'w _err 'w _err + +: applyBinop ( left right opid -- res ) _tbl swap wexec ; + +\ Parse the "right" part of an expression with the leftmost factor and leftmost +\ binary operator already parsed. +: parseRExpr ( left binop -- res ) >r >r \ V1=binop V2=left + nextt parseFactor nextt ( right tok ) + dup bopid if ( right tok opright ) + \ another binop! let's apply precedence rules. + nip V1 bopprec over bopprec ( right opright lprec rprec ) > if + \ the right part has more precedence. + parseRExpr ( newright ) r> swap r> ( left right opid ) applyBinop + else ( right opright ) \ the left part has more precedence + swap r> swap r> ( opright left right opid ) applyBinop ( opr newleft ) + swap parseRExpr then + else ( right tok ) to nexttputback r> swap r> applyBinop then ; + \ An expression can be 2 things: \ 1. a factor -\ 3. A binaryop containing two expressions. -: _ ( tok -- operand isconst? ) \ parseExpression +\ 2. A binaryop containing two expressions. +: _ ( tok -- res ) \ parseExpression \ first tok is always a factor - parseFactor ; + parseFactor nextt ( left tok ) + dup bopid if ( left tok binop ) + nip parseRExpr else to nexttputback then ; current ' parseExpression realias diff --git a/fs/comp/c/fgen.fs b/fs/comp/c/fgen.fs @@ -1,18 +1,16 @@ \ Function code generation ?f<< /lib/arena.fs ?f<< /comp/c/tok.fs +?f<< /comp/c/func.fs ?f<< /comp/c/egen.fs : _err ( -- ) tokdbg abort" fgen error" ; : _assert ( f -- ) not if _err then ; -0 value _curfunc \ ctype of the current function (includes arguments) -0 value _locvars \ the root ctype of local variables for current function - : _postlude _curfunc CType :argssize ?dup if ps+, then _locvars CType :size rs+, ; -: emitRet ( operand isconst? -- ) if LIT>W, else @, then _postlude exit, ; +: emitRet ( res -- ) Result :>W _postlude exit, ; : emitNullRet ( -- ) _postlude drop, exit, ; alias noop parseStatement ( tok -- ) \ forward declaration @@ -33,13 +31,21 @@ alias noop parseStatement ( tok -- ) \ forward declaration 0 value _laststmtid : _ ( tok -- ) \ parseStatement dup statementnames sfind dup >r dup 0< if ( tok -1 ) \ V1=stmtidx - drop parseExpression 2drop read; else nip statementhandler swap wexec then + drop parseExpression drop read; else nip statementhandler swap wexec then r> to _laststmtid ; current ' parseStatement realias + +\ When there's variable initialization code, it has to come before the prelude +\ and we jump to it after we've created the stack frame. +0 value _initcode + : parseDeclLine ( type -- ) parseDeclarator ( ctype ) dup _locvars ?dup if CType :append else to _locvars then begin ( ctype ) - '=' readChar? if ( ctype ) abort" TODO" then ( ctype tok ) + '=' readChar? if ( ctype ) + _initcode not if here to _initcode then + nextt parseExpression ( ctype res ) + Result :>W dup CType :halop !, nextt then ( ctype tok ) dup ';' isChar? not while ( ctype tok ) ',' expectChar CType type parseDeclarator ( ctype ) dup _locvars CType :append repeat ( ctype tok ) 2drop ; @@ -57,15 +63,17 @@ current ' parseStatement realias \ '{' is already parsed : parseFunctionBody ( ctype -- ) - 0 to _locvars to _curfunc _litarena :reserve ( ) + 0 to _locvars 0 to _initcode to _curfunc _litarena :reserve ( ) STORAGE_SF to@! curstorage >r begin nextt dup parseType while ( tok type ) nip parseDeclLine repeat ( tok ) to nexttputback r> to curstorage + _initcode if [compile] ahead >r then _curfunc CType :static? not if sysdict _curfunc CType name entry then ( ) here _curfunc to CType offset ( ) _curfunc ?updateFunctionPrototype _curfunc addSymbol \ prelude: space for stack frame. "dup," is wiggle room for W dup, _locvars CType :size neg rs+, + _initcode ?dup if [compile] again r> [compile] then then 0 to _laststmtid parseStatements _laststmtid 1 <> if emitRet then \ emit implicit return if needed 0 to _curfunc ; @@ -78,4 +86,3 @@ current ' parseStatement realias else dup CType name sysdict @ find ?dup not if CType name stype abort" not found" then then ( ctype addr ) swap to CType offset ; - diff --git a/fs/comp/c/func.fs b/fs/comp/c/func.fs @@ -0,0 +1,10 @@ +\ Function metadata +?f<< /comp/c/type.fs + +0 value _curfunc \ ctype of the current function (includes arguments) +0 value _locvars \ the root ctype of local variables for current function + +: findIdent ( name -- ctype-or-0 ) + _curfunc if dup _curfunc CType :find ?dup if nip exit then then ( name ) + dup _locvars if to' _locvars CType :find else drop 0 then ( name ctype-or-0 ) + ?dup if nip else findSymbol then ; diff --git a/fs/comp/c/op.fs b/fs/comp/c/op.fs @@ -0,0 +1,37 @@ +\ Operators +?f<< /lib/str.fs + +\ Unary operators +7 const UOPSCNT +UOPSCNT stringlist UOPTlist "-" "~" "!" "&" "*" "++" "--" + +: uopid ( tok -- opid? f ) + UOPTlist sfind dup 0< if drop 0 else 1 then ; +: uoptoken ( opid -- tok ) UOPTlist slistiter ; + +\ Postfix operators +2 const POPSCNT +POPSCNT stringlist POPTlist "++" "--" + +: popid ( tok -- opid? f ) + POPTlist sfind dup 0< if drop 0 else 1 then ; +: poptoken ( opid -- tok ) POPTlist slistiter ; + +\ Binary operators +31 const BOPSCNT +BOPSCNT stringlist BOPTlist + "+" "-" "*" "/" "%" "<<" ">>" "<" ">" "<=" ">=" "==" "!=" "&" "^" "|" + "&&" "||" "=" "+=" "-=" "*=" "/=" "%=" "<<=" ">>=" "&=" "^=" "|=" "?" ":" + +\ binary ops precedence. lower means more precedence +create bopsprectbl BOPSCNT nc, + 1 1 0 0 0 2 2 3 3 3 3 4 4 5 5 5 + 6 6 7 7 7 7 7 7 7 7 7 7 7 8 9 + +: bopid ( tok -- opid? f ) + BOPTlist sfind dup 0< if drop 0 else 1 then ; +: bopidconst ( tok -- opid? f ) \ bopid, but only for const ops + bopid dup if over 17 > if 2drop 0 then then ; +: bopprec ( opid -- precedence ) BOPSCNT min bopsprectbl + c@ ; +: boptoken ( opid -- tok ) BOPTlist slistiter ; +: ptrbop? ( opid -- f ) 2 < ; \ can op be applied to pointers? diff --git a/fs/comp/c/type.fs b/fs/comp/c/type.fs @@ -104,6 +104,12 @@ struct[ CType : :isarg? ( dnode -- f ) storage STORAGE_PS = ; : :isglobal? ( dnode -- f ) storage STORAGE_MEM = ; + : :halop ( self -- operand ) dup bi offset | storage case ( self offset ) + STORAGE_SF of = RSP) swap +) endof + STORAGE_PS of = PSP) swap +) endof + STORAGE_MEM of = m) endof _err endcase ( self operand ) + swap type _typesize case 1 of = 8b) endof 2 of = 16b) endof endcase ; + \ Combined size of all fields in the LL. : :size ( self -- size ) dup :isarg? over :funcsig? or if drop CELLSZ exit then diff --git a/fs/tests/comp/c/cc.fs b/fs/tests/comp/c/cc.fs @@ -5,8 +5,8 @@ testbegin \ Tests for the C compiler cc<< tests/comp/c/test2.c retconst 42 #eq -testend \s variables 82 #eq +testend \s negate -42 #eq bwnot $ffffffd5 #eq exprbinops 7 #eq diff --git a/fs/tests/comp/c/test2.c b/fs/tests/comp/c/test2.c @@ -8,3 +8,8 @@ short retconst() { return 42; } +short variables() { + short foo = 40, _bar = 2; + _bar = foo + _bar; + return foo + _bar; +}