Merge pull request #1260 from enurlyx/structs-in-structs

c2nim -> Support for anonymous structs/unions
This commit is contained in:
Andreas Rumpf 2014-06-28 02:24:36 +02:00
commit e383200cf8
3 changed files with 248 additions and 51 deletions

View file

@ -19,7 +19,7 @@
import import
os, llstream, renderer, clex, idents, strutils, pegs, ast, astalgo, msgs, os, llstream, renderer, clex, idents, strutils, pegs, ast, astalgo, msgs,
options, strtabs options, strtabs, hashes, algorithm
type type
TParserFlag = enum TParserFlag = enum
@ -63,6 +63,15 @@ type
ERetryParsing = object of ESynch ERetryParsing = object of ESynch
proc addTypeDef(section, name, t: PNode)
proc parseStruct(p: var TParser, stmtList: PNode, isUnion: bool): PNode
proc parseStructBody(p: var TParser, stmtList: PNode, isUnion: bool,
kind: TNodeKind = nkRecList): PNode
proc newParserOptions*(): PParserOptions = proc newParserOptions*(): PParserOptions =
new(result) new(result)
result.prefixes = @[] result.prefixes = @[]
@ -682,24 +691,6 @@ proc parseField(p: var TParser, kind: TNodeKind): PNode =
else: result = mangledIdent(p.tok.s, p) else: result = mangledIdent(p.tok.s, p)
getTok(p, result) getTok(p, result)
proc parseStructBody(p: var TParser, isUnion: bool,
kind: TNodeKind = nkRecList): PNode =
result = newNodeP(kind, p)
eat(p, pxCurlyLe, result)
while p.tok.xkind notin {pxEof, pxCurlyRi}:
var baseTyp = typeAtom(p)
while true:
var def = newNodeP(nkIdentDefs, p)
var t = pointer(p, baseTyp)
var i = parseField(p, kind)
t = parseTypeSuffix(p, t)
addSon(def, i, t, ast.emptyNode)
addSon(result, def)
if p.tok.xkind != pxComma: break
getTok(p, def)
eat(p, pxSemicolon, lastSon(result))
eat(p, pxCurlyRi, result)
proc structPragmas(p: TParser, name: PNode, origName: string): PNode = proc structPragmas(p: TParser, name: PNode, origName: string): PNode =
assert name.kind == nkIdent assert name.kind == nkIdent
result = newNodeP(nkPragmaExpr, p) result = newNodeP(nkPragmaExpr, p)
@ -712,6 +703,75 @@ proc structPragmas(p: TParser, name: PNode, origName: string): PNode =
if pragmas.len > 0: addSon(result, pragmas) if pragmas.len > 0: addSon(result, pragmas)
else: addSon(result, ast.emptyNode) else: addSon(result, ast.emptyNode)
proc hashPosition(p: TParser): string =
let lineInfo = parLineInfo(p)
let fileInfo = fileInfos[lineInfo.fileIndex]
result = $hash(fileInfo.shortName & "_" & $lineInfo.line & "_" & $lineInfo.col).uint
proc parseInnerStruct(p: var TParser, stmtList: PNode, isUnion: bool): PNode =
getTok(p, nil)
if p.tok.xkind != pxCurlyLe:
parMessage(p, errUser, "Expected '{' but found '" & $(p.tok[]) & "'")
let structName = if isUnion: "INNER_C_UNION_" & p.hashPosition
else: "INNER_C_STRUCT_" & p.hashPosition
let typeSection = newNodeP(nkTypeSection, p)
let newStruct = newNodeP(nkObjectTy, p)
var pragmas = ast.emptyNode
if isUnion:
pragmas = newNodeP(nkPragma, p)
addSon(pragmas, newIdentNodeP("union", p))
addSon(newStruct, pragmas, ast.emptyNode) # no inheritance
result = newNodeP(nkIdent, p)
result.ident = getIdent(structName)
let struct = parseStructBody(p, stmtList, isUnion)
let defName = newNodeP(nkIdent, p)
defName.ident = getIdent(structName)
addSon(newStruct, struct)
addTypeDef(typeSection, structPragmas(p, defName, "no_name"), newStruct)
addSon(stmtList, typeSection)
proc parseStructBody(p: var TParser, stmtList: PNode, isUnion: bool,
kind: TNodeKind = nkRecList): PNode =
result = newNodeP(kind, p)
eat(p, pxCurlyLe, result)
while p.tok.xkind notin {pxEof, pxCurlyRi}:
skipConst(p)
var baseTyp: PNode
if p.tok.xkind == pxSymbol and (p.tok.s == "struct" or p.tok.s == "union"):
let gotUnion = if p.tok.s == "union": true else: false
saveContext(p)
getTok(p, nil)
if p.tok.xkind == pxSymbol:
backtrackContext(p)
baseTyp = typeAtom(p)
else:
backtrackContext(p)
baseTyp = parseInnerStruct(p, stmtList, gotUnion)
if p.tok.xkind == pxSemiColon:
let def = newNodeP(nkIdentDefs, p)
var t = pointer(p, baseTyp)
let i = fieldIdent("ano_" & p.hashPosition, p)
t = parseTypeSuffix(p, t)
addSon(def, i, t, ast.emptyNode)
addSon(result, def)
getTok(p, nil)
continue
else:
baseTyp = typeAtom(p)
while true:
var def = newNodeP(nkIdentDefs, p)
var t = pointer(p, baseTyp)
var i = parseField(p, kind)
t = parseTypeSuffix(p, t)
addSon(def, i, t, ast.emptyNode)
addSon(result, def)
if p.tok.xkind != pxComma: break
getTok(p, def)
eat(p, pxSemicolon, lastSon(result))
eat(p, pxCurlyRi, result)
proc enumPragmas(p: TParser, name: PNode): PNode = proc enumPragmas(p: TParser, name: PNode): PNode =
result = newNodeP(nkPragmaExpr, p) result = newNodeP(nkPragmaExpr, p)
addSon(result, name) addSon(result, name)
@ -722,7 +782,7 @@ proc enumPragmas(p: TParser, name: PNode): PNode =
addSon(pragmas, e) addSon(pragmas, e)
addSon(result, pragmas) addSon(result, pragmas)
proc parseStruct(p: var TParser, isUnion: bool): PNode = proc parseStruct(p: var TParser, stmtList: PNode, isUnion: bool): PNode =
result = newNodeP(nkObjectTy, p) result = newNodeP(nkObjectTy, p)
var pragmas = ast.emptyNode var pragmas = ast.emptyNode
if isUnion: if isUnion:
@ -730,7 +790,7 @@ proc parseStruct(p: var TParser, isUnion: bool): PNode =
addSon(pragmas, newIdentNodeP("union", p)) addSon(pragmas, newIdentNodeP("union", p))
addSon(result, pragmas, ast.emptyNode) # no inheritance addSon(result, pragmas, ast.emptyNode) # no inheritance
if p.tok.xkind == pxCurlyLe: if p.tok.xkind == pxCurlyLe:
addSon(result, parseStructBody(p, isUnion)) addSon(result, parseStructBody(p, stmtList, isUnion))
else: else:
addSon(result, newNodeP(nkRecList, p)) addSon(result, newNodeP(nkRecList, p))
@ -855,9 +915,28 @@ proc parseTrailingDefinedTypes(p: var TParser, section, typ: PNode) =
newTyp = parseTypeSuffix(p, newTyp) newTyp = parseTypeSuffix(p, newTyp)
addTypeDef(section, newName, newTyp) addTypeDef(section, newName, newTyp)
proc enumFields(p: var TParser): PNode = proc createConst(name, typ, val: PNode, p: TParser): PNode =
result = newNodeP(nkConstDef, p)
addSon(result, name, typ, val)
proc exprToNumber(n: PNode not nil): tuple[succ: bool, val: BiggestInt] =
result = (false, 0.BiggestInt)
case n.kind:
of nkPrefix:
# Check for negative/positive numbers -3 or +6
if n.sons.len == 2 and n.sons[0].kind == nkIdent and n.sons[1].kind == nkIntLit:
let pre = n.sons[0]
let num = n.sons[1]
if pre.ident.s == "-": result = (true, - num.intVal)
elif pre.ident.s == "+": result = (true, num.intVal)
else: discard
proc enumFields(p: var TParser, constList: PNode): PNode =
result = newNodeP(nkEnumTy, p) result = newNodeP(nkEnumTy, p)
addSon(result, ast.emptyNode) # enum does not inherit from anything addSon(result, ast.emptyNode) # enum does not inherit from anything
var i: BiggestInt = 0
var field: tuple[id: BiggestInt, isNumber: bool, node: PNode]
var fields = newSeq[type(field)]()
while true: while true:
var e = skipIdent(p) var e = skipIdent(p)
if p.tok.xkind == pxAsgn: if p.tok.xkind == pxAsgn:
@ -867,17 +946,59 @@ proc enumFields(p: var TParser): PNode =
e = newNodeP(nkEnumFieldDef, p) e = newNodeP(nkEnumFieldDef, p)
addSon(e, a, c) addSon(e, a, c)
skipCom(p, e) skipCom(p, e)
if c.kind == nkIntLit:
addSon(result, e) i = c.intVal
field.isNumber = true
else:
var (success, number) = exprToNumber(c)
if success:
i = number
field.isNumber = true
else:
field.isNumber = false
else:
inc(i)
field.isNumber = true
field.id = i
field.node = e
fields.add(field)
if p.tok.xkind != pxComma: break if p.tok.xkind != pxComma: break
getTok(p, e) getTok(p, e)
# allow trailing comma: # allow trailing comma:
if p.tok.xkind == pxCurlyRi: break if p.tok.xkind == pxCurlyRi: break
fields.sort do (x, y: type(field)) -> int:
cmp(x.id, y.id)
var lastId: BiggestInt
var lastIdent: PNode
for count, f in fields:
if not f.isNumber:
addSon(result, f.node)
elif f.id == lastId and count > 0:
var currentIdent: PNode
case f.node.kind:
of nkEnumFieldDef:
if f.node.sons.len > 0 and f.node.sons[0].kind == nkIdent:
currentIdent = f.node.sons[0]
else: parMessage(p, errGenerated, "Warning: When sorting enum fields an expected nkIdent was not found. Check the fields!")
of nkIdent: currentIdent = f.node
else: parMessage(p, errGenerated, "Warning: When sorting enum fields an expected nkIdent was not found. Check the fields!")
var constant = createConst( currentIdent, ast.emptyNode, lastIdent, p)
constList.addSon(constant)
else:
addSon(result, f.node)
lastId = f.id
case f.node.kind:
of nkEnumFieldDef:
if f.node.sons.len > 0 and f.node.sons[0].kind == nkIdent:
lastIdent = f.node.sons[0]
else: parMessage(p, errGenerated, "Warning: When sorting enum fields an expected nkIdent was not found. Check the fields!")
of nkIdent: lastIdent = f.node
else: parMessage(p, errGenerated, "Warning: When sorting enum fields an expected nkIdent was not found. Check the fields!")
proc parseTypedefStruct(p: var TParser, result: PNode, isUnion: bool) = proc parseTypedefStruct(p: var TParser, result: PNode, stmtList: PNode, isUnion: bool) =
getTok(p, result) getTok(p, result)
if p.tok.xkind == pxCurlyLe: if p.tok.xkind == pxCurlyLe:
var t = parseStruct(p, isUnion) var t = parseStruct(p, stmtList, isUnion)
var origName = p.tok.s var origName = p.tok.s
markTypeIdent(p, nil) markTypeIdent(p, nil)
var name = skipIdent(p) var name = skipIdent(p)
@ -890,7 +1011,7 @@ proc parseTypedefStruct(p: var TParser, result: PNode, isUnion: bool) =
var nameOrType = skipIdent(p) var nameOrType = skipIdent(p)
case p.tok.xkind case p.tok.xkind
of pxCurlyLe: of pxCurlyLe:
var t = parseStruct(p, isUnion) var t = parseStruct(p, stmtList, isUnion)
if p.tok.xkind == pxSymbol: if p.tok.xkind == pxSymbol:
# typedef struct tagABC {} abc, *pabc; # typedef struct tagABC {} abc, *pabc;
# --> abc is a better type name than tagABC! # --> abc is a better type name than tagABC!
@ -914,11 +1035,11 @@ proc parseTypedefStruct(p: var TParser, result: PNode, isUnion: bool) =
else: else:
expectIdent(p) expectIdent(p)
proc parseTypedefEnum(p: var TParser, result: PNode) = proc parseTypedefEnum(p: var TParser, result, constSection: PNode) =
getTok(p, result) getTok(p, result)
if p.tok.xkind == pxCurlyLe: if p.tok.xkind == pxCurlyLe:
getTok(p, result) getTok(p, result)
var t = enumFields(p) var t = enumFields(p, constSection)
eat(p, pxCurlyRi, t) eat(p, pxCurlyRi, t)
var origName = p.tok.s var origName = p.tok.s
markTypeIdent(p, nil) markTypeIdent(p, nil)
@ -933,7 +1054,7 @@ proc parseTypedefEnum(p: var TParser, result: PNode) =
case p.tok.xkind case p.tok.xkind
of pxCurlyLe: of pxCurlyLe:
getTok(p, result) getTok(p, result)
var t = enumFields(p) var t = enumFields(p, constSection)
eat(p, pxCurlyRi, t) eat(p, pxCurlyRi, t)
if p.tok.xkind == pxSymbol: if p.tok.xkind == pxSymbol:
# typedef enum tagABC {} abc, *pabc; # typedef enum tagABC {} abc, *pabc;
@ -960,27 +1081,36 @@ proc parseTypedefEnum(p: var TParser, result: PNode) =
expectIdent(p) expectIdent(p)
proc parseTypeDef(p: var TParser): PNode = proc parseTypeDef(p: var TParser): PNode =
result = newNodeP(nkTypeSection, p) result = newNodeP(nkStmtList, p)
var typeSection = newNodeP(nkTypeSection, p)
var afterStatements = newNodeP(nkStmtList, p)
while p.tok.xkind == pxSymbol and p.tok.s == "typedef": while p.tok.xkind == pxSymbol and p.tok.s == "typedef":
getTok(p, result) getTok(p, typeSection)
inc(p.inTypeDef) inc(p.inTypeDef)
expectIdent(p) expectIdent(p)
case p.tok.s case p.tok.s
of "struct": parseTypedefStruct(p, result, isUnion=false) of "struct": parseTypedefStruct(p, typeSection, result, isUnion=false)
of "union": parseTypedefStruct(p, result, isUnion=true) of "union": parseTypedefStruct(p, typeSection, result, isUnion=true)
of "enum": parseTypedefEnum(p, result) of "enum":
var constSection = newNodeP(nkConstSection, p)
parseTypedefEnum(p, typeSection, constSection)
addSon(afterStatements, constSection)
of "class": of "class":
if pfCpp in p.options.flags: if pfCpp in p.options.flags:
parseTypedefStruct(p, result, isUnion=false) parseTypedefStruct(p, typeSection, result, isUnion=false)
else: else:
var t = typeAtom(p) var t = typeAtom(p)
otherTypeDef(p, result, t) otherTypeDef(p, typeSection, t)
else: else:
var t = typeAtom(p) var t = typeAtom(p)
otherTypeDef(p, result, t) otherTypeDef(p, typeSection, t)
eat(p, pxSemicolon) eat(p, pxSemicolon)
dec(p.inTypeDef) dec(p.inTypeDef)
addSon(result, typeSection)
for s in afterStatements:
addSon(result, s)
proc skipDeclarationSpecifiers(p: var TParser) = proc skipDeclarationSpecifiers(p: var TParser) =
while p.tok.xkind == pxSymbol: while p.tok.xkind == pxSymbol:
case p.tok.s case p.tok.s
@ -1092,10 +1222,6 @@ proc declaration(p: var TParser): PNode =
result = parseVarDecl(p, baseTyp, rettyp, origName) result = parseVarDecl(p, baseTyp, rettyp, origName)
assert result != nil assert result != nil
proc createConst(name, typ, val: PNode, p: TParser): PNode =
result = newNodeP(nkConstDef, p)
addSon(result, name, typ, val)
proc enumSpecifier(p: var TParser): PNode = proc enumSpecifier(p: var TParser): PNode =
saveContext(p) saveContext(p)
getTok(p, nil) # skip "enum" getTok(p, nil) # skip "enum"
@ -1141,12 +1267,16 @@ proc enumSpecifier(p: var TParser): PNode =
closeContext(p) closeContext(p)
var name = result var name = result
# create a type section containing the enum # create a type section containing the enum
result = newNodeP(nkTypeSection, p) result = newNodeP(nkStmtList, p)
var tSection = newNodeP(nkTypeSection, p)
var t = newNodeP(nkTypeDef, p) var t = newNodeP(nkTypeDef, p)
getTok(p, t) getTok(p, t)
var e = enumFields(p) var constSection = newNodeP(nkConstSection, p)
var e = enumFields(p, constSection)
addSon(t, exportSym(p, name, origName), ast.emptyNode, e) addSon(t, exportSym(p, name, origName), ast.emptyNode, e)
addSon(result, t) addSon(tSection, t)
addSon(result, tSection)
addSon(result, constSection)
eat(p, pxCurlyRi, result) eat(p, pxCurlyRi, result)
eat(p, pxSemicolon) eat(p, pxSemicolon)
of pxSemicolon: of pxSemicolon:
@ -1608,8 +1738,8 @@ proc declarationOrStatement(p: var TParser): PNode =
result = expressionStatement(p) result = expressionStatement(p)
assert result != nil assert result != nil
proc parseTuple(p: var TParser, isUnion: bool): PNode = proc parseTuple(p: var TParser, statements: PNode, isUnion: bool): PNode =
result = parseStructBody(p, isUnion, nkTupleTy) parseStructBody(p, statements, isUnion, nkTupleTy)
proc parseTrailingDefinedIdents(p: var TParser, result, baseTyp: PNode) = proc parseTrailingDefinedIdents(p: var TParser, result, baseTyp: PNode) =
var varSection = newNodeP(nkVarSection, p) var varSection = newNodeP(nkVarSection, p)
@ -1640,13 +1770,13 @@ proc parseStandaloneStruct(p: var TParser, isUnion: bool): PNode =
if p.tok.xkind in {pxCurlyLe, pxSemiColon}: if p.tok.xkind in {pxCurlyLe, pxSemiColon}:
if origName.len > 0: if origName.len > 0:
var name = mangledIdent(origName, p) var name = mangledIdent(origName, p)
var t = parseStruct(p, isUnion) var t = parseStruct(p, result, isUnion)
var typeSection = newNodeP(nkTypeSection, p) var typeSection = newNodeP(nkTypeSection, p)
addTypeDef(typeSection, structPragmas(p, name, origName), t) addTypeDef(typeSection, structPragmas(p, name, origName), t)
addSon(result, typeSection) addSon(result, typeSection)
parseTrailingDefinedIdents(p, result, name) parseTrailingDefinedIdents(p, result, name)
else: else:
var t = parseTuple(p, isUnion) var t = parseTuple(p, result, isUnion)
parseTrailingDefinedIdents(p, result, t) parseTrailingDefinedIdents(p, result, t)
else: else:
backtrackContext(p) backtrackContext(p)
@ -2034,7 +2164,7 @@ proc parseStandaloneClass(p: var TParser, isStruct: bool): PNode =
addTypeDef(typeSection, structPragmas(p, name, origName), t) addTypeDef(typeSection, structPragmas(p, name, origName), t)
parseTrailingDefinedIdents(p, result, name) parseTrailingDefinedIdents(p, result, name)
else: else:
var t = parseTuple(p, isUnion=false) var t = parseTuple(p, result, isUnion=false)
parseTrailingDefinedIdents(p, result, t) parseTrailingDefinedIdents(p, result, t)
else: else:
backtrackContext(p) backtrackContext(p)

View file

@ -0,0 +1,40 @@
enum vehicles
{
car = 0x10,
truck,
boat = 0x01,
ship = 1,
speedboat = 1,
bicycle = 4,
bobycar
};
enum
{
red = 4,
green = 2,
blue
};
typedef enum food
{
bread = 4,
toast = 4,
bun = 0x04,
cucumber = 2,
chocolate = 6
};
typedef enum numbers
{
one = 1,
two,
nten = - 10,
nnine,
four = 4,
three = + 3,
positivenine = + 9,
nfour = - 4,
negativeten = -10
};

View file

@ -0,0 +1,27 @@
struct normal{
int a;
int b;
};
typedef struct outerStruct {
struct normal a_nomal_one;
int a;
struct {
union {
int b;
} a_union_in_the_struct;
int c;
};
union {
int d;
struct {
int e;
} a_struct_in_the_union;
} a_union;
};