diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | ccross.mlb | 1 | ||||
-rw-r--r-- | ccross.sml | 3 | ||||
-rw-r--r-- | common.sml | 2 | ||||
-rw-r--r-- | dynarray.sig | 14 | ||||
-rw-r--r-- | dynarray.sml | 55 | ||||
-rw-r--r-- | parser.fun | 435 |
7 files changed, 457 insertions, 55 deletions
@@ -3,6 +3,6 @@ ffi := -default-ann "allowFFI true" -export-header export.h caux := caux.c def: - mlton $(history) $(ffi) ccross.mlb $(caux) + mlton $(history) $(ffi) -default-type word64 ccross.mlb $(caux) clean: rm -f ccross export.h @@ -12,6 +12,7 @@ in stream.sig stream.sml hashtable.sig hashtable.sml tree.sig tree.sml + dynarray.sig dynarray.sml symtab.sig symtab.fun tokenizer.sig tokenizer.fun @@ -4,7 +4,8 @@ structure ccross:> CCROSS = struct Tokenizer(structure ST = ST; structure S = Stream) structure ppc:> PPC = ppc(structure Tree = Tree; structure T = T) structure Parser:> PARSER = - Parser(structure Tree = Tree; structure P = ppc) + Parser(structure Tree = Tree; structure P = ppc; + structure D = Dynarray) structure D:> DRIVER = Driver(Parser) structure ExnHandler:> EXN_HANDLER = ExnHandler end @@ -149,7 +149,7 @@ fun F z = bind A0 (fn (_, mf) => mf ()) z val I = fn z => bindWith2str Int.toString z val C = fn z => bindWith2str str z val B = fn z => bindWith2str Bool.toString z -val W64 = fn z => bindWith2str Word64.toString z +val W = fn z => bindWith2str (Word.fmt StringCvt.DEC) z val R = fn z => bind A1 (fn n => fn (output, _) => app (fn f => f ()) (List.tabulate (n, fn _ => fn () => output " "))) z diff --git a/dynarray.sig b/dynarray.sig new file mode 100644 index 0000000..ab3a248 --- /dev/null +++ b/dynarray.sig @@ -0,0 +1,14 @@ +signature DYNARRAY = sig + type 'a t = (int * 'a option Array.array) ref + + exception OutOfBounds + + val create: int -> 'a t + val create0: unit -> 'a t + + val length: 'a t -> int + + val push: 'a t -> 'a -> unit + val get: 'a t -> int -> 'a + val set: 'a t -> int -> 'a -> unit +end diff --git a/dynarray.sml b/dynarray.sml new file mode 100644 index 0000000..0c1cd7f --- /dev/null +++ b/dynarray.sml @@ -0,0 +1,55 @@ +structure Dynarray: DYNARRAY = struct + type 'a t = (int * 'a option Array.array) ref + + exception OutOfBounds + + fun create n = + ref (0, Array.array (n, NONE)) + + fun create0 () = create 10 + + fun length dynarr = + let + val (len, _) = !dynarr + in + len + end + + fun push dynarr v = + let + val (len, arr) = !dynarr + in + if len = Array.length arr then + let + val arr2 = Array.array (len * 2, NONE) + in + Array.copy { src = arr, dst = arr2, di = 0 }; + dynarr := (len, arr2); + push dynarr v + end + else + Array.update (arr, len, SOME v); + dynarr := (len + 1, arr) + end + + fun get dynarr n = + let + val (len, arr) = !dynarr + in + if n >= len then + raise OutOfBounds + else + valOf $ Array.sub (arr, n) + end + + fun set dynarr n v = + let + val (len, arr) = !dynarr + in + if n >= len then + raise OutOfBounds + else + Array.update (arr, n, SOME v) + end + +end @@ -1,8 +1,11 @@ -functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct +functor Parser(structure Tree: TREE; structure P: PPC; + structure D: DYNARRAY): PARSER = struct structure P = P structure T = P.T + type nid = int + datatype unop = UnopPreInc | UnopPreDec | @@ -67,8 +70,8 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct Eid of int * id option | Econst of int * cnum | Estrlit of int | - EmemberByV of int * exprAug | - EmemberByP of int * exprAug | + EmemberByV of exprAug * int | + EmemberByP of exprAug * int | EfuncCall of exprAug * exprAug list | Eternary of exprAug * exprAug * exprAug | EsizeofType of ctype | @@ -92,13 +95,19 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct ulong_t | longlong_t | ulonglong_t | + (* float_t | double_t | *) pointer_t of int * ctype | function_t of ctype * ctype list | - array_t of Word64.word * ctype + array_t of Word64.word * ctype | + struct_t of + { name: nid, size: word, alignment: word, + fields: (nid * word * ctype) list } | + + remote_t of int val typeSizes = [ (char_t, 1), (uchar_t, 1), @@ -133,6 +142,7 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct SpecStatic | SpecRegister + type rawDecl = { id: int option, pos: P.tkPos, @@ -186,11 +196,19 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct datatype def = Objects of objDef list | Definition of funcInfo - type nid = int - type scope = (nid, int) Tree.t + datatype typeStatus = TsDefined | TsIncomplete | TsNotDefined + + (* + * For structures and unions the type name (nid) is duplicated for the + * ease of pctype function + *) + val types: (nid * P.tkPos * ctype) D.t = D.create0 () + datatype ctx = Ctx of { + aggrTypeNames: scope, + localScopes: scope list, localVars: (int * P.tkPos * ctype) list, funcRetType: ctype option, @@ -208,16 +226,19 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct fun updateCtx (Ctx ctx) = fn z => let - fun from localScopes localVars funcRetType globalDecls - tokenBuf loopLevel = - { localScopes, localVars, funcRetType, globalDecls, - tokenBuf, loopLevel } + fun from aggrTypeNames localScopes localVars + funcRetType globalDecls tokenBuf loopLevel + = + { aggrTypeNames, localScopes, localVars, + funcRetType, globalDecls, tokenBuf, loopLevel } - fun to f { localScopes, localVars, funcRetType, globalDecls, - tokenBuf, loopLevel } = - f localScopes localVars funcRetType globalDecls tokenBuf loopLevel + fun to f { aggrTypeNames, localScopes, localVars, + funcRetType, globalDecls, tokenBuf, loopLevel } + = + f aggrTypeNames localScopes localVars funcRetType + globalDecls tokenBuf loopLevel in - FRU.makeUpdate6 (from, from, to) ctx (fn (a, f) => z (a, Ctx o f)) + FRU.makeUpdate7 (from, from, to) ctx (fn (a, f) => z (a, Ctx o f)) end datatype declParts = @@ -229,7 +250,8 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct datatype abstructPolicy = APpermitted | APenforced | APprohibited - datatype specType = StorageSpec of storageSpec | TypeSpec of T.token + datatype specType = + StorageSpec of storageSpec | TypeSpec of T.token val binopTable = [ (BrSubscript, T.Invalid, 0, false), @@ -287,6 +309,12 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct | ulong_t => & ("unsigned long", "L") | longlong_t => & ("long long", "w") | ulonglong_t => & ("unsigned long long", "W") + | remote_t id => + let + val (_, _, t) = D.get types id + in + pctype short t out + end (* | float_t => & ("float", "f") | double_t => & ("double", "d") @@ -301,6 +329,11 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct `"}" `(if short then "" else " -> ") A2 pctype short ret % | array_t (n, el) => Printf out `"[" `(Word64.toString n) `"]" A2 pctype short el % + | struct_t { name, ... } => + if short then + Printf out `"r" I name % + else + Printf out `"struct " P.? name % end val Pctype = fn z => bind A1 (pctype false) z @@ -314,7 +347,9 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct T.kwFloat, T.kwDouble, T.kwSigned, - T.kwUnsigned + T.kwUnsigned, + + T.kwStruct ] fun ts2idx ts = @@ -329,8 +364,6 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct find 0 typeSpecs end - fun idx2ts idx = List.nth (typeSpecs, idx) - val tsMaxIdxP1 = length typeSpecs val prefixes = [ @@ -424,6 +457,7 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct (repr2id, (id, ctype) :: id2type, trs) end + (* fun prefixFsmPrint fsm repr2id = let fun findRepr id = @@ -441,6 +475,8 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct Printf out `"[" A1 printRepr' l `"]" % end + fun idx2ts idx = List.nth (typeSpecs, idx) + open Array fun printRow i = @@ -470,6 +506,7 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct i := !i + 1 ) end + *) fun buildPrefixFsm () = let @@ -529,6 +566,7 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct fun typeRepr2type typeReprId = valOf o #1 o Array.sub $ (prefixFsm, typeReprId) + (* fun pTokenL l out = let fun pToken (tk, _) out = @@ -546,6 +584,7 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct in Printf out Plist pToken l (",", false) % end + *) val isIntegral = fn char_t | uchar_t | short_t | ushort_t | int_t | uint_t @@ -594,7 +633,13 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct if n < 2 then raise Unreachable else pointer_t (n - 1, t) | _ => raise Unreachable + fun tryGetFields (struct_t { fields, ... }) = SOME fields + | tryGetFields (remote_t id) = (tryGetFields o #3 o D.get types) id + | tryGetFields _ = NONE + fun createCtx fname incDirs = Ctx { + aggrTypeNames = Tree.empty, + localScopes = [], localVars = [], funcRetType = NONE, @@ -723,7 +768,7 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct and pexpr e out = let - fun mem (id, ea) s = Printf out A1 pea ea `s P.? id % + fun mem (ea, id) s = Printf out A1 pea ea `s P.? id % in case e of Eid (nid, id) => Printf out P.? nid `"{" A3 poptN "none" pid id `"}" % @@ -888,7 +933,7 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct val (tk, pos2, ctx2) = getTokenCtx ctx1 in case tk of - Tk (T.Id id) => (SOME $ makeEA (unop (id, eAug)) pos1, ctx2) + Tk (T.Id id) => (SOME $ makeEA (unop (eAug, id)) pos1, ctx2) | _ => P.clerror pos2 [P.Cid] end in @@ -1220,8 +1265,6 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct and findId (Ctx ctx) pos sizeofOrAddr id = let - val () = printf `"findId: " B sizeofOrAddr `"\n" % - fun findLocal [] = NONE | findLocal (scope :: scopes) = let @@ -1266,6 +1309,8 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct | pointer_t _ => 13 | array_t _ => 14 | function_t _ => 15 + | struct_t _ => 16 + | remote_t id => (typeRank o #3 o D.get types) id | unknown_t => raise Unreachable and convEA t (E as EA (_, pos, _, t')) = @@ -1657,6 +1702,43 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct end | checkTernary _ _ = raise Unreachable + and checkMemberAccess check byP + (EA (EmemberByV (ea, field) | EmemberByP (ea, field), pos, _, _)) + = + let + val ea = check ea + + val pos' = getPos ea + val t = getT ea + + val t = + if byP then + if isPointer t then + pointsTo t + else + P.error pos' `"expected a pointer to aggregate" % + else + t + + val fields = + case (tryGetFields t, byP) of + (NONE, true) => + P.error pos' `"expected a pointer to an aggregate" % + | (NONE, false) => P.error pos' `"expected an aggregate" % + | (SOME fields, _) => fields + + val e = + if byP then + EmemberByP (ea, field) + else + EmemberByV (ea, field) + in + case List.find (fn (f, _, _) => f = field) fields of + NONE => P.error pos `"unknown field" % + | SOME (_, _, field_type) => EA (e, pos, true, field_type) + end + | checkMemberAccess _ _ _ = raise Unreachable + and checkExpr ctx sizeofOrAddr (E as EA (e, pos, _, _)) = let val check = checkExpr ctx @@ -1675,7 +1757,9 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct | Ebinop (_, _, _) => checkBinop (check false) E | Eternary _ => checkTernary (check false) E | Eunop (_, _) => checkUnop check sizeofOrAddr E - | _ => E + | EmemberByV _ => checkMemberAccess (check false) false E + | EmemberByP _ => checkMemberAccess (check false) true E + | Econst _ | Estrlit _ => E end and tryGetSpec ctx = @@ -1701,13 +1785,23 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct ) end - and sizeOfType (pointer_t _) = pointerSize - | sizeOfType (array_t (n, t)) = Word64.* (n, sizeOfType t) - | sizeOfType t = + and findPrimTypeSize t = case List.find (fn (t', _) => t' = t) typeSizes of SOME (_, size) => Word64.fromInt size | _ => raise Unreachable + and alignOfType (pointer_t _) = pointerSize + | alignOfType (array_t (_, t)) = alignOfType t + | alignOfType (struct_t { alignment, ... }) = alignment + | alignOfType (remote_t id) = (alignOfType o #3 o D.get types) id + | alignOfType t = findPrimTypeSize t + + and sizeOfType (pointer_t _) = pointerSize + | sizeOfType (array_t (n, t)) = Word64.* (n, sizeOfType t) + | sizeOfType (struct_t { size, ... }) = size + | sizeOfType (remote_t id) = (sizeOfType o #3 o D.get types) id + | sizeOfType t = findPrimTypeSize t + and sizeofWrapper t = Word64.toInt $ sizeOfType t and zeroExtend (ER (w, t)) = @@ -1716,9 +1810,9 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct val minus1 = Word64.notb (Word64.fromInt 0) val mask = Word64.>> (minus1, 0w64 - size * 0w8) - val () = printf `"ZH0: " W64 w `"\n" % + val () = printf `"ZH0: " W w `"\n" % val res = Word64.andb (mask, w) - val () = printf `"ZH1: " W64 res `"\n" % + val () = printf `"ZH1: " W res `"\n" % in res end @@ -1757,7 +1851,7 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct let val minus1 = Word64.notb $ Word64.fromInt 0 val res as ER (w, _) = ER (Word64.xorb (minus1, w), t) - val () = printf `"~ after: " W64 w `"\n" % + val () = printf `"~ after: " W w `"\n" % in res end @@ -1832,7 +1926,7 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct val left' = conv left val right' = conv right - val () = printf `"eval compare: " W64 left' `", " W64 right' `"\n" % + val () = printf `"eval compare: " W left' `", " W right' `"\n" % val res = convResult $ comp (left', right') in ER (w64FromBool res, int_t) @@ -1938,7 +2032,7 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct case e of Eid _ => P.error pos `"variable in constant expression" % | Econst (_, Ninteger w) => - (printf `"eval num: " W64 w `": " Pctype t `"\n" %; + (printf `"eval num: " W w `": " Pctype t `"\n" %; ER (w, t)) | Econst _ => raise Unreachable | Estrlit _ => P.error pos `"string literal in constant expression" % @@ -1968,42 +2062,274 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct val res = eval' $ EA (e, pos, false, t') val ER (w, _) = res - val () = printf `"eval: " W64 w `"\n" % + val () = printf `"eval: " W w `"\n" % in zeroExtend res end and parseDeclPrefix ctx = let + datatype state = TypeId of int | Type of ctype + fun collect ctx (storSpec, typeReprId) = let val (spec, ctx) = tryGetSpec ctx in - case spec of - NONE => - if typeReprId = 0 then - let - val (_, pos, _) = getTokenCtx ctx - val ets = "expected type specifier" - val etss = "expected type or storage specifier" - in - P.error pos `(if isSome storSpec then ets else etss) % - end - else - ((storSpec, typeRepr2type typeReprId), ctx) - | SOME (StorageSpec spec, pos) => ( + case (spec, typeReprId) of + (NONE, TypeId 0) => + let + val (_, pos, _) = getTokenCtx ctx + val ets = "expected type specifier" + val etss = "expected type or storage specifier" + in + P.error pos `(if isSome storSpec then ets else etss) % + end + + | (NONE, TypeId id) => ((storSpec, typeRepr2type id), ctx) + | (NONE, Type t) => ((storSpec, t), ctx) + + | (SOME (StorageSpec spec, pos), _) => ( case storSpec of NONE => collect ctx (SOME spec, typeReprId) | SOME _ => P.error pos `"storage specifier is already provided" % ) - | SOME (TypeSpec tk, pos) => - collect ctx (storSpec, advanceTypeRepr typeReprId (tk, pos)) + + | (SOME (TypeSpec T.kwStruct, _), TypeId 0) => + let + val (t, ctx) = processStruct ctx + in + ((storSpec, t), ctx) + end + | (SOME (TypeSpec T.kwStruct, pos), _) => + P.error pos `"invalid type specifier" % + | (SOME (TypeSpec tk, pos), TypeId id) => + collect ctx (storSpec, TypeId $ advanceTypeRepr id (tk, pos)) + | (SOME (TypeSpec _, pos), _) => + P.error pos `"invalid type specifier" % + end + in + collect ctx (NONE, TypeId 0) + end + + and getStructName ctx = + let + val (tk, pos, ctx) = getTokenCtx ctx + in + case tk of + Tk (T.Id id) => (id, pos, ctx) + | TkBrackets _ => + P.error pos `"anonymous structures are not supported" % + | _ => P.error pos `"expected struct name" % + end + + and parseStructDeclaration ctx = + let + val (prefix, ctx) = parseDeclPrefix ctx + + fun convToField ({ pos, spec = SOME _, ... }) = + P.error pos `"aggregate field with storage specifier" % + | convToField ({ id, pos, spec = NONE, t, ... }) = + if isFunc t then + P.error pos `"field of function type" % + else + (valOf id, pos, t) + + fun collect acc ctx = + let + val (parts, ctx) = parseDeclarator (false, APprohibited) [] ctx + val declaredId = assembleDeclarator prefix parts + + val field = convToField declaredId + val acc = field :: acc + + val (tk, pos, ctx) = getTokenCtx ctx + in + case tk of + Tk T.Semicolon => (rev acc, ctx) + | Tk T.Comma => collect acc ctx + | _ => P.clerror pos [P.Ctk T.Semicolon, P.Ctk T.Comma] end in - collect ctx (NONE, 0) + collect [] ctx end + and tryGetStructBody pos ctx: (nid * ctype) list option * ctx = + let + val (tk, _, ctx') = getTokenCtx ctx + + fun checkFieldUniqueness ((id, _, _) :: fs) = ( + case List.find (fn (id', _, _) => id' = id) fs of + SOME (_, pos, _) => P.error pos `"field name is reused" % + | NONE => checkFieldUniqueness fs + ) + | checkFieldUniqueness [] = () + + fun collectFields acc ctx = + let + val (tk, _, _) = getTokenCtx ctx + in + case tk of + Tk T.EOS => + let + val acc = rev acc + in + if null acc then + P.error pos `"empty structures are not supported" % + else ( + checkFieldUniqueness acc; + (SOME $ map (fn (id, _, t) => (id, t)) acc, ctx) + ) + end + | _ => + let + val (fields, ctx) = parseStructDeclaration ctx + in + collectFields (List.revAppend (fields, acc)) ctx + end + end + in + case tk of + TkBraces list => ctxWithLayer ctx' list (collectFields []) + | _ => (NONE, ctx) + end + + and getStructStatus id (Ctx { aggrTypeNames, ... }) = + let + val bufId = lookup aggrTypeNames id + + (* val () = printf `"Searching for " P.? id `"\n" % *) + in + case bufId of + NONE => TsNotDefined + | SOME id => + case #3 $ D.get types id of + struct_t { fields = [], ... } => TsIncomplete + | _ => TsDefined + end + + and getTypeIdFromName id (Ctx { aggrTypeNames, ... }) = + valOf $ lookup aggrTypeNames id + + and calcStruct id [] = + struct_t { name = id, size = 0w0, alignment = 0w0, fields = [] } + | calcStruct id fields = + let + val alignment: word = + List.foldl (fn ((_, t), m) => + let + val fa = alignOfType t + in + if fa > m then fa else m + end) 0w0 $ fields + + fun align v align = + if v mod align = 0w0 then v else v + align - v mod align + + fun calcSize size [] offsets = + if size mod alignment = 0w0 then + (size, rev offsets) + else + (align size alignment, rev offsets) + | calcSize size ((_, t) :: fields) offsets = + let + val fieldOffset = align size (alignOfType t) + val size = fieldOffset + sizeOfType t + + val () = printf `"foffset : " W fieldOffset `"\n" % + in + calcSize size fields (fieldOffset :: offsets) + end + + val (size, offsets) = + calcSize ((sizeOfType o #2 o hd) fields) (tl fields) [0w0] + + fun zipOffsets (off :: offs) ((id, t) :: fs) = + (id, off, t) :: zipOffsets offs fs + | zipOffsets [] [] = [] + | zipOffsets _ _ = raise Unreachable + in + struct_t { name = id, size, alignment, + fields = zipOffsets offsets fields } + end + + and Pstruct z = + let + fun p [] _ = () + | p ((id, offset, t) :: fields) out = + Printf out `"\t" W offset `": " P.? id `": " + Pctype t `"\n" A1 p fields % + + fun f (struct_t { size, alignment, fields, ... }) out = + Printf out `"{ size = " W size `", alignment = " W alignment `"\n" + A1 p fields `"}\n" % + | f _ _ = raise Unreachable + in + bind A1 f + end z + + (* + val Ptk = fn z => + let + fun f tk out = Printf out T.Ptk symtab tk % + in + bind A1 f + end z + *) + + and registerStruct id _ TsIncomplete NONE ctx = + (getTypeIdFromName id ctx, ctx) + | registerStruct id _ TsDefined NONE ctx = + (getTypeIdFromName id ctx, ctx) + + | registerStruct id pos TsNotDefined body + (C as Ctx { aggrTypeNames, ... }) + = + let + val newBufId = D.length types + val (_, aggrTypeNames) = Tree.insert intCompare aggrTypeNames id newBufId + + val (body', status) = + case body of + NONE => ([], "incomplete") + | SOME body => (body, "complete") + + val newInfo = (id, pos, calcStruct id body') + in + D.push types newInfo; + printf `"new " `status `" struct: " P.? id `":" I id `"\n" %; + printf Pstruct (#3 newInfo) %; + (newBufId, updateCtx C s#aggrTypeNames aggrTypeNames %) + end + + | registerStruct id pos TsIncomplete (SOME body) + (C as Ctx { aggrTypeNames, ... }) + = + let + val bufId = valOf $ lookup aggrTypeNames id + val newInfo = (id, pos, calcStruct id body) + in + D.set types bufId newInfo; + printf `"completing struct: " P.? id `":" I id `"\n" %; + printf Pstruct (#3 newInfo) %; + (bufId, C) + end + | registerStruct _ pos TsDefined (SOME _) _ = + P.error pos `"struct redefinition" % + + and processStruct ctx = + let + val (id, pos, ctx) = getStructName ctx + + val status = getStructStatus id ctx + val (body, ctx) = tryGetStructBody pos ctx + + val (bufTypeId, ctx) = registerStruct id pos status body ctx + in + (remote_t bufTypeId, ctx) + end + + (* and Ppart part out = case part of Pointer plevel => Printf out `"[" I plevel `"] " % @@ -2011,6 +2337,7 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct | AbstructRoot _ => Printf out `":root" % | FuncApp _ => Printf out `"()" % | ArrayApplication _ => Printf out `"[]" % + *) and isTypeNameStart tk = isSome $ List.find @@ -2197,8 +2524,8 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct | _ => NONE in - { id, pos, spec = storSpec, t = complete $ tl parts, - ini = NONE, params } + ({ id, pos, spec = storSpec, t = complete $ tl parts, + ini = NONE, params }: rawDecl) end fun printIni (IniExpr ea) out = Printf out A1 pea ea % @@ -2489,8 +2816,12 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct else (finishNormal $ add toplevMaybe, ctx) end + + val (tk, _, ctx') = getTokenCtx ctx in - collectDeclarators [] ctx + case tk of + Tk T.Semicolon => (finishNormal [], ctx') + | _ => collectDeclarators [] ctx end fun skipExpected expectedTk ctx = @@ -2690,7 +3021,7 @@ functor Parser(structure Tree: TREE; structure P: PPC): PARSER = struct in if isTypeNameStart tk then let - val (res , ctx) = parseDeclaration ctx + val (res, ctx) = parseDeclaration ctx val inits = case res of LocalVarInits l => l |