standalone structs; function pointers

This commit is contained in:
Andreas Rumpf 2010-07-23 15:56:27 +02:00
commit 5a2163d71d
5 changed files with 271 additions and 87 deletions

View file

@ -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
""" """

View file

@ -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,23 +186,19 @@ proc getTok(p: var TParser) =
proc parLineInfo(p: TParser): TLineInfo = proc parLineInfo(p: TParser): TLineInfo =
result = getLineInfo(p.lex) result = getLineInfo(p.lex)
proc skipComAux(p: var TParser, n: PNode) =
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 skipCom(p: var TParser, n: PNode) = proc skipCom(p: var TParser, n: PNode) =
while p.tok.xkind in {pxLineComment, pxStarComment}: while p.tok.xkind in {pxLineComment, 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 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,51 +425,99 @@ 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:
getTok(p, result) case p.tok.xkind
skipConst(p) # POSIX contains: ``int [restrict]`` of pxBracketLe:
if p.tok.xkind != pxBracketRi: getTok(p, result)
var tmp = result skipConst(p) # POSIX contains: ``int [restrict]``
var index = expression(p) if p.tok.xkind != pxBracketRi:
# array type: var tmp = result
result = newNodeP(nkBracketExpr, p) var index = expression(p)
addSon(result, newIdentNodeP("array", p)) # array type:
var r = newNodeP(nkRange, p) result = newNodeP(nkBracketExpr, p)
addSon(r, newIntNodeP(nkIntLit, 0, p)) addSon(result, newIdentNodeP("array", p))
addSon(r, newBinary("-", index, newIntNodeP(nkIntLit, 1, p), p)) var r = newNodeP(nkRange, p)
addSon(result, r) addSon(r, newIntNodeP(nkIntLit, 0, p))
addSon(result, tmp) addSon(r, newBinary("-", index, newIntNodeP(nkIntLit, 1, p), p))
else: addSon(result, r)
# pointer type: addSon(result, tmp)
var tmp = result
if pfRefs in p.options.flags:
result = newNodeP(nkRefTy, p)
else: else:
result = newNodeP(nkPtrTy, p) # pointer type:
result.addSon(tmp) var tmp = result
eat(p, pxBracketRi, result) if pfRefs in p.options.flags:
result = newNodeP(nkRefTy, p)
else:
result = newNodeP(nkPtrTy, p)
result.addSon(tmp)
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)
addSon(result, def) if not takeOnlyFirstField(p, isUnion) or sonsLen(result) < 1:
addSon(result, def)
if p.tok.xkind != pxComma: break if p.tok.xkind != pxComma: break
getTok(p, def) getTok(p, def)
eat(p, pxSemicolon, lastSon(result)) eat(p, pxSemicolon, lastSon(result))
@ -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:

View file

@ -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: eatNewLine(p, nil)
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p)
else: else:
parMessage(p, errXExpected, "string literal") skipLine(p)
eatNewLine(p, nil)
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)

View file

@ -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...

View file

@ -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)