@@ -230,6 +230,24 @@ function Parser:parseType()
230230 return { qualifiers = quals , name = name , pointer = pointer , reference = reference or nil }
231231end
232232
233+ --- @return string ?
234+ function Parser :parseArraySize ()
235+ if not self :consume (" [" ) then return nil end
236+ local parts = {}
237+ while not self :consume (" ]" ) do
238+ local t = self :advance ()
239+ if t .variant == " ident" then
240+ parts [# parts + 1 ] = t .ident
241+ elseif t .variant == " number" then
242+ local n = t .number
243+ parts [# parts + 1 ] = n == math.floor (n ) and tostring (math.floor (n )) or tostring (n )
244+ else
245+ parts [# parts + 1 ] = t .variant
246+ end
247+ end
248+ return table.concat (parts )
249+ end
250+
233251--- @return ffix.c.Parser.Field[]
234252function Parser :parseFields ()
235253 local fields = {}
@@ -241,25 +259,27 @@ function Parser:parseFields()
241259 else
242260 name_tok = self :expect (" ident" )
243261 end
244- local array_size
245- if self :consume (" [" ) then
246- local parts = {}
247- while not self :consume (" ]" ) do
248- local t = self :advance ()
249- if t .variant == " ident" then
250- parts [# parts + 1 ] = t .ident
251- elseif t .variant == " number" then
252- local n = t .number
253- parts [# parts + 1 ] = n == math.floor (n ) and tostring (math.floor (n )) or tostring (n )
254- else
255- parts [# parts + 1 ] = t .variant
256- end
262+ local array_size = self :parseArraySize ()
263+ local attrs = self :parseAttrs ()
264+ fields [# fields + 1 ] = { type = ftype , name = name_tok and name_tok .ident , array_size = array_size , attrs = attrs }
265+ -- comma-separated names sharing the same base type: unsigned int lo, hi;
266+ while self :consume (" ," ) do
267+ local extra_ptr = 0
268+ while self :consume (" *" ) do extra_ptr = extra_ptr + 1 end
269+ local extra_name = self :expect (" ident" )
270+ local extra_type
271+ if ftype .inline_kind then
272+ extra_type = { qualifiers = ftype .qualifiers , inline_kind = ftype .inline_kind ,
273+ inline_tag = ftype .inline_tag , inline_fields = ftype .inline_fields ,
274+ inline_variants = ftype .inline_variants , inline_attrs = ftype .inline_attrs ,
275+ pointer = ftype .pointer + extra_ptr , reference = ftype .reference }
276+ else
277+ extra_type = { qualifiers = ftype .qualifiers , name = ftype .name ,
278+ pointer = ftype .pointer + extra_ptr , reference = ftype .reference }
257279 end
258- array_size = table.concat ( parts )
280+ fields [ # fields + 1 ] = { type = extra_type , name = extra_name . ident , array_size = self : parseArraySize () }
259281 end
260- local attrs = self :parseAttrs ()
261282 self :expect (" ;" )
262- fields [# fields + 1 ] = { type = ftype , name = name_tok and name_tok .ident , array_size = array_size , attrs = attrs }
263283 end
264284 return fields
265285end
@@ -362,27 +382,52 @@ function Parser:parseAttrs()
362382 return attrs
363383end
364384
365- --- @return ffix.c.Parser.Node
385+ --- @return ffix.c.Parser.Node[]
366386function Parser :parseDecl ()
367387 if self :consume (" typedef" ) then
368388 local kw = self :peek ()
369389
370390 if kw and (kw .variant == " struct" or kw .variant == " union" ) then
391+ local kw_str = kw .variant
371392 self :advance ()
372393 local pre_attrs = self :parseAttrs ()
373394 local tag_tok = self :consume (" ident" )
395+
396+ -- forward typedef: typedef struct Foo Foo; (no body follows)
397+ if not (self :peek () and self :peek ().variant == " {" ) then
398+ if not tag_tok then error (" expected tag or '{' after " .. kw_str ) end
399+ local name = self :expect (" ident" )
400+ self :expect (" ;" )
401+ return {{ kind = " typedef_alias" ,
402+ type = { qualifiers = {}, name = kw_str .. " " .. tag_tok .ident , pointer = 0 },
403+ name = name .ident }}
404+ end
405+
374406 self :expect (" {" )
375407 local fields = self :parseFields ()
376408 local post_attrs = self :parseAttrs ()
377- local name = self :expect (" ident" )
378- self :expect (" ;" )
379409 local attrs
380410 if pre_attrs or post_attrs then
381411 attrs = {}
382412 if pre_attrs then for _ , a in ipairs (pre_attrs ) do attrs [# attrs + 1 ] = a end end
383413 if post_attrs then for _ , a in ipairs (post_attrs ) do attrs [# attrs + 1 ] = a end end
384414 end
385- return { kind = " typedef_struct" , tag = tag_tok and tag_tok .ident , fields = fields , name = name .ident , attrs = attrs }
415+
416+ local first_name = self :expect (" ident" )
417+ local result = {{ kind = " typedef_struct" , kw = kw_str ,
418+ tag = tag_tok and tag_tok .ident , fields = fields ,
419+ name = first_name .ident , attrs = attrs }}
420+ -- additional declarators: typedef struct { } Foo, *FooPtr;
421+ while self :consume (" ," ) do
422+ local ptr = 0
423+ while self :consume (" *" ) do ptr = ptr + 1 end
424+ local alias_name = self :expect (" ident" )
425+ result [# result + 1 ] = { kind = " typedef_alias" ,
426+ type = { qualifiers = {}, name = first_name .ident , pointer = ptr },
427+ name = alias_name .ident }
428+ end
429+ self :expect (" ;" )
430+ return result
386431 end
387432
388433 if kw and kw .variant == " enum" then
@@ -392,7 +437,7 @@ function Parser:parseDecl()
392437 local variants = self :parseVariants ()
393438 local name = self :expect (" ident" )
394439 self :expect (" ;" )
395- return { kind = " typedef_enum" , tag = tag_tok and tag_tok .ident , variants = variants , name = name .ident }
440+ return {{ kind = " typedef_enum" , tag = tag_tok and tag_tok .ident , variants = variants , name = name .ident } }
396441 end
397442
398443 local ret = self :parseType ()
@@ -404,20 +449,41 @@ function Parser:parseDecl()
404449 self :expect (" )" )
405450 local params = self :parseParams ()
406451 self :expect (" ;" )
407- return { kind = " typedef_fnptr" , ret = ret , name = name .ident , params = params }
452+ return {{ kind = " typedef_fnptr" , ret = ret , name = name .ident , params = params } }
408453 end
409454
410455 local name = self :expect (" ident" )
411456 self :expect (" ;" )
412- return { kind = " typedef_alias" , type = ret , name = name .ident }
457+ return {{ kind = " typedef_alias" , type = ret , name = name .ident } }
413458 end
414459
415460 if self :consume (" extern" ) then
416461 local type = self :parseType ()
417462 local name = self :expect (" ident" )
418463 local asm_name = self :parseAsmName ()
419464 self :expect (" ;" )
420- return { kind = " extern_var" , type = type , name = name .ident , asm_name = asm_name }
465+ return {{ kind = " extern_var" , type = type , name = name .ident , asm_name = asm_name }}
466+ end
467+
468+ -- bare struct/union/enum definition: struct Foo { ... };
469+ local kw_tok = self :peek ()
470+ if kw_tok and (kw_tok .variant == " struct" or kw_tok .variant == " union" or kw_tok .variant == " enum" ) then
471+ local saved = self .ptr
472+ self :advance ()
473+ local tag_tok = self :consume (" ident" )
474+ if self :peek () and self :peek ().variant == " {" then
475+ self :advance ()
476+ local fields , variants
477+ if kw_tok .variant == " enum" then
478+ variants = self :parseVariants ()
479+ else
480+ fields = self :parseFields ()
481+ end
482+ self :expect (" ;" )
483+ return {{ kind = " struct_def" , kw = kw_tok .variant ,
484+ tag = tag_tok and tag_tok .ident , fields = fields , variants = variants }}
485+ end
486+ self .ptr = saved
421487 end
422488
423489 local ret = self :parseType ()
@@ -426,8 +492,7 @@ function Parser:parseDecl()
426492 local asm_name = self :parseAsmName ()
427493 local attrs = self :parseAttrs ()
428494 self :expect (" ;" )
429-
430- return { kind = " fn_decl" , ret = ret , name = name .ident , params = params , asm_name = asm_name , attrs = attrs }
495+ return {{ kind = " fn_decl" , ret = ret , name = name .ident , params = params , asm_name = asm_name , attrs = attrs }}
431496end
432497
433498--- @param tokens ffix.c.Tokenizer.Token[]
@@ -439,7 +504,9 @@ function Parser:parse(tokens)
439504 local nodes = {}
440505 local ok , err = pcall (function ()
441506 while self .ptr <= # self .tokens do
442- nodes [# nodes + 1 ] = self :parseDecl ()
507+ for _ , node in ipairs (self :parseDecl ()) do
508+ nodes [# nodes + 1 ] = node
509+ end
443510 end
444511 end )
445512
0 commit comments