diff options
-rwxr-xr-x | doc/nimrodc.txt | 6 | ||||
-rwxr-xr-x | lib/system/mmdisp.nim | 57 | ||||
-rwxr-xr-x | rod/c2nim/c2nim.nim | 1 | ||||
-rwxr-xr-x | rod/c2nim/clex.nim | 11 | ||||
-rwxr-xr-x | rod/c2nim/cparse.nim | 105 | ||||
-rwxr-xr-x | rod/c2nim/cpp.nim | 253 | ||||
-rw-r--r-- | rod/c2nim/manual.txt | 28 | ||||
-rw-r--r-- | rod/c2nim/tests/systest.c | 41 |
8 files changed, 404 insertions, 98 deletions
diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt index b4960c5e4..1ada1fffb 100755 --- a/doc/nimrodc.txt +++ b/doc/nimrodc.txt @@ -75,9 +75,11 @@ C file lists the OS, CPU and CC the file has been compiled for. ============== Nimrod supports the generation of DLLs. However, there must be only one - instance of the GC per address space. This instance is contained in + instance of the GC per process/address space. This instance is contained in ``nimrtl.dll``. This means that every generated Nimrod DLL depends - on ``nimrtl.dll``. + on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command:: + + nimrod c -d:release lib/nimrtl.nim Additional Features diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index c89e7dffa..44b3f7326 100755 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2009 Andreas Rumpf +# (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -187,6 +187,60 @@ elif defined(nogc): dest^ = src include "system/cellsets" +elif appType == "lib": + {.warning: "gc in a library context may not work".} + when hostOS == "windows": + const nimrtl = "nimrtl.dll" + elif hostOS == "macosx": + const nimrtl = "nimrtl.dynlib" + else: + const nimrtl = "libnimrtl.so" + + when not defined(includeGC): + # ordinary client; use the GC from nimrtl.dll: + proc initGC() {.cdecl, importc, dynlib: nimrtl.} + proc GC_disable() {.cdecl, importc, dynlib: nimrtl.} + proc GC_enable() {.cdecl, importc, dynlib: nimrtl.} + proc GC_fullCollect() {.cdecl, importc, dynlib: nimrtl.} + proc GC_setStrategy(strategy: TGC_Strategy) {. + cdecl, importc, dynlib: nimrtl.} + proc GC_enableMarkAndSweep() {.cdecl, importc, dynlib: nimrtl.} + proc GC_disableMarkAndSweep() {.cdecl, importc, dynlib: nimrtl.} + proc GC_getStatistics(): string {.cdecl, importc, dynlib: nimrtl.} + + proc newObj(typ: PNimType, size: int): pointer {. + compilerproc, cdecl, importc, dynlib: nimrtl.} + proc newSeq(typ: PNimType, len: int): pointer {. + compilerproc, cdecl, importc, dynlib: nimrtl.} + proc growObj(old: pointer, newsize: int): pointer {. + cdecl, importc, dynlib: nimrtl.} + + proc setStackBottom(theStackBottom: pointer) {. + compilerproc, cdecl, importc, dynlib: nimrtl.} + proc nimGCref(p: pointer) {. + compilerproc, cdecl, importc, dynlib: nimrtl.} + proc nimGCunref(p: pointer) {. + compilerproc, cdecl, importc, dynlib: nimrtl.} + + # The write barrier is performance critical! + # XXX We should ensure that they are inlined here. + # Later implementations will do this. + + proc unsureAsgnRef(dest: ppointer, src: pointer) {. + compilerproc, cdecl, importc, dynlib: nimrtl.} + proc asgnRef(dest: ppointer, src: pointer) {. + compilerproc, cdecl, importc, dynlib: nimrtl.} + proc asgnRefNoCycle(dest: ppointer, src: pointer) {. + compilerproc, cdecl, importc, dynlib: nimrtl.} + + else: + # include the GC and export it! + include "system/alloc" + include "system/cellsets" + assert(sizeof(TCell) == sizeof(TFreeCell)) + include "system/gc" + + include "system/cellsets" else: include "system/alloc" include "system/cellsets" @@ -195,4 +249,3 @@ else: {.pop.} - diff --git a/rod/c2nim/c2nim.nim b/rod/c2nim/c2nim.nim index 52d16ce05..118ff608d 100755 --- a/rod/c2nim/c2nim.nim +++ b/rod/c2nim/c2nim.nim @@ -28,7 +28,6 @@ Options: (multiple --prefix options are supported) --suffix:SUFFIX strip suffix for the generated Nimrod identifiers (multiple --suffix options are supported) - --skip:IDENT skip IDENT in the input file -v, --version write c2nim's version -h, --help show this help """ diff --git a/rod/c2nim/clex.nim b/rod/c2nim/clex.nim index ecf337dd9..7b4fa73fc 100755 --- a/rod/c2nim/clex.nim +++ b/rod/c2nim/clex.nim @@ -24,6 +24,7 @@ const type TTokKind* = enum pxInvalid, pxEof, + pxMacroParam, # fake token: macro parameter (with its index) pxStarComment, # /* */ comment pxLineComment, # // comment pxDirective, # #define, etc. @@ -78,10 +79,9 @@ type pxIntLit, pxInt64Lit, # long constant like 0x70fffffff or out of int range pxFloatLit, - pxParLe, pxParRi, - pxBracketLe, pxBracketRi, + pxParLe, pxBracketLe, pxCurlyLe, # this order is important + pxParRi, pxBracketRi, pxCurlyRi, # for macro argument parsing! pxComma, pxSemiColon, pxColon, - pxCurlyLe, pxCurlyRi TTokKinds* = set[TTokKind] type @@ -89,7 +89,8 @@ type TToken* = object xkind*: TTokKind # the type of the token s*: string # parsed symbol, char or string literal - iNumber*: BiggestInt # the parsed integer literal + iNumber*: BiggestInt # the parsed integer literal; + # if xkind == pxMacroParam: parameter's position fNumber*: BiggestFloat # the parsed floating point literal base*: TNumericalBase # the numerical base; only valid for int # or float literals @@ -99,7 +100,6 @@ type filename*: string inDirective: bool - proc getTok*(L: var TLexer, tok: var TToken) proc PrintTok*(tok: TToken) proc `$`*(tok: TToken): string @@ -140,6 +140,7 @@ proc TokKindToStr*(k: TTokKind): string = case k of pxEof: result = "[EOF]" of pxInvalid: result = "[invalid]" + of pxMacroParam: result = "[macro param]" of pxStarComment, pxLineComment: result = "[comment]" of pxStrLit: result = "[string literal]" of pxCharLit: result = "[char literal]" diff --git a/rod/c2nim/cparse.nim b/rod/c2nim/cparse.nim index b0f2a3e3d..3ec1594f1 100755 --- a/rod/c2nim/cparse.nim +++ b/rod/c2nim/cparse.nim @@ -7,9 +7,9 @@ # distribution, for details about the copyright. # -# This module implements an Ansi C parser. -# It transfers a C source file into a Nimrod AST. Then the renderer can be -# used to convert the AST to its text representation. +## This module implements an Ansi C parser. +## It translates a C source file into a Nimrod AST. Then the renderer can be +## used to convert the AST to its text representation. # XXX standalone structs and unions! # XXX header pragma for struct and union fields! @@ -20,16 +20,22 @@ import options, strtabs type - TParserFlag* = enum + TParserFlag = enum pfRefs, ## use "ref" instead of "ptr" for C's typ* pfCDecl, ## annotate procs with cdecl pfStdCall ## annotate procs with stdcall + TMacro {.final.} = object + name: string + params: int # number of parameters + body: seq[ref TToken] # can contain pxMacroParam tokens + TParserOptions {.final.} = object flags: set[TParserFlag] - prefixes, suffixes, skipWords: seq[string] + prefixes, suffixes: seq[string] mangleRules: seq[tuple[pattern: TPeg, frmt: string]] dynlibSym, header: string + macros: seq[TMacro] PParserOptions* = ref TParserOptions TParser* {.final.} = object @@ -46,7 +52,7 @@ proc newParserOptions*(): PParserOptions = new(result) result.prefixes = @[] result.suffixes = @[] - result.skipWords = @[] + result.macros = @[] result.mangleRules = @[] result.flags = {} result.dynlibSym = "" @@ -62,7 +68,6 @@ proc setOption*(parserOptions: PParserOptions, key: string, val=""): bool = of "stdcall": incl(parserOptions.flags, pfStdCall) of "prefix": parserOptions.prefixes.add(val) of "suffix": parserOptions.suffixes.add(val) - of "skip": parserOptions.skipWords.add(val) else: result = false proc ParseUnit*(p: var TParser): PNode @@ -71,7 +76,6 @@ proc openParser*(p: var TParser, filename: string, inputStream: PLLStream, proc closeParser*(p: var TParser) proc exSymbol*(n: var PNode) proc fixRecordDef*(n: var PNode) - # XXX: move these two to an auxiliary module # implementation @@ -81,7 +85,11 @@ proc OpenParser(p: var TParser, filename: string, p.options = options p.backtrack = @[] new(p.tok) - + +proc parMessage(p: TParser, msg: TMsgKind, arg = "") = + #assert false + lexMessage(p.lex, msg, arg) + proc CloseParser(p: var TParser) = CloseLexer(p.lex) proc safeContext(p: var TParser) = p.backtrack.add(p.tok) proc closeContext(p: var TParser) = discard p.backtrack.pop() @@ -102,18 +110,81 @@ proc rawGetTok(p: var TParser) = p.tok.next = t p.tok = t -proc isSkipWord(p: TParser): bool = - for s in items(p.options.skipWords): - if p.tok.s == s: return true +proc findMacro(p: TParser): int = + for i in 0..high(p.options.macros): + if p.tok.s == p.options.macros[i].name: return i + return -1 -proc getTok(p: var TParser) = +proc rawEat(p: var TParser, xkind: TTokKind) = + if p.tok.xkind == xkind: rawGetTok(p) + else: parMessage(p, errTokenExpected, TokKindToStr(xkind)) + +proc parseMacroArguments(p: var TParser): seq[seq[ref TToken]] = + result = @[] + result.add(@[]) + var i: array[pxParLe..pxCurlyLe, int] + var L = 0 + safeContext(p) while true: + var kind = p.tok.xkind + case kind + of pxEof: rawEat(p, pxParRi) + of pxParLe, pxBracketLe, pxCurlyLe: + inc(i[kind]) + result[L].add(p.tok) + of pxParRi: + # end of arguments? + if i[pxParLe] == 0: break + dec(i[pxParLe]) + result[L].add(p.tok) + of pxBracketRi, pxCurlyRi: + kind = pred(kind, 3) + if i[kind] > 0: dec(i[kind]) + result[L].add(p.tok) + of pxComma: + if i[pxParLe] == 0 and i[pxBracketLe] == 0 and i[pxCurlyLe] == 0: + # next argument: comma is not part of the argument + rawGetTok(p) + result.add(@[]) + inc(L) + else: + # comma does not separate different arguments: + result[L].add(p.tok) + else: + result[L].add(p.tok) rawGetTok(p) - if p.tok.xkind != pxSymbol or not isSkipWord(p): break + closeContext(p) -proc parMessage(p: TParser, msg: TMsgKind, arg = "") = - #assert false - lexMessage(p.lex, msg, arg) +proc expandMacro(p: var TParser, m: TMacro) = + rawGetTok(p) # skip macro name + var arguments: seq[seq[ref TToken]] + if m.params > 0: + rawEat(p, pxParLe) + arguments = parseMacroArguments(p) + if arguments.len != m.params: parMessage(p, errWrongNumberOfArguments) + rawEat(p, pxParRi) + # insert into the token list: + if m.body.len > 0: + var newList: ref TToken + new(newList) + var lastTok = newList + for tok in items(m.body): + if tok.xkind == pxMacroParam: + for t in items(arguments[int(tok.iNumber)]): + lastTok.next = t + lastTok = t + else: + lastTok.next = tok + lastTok = tok + lastTok.next = p.tok + p.tok = newList.next + +proc getTok(p: var TParser) = + rawGetTok(p) + if p.tok.xkind == pxSymbol: + var idx = findMacro(p) + if idx >= 0: + expandMacro(p, p.options.macros[idx]) proc parLineInfo(p: TParser): TLineInfo = result = getLineInfo(p.lex) diff --git a/rod/c2nim/cpp.nim b/rod/c2nim/cpp.nim index 61873628e..2b4226fd9 100755 --- a/rod/c2nim/cpp.nim +++ b/rod/c2nim/cpp.nim @@ -1,3 +1,12 @@ +# +# +# c2nim - C to Nimrod source converter +# (c) Copyright 2010 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + # Preprocessor support const @@ -9,6 +18,10 @@ proc eatNewLine(p: var TParser, n: PNode) = if p.tok.xkind == pxNewLine: getTok(p) else: eat(p, pxNewLine) + +proc skipLine(p: var TParser) = + while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p) + eatNewLine(p, nil) proc parseDefineBody(p: var TParser, tmplDef: PNode): string = if p.tok.xkind == pxCurlyLe or @@ -65,6 +78,57 @@ proc parseDefine(p: var TParser): PNode = addSon(result, c) eatNewLine(p, c) +proc parseDefBody(p: var TParser, m: var TMacro, params: seq[string]) = + m.body = @[] + # 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 + # reference to the token in the macro's body. + safeContext(p) + while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: + case p.tok.xkind + of pxSymbol: + # is it a parameter reference? + var tok = p.tok + for i in 0..high(params): + if params[i] == p.tok.s: + new(tok) + tok.xkind = pxMacroParam + tok.iNumber = i + break + m.body.add(tok) + of pxDirConc: + # just ignore this token: this implements token merging correctly + nil + else: + m.body.add(p.tok) + # we do not want macro expansion here: + rawGetTok(p) + eatNewLine(p, nil) + closeContext(p) + # newline token might be overwritten, but this is not + # part of the macro body, so it is safe. + +proc parseDef(p: var TParser, m: var TMacro) = + var hasParams = p.tok.xkind == pxDirectiveParLe + getTok(p) + expectIdent(p) + m.name = p.tok.s + getTok(p) + var params: seq[string] = @[] + # parse parameters: + if hasParams: + eat(p, pxParLe) + while p.tok.xkind != pxParRi: + expectIdent(p) + params.add(p.tok.s) + getTok(p) + skipStarCom(p, nil) + if p.tok.xkind != pxComma: break + getTok(p) + eat(p, pxParRi) + m.params = params.len + parseDefBody(p, m, params) + proc isDir(p: TParser, dir: string): bool = result = p.tok.xkind in {pxDirectiveParLe, pxDirective} and p.tok.s == dir @@ -102,6 +166,12 @@ proc parseStmtList(p: var TParser): PNode = else: nil addSon(result, statement(p)) +proc eatEndif(p: var TParser) = + if isDir(p, "endif"): + skipLine(p) + else: + parMessage(p, errXExpected, "#endif") + proc parseIfDirAux(p: var TParser, result: PNode) = addSon(result.sons[0], parseStmtList(p)) while isDir(p, "elif"): @@ -113,67 +183,133 @@ proc parseIfDirAux(p: var TParser, result: PNode) = addSon(result, b) if isDir(p, "else"): var s = newNodeP(nkElse, p) - while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p) - eatNewLine(p, nil) + skipLine(p) addSon(s, parseStmtList(p)) addSon(result, s) - if isDir(p, "endif"): - while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p) - eatNewLine(p, nil) - else: - parMessage(p, errXExpected, "#endif") + eatEndif(p) -proc specialIf(p: TParser): bool = - ExpectIdent(p) - result = p.tok.s == c2nimSymbol +when false: + proc specialIf(p: TParser): bool = + ExpectIdent(p) + result = p.tok.s == c2nimSymbol + + proc chooseBranch(whenStmt: PNode, branch: int): PNode = + var L = sonsLen(whenStmt) + if branch < L: + if L == 2 and whenStmt[1].kind == nkElse or branch == 0: + result = lastSon(whenStmt[branch]) + else: + var b = whenStmt[branch] + assert(b.kind == nkElifBranch) + result = newNodeI(nkWhenStmt, whenStmt.info) + for i in branch .. L-1: + addSon(result, whenStmt[i]) -proc chooseBranch(whenStmt: PNode, branch: int): PNode = - var L = sonsLen(whenStmt) - if branch < L: - if L == 2 and whenStmt[1].kind == nkElse or branch == 0: - result = lastSon(whenStmt[branch]) - else: - var b = whenStmt[branch] - assert(b.kind == nkElifBranch) - result = newNodeI(nkWhenStmt, whenStmt.info) - for i in branch .. L-1: - addSon(result, whenStmt[i]) +proc skipUntilEndif(p: var TParser) = + var nested = 1 + while p.tok.xkind != pxEof: + if isDir(p, "ifdef") or isDir(p, "ifndef") or isDir(p, "if"): + inc(nested) + elif isDir(p, "endif"): + dec(nested) + if nested <= 0: + skipLine(p) + return + getTok(p) + parMessage(p, errXExpected, "#endif") + +type + TEndifMarker = enum + emElif, emElse, emEndif -proc skipIfdefCPlusPlus(p: var TParser): PNode = +proc skipUntilElifElseEndif(p: var TParser): TEndifMarker = + var nested = 1 while p.tok.xkind != pxEof: - if isDir(p, "endif"): - while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p) - eatNewLine(p, nil) - return + if isDir(p, "ifdef") or isDir(p, "ifndef") or isDir(p, "if"): + inc(nested) + elif isDir(p, "elif") and nested <= 1: + return emElif + elif isDir(p, "else") and nested <= 1: + return emElse + elif isDir(p, "endif"): + dec(nested) + if nested <= 0: + return emEndif getTok(p) parMessage(p, errXExpected, "#endif") -proc parseIfdefDir(p: var TParser): PNode = - result = newNodeP(nkWhenStmt, p) - addSon(result, newNodeP(nkElifBranch, p)) - getTok(p) - var special = specialIf(p) - if p.tok.s == "__cplusplus": - return skipIfdefCPlusPlus(p) - addSon(result.sons[0], definedExprAux(p)) - eatNewLine(p, nil) - parseIfDirAux(p, result) - if special: - result = chooseBranch(result, 0) +proc parseIfdef(p: var TParser): PNode = + getTok(p) # skip #ifdef + ExpectIdent(p) + case p.tok.s + of "__cplusplus": + skipUntilEndif(p) + of c2nimSymbol: + skipLine(p) + result = parseStmtList(p) + skipUntilEndif(p) + else: + result = newNodeP(nkWhenStmt, p) + addSon(result, newNodeP(nkElifBranch, p)) + addSon(result.sons[0], definedExprAux(p)) + eatNewLine(p, nil) + parseIfDirAux(p, result) + +proc parseIfndef(p: var TParser): PNode = + getTok(p) # skip #ifndef + ExpectIdent(p) + if p.tok.s == c2nimSymbol: + skipLine(p) + case skipUntilElifElseEndif(p) + of emElif: + result = newNodeP(nkWhenStmt, p) + addSon(result, newNodeP(nkElifBranch, p)) + getTok(p) + addSon(result.sons[0], expression(p)) + eatNewLine(p, nil) + parseIfDirAux(p, result) + of emElse: + skipLine(p) + result = parseStmtList(p) + eatEndif(p) + of emEndif: skipLine(p) + else: + result = newNodeP(nkWhenStmt, p) + addSon(result, newNodeP(nkElifBranch, p)) + var e = newNodeP(nkCall, p) + addSon(e, newIdentNodeP("not", p)) + addSon(e, definedExprAux(p)) + eatNewLine(p, nil) + addSon(result.sons[0], e) + parseIfDirAux(p, result) + +when false: + proc parseIfdefDir(p: var TParser): PNode = + result = newNodeP(nkWhenStmt, p) + addSon(result, newNodeP(nkElifBranch, p)) + getTok(p) + var special = specialIf(p) + if p.tok.s == "__cplusplus": + return skipIfdefCPlusPlus(p) + addSon(result.sons[0], definedExprAux(p)) + eatNewLine(p, nil) + parseIfDirAux(p, result) + if special: + result = chooseBranch(result, 0) -proc parseIfndefDir(p: var TParser): PNode = - result = newNodeP(nkWhenStmt, p) - addSon(result, newNodeP(nkElifBranch, p)) - getTok(p) - var special = specialIf(p) - var e = newNodeP(nkCall, p) - addSon(e, newIdentNodeP("not", p)) - addSon(e, definedExprAux(p)) - eatNewLine(p, nil) - addSon(result.sons[0], e) - parseIfDirAux(p, result) - if special: - result = chooseBranch(result, 1) + proc parseIfndefDir(p: var TParser): PNode = + result = newNodeP(nkWhenStmt, p) + addSon(result, newNodeP(nkElifBranch, p)) + getTok(p) + var special = specialIf(p) + var e = newNodeP(nkCall, p) + addSon(e, newIdentNodeP("not", p)) + addSon(e, definedExprAux(p)) + eatNewLine(p, nil) + addSon(result.sons[0], e) + parseIfDirAux(p, result) + if special: + result = chooseBranch(result, 1) proc parseIfDir(p: var TParser): PNode = result = newNodeP(nkWhenStmt, p) @@ -206,14 +342,14 @@ proc parseDir(p: var TParser): PNode = case p.tok.s of "define": result = parseDefine(p) of "include": result = parseInclude(p) - of "ifdef": result = parseIfdefDir(p) - of "ifndef": result = parseIfndefDir(p) + of "ifdef": result = parseIfdef(p) + of "ifndef": result = parseIfndef(p) of "if": result = parseIfDir(p) of "cdecl", "stdcall", "ref": discard setOption(p.options, p.tok.s) getTok(p) eatNewLine(p, nil) - of "dynlib", "header", "prefix", "suffix", "skip": + of "dynlib", "header", "prefix", "suffix": var key = p.tok.s getTok(p) if p.tok.xkind != pxStrLit: ExpectIdent(p) @@ -222,10 +358,11 @@ proc parseDir(p: var TParser): PNode = eatNewLine(p, nil) of "mangle": parseMangleDir(p) + of "def": + var L = p.options.macros.len + setLen(p.options.macros, L+1) + parseDef(p, p.options.macros[L]) else: # ignore unimportant/unknown directive ("undef", "pragma", "error") - while true: - getTok(p) - if p.tok.xkind in {pxEof, pxNewLine, pxLineComment}: break - eatNewLine(p, nil) + skipLine(p) diff --git a/rod/c2nim/manual.txt b/rod/c2nim/manual.txt index 68ad7a8bd..3aca188b4 100644 --- a/rod/c2nim/manual.txt +++ b/rod/c2nim/manual.txt @@ -202,27 +202,31 @@ identifier should be converted: #mangle "'GTK_'{.*}" "TGtk$1" -``#skip`` directive -------------------- -**Note**: There is also ``--skip`` command line option that can be used for the -same purpose. +``#def`` directive +------------------ Often C code contains special macros that affect the declaration of a function prototype but confuse c2nim's parser: .. code-block:: C // does not parse! - EXPORT int f(void); - EXPORT int g(void); + EXTERN(int) f(void); + EXTERN(int) g(void); -Instead of removing ``EXPORT`` from the input source file, one can tell c2nim -to skip special identifiers: +Instead of removing ``EXTERN()`` from the input source file (which cannot be +done reliably even with a regular expression!), one can tell c2nim +that ``EXPORT`` is a macro that should be expanded by c2nim too: .. code-block:: C - #skip EXPORT - // does parse now! - EXPORT int f(void); - EXPORT int g(void); + #ifdef C2NIM + # def EXTERN(x) static x + #endif + // parses now! + EXTERN(int) f(void); + EXTERN(int) g(void); + +``#def`` is very similar to C's ``#define``. + Limitations diff --git a/rod/c2nim/tests/systest.c b/rod/c2nim/tests/systest.c index 528ae89e3..0cd174dc8 100644 --- a/rod/c2nim/tests/systest.c +++ b/rod/c2nim/tests/systest.c @@ -4,12 +4,43 @@ */ #ifdef __cplusplus +# ifdef __SOME_OTHER_CRAP extern "C" { +# endif +#endif + +// Test C2NIM skipping: + +#ifndef C2NIM + #if someNestedCond + This is an invalid text that should generate a parser error, if not + #endif + skipped correctly. #endif +#ifndef C2NIM + #if someNestedCond + This is an invalid text that should generate a parser error, if not + #endif + skipped correctly. +#else typedef char gchar; typedef unsigned int gunsignedint; typedef unsigned char guchar; +#endif + +#ifdef C2NIM +# mangle "'those'" "these" +int those; +#elif abc + #if someNestedCond + This is an invalid text that should generate a parser error, if not + #else + skipped correctly. + #endif +#else + Another crappy input line. +#endif point* newPoint(void) { for (int i = 0; i < 89; ++i) echo("test" " string " "concatenation"); @@ -97,7 +128,15 @@ int IupConvertXYToPos(PIhandle ih, int x, int y); #endif - #skip EXPORT + #ifdef C2NIM + # def EXTERN(x) static x + #endif + // parses now! + EXTERN(int) f(void); + EXTERN(int) g(void); + + + #def EXPORT // does parse now! EXPORT int f(void); EXPORT int g(void); |