~vdupras/duskos

778f643dbfe9a81ee03f6dc26f8a841f5b8717af — Virgil Dupras a month ago 5693daf
halcc: fix complex declaration parsing
3 files changed, 39 insertions(+), 32 deletions(-)

M fs/comp/c/ptype.fs
M fs/comp/c/type.fs
M fs/tests/comp/c/type.fs
M fs/comp/c/ptype.fs => fs/comp/c/ptype.fs +10 -4
@@ 47,10 47,16 @@ alias _err parseDeclarator ( type -- cdecl ) \ forward declaration
  0 begin ( type lvl )
    '*' readChar? while ( type lvl tok ) 1+ repeat ( type lvl tok )
  dup '(' isChar? if ( type lvl tok )
    drop swap _parseDeclarator read) ( lvl cdecl )
    \ type recursion in C is "inside out". The cdecl we have now is the result.
    \ We need to apply indirection levels we've already parsed to it.
    tuck to+ CDecl lvl
    \ Complex type parsing is messed up. Example "int (*foo)[42]", a pointer to
    \ an array of int (an array of int* is "int *foo[42]"). Right now, "type" is
    \ "int" and we're about to parse the "(*foo)" part. This will give us a
    \ CDecl {type=int,lvl=1,name=foo}. Now, for the _post part, we want a brand
    \ new CDecl {type=int,lvl=0,nbelem=42,name=null}. Then, we set the first
    \ CDecl's type to the newly parsed type. We have our "int (*foo)[42]".
    \ The "lvl" we've just parsed above goes to the *inner* type.
    drop over parseDeclarator read) ( type inner-lvl outer-type )
    rot NULLSTR swap CDecl :new _post ( il ot inner-type )
    rot over to CDecl lvl over to CDecl type ( cdecl )
  else ( type lvl tok )
    dup isIdent? not if to nexttputback NULLSTR then ( type lvl name )
    rot CDecl :new ( lvl cdecl ) tuck to CDecl lvl then _post ;

M fs/comp/c/type.fs => fs/comp/c/type.fs +1 -0
@@ 82,6 82,7 @@ struct[ CDecl
    dup lvl if drop 0 else _ then ;
  : :structarrow? ( self -- f ) \ is an indirect Struct reference?
    dup lvl 1 = if _ else drop 0 then ;
  : :funcptr? ( self -- f ) bi lvl 1 = | type :funcsig? and ;
  : :constfuncsig? ( self -- f ) bi :funcsig? | :isglobal? and ;

  \ Arrays, function signatures and struct ident "naturally" yield references.

M fs/tests/comp/c/type.fs => fs/tests/comp/c/type.fs +28 -28
@@ 55,41 55,41 @@ dup CDecl lvl 1 #eq
dup CDecl nbelem 42 #eq
CDecl name S" foo" #s=

\ TODO: This test is not working. It's supposed to yield a pointer to an array
\ of 42 ints, not an array of 42 pointers to ints.
\ _parse int (*foo)[42] STOP
\ dup CDecl type TYPE_INT #
\ dup CDecl type lvl 1 #eq
\ dup CDecl nbelem 0 #eq
\ dup CDecl name S" foo" #s=
\ CDecl type
\   dup CDecl type TYPE_INT #eq
\   dup CDecl nbelem 42 #eq
\   CDecl name NULLSTR #s=
_parse int (*foo)[42] STOP
dup CDecl lvl 1 #eq
dup CDecl nbelem 0 #eq
dup CDecl name S" foo" #s=
CDecl type
  dup CDecl type TYPE_INT #eq
  dup CDecl lvl 0 #eq
  dup CDecl nbelem 42 #eq
  CDecl name NULLSTR #s=

_parse unsigned int (*foo)(char,short) STOP
dup CDecl :funcsig? #
dup CDecl :funcptr? #
dup CDecl name S" foo" #s=
dup CDecl type TYPE_UINT #eq
CDecl args
dup CDecl type TYPE_CHAR #eq
dup CDecl offset 4 #eq \ PS args are always 4b in size
llnext
dup CDecl type TYPE_SHORT #eq
CDecl offset 0 #eq
CDecl type
  dup CDecl type TYPE_UINT #eq
  CDecl args
  dup CDecl type TYPE_CHAR #eq
  dup CDecl offset 4 #eq \ PS args are always 4b in size
  llnext
  dup CDecl type TYPE_SHORT #eq
  CDecl offset 0 #eq

\ We can also have a function signature with argument names.
_parse unsigned int (*foo)(short bar,char baz) STOP
dup CDecl :funcsig? #
dup CDecl :funcptr? #
dup CDecl name S" foo" #s=
CDecl args
dup CDecl name S" bar" #s=
dup CDecl type TYPE_SHORT #eq
dup CDecl offset 4 #eq
llnext
dup CDecl name S" baz" #s=
dup CDecl type TYPE_CHAR #eq
CDecl offset 0 #eq
CDecl type
  CDecl args
    dup CDecl name S" bar" #s=
    dup CDecl type TYPE_SHORT #eq
    dup CDecl offset 4 #eq
    llnext
    dup CDecl name S" baz" #s=
    dup CDecl type TYPE_CHAR #eq
    CDecl offset 0 #eq

_parse Struct1 *mystructptr STOP
capture printtype