standalone structs; function pointers
This commit is contained in:
parent
f30784b839
commit
5a2163d71d
5 changed files with 271 additions and 87 deletions
|
|
@ -28,6 +28,7 @@ Options:
|
||||||
(multiple --prefix options are supported)
|
(multiple --prefix options are supported)
|
||||||
--suffix:SUFFIX strip suffix for the generated Nimrod identifiers
|
--suffix:SUFFIX strip suffix for the generated Nimrod identifiers
|
||||||
(multiple --suffix options are supported)
|
(multiple --suffix options are supported)
|
||||||
|
--skipinclude do not convert ``#include`` to ``import``
|
||||||
-v, --version write c2nim's version
|
-v, --version write c2nim's version
|
||||||
-h, --help show this help
|
-h, --help show this help
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,6 @@
|
||||||
## It translates a C source file into a Nimrod AST. Then the renderer can be
|
## It translates a C source file into a Nimrod AST. Then the renderer can be
|
||||||
## used to convert the AST to its text representation.
|
## used to convert the AST to its text representation.
|
||||||
|
|
||||||
# XXX standalone structs and unions!
|
|
||||||
|
|
||||||
import
|
import
|
||||||
os, llstream, rnimsyn, clex, idents, strutils, pegs, ast, astalgo, msgs,
|
os, llstream, rnimsyn, clex, idents, strutils, pegs, ast, astalgo, msgs,
|
||||||
options, strtabs
|
options, strtabs
|
||||||
|
|
@ -21,7 +19,8 @@ type
|
||||||
TParserFlag = enum
|
TParserFlag = enum
|
||||||
pfRefs, ## use "ref" instead of "ptr" for C's typ*
|
pfRefs, ## use "ref" instead of "ptr" for C's typ*
|
||||||
pfCDecl, ## annotate procs with cdecl
|
pfCDecl, ## annotate procs with cdecl
|
||||||
pfStdCall ## annotate procs with stdcall
|
pfStdCall, ## annotate procs with stdcall
|
||||||
|
pfSkipInclude ## skip all ``#include``
|
||||||
|
|
||||||
TMacro {.final.} = object
|
TMacro {.final.} = object
|
||||||
name: string
|
name: string
|
||||||
|
|
@ -66,6 +65,7 @@ proc setOption*(parserOptions: PParserOptions, key: string, val=""): bool =
|
||||||
of "stdcall": incl(parserOptions.flags, pfStdCall)
|
of "stdcall": incl(parserOptions.flags, pfStdCall)
|
||||||
of "prefix": parserOptions.prefixes.add(val)
|
of "prefix": parserOptions.prefixes.add(val)
|
||||||
of "suffix": parserOptions.suffixes.add(val)
|
of "suffix": parserOptions.suffixes.add(val)
|
||||||
|
of "skipinclude": incl(parserOptions.flags, pfSkipInclude)
|
||||||
else: result = false
|
else: result = false
|
||||||
|
|
||||||
proc ParseUnit*(p: var TParser): PNode
|
proc ParseUnit*(p: var TParser): PNode
|
||||||
|
|
@ -87,7 +87,7 @@ proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
|
||||||
lexMessage(p.lex, msg, arg)
|
lexMessage(p.lex, msg, arg)
|
||||||
|
|
||||||
proc CloseParser(p: var TParser) = CloseLexer(p.lex)
|
proc CloseParser(p: var TParser) = CloseLexer(p.lex)
|
||||||
proc safeContext(p: var TParser) = p.backtrack.add(p.tok)
|
proc saveContext(p: var TParser) = p.backtrack.add(p.tok)
|
||||||
proc closeContext(p: var TParser) = discard p.backtrack.pop()
|
proc closeContext(p: var TParser) = discard p.backtrack.pop()
|
||||||
proc backtrackContext(p: var TParser) = p.tok = p.backtrack.pop()
|
proc backtrackContext(p: var TParser) = p.tok = p.backtrack.pop()
|
||||||
|
|
||||||
|
|
@ -120,7 +120,7 @@ proc parseMacroArguments(p: var TParser): seq[seq[ref TToken]] =
|
||||||
result.add(@[])
|
result.add(@[])
|
||||||
var i: array[pxParLe..pxCurlyLe, int]
|
var i: array[pxParLe..pxCurlyLe, int]
|
||||||
var L = 0
|
var L = 0
|
||||||
safeContext(p)
|
saveContext(p)
|
||||||
while true:
|
while true:
|
||||||
var kind = p.tok.xkind
|
var kind = p.tok.xkind
|
||||||
case kind
|
case kind
|
||||||
|
|
@ -166,9 +166,11 @@ proc expandMacro(p: var TParser, m: TMacro) =
|
||||||
for tok in items(m.body):
|
for tok in items(m.body):
|
||||||
if tok.xkind == pxMacroParam:
|
if tok.xkind == pxMacroParam:
|
||||||
for t in items(arguments[int(tok.iNumber)]):
|
for t in items(arguments[int(tok.iNumber)]):
|
||||||
|
#echo "t: ", t^
|
||||||
lastTok.next = t
|
lastTok.next = t
|
||||||
lastTok = t
|
lastTok = t
|
||||||
else:
|
else:
|
||||||
|
#echo "tok: ", tok^
|
||||||
lastTok.next = tok
|
lastTok.next = tok
|
||||||
lastTok = tok
|
lastTok = tok
|
||||||
lastTok.next = p.tok
|
lastTok.next = p.tok
|
||||||
|
|
@ -184,8 +186,7 @@ proc getTok(p: var TParser) =
|
||||||
proc parLineInfo(p: TParser): TLineInfo =
|
proc parLineInfo(p: TParser): TLineInfo =
|
||||||
result = getLineInfo(p.lex)
|
result = getLineInfo(p.lex)
|
||||||
|
|
||||||
proc skipCom(p: var TParser, n: PNode) =
|
proc skipComAux(p: var TParser, n: PNode) =
|
||||||
while p.tok.xkind in {pxLineComment, pxStarComment}:
|
|
||||||
if (n != nil):
|
if (n != nil):
|
||||||
if n.comment == nil: n.comment = p.tok.s
|
if n.comment == nil: n.comment = p.tok.s
|
||||||
else: add(n.comment, "\n" & p.tok.s)
|
else: add(n.comment, "\n" & p.tok.s)
|
||||||
|
|
@ -193,14 +194,11 @@ proc skipCom(p: var TParser, n: PNode) =
|
||||||
parMessage(p, warnCommentXIgnored, p.tok.s)
|
parMessage(p, warnCommentXIgnored, p.tok.s)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
||||||
|
proc skipCom(p: var TParser, n: PNode) =
|
||||||
|
while p.tok.xkind in {pxLineComment, pxStarComment}: skipcomAux(p, n)
|
||||||
|
|
||||||
proc skipStarCom(p: var TParser, n: PNode) =
|
proc skipStarCom(p: var TParser, n: PNode) =
|
||||||
while p.tok.xkind == pxStarComment:
|
while p.tok.xkind == pxStarComment: skipComAux(p, n)
|
||||||
if (n != nil):
|
|
||||||
if n.comment == nil: n.comment = p.tok.s
|
|
||||||
else: add(n.comment, "\n" & p.tok.s)
|
|
||||||
else:
|
|
||||||
parMessage(p, warnCommentXIgnored, p.tok.s)
|
|
||||||
getTok(p)
|
|
||||||
|
|
||||||
proc getTok(p: var TParser, n: PNode) =
|
proc getTok(p: var TParser, n: PNode) =
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -382,7 +380,6 @@ proc skipConst(p: var TParser) =
|
||||||
getTok(p, nil)
|
getTok(p, nil)
|
||||||
|
|
||||||
proc typeAtom(p: var TParser): PNode =
|
proc typeAtom(p: var TParser): PNode =
|
||||||
if p.tok.xkind != pxSymbol: return nil
|
|
||||||
skipConst(p)
|
skipConst(p)
|
||||||
ExpectIdent(p)
|
ExpectIdent(p)
|
||||||
case p.tok.s
|
case p.tok.s
|
||||||
|
|
@ -428,9 +425,28 @@ proc pointer(p: var TParser, a: PNode): PNode =
|
||||||
result = newIdentNodeP("pointer", p)
|
result = newIdentNodeP("pointer", p)
|
||||||
for j in 1..i-1: result = newPointerTy(p, result)
|
for j in 1..i-1: result = newPointerTy(p, result)
|
||||||
|
|
||||||
|
proc newProcPragmas(p: TParser): PNode =
|
||||||
|
result = newNodeP(nkPragma, p)
|
||||||
|
if pfCDecl in p.options.flags:
|
||||||
|
addSon(result, newIdentNodeP("cdecl", p))
|
||||||
|
elif pfStdCall in p.options.flags:
|
||||||
|
addSon(result, newIdentNodeP("stdcall", p))
|
||||||
|
|
||||||
|
proc addPragmas(father, pragmas: PNode) =
|
||||||
|
if sonsLen(pragmas) > 0: addSon(father, pragmas)
|
||||||
|
else: addSon(father, nil)
|
||||||
|
|
||||||
|
proc addReturnType(params, rettyp: PNode) =
|
||||||
|
if rettyp == nil or rettyp.kind != nkNilLit: addSon(params, rettyp)
|
||||||
|
else: addson(params, nil)
|
||||||
|
|
||||||
|
proc parseFormalParams(p: var TParser, params, pragmas: PNode)
|
||||||
|
|
||||||
proc parseTypeSuffix(p: var TParser, typ: PNode): PNode =
|
proc parseTypeSuffix(p: var TParser, typ: PNode): PNode =
|
||||||
result = typ
|
result = typ
|
||||||
while p.tok.xkind == pxBracketLe:
|
while true:
|
||||||
|
case p.tok.xkind
|
||||||
|
of pxBracketLe:
|
||||||
getTok(p, result)
|
getTok(p, result)
|
||||||
skipConst(p) # POSIX contains: ``int [restrict]``
|
skipConst(p) # POSIX contains: ``int [restrict]``
|
||||||
if p.tok.xkind != pxBracketRi:
|
if p.tok.xkind != pxBracketRi:
|
||||||
|
|
@ -453,25 +469,54 @@ proc parseTypeSuffix(p: var TParser, typ: PNode): PNode =
|
||||||
result = newNodeP(nkPtrTy, p)
|
result = newNodeP(nkPtrTy, p)
|
||||||
result.addSon(tmp)
|
result.addSon(tmp)
|
||||||
eat(p, pxBracketRi, result)
|
eat(p, pxBracketRi, result)
|
||||||
|
of pxParLe:
|
||||||
|
# function pointer:
|
||||||
|
var procType = newNodeP(nkProcTy, p)
|
||||||
|
var pragmas = newProcPragmas(p)
|
||||||
|
var params = newNodeP(nkFormalParams, p)
|
||||||
|
addReturnType(params, result)
|
||||||
|
parseFormalParams(p, params, pragmas)
|
||||||
|
addSon(procType, params)
|
||||||
|
addPragmas(procType, pragmas)
|
||||||
|
result = procType
|
||||||
|
else: break
|
||||||
|
|
||||||
proc typeDesc(p: var TParser): PNode =
|
proc typeDesc(p: var TParser): PNode =
|
||||||
result = typeAtom(p)
|
#result = typeAtom(p)
|
||||||
if result != nil:
|
#if result != nil:
|
||||||
result = pointer(p, result)
|
# result = pointer(p, result)
|
||||||
|
result = pointer(p, typeAtom(p))
|
||||||
|
|
||||||
proc parseStructBody(p: var TParser): PNode =
|
proc parseField(p: var TParser, kind: TNodeKind): PNode =
|
||||||
result = newNodeP(nkRecList, p)
|
if p.tok.xkind == pxParLe:
|
||||||
|
getTok(p, nil)
|
||||||
|
while p.tok.xkind == pxStar: getTok(p, nil)
|
||||||
|
result = parseField(p, kind)
|
||||||
|
eat(p, pxParRi, result)
|
||||||
|
else:
|
||||||
|
expectIdent(p)
|
||||||
|
if kind == nkRecList: result = fieldIdent(p.tok.s, p)
|
||||||
|
else: result = mangledIdent(p.tok.s, p)
|
||||||
|
getTok(p, result)
|
||||||
|
|
||||||
|
proc takeOnlyFirstField(p: TParser, isUnion: bool): bool =
|
||||||
|
# if we generate an interface to a header file, *all* fields can be
|
||||||
|
# generated:
|
||||||
|
result = isUnion and p.options.header.len == 0
|
||||||
|
|
||||||
|
proc parseStructBody(p: var TParser, isUnion: bool,
|
||||||
|
kind: TNodeKind = nkRecList): PNode =
|
||||||
|
result = newNodeP(kind, p)
|
||||||
eat(p, pxCurlyLe, result)
|
eat(p, pxCurlyLe, result)
|
||||||
while p.tok.xkind notin {pxEof, pxCurlyRi}:
|
while p.tok.xkind notin {pxEof, pxCurlyRi}:
|
||||||
var baseTyp = typeAtom(p)
|
var baseTyp = typeAtom(p)
|
||||||
while true:
|
while true:
|
||||||
var def = newNodeP(nkIdentDefs, p)
|
var def = newNodeP(nkIdentDefs, p)
|
||||||
var t = pointer(p, baseTyp)
|
var t = pointer(p, baseTyp)
|
||||||
expectIdent(p)
|
var i = parseField(p, kind)
|
||||||
var i = fieldIdent(p.tok.s, p)
|
|
||||||
getTok(p, i)
|
|
||||||
t = parseTypeSuffix(p, t)
|
t = parseTypeSuffix(p, t)
|
||||||
addSon(def, i, t, nil)
|
addSon(def, i, t, nil)
|
||||||
|
if not takeOnlyFirstField(p, isUnion) or sonsLen(result) < 1:
|
||||||
addSon(result, def)
|
addSon(result, def)
|
||||||
if p.tok.xkind != pxComma: break
|
if p.tok.xkind != pxComma: break
|
||||||
getTok(p, def)
|
getTok(p, def)
|
||||||
|
|
@ -500,12 +545,12 @@ proc enumPragmas(p: TParser, name: PNode): PNode =
|
||||||
addSon(pragmas, e)
|
addSon(pragmas, e)
|
||||||
addSon(result, pragmas)
|
addSon(result, pragmas)
|
||||||
|
|
||||||
proc parseStruct(p: var TParser): PNode =
|
proc parseStruct(p: var TParser, isUnion: bool): PNode =
|
||||||
result = newNodeP(nkObjectTy, p)
|
result = newNodeP(nkObjectTy, p)
|
||||||
addSon(result, nil) # no pragmas
|
addSon(result, nil) # no pragmas
|
||||||
addSon(result, nil) # no inheritance
|
addSon(result, nil) # no inheritance
|
||||||
if p.tok.xkind == pxCurlyLe:
|
if p.tok.xkind == pxCurlyLe:
|
||||||
addSon(result, parseStructBody(p))
|
addSon(result, parseStructBody(p, isUnion))
|
||||||
else:
|
else:
|
||||||
addSon(result, newNodeP(nkRecList, p))
|
addSon(result, newNodeP(nkRecList, p))
|
||||||
|
|
||||||
|
|
@ -558,14 +603,10 @@ proc parseCallConv(p: var TParser, pragmas: PNode) =
|
||||||
|
|
||||||
proc parseFunctionPointerDecl(p: var TParser, rettyp: PNode): PNode =
|
proc parseFunctionPointerDecl(p: var TParser, rettyp: PNode): PNode =
|
||||||
var procType = newNodeP(nkProcTy, p)
|
var procType = newNodeP(nkProcTy, p)
|
||||||
var pragmas = newNodeP(nkPragma, p)
|
var pragmas = newProcPragmas(p)
|
||||||
if pfCDecl in p.options.flags:
|
|
||||||
addSon(pragmas, newIdentNodeP("cdecl", p))
|
|
||||||
elif pfStdCall in p.options.flags:
|
|
||||||
addSon(pragmas, newIdentNodeP("stdcall", p))
|
|
||||||
var params = newNodeP(nkFormalParams, p)
|
var params = newNodeP(nkFormalParams, p)
|
||||||
eat(p, pxParLe, params)
|
eat(p, pxParLe, params)
|
||||||
addSon(params, rettyp)
|
addReturnType(params, rettyp)
|
||||||
parseCallConv(p, pragmas)
|
parseCallConv(p, pragmas)
|
||||||
if p.tok.xkind == pxStar: getTok(p, params)
|
if p.tok.xkind == pxStar: getTok(p, params)
|
||||||
else: parMessage(p, errTokenExpected, "*")
|
else: parMessage(p, errTokenExpected, "*")
|
||||||
|
|
@ -573,7 +614,7 @@ proc parseFunctionPointerDecl(p: var TParser, rettyp: PNode): PNode =
|
||||||
eat(p, pxParRi, name)
|
eat(p, pxParRi, name)
|
||||||
parseFormalParams(p, params, pragmas)
|
parseFormalParams(p, params, pragmas)
|
||||||
addSon(procType, params)
|
addSon(procType, params)
|
||||||
addSon(procType, pragmas)
|
addPragmas(procType, pragmas)
|
||||||
|
|
||||||
if p.inTypeDef == 0:
|
if p.inTypeDef == 0:
|
||||||
result = newNodeP(nkVarSection, p)
|
result = newNodeP(nkVarSection, p)
|
||||||
|
|
@ -639,10 +680,10 @@ proc enumFields(p: var TParser): PNode =
|
||||||
if p.tok.xkind != pxComma: break
|
if p.tok.xkind != pxComma: break
|
||||||
getTok(p, e)
|
getTok(p, e)
|
||||||
|
|
||||||
proc parseTypedefStruct(p: var TParser, result: PNode) =
|
proc parseTypedefStruct(p: var TParser, result: PNode, isUnion: bool) =
|
||||||
getTok(p, result)
|
getTok(p, result)
|
||||||
if p.tok.xkind == pxCurlyLe:
|
if p.tok.xkind == pxCurlyLe:
|
||||||
var t = parseStruct(p)
|
var t = parseStruct(p, isUnion)
|
||||||
var origName = p.tok.s
|
var origName = p.tok.s
|
||||||
var name = skipIdent(p)
|
var name = skipIdent(p)
|
||||||
addTypeDef(result, structPragmas(p, name, origName), t)
|
addTypeDef(result, structPragmas(p, name, origName), t)
|
||||||
|
|
@ -653,7 +694,7 @@ proc parseTypedefStruct(p: var TParser, result: PNode) =
|
||||||
var nameOrType = skipIdent(p)
|
var nameOrType = skipIdent(p)
|
||||||
case p.tok.xkind
|
case p.tok.xkind
|
||||||
of pxCurlyLe:
|
of pxCurlyLe:
|
||||||
var t = parseStruct(p)
|
var t = parseStruct(p, 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!
|
||||||
|
|
@ -721,7 +762,8 @@ proc parseTypeDef(p: var TParser): PNode =
|
||||||
inc(p.inTypeDef)
|
inc(p.inTypeDef)
|
||||||
expectIdent(p)
|
expectIdent(p)
|
||||||
case p.tok.s
|
case p.tok.s
|
||||||
of "struct", "union": parseTypedefStruct(p, result)
|
of "struct": parseTypedefStruct(p, result, isUnion=false)
|
||||||
|
of "union": parseTypedefStruct(p, result, isUnion=true)
|
||||||
of "enum": parseTypedefEnum(p, result)
|
of "enum": parseTypedefEnum(p, result)
|
||||||
else:
|
else:
|
||||||
var t = typeAtom(p)
|
var t = typeAtom(p)
|
||||||
|
|
@ -773,7 +815,24 @@ proc parseVarDecl(p: var TParser, baseTyp, typ: PNode,
|
||||||
addSon(def, parseTypeSuffix(p, t))
|
addSon(def, parseTypeSuffix(p, t))
|
||||||
addInitializer(p, def)
|
addInitializer(p, def)
|
||||||
addSon(result, def)
|
addSon(result, def)
|
||||||
eat(p, pxSemicolon, result)
|
eat(p, pxSemicolon)
|
||||||
|
|
||||||
|
when false:
|
||||||
|
proc declaration(p: var TParser, father: PNode) =
|
||||||
|
# general syntax to parse is::
|
||||||
|
#
|
||||||
|
# baseType ::= typeIdent | ((struct|union|enum) ident ("{" body "}" )?
|
||||||
|
# | "{" body "}")
|
||||||
|
# declIdent ::= "(" "*" ident ")" formalParams ("=" exprNoComma)?
|
||||||
|
# | ident ((formalParams ("{" statements "}")?)|"="
|
||||||
|
# exprNoComma|(typeSuffix("=" exprNoComma)? ))?
|
||||||
|
# declaration ::= baseType (pointers)? declIdent ("," declIdent)*
|
||||||
|
var pragmas = newNodeP(nkPragma, p)
|
||||||
|
|
||||||
|
skipDeclarationSpecifiers(p)
|
||||||
|
parseCallConv(p, pragmas)
|
||||||
|
skipDeclarationSpecifiers(p)
|
||||||
|
expectIdent(p)
|
||||||
|
|
||||||
proc declaration(p: var TParser): PNode =
|
proc declaration(p: var TParser): PNode =
|
||||||
result = newNodeP(nkProcDef, p)
|
result = newNodeP(nkProcDef, p)
|
||||||
|
|
@ -785,7 +844,6 @@ proc declaration(p: var TParser): PNode =
|
||||||
expectIdent(p)
|
expectIdent(p)
|
||||||
var baseTyp = typeAtom(p)
|
var baseTyp = typeAtom(p)
|
||||||
var rettyp = pointer(p, baseTyp)
|
var rettyp = pointer(p, baseTyp)
|
||||||
if rettyp != nil and rettyp.kind == nkNilLit: rettyp = nil
|
|
||||||
skipDeclarationSpecifiers(p)
|
skipDeclarationSpecifiers(p)
|
||||||
parseCallConv(p, pragmas)
|
parseCallConv(p, pragmas)
|
||||||
skipDeclarationSpecifiers(p)
|
skipDeclarationSpecifiers(p)
|
||||||
|
|
@ -794,7 +852,7 @@ proc declaration(p: var TParser): PNode =
|
||||||
# Function pointer declaration: This is of course only a heuristic, but the
|
# Function pointer declaration: This is of course only a heuristic, but the
|
||||||
# best we can do here.
|
# best we can do here.
|
||||||
result = parseFunctionPointerDecl(p, rettyp)
|
result = parseFunctionPointerDecl(p, rettyp)
|
||||||
eat(p, pxSemicolon, result)
|
eat(p, pxSemicolon)
|
||||||
return
|
return
|
||||||
ExpectIdent(p)
|
ExpectIdent(p)
|
||||||
var origName = p.tok.s
|
var origName = p.tok.s
|
||||||
|
|
@ -804,7 +862,7 @@ proc declaration(p: var TParser): PNode =
|
||||||
# really a function!
|
# really a function!
|
||||||
var name = mangledIdent(origName, p)
|
var name = mangledIdent(origName, p)
|
||||||
var params = newNodeP(nkFormalParams, p)
|
var params = newNodeP(nkFormalParams, p)
|
||||||
addSon(params, rettyp)
|
addReturnType(params, rettyp)
|
||||||
parseFormalParams(p, params, pragmas)
|
parseFormalParams(p, params, pragmas)
|
||||||
|
|
||||||
if pfCDecl in p.options.flags:
|
if pfCDecl in p.options.flags:
|
||||||
|
|
@ -901,7 +959,7 @@ proc isDefinitelyAType(p: var TParser): bool =
|
||||||
|
|
||||||
proc castExpression(p: var TParser): PNode =
|
proc castExpression(p: var TParser): PNode =
|
||||||
if p.tok.xkind == pxParLe:
|
if p.tok.xkind == pxParLe:
|
||||||
SafeContext(p)
|
saveContext(p)
|
||||||
result = newNodeP(nkCast, p)
|
result = newNodeP(nkCast, p)
|
||||||
getTok(p, result)
|
getTok(p, result)
|
||||||
var t = isDefinitelyAType(p)
|
var t = isDefinitelyAType(p)
|
||||||
|
|
@ -1128,7 +1186,7 @@ proc incdec(p: var TParser, opr: string, a: PNode): PNode =
|
||||||
addSon(result, b)
|
addSon(result, b)
|
||||||
|
|
||||||
proc assignmentExpression(p: var TParser): PNode =
|
proc assignmentExpression(p: var TParser): PNode =
|
||||||
safeContext(p)
|
saveContext(p)
|
||||||
var a = lvalue(p)
|
var a = lvalue(p)
|
||||||
case p.tok.xkind
|
case p.tok.xkind
|
||||||
of pxAsgn:
|
of pxAsgn:
|
||||||
|
|
@ -1325,7 +1383,7 @@ proc declarationOrStatement(p: var TParser): PNode =
|
||||||
result = declaration(p)
|
result = declaration(p)
|
||||||
else:
|
else:
|
||||||
# ordinary identifier:
|
# ordinary identifier:
|
||||||
safeContext(p)
|
saveContext(p)
|
||||||
getTok(p) # skip identifier to look ahead
|
getTok(p) # skip identifier to look ahead
|
||||||
case p.tok.xkind
|
case p.tok.xkind
|
||||||
of pxSymbol, pxStar:
|
of pxSymbol, pxStar:
|
||||||
|
|
@ -1345,6 +1403,49 @@ proc declarationOrStatement(p: var TParser): PNode =
|
||||||
backtrackContext(p)
|
backtrackContext(p)
|
||||||
result = expressionStatement(p)
|
result = expressionStatement(p)
|
||||||
|
|
||||||
|
proc parseTuple(p: var TParser, isUnion: bool): PNode =
|
||||||
|
result = parseStructBody(p, isUnion, nkTupleTy)
|
||||||
|
|
||||||
|
proc parseTrailingDefinedIdents(p: var TParser, result, baseTyp: PNode) =
|
||||||
|
var varSection = newNodeP(nkVarSection, p)
|
||||||
|
while p.tok.xkind notin {pxEof, pxSemicolon}:
|
||||||
|
var t = pointer(p, baseTyp)
|
||||||
|
expectIdent(p)
|
||||||
|
var def = newNodeP(nkIdentDefs, p)
|
||||||
|
addSon(def, varIdent(p.tok.s, p))
|
||||||
|
getTok(p, def)
|
||||||
|
addSon(def, parseTypeSuffix(p, t))
|
||||||
|
addInitializer(p, def)
|
||||||
|
addSon(varSection, def)
|
||||||
|
if p.tok.xkind != pxComma: break
|
||||||
|
getTok(p, def)
|
||||||
|
eat(p, pxSemicolon)
|
||||||
|
if sonsLen(varSection) > 0:
|
||||||
|
addSon(result, varSection)
|
||||||
|
|
||||||
|
proc parseStandaloneStruct(p: var TParser, isUnion: bool): PNode =
|
||||||
|
result = newNodeP(nkStmtList, p)
|
||||||
|
saveContext(p)
|
||||||
|
getTok(p, result) # skip "struct" or "union"
|
||||||
|
var origName = ""
|
||||||
|
if p.tok.xkind == pxSymbol:
|
||||||
|
origName = p.tok.s
|
||||||
|
getTok(p, result)
|
||||||
|
if p.tok.xkind == pxCurlyLe:
|
||||||
|
if origName.len > 0:
|
||||||
|
var name = mangledIdent(origName, p)
|
||||||
|
var t = parseStruct(p, isUnion)
|
||||||
|
var typeSection = newNodeP(nkTypeSection, p)
|
||||||
|
addTypeDef(typeSection, structPragmas(p, name, origName), t)
|
||||||
|
addSon(result, typeSection)
|
||||||
|
parseTrailingDefinedIdents(p, result, name)
|
||||||
|
else:
|
||||||
|
var t = parseTuple(p, isUnion)
|
||||||
|
parseTrailingDefinedIdents(p, result, t)
|
||||||
|
else:
|
||||||
|
backtrackContext(p)
|
||||||
|
result = declaration(p)
|
||||||
|
|
||||||
proc parseFor(p: var TParser, result: PNode) =
|
proc parseFor(p: var TParser, result: PNode) =
|
||||||
# 'for' '(' expression_statement expression_statement expression? ')'
|
# 'for' '(' expression_statement expression_statement expression? ')'
|
||||||
# statement
|
# statement
|
||||||
|
|
@ -1425,11 +1526,21 @@ proc parseSwitch(p: var TParser): PNode =
|
||||||
if b.kind == nkElse: break
|
if b.kind == nkElse: break
|
||||||
eat(p, pxCurlyRi)
|
eat(p, pxCurlyRi)
|
||||||
|
|
||||||
proc embedStmts(sl, a: PNode) =
|
proc addStmt(sl, a: PNode) =
|
||||||
if a.kind != nkStmtList:
|
# merge type sections is possible:
|
||||||
|
if a.kind != nkTypeSection or sonsLen(sl) == 0 or
|
||||||
|
lastSon(sl).kind != nkTypeSection:
|
||||||
addSon(sl, a)
|
addSon(sl, a)
|
||||||
else:
|
else:
|
||||||
for i in 0..sonsLen(a)-1: addSon(sl, a[i])
|
var ts = lastSon(sl)
|
||||||
|
for i in 0..sonsLen(a)-1: addSon(ts, a.sons[i])
|
||||||
|
|
||||||
|
proc embedStmts(sl, a: PNode) =
|
||||||
|
if a.kind != nkStmtList:
|
||||||
|
addStmt(sl, a)
|
||||||
|
else:
|
||||||
|
for i in 0..sonsLen(a)-1:
|
||||||
|
if a[i] != nil: addStmt(sl, a[i])
|
||||||
|
|
||||||
proc compoundStatement(p: var TParser): PNode =
|
proc compoundStatement(p: var TParser): PNode =
|
||||||
result = newNodeP(nkStmtList, p)
|
result = newNodeP(nkStmtList, p)
|
||||||
|
|
@ -1493,6 +1604,10 @@ proc statement(p: var TParser): PNode =
|
||||||
result = enumSpecifier(p)
|
result = enumSpecifier(p)
|
||||||
of "typedef":
|
of "typedef":
|
||||||
result = parseTypeDef(p)
|
result = parseTypeDef(p)
|
||||||
|
of "struct":
|
||||||
|
result = parseStandaloneStruct(p, isUnion=false)
|
||||||
|
of "union":
|
||||||
|
result = parseStandaloneStruct(p, isUnion=true)
|
||||||
else:
|
else:
|
||||||
result = declarationOrStatement(p)
|
result = declarationOrStatement(p)
|
||||||
of pxCurlyLe:
|
of pxCurlyLe:
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ proc parseDefBody(p: var TParser, m: var TMacro, params: seq[string]) =
|
||||||
# A little hack: We safe the context, so that every following token will be
|
# A little hack: We safe the context, so that every following token will be
|
||||||
# put into a newly allocated TToken object. Thus we can just save a
|
# put into a newly allocated TToken object. Thus we can just save a
|
||||||
# reference to the token in the macro's body.
|
# reference to the token in the macro's body.
|
||||||
safeContext(p)
|
saveContext(p)
|
||||||
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}:
|
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}:
|
||||||
case p.tok.xkind
|
case p.tok.xkind
|
||||||
of pxSymbol:
|
of pxSymbol:
|
||||||
|
|
@ -136,16 +136,14 @@ proc parseInclude(p: var TParser): PNode =
|
||||||
result = newNodeP(nkImportStmt, p)
|
result = newNodeP(nkImportStmt, p)
|
||||||
while isDir(p, "include"):
|
while isDir(p, "include"):
|
||||||
getTok(p) # skip "include"
|
getTok(p) # skip "include"
|
||||||
if p.tok.xkind == pxStrLit:
|
if p.tok.xkind == pxStrLit and pfSkipInclude notin p.options.flags:
|
||||||
var file = newStrNodeP(nkStrLit, p.tok.s, p)
|
var file = newStrNodeP(nkStrLit, changeFileExt(p.tok.s, ""), p)
|
||||||
addSon(result, file)
|
addSon(result, file)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
skipStarCom(p, file)
|
skipStarCom(p, file)
|
||||||
elif p.tok.xkind == pxLt:
|
|
||||||
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p)
|
|
||||||
else:
|
|
||||||
parMessage(p, errXExpected, "string literal")
|
|
||||||
eatNewLine(p, nil)
|
eatNewLine(p, nil)
|
||||||
|
else:
|
||||||
|
skipLine(p)
|
||||||
if sonsLen(result) == 0:
|
if sonsLen(result) == 0:
|
||||||
# we only parsed includes that we chose to ignore:
|
# we only parsed includes that we chose to ignore:
|
||||||
result = nil
|
result = nil
|
||||||
|
|
@ -300,7 +298,7 @@ proc parseDir(p: var TParser): PNode =
|
||||||
of "ifdef": result = parseIfdef(p)
|
of "ifdef": result = parseIfdef(p)
|
||||||
of "ifndef": result = parseIfndef(p)
|
of "ifndef": result = parseIfndef(p)
|
||||||
of "if": result = parseIfDir(p)
|
of "if": result = parseIfDir(p)
|
||||||
of "cdecl", "stdcall", "ref":
|
of "cdecl", "stdcall", "ref", "skipinclude":
|
||||||
discard setOption(p.options, p.tok.s)
|
discard setOption(p.options, p.tok.s)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
eatNewLine(p, nil)
|
eatNewLine(p, nil)
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,16 @@ is generated. They should be put into a ``#ifdef C2NIM`` section so that
|
||||||
ordinary C compilers ignore them.
|
ordinary C compilers ignore them.
|
||||||
|
|
||||||
|
|
||||||
|
``#skipinclude`` directive
|
||||||
|
--------------------------
|
||||||
|
**Note**: There is also a ``--skipinclude`` command line option that can be
|
||||||
|
used for the same purpose.
|
||||||
|
|
||||||
|
By default, c2nim translates an ``#include`` that is not followed by ``<``
|
||||||
|
(like in ``#include <stdlib>``) to a Nimrod ``import`` statement. This
|
||||||
|
directive tells c2nim to just skip any ``#include``.
|
||||||
|
|
||||||
|
|
||||||
``#stdcall`` and ``#cdecl`` directives
|
``#stdcall`` and ``#cdecl`` directives
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
**Note**: There are also ``--stdcall`` and ``--cdecl`` command line options
|
**Note**: There are also ``--stdcall`` and ``--cdecl`` command line options
|
||||||
|
|
@ -225,17 +235,17 @@ that ``EXPORT`` is a macro that should be expanded by c2nim too:
|
||||||
EXTERN(int) f(void);
|
EXTERN(int) f(void);
|
||||||
EXTERN(int) g(void);
|
EXTERN(int) g(void);
|
||||||
|
|
||||||
``#def`` is very similar to C's ``#define``.
|
``#def`` is very similar to C's ``#define``, so in general the macro definition
|
||||||
|
can be copied and pasted into a ``#def`` directive.
|
||||||
|
|
||||||
|
|
||||||
Limitations
|
Limitations
|
||||||
===========
|
===========
|
||||||
|
|
||||||
* C's ``,`` operator (comma operator) is not supported.
|
* C's ``,`` operator (comma operator) is not supported.
|
||||||
* C's ``union`` has no equivalent in Nimrod.
|
* C's ``union`` are translated to Nimrod's objects and only the first field
|
||||||
* Standalone ``struct x {}`` declarations are not implemented. Put them into
|
is included in the object type. This way there is a high chance that it is
|
||||||
a ``typedef``.
|
binary compatible to the union.
|
||||||
* The condition in a ``do while(condition)`` statement must be ``0``.
|
* The condition in a ``do while(condition)`` statement must be ``0``.
|
||||||
* Lots of other small issues...
|
* Lots of other small issues...
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,66 @@ extern "C" {
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void* x;
|
||||||
|
void* fn(void);
|
||||||
|
void (*fn)(void);
|
||||||
|
void* (*fn)(void);
|
||||||
|
void* (*fn)(void*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Very ugly real world code ahead:
|
||||||
|
*/
|
||||||
|
|
||||||
|
#def JMETHOD(rettype, name, params) rettype (*name) params
|
||||||
|
|
||||||
|
typedef struct cjpeg_source_struct * cjpeg_source_ptr;
|
||||||
|
|
||||||
|
struct cjpeg_source_struct {
|
||||||
|
JMETHOD(void, start_input, (j_compress_ptr cinfo,
|
||||||
|
cjpeg_source_ptr sinfo));
|
||||||
|
JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,
|
||||||
|
cjpeg_source_ptr sinfo));
|
||||||
|
JMETHOD(void, finish_input, (j_compress_ptr cinfo,
|
||||||
|
cjpeg_source_ptr sinfo));
|
||||||
|
|
||||||
|
FILE *input_file;
|
||||||
|
|
||||||
|
JSAMPARRAY buffer;
|
||||||
|
JDIMENSION buffer_height;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test standalone structs:
|
||||||
|
|
||||||
|
union myunion {
|
||||||
|
char x, y, *z;
|
||||||
|
myint a, b;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
struct mystruct {
|
||||||
|
char x, y, *z;
|
||||||
|
myint a, b;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mystruct fn(i32 x, i64 y);
|
||||||
|
|
||||||
|
struct mystruct {
|
||||||
|
char x, y, *z;
|
||||||
|
myint a, b;
|
||||||
|
} *myvar = NULL, **myvar2 = NULL;
|
||||||
|
|
||||||
|
// anonymous struct:
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char x, y, *z;
|
||||||
|
myint a, b;
|
||||||
|
} varX, **varY;
|
||||||
|
|
||||||
|
// empty anonymous struct:
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
} varX, **varY;
|
||||||
|
|
||||||
// Test C2NIM skipping:
|
// Test C2NIM skipping:
|
||||||
|
|
||||||
#define MASK(x) ((x) & 0xff)
|
#define MASK(x) ((x) & 0xff)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue