diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2014-01-14 13:42:20 -0800 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2014-01-14 13:42:20 -0800 |
commit | 0132f350af914d5b9c64fe67c98f0641c9701a16 (patch) | |
tree | ff1126815401f6e4cce7c3d17ea1404d33375322 /compiler | |
parent | a1713bc2f95ddfa6b042315196607f7d5a01d135 (diff) | |
parent | aec9195c95b62a5f496c878cc3e40c03b0c7104f (diff) | |
download | Nim-0132f350af914d5b9c64fe67c98f0641c9701a16.tar.gz |
Merge pull request #814 from discoloda/devel
Many small improvements to c2nim
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/c2nim/c2nim.nim | 22 | ||||
-rw-r--r-- | compiler/c2nim/clex.nim | 42 | ||||
-rw-r--r-- | compiler/c2nim/cparse.nim | 753 | ||||
-rw-r--r-- | compiler/c2nim/tests/vincent.c | 33 | ||||
-rw-r--r-- | compiler/c2nim/tests/vincent.h | 3 |
5 files changed, 463 insertions, 390 deletions
diff --git a/compiler/c2nim/c2nim.nim b/compiler/c2nim/c2nim.nim index 1c701a386..9b12b9e47 100644 --- a/compiler/c2nim/c2nim.nim +++ b/compiler/c2nim/c2nim.nim @@ -34,25 +34,36 @@ Options: --skipcomments do not copy comments --ignoreRValueRefs translate C++'s ``T&&`` to ``T`` instead ``of var T`` --keepBodies keep C++'s method bodies + --spliceHeader parse and emit header before source file -v, --version write c2nim's version -h, --help show this help """ -proc main(infile, outfile: string, options: PParserOptions) = - var start = getTime() +proc parse(infile: string, options: PParserOptions): PNode = var stream = llStreamOpen(infile, fmRead) if stream == nil: rawMessage(errCannotOpenFile, infile) var p: TParser openParser(p, infile, stream, options) - var module = parseUnit(p) + result = parseUnit(p) closeParser(p) - renderModule(module, outfile) + +proc main(infile, outfile: string, options: PParserOptions, spliceHeader: bool) = + var start = getTime() + if spliceHeader and infile.splitFile.ext == ".c" and existsFile(infile.changeFileExt(".h")): + var header_module = parse(infile.changeFileExt(".h"), options) + var source_module = parse(infile, options) + for n in source_module: + addson(header_module, n) + renderModule(header_module, outfile) + else: + renderModule(parse(infile, options), outfile) rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start), formatSize(getTotalMem())]) var infile = "" outfile = "" + spliceHeader = false parserOptions = newParserOptions() for kind, key, val in getopt(): case kind @@ -66,6 +77,7 @@ for kind, key, val in getopt(): stdout.write(Version & "\n") quit(0) of "o", "out": outfile = val + of "spliceheader": spliceHeader = true else: if not parserOptions.setOption(key, val): stdout.writeln("[Error] unknown option: " & key) @@ -77,4 +89,4 @@ else: if outfile.len == 0: outfile = changeFileExt(infile, "nim") infile = addFileExt(infile, "h") - main(infile, outfile, parserOptions) + main(infile, outfile, parserOptions, spliceHeader) diff --git a/compiler/c2nim/clex.nim b/compiler/c2nim/clex.nim index 7e5526a10..3934eea63 100644 --- a/compiler/c2nim/clex.nim +++ b/compiler/c2nim/clex.nim @@ -315,13 +315,28 @@ proc getNumber16(L: var TLexer, tok: var TToken) = else: tok.xkind = pxIntLit L.bufpos = pos +proc getFloating(L: var TLexer, tok: var TToken) = + matchUnderscoreChars(L, tok, {'0'..'9'}) + if L.buf[L.bufpos] in {'e', 'E'}: + add(tok.s, L.buf[L.bufpos]) + inc(L.bufpos) + if L.buf[L.bufpos] in {'+', '-'}: + add(tok.s, L.buf[L.bufpos]) + inc(L.bufpos) + matchUnderscoreChars(L, tok, {'0'..'9'}) + proc getNumber(L: var TLexer, tok: var TToken) = tok.base = base10 - matchUnderscoreChars(L, tok, {'0'..'9'}) - if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}): - add(tok.s, '.') + if L.buf[L.bufpos] == '.': + add(tok.s, "0.") inc(L.bufpos) - matchUnderscoreChars(L, tok, {'e', 'E', '+', '-', '0'..'9'}) + getFloating(L, tok) + else: + matchUnderscoreChars(L, tok, {'0'..'9'}) + if L.buf[L.bufpos] == '.': + add(tok.s, '.') + inc(L.bufpos) + getFloating(L, tok) try: if isFloatLiteral(tok.s): tok.fnumber = parseFloat(tok.s) @@ -382,6 +397,23 @@ proc escape(L: var TLexer, tok: var TToken, allowEmpty=false) = xi = (xi shl 3) or (ord(L.buf[L.bufpos]) - ord('0')) inc(L.bufpos) add(tok.s, chr(xi)) + of 'x': + var xi = 0 + inc(L.bufpos) + while true: + case L.buf[L.bufpos] + of '0'..'9': + xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('0')) + inc(L.bufpos) + of 'a'..'f': + xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('a') + 10) + inc(L.bufpos) + of 'A'..'F': + xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('A') + 10) + inc(L.bufpos) + else: + break + add(tok.s, chr(xi)) elif not allowEmpty: lexMessage(L, errInvalidCharacterConstant) @@ -559,7 +591,7 @@ proc getTok(L: var TLexer, tok: var TToken) = of 'b', 'B': getNumber2(L, tok) of '1'..'7': getNumber8(L, tok) else: getNumber(L, tok) - elif c in {'1'..'9'}: + elif c in {'1'..'9'} or (c == '.' and L.buf[L.bufpos+1] in {'0'..'9'}): getNumber(L, tok) else: case c diff --git a/compiler/c2nim/cparse.nim b/compiler/c2nim/cparse.nim index 3adab0f44..ffab05788 100644 --- a/compiler/c2nim/cparse.nim +++ b/compiler/c2nim/cparse.nim @@ -61,6 +61,8 @@ type TReplaceTuple* = array[0..1, string] + ERetryParsing = object of ESynch + proc newParserOptions*(): PParserOptions = new(result) result.prefixes = @[] @@ -420,9 +422,9 @@ proc markTypeIdent(p: var TParser, typ: PNode) = # avoids to build a symbol table, which can't be done reliably anyway for our # purposes. -proc expression(p: var TParser): PNode -proc constantExpression(p: var TParser): PNode -proc assignmentExpression(p: var TParser): PNode +proc expression(p: var TParser, rbp: int = 0): PNode +proc constantExpression(p: var TParser): PNode = expression(p, 40) +proc assignmentExpression(p: var TParser): PNode = expression(p, 30) proc compoundStatement(p: var TParser): PNode proc statement(p: var TParser): PNode @@ -651,6 +653,22 @@ proc parseTypeSuffix(p: var TParser, typ: PNode): PNode = proc typeDesc(p: var TParser): PNode = result = pointer(p, typeAtom(p)) +proc abstractDeclarator(p: var TParser, a: PNode): PNode + +proc directAbstractDeclarator(p: var TParser, a: PNode): PNode = + if p.tok.xkind == pxParLe: + getTok(p, a) + if p.tok.xkind in {pxStar, pxAmp, pxAmpAmp}: + result = abstractDeclarator(p, a) + eat(p, pxParRi, result) + return parseTypeSuffix(p, a) + +proc abstractDeclarator(p: var TParser, a: PNode): PNode = + return directAbstractDeclarator(p, pointer(p, a)) + +proc typeName(p: var TParser): PNode = + return abstractDeclarator(p, typeAtom(p)) + proc parseField(p: var TParser, kind: TNodeKind): PNode = if p.tok.xkind == pxParLe: getTok(p, nil) @@ -716,18 +734,36 @@ proc parseStruct(p: var TParser, isUnion: bool): PNode = else: addSon(result, newNodeP(nkRecList, p)) +proc declarator(p: var TParser, a: PNode, ident: ptr PNode): PNode + +proc directDeclarator(p: var TParser, a: PNode, ident: ptr PNode): PNode = + case p.tok.xkind + of pxSymbol: + ident[] = skipIdent(p) + of pxParLe: + getTok(p, a) + if p.tok.xkind in {pxStar, pxAmp, pxAmpAmp, pxSymbol}: + result = declarator(p, a, ident) + eat(p, pxParRi, result) + else: + nil + return parseTypeSuffix(p, a) + +proc declarator(p: var TParser, a: PNode, ident: ptr PNode): PNode = + return directDeclarator(p, pointer(p, a), ident) + +# parameter-declaration +# declaration-specifiers declarator +# declaration-specifiers asbtract-declarator(opt) proc parseParam(p: var TParser, params: PNode) = var typ = typeDesc(p) # support for ``(void)`` parameter list: if typ.kind == nkNilLit and p.tok.xkind == pxParRi: return var name: PNode - if p.tok.xkind == pxSymbol: - name = skipIdent(p) - else: - # generate a name for the formal parameter: + typ = declarator(p, typ, addr name) + if name == nil: var idx = sonsLen(params)+1 name = newIdentNodeP("a" & $idx, p) - typ = parseTypeSuffix(p, typ) var x = newNodeP(nkIdentDefs, p) addSon(x, name, typ) if p.tok.xkind == pxAsgn: @@ -1134,224 +1170,27 @@ proc setBaseFlags(n: PNode, base: TNumericalBase) = of base8: incl(n.flags, nfBase8) of base16: incl(n.flags, nfBase16) -proc unaryExpression(p: var TParser): PNode - -proc isDefinitelyAType(p: var TParser): bool = - var starFound = false - var words = 0 - while true: - case p.tok.xkind - of pxSymbol: - if declKeyword(p, p.tok.s): return true - elif starFound: return false - else: inc(words) - of pxStar, pxAmp, pxAmpAmp: - starFound = true - of pxParRi: return words == 0 or words > 1 or starFound - else: return false - getTok(p, nil) - -proc castExpression(p: var TParser): PNode = - if p.tok.xkind == pxParLe: - saveContext(p) - result = newNodeP(nkCast, p) - getTok(p, result) - var t = isDefinitelyAType(p) - backtrackContext(p) - if t: - eat(p, pxParLe, result) - var a = typeDesc(p) - eat(p, pxParRi, result) - addSon(result, a) - addSon(result, castExpression(p)) - else: - # else it is just an expression in (): - result = newNodeP(nkPar, p) - eat(p, pxParLe, result) - addSon(result, expression(p)) - if p.tok.xkind != pxParRi: - # ugh, it is a cast, even though it does not look like one: - result.kind = nkCast - addSon(result, castExpression(p)) - eat(p, pxParRi, result) - #result = unaryExpression(p) - else: - result = unaryExpression(p) - -proc primaryExpression(p: var TParser): PNode = - case p.tok.xkind - of pxSymbol: - if p.tok.s == "NULL": - result = newNodeP(nkNilLit, p) - else: - result = mangledIdent(p.tok.s, p) - getTok(p, result) - result = optScope(p, result) - of pxIntLit: - result = newIntNodeP(nkIntLit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p, result) - of pxInt64Lit: - result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p, result) - of pxFloatLit: - result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p, result) - of pxStrLit: - # Ansi C allows implicit string literal concatenations: - result = newStrNodeP(nkStrLit, p.tok.s, p) - getTok(p, result) - while p.tok.xkind == pxStrLit: - add(result.strVal, p.tok.s) - getTok(p, result) - of pxCharLit: - result = newIntNodeP(nkCharLit, ord(p.tok.s[0]), p) - getTok(p, result) - of pxParLe: - result = castExpression(p) - else: - result = ast.emptyNode - -proc multiplicativeExpression(p: var TParser): PNode = - result = castExpression(p) - while true: - case p.tok.xkind - of pxStar: - var a = result - result = newNodeP(nkInfix, p) - addSon(result, newIdentNodeP("*", p), a) - getTok(p, result) - var b = castExpression(p) - addSon(result, b) - of pxSlash: - var a = result - result = newNodeP(nkInfix, p) - addSon(result, newIdentNodeP("div", p), a) - getTok(p, result) - var b = castExpression(p) - addSon(result, b) - of pxMod: - var a = result - result = newNodeP(nkInfix, p) - addSon(result, newIdentNodeP("mod", p), a) - getTok(p, result) - var b = castExpression(p) - addSon(result, b) - else: break - -proc additiveExpression(p: var TParser): PNode = - result = multiplicativeExpression(p) - while true: - case p.tok.xkind - of pxPlus: - var a = result - result = newNodeP(nkInfix, p) - addSon(result, newIdentNodeP("+", p), a) - getTok(p, result) - var b = multiplicativeExpression(p) - addSon(result, b) - of pxMinus: - var a = result - result = newNodeP(nkInfix, p) - addSon(result, newIdentNodeP("-", p), a) - getTok(p, result) - var b = multiplicativeExpression(p) - addSon(result, b) - else: break - -proc incdec(p: var TParser, opr: string): PNode = - result = newNodeP(nkCall, p) - addSon(result, newIdentNodeP(opr, p)) - getTok(p, result) - addSon(result, unaryExpression(p)) - -proc unaryOp(p: var TParser, kind: TNodeKind): PNode = - result = newNodeP(kind, p) - getTok(p, result) - addSon(result, castExpression(p)) - -proc prefixCall(p: var TParser, opr: string): PNode = - result = newNodeP(nkPrefix, p) - addSon(result, newIdentNodeP(opr, p)) - getTok(p, result) - addSon(result, castExpression(p)) - -proc postfixExpression(p: var TParser): PNode = - result = primaryExpression(p) - while true: - case p.tok.xkind - of pxBracketLe: - var a = result - result = newNodeP(nkBracketExpr, p) - addSon(result, a) - getTok(p, result) - var b = expression(p) - addSon(result, b) - eat(p, pxBracketRi, result) - of pxParLe: - var a = result - result = newNodeP(nkCall, p) - addSon(result, a) - getTok(p, result) - if p.tok.xkind != pxParRi: - a = assignmentExpression(p) - addSon(result, a) - while p.tok.xkind == pxComma: - getTok(p, a) - a = assignmentExpression(p) - addSon(result, a) - eat(p, pxParRi, result) - of pxDot, pxArrow: - var a = result - result = newNodeP(nkDotExpr, p) - addSon(result, a) - getTok(p, result) - addSon(result, skipIdent(p)) - of pxPlusPlus: - var a = result - result = newNodeP(nkCall, p) - addSon(result, newIdentNodeP("inc", p)) - getTok(p, result) - addSon(result, a) - of pxMinusMinus: - var a = result - result = newNodeP(nkCall, p) - addSon(result, newIdentNodeP("dec", p)) - getTok(p, result) - addSon(result, a) - of pxLt: - if isTemplateAngleBracket(p): - result = optAngle(p, result) - else: break - else: break - -proc unaryExpression(p: var TParser): PNode = - case p.tok.xkind - of pxPlusPlus: result = incdec(p, "inc") - of pxMinusMinus: result = incdec(p, "dec") - of pxAmp: result = unaryOp(p, nkAddr) - of pxStar: result = unaryOp(p, nkBracketExpr) - of pxPlus: result = prefixCall(p, "+") - of pxMinus: result = prefixCall(p, "-") - of pxTilde: result = prefixCall(p, "not") - of pxNot: result = prefixCall(p, "not") +proc startExpression(p : var TParser, tok : TToken) : PNode = + #echo "nud ", $tok + case tok.xkind: of pxSymbol: - if p.tok.s == "sizeof": + if tok.s == "NULL": + result = newNodeP(nkNilLit, p) + elif tok.s == "sizeof": result = newNodeP(nkCall, p) addSon(result, newIdentNodeP("sizeof", p)) - getTok(p, result) - if p.tok.xkind == pxParLe: - getTok(p, result) - addSon(result, typeDesc(p)) - eat(p, pxParRi, result) - else: - addSon(result, unaryExpression(p)) - elif p.tok.s == "new" or p.tok.s == "delete" and pfCpp in p.options.flags: - var opr = p.tok.s + saveContext(p) + try: + addSon(result, expression(p, 139)) + closeContext(p) + except ERetryParsing: + backtrackContext(p) + eat(p, pxParLe) + addSon(result, typeName(p)) + eat(p, pxParRi) + elif (tok.s == "new" or tok.s == "delete") and pfCpp in p.options.flags: + var opr = tok.s result = newNodeP(nkCall, p) - getTok(p, result) if p.tok.xkind == pxBracketLe: getTok(p) eat(p, pxBracketRi) @@ -1362,148 +1201,269 @@ proc unaryExpression(p: var TParser): PNode = addSon(result, typeDesc(p)) eat(p, pxParRi, result) else: - addSon(result, unaryExpression(p)) + addSon(result, expression(p, 139)) else: - result = postfixExpression(p) - else: result = postfixExpression(p) - -proc expression(p: var TParser): PNode = - # we cannot support C's ``,`` operator - result = assignmentExpression(p) - if p.tok.xkind == pxComma: - getTok(p, result) - parMessage(p, errOperatorExpected, ",") - -proc conditionalExpression(p: var TParser): PNode - -proc constantExpression(p: var TParser): PNode = - result = conditionalExpression(p) - -proc lvalue(p: var TParser): PNode = - result = unaryExpression(p) - -proc asgnExpr(p: var TParser, opr: string, a: PNode): PNode = - closeContext(p) - getTok(p, a) - var b = assignmentExpression(p) - result = newNodeP(nkAsgn, p) - addSon(result, a, newBinary(opr, copyTree(a), b, p)) - -proc incdec(p: var TParser, opr: string, a: PNode): PNode = - closeContext(p) - getTok(p, a) - var b = assignmentExpression(p) - result = newNodeP(nkCall, p) - addSon(result, newIdentNodeP(getIdent(opr), p), a, b) - -proc assignmentExpression(p: var TParser): PNode = - saveContext(p) - var a = lvalue(p) - case p.tok.xkind - of pxAsgn: - closeContext(p) - getTok(p, a) - var b = assignmentExpression(p) + result = mangledIdent(tok.s, p) + result = optScope(p, result) + result = optAngle(p, result) + of pxIntLit: + result = newIntNodeP(nkIntLit, tok.iNumber, p) + setBaseFlags(result, tok.base) + of pxInt64Lit: + result = newIntNodeP(nkInt64Lit, tok.iNumber, p) + setBaseFlags(result, tok.base) + of pxFloatLit: + result = newFloatNodeP(nkFloatLit, tok.fNumber, p) + setBaseFlags(result, tok.base) + of pxStrLit: + result = newStrNodeP(nkStrLit, tok.s, p) + while p.tok.xkind == pxStrLit: + add(result.strVal, p.tok.s) + getTok(p, result) + of pxCharLit: + result = newIntNodeP(nkCharLit, ord(tok.s[0]), p) + of pxParLe: + try: + saveContext(p) + result = newNodeP(nkPar, p) + addSon(result, expression(p, 0)) + if p.tok.xkind != pxParRi: + raise newException(ERetryParsing, "expected a ')'") + getTok(p, result) + if p.tok.xkind in {pxSymbol, pxIntLit, pxFloatLit, pxStrLit, pxCharLit}: + raise newException(ERetryParsing, "expected a non literal token") + closeContext(p) + except ERetryParsing: + backtrackContext(p) + result = newNodeP(nkCast, p) + addSon(result, typeName(p)) + eat(p, pxParRi, result) + addSon(result, expression(p, 139)) + of pxPlusPlus: + result = newNodeP(nkCall, p) + addSon(result, newIdentNodeP("inc", p)) + addSon(result, expression(p, 139)) + of pxMinusMinus: + result = newNodeP(nkCall, p) + addSon(result, newIdentNodeP("dec", p)) + addSon(result, expression(p, 139)) + of pxAmp: + result = newNodeP(nkAddr, p) + addSon(result, expression(p, 139)) + of pxStar: + result = newNodeP(nkBracketExpr, p) + addSon(result, expression(p, 139)) + of pxPlus: + result = newNodeP(nkPrefix, p) + addSon(result, newIdentNodeP("+", p)) + addSon(result, expression(p, 139)) + of pxMinus: + result = newNodeP(nkPrefix, p) + addSon(result, newIdentNodeP("-", p)) + addSon(result, expression(p, 139)) + of pxTilde: + result = newNodeP(nkPrefix, p) + addSon(result, newIdentNodeP("not", p)) + addSon(result, expression(p, 139)) + of pxNot: + result = newNodeP(nkPrefix, p) + addSon(result, newIdentNodeP("not", p)) + addSon(result, expression(p, 139)) + else: + # probably from a failed sub expression attempt, try a type cast + raise newException(ERetryParsing, "did not expect " & $tok) + +proc leftBindingPower(p : var TParser, tok : ref TToken) : int = + #echo "lbp ", $tok[] + case tok.xkind: + of pxComma: + return 10 + # throw == 20 + of pxAsgn, pxPlusAsgn, pxMinusAsgn, pxStarAsgn, pxSlashAsgn, pxModAsgn, pxShlAsgn, pxShrAsgn, pxAmpAsgn, pxHatAsgn, pxBarAsgn: + return 30 + of pxConditional: + return 40 + of pxBarBar: + return 50 + of pxAmpAmp: + return 60 + of pxBar: + return 70 + of pxHat: + return 80 + of pxAmp: + return 90 + of pxEquals, pxNeq: + return 100 + of pxLt, pxLe, pxGt, pxGe: + return 110 + of pxShl, pxShr: + return 120 + of pxPlus, pxMinus: + return 130 + of pxStar, pxSlash, pxMod: + return 140 + # .* ->* == 150 + of pxPlusPlus, pxMinusMinus, pxParLe, pxDot, pxArrow, pxBracketLe: + return 160 + # :: == 170 + else: + return 0 + +proc buildStmtList(a: PNode): PNode + +proc leftExpression(p : var TParser, tok : TToken, left : PNode) : PNode = + #echo "led ", $tok + case tok.xkind: + of pxComma: # 10 + # not supported as an expression, turns into a statement list + result = buildStmtList(left) + addSon(result, expression(p, 0)) + # throw == 20 + of pxAsgn: # 30 + result = newNodeP(nkAsgn, p) + addSon(result, left, expression(p, 29)) + of pxPlusAsgn: # 30 + result = newNodeP(nkCall, p) + addSon(result, newIdentNodeP(getIdent("inc"), p), left, expression(p, 29)) + of pxMinusAsgn: # 30 + result = newNodeP(nkCall, p) + addSon(result, newIdentNodeP(getIdent("dec"), p), left, expression(p, 29)) + of pxStarAsgn: # 30 + result = newNodeP(nkAsgn, p) + var right = expression(p, 29) + addSon(result, left, newBinary("*", copyTree(left), right, p)) + of pxSlashAsgn: # 30 + result = newNodeP(nkAsgn, p) + var right = expression(p, 29) + addSon(result, left, newBinary("/", copyTree(left), right, p)) + of pxModAsgn: # 30 + result = newNodeP(nkAsgn, p) + var right = expression(p, 29) + addSon(result, left, newBinary("mod", copyTree(left), right, p)) + of pxShlAsgn: # 30 + result = newNodeP(nkAsgn, p) + var right = expression(p, 29) + addSon(result, left, newBinary("shl", copyTree(left), right, p)) + of pxShrAsgn: # 30 + result = newNodeP(nkAsgn, p) + var right = expression(p, 29) + addSon(result, left, newBinary("shr", copyTree(left), right, p)) + of pxAmpAsgn: # 30 + result = newNodeP(nkAsgn, p) + var right = expression(p, 29) + addSon(result, left, newBinary("and", copyTree(left), right, p)) + of pxHatAsgn: # 30 result = newNodeP(nkAsgn, p) - addSon(result, a, b) - of pxPlusAsgn: result = incdec(p, "inc", a) - of pxMinusAsgn: result = incdec(p, "dec", a) - of pxStarAsgn: result = asgnExpr(p, "*", a) - of pxSlashAsgn: result = asgnExpr(p, "/", a) - of pxModAsgn: result = asgnExpr(p, "mod", a) - of pxShlAsgn: result = asgnExpr(p, "shl", a) - of pxShrAsgn: result = asgnExpr(p, "shr", a) - of pxAmpAsgn: result = asgnExpr(p, "and", a) - of pxHatAsgn: result = asgnExpr(p, "xor", a) - of pxBarAsgn: result = asgnExpr(p, "or", a) + var right = expression(p, 29) + addSon(result, left, newBinary("xor", copyTree(left), right, p)) + of pxBarAsgn: # 30 + result = newNodeP(nkAsgn, p) + var right = expression(p, 29) + addSon(result, left, newBinary("or", copyTree(left), right, p)) + of pxConditional: # 40 + var a = expression(p, 0) + eat(p, pxColon, a) + var b = expression(p, 39) + result = newNodeP(nkIfExpr, p) + var branch = newNodeP(nkElifExpr, p) + addSon(branch, left, a) + addSon(result, branch) + branch = newNodeP(nkElseExpr, p) + addSon(branch, b) + addSon(result, branch) + of pxBarBar: # 50 + result = newBinary("or", left, expression(p, 50), p) + of pxAmpAmp: # 60 + result = newBinary("and", left, expression(p, 60), p) + of pxBar: # 70 + result = newBinary("or", left, expression(p, 70), p) + of pxHat: # 80 + result = newBinary("^", left, expression(p, 80), p) + of pxAmp: # 90 + result = newBinary("and", left, expression(p, 90), p) + of pxEquals: # 100 + result = newBinary("==", left, expression(p, 100), p) + of pxNeq: # 100 + result = newBinary("!=", left, expression(p, 100), p) + of pxLt: # 110 + result = newBinary("<", left, expression(p, 110), p) + of pxLe: # 110 + result = newBinary("<=", left, expression(p, 110), p) + of pxGt: # 110 + result = newBinary(">", left, expression(p, 110), p) + of pxGe: # 110 + result = newBinary(">=", left, expression(p, 110), p) + of pxShl: # 120 + result = newBinary("shl", left, expression(p, 120), p) + of pxShr: # 120 + result = newBinary("shr", left, expression(p, 120), p) + of pxPlus: # 130 + result = newNodeP(nkInfix, p) + addSon(result, newIdentNodeP("+", p), left) + addSon(result, expression(p, 130)) + of pxMinus: # 130 + result = newNodeP(nkInfix, p) + addSon(result, newIdentNodeP("+", p), left) + addSon(result, expression(p, 130)) + of pxStar: # 140 + result = newNodeP(nkInfix, p) + addSon(result, newIdentNodeP("*", p), left) + addSon(result, expression(p, 140)) + of pxSlash: # 140 + result = newNodeP(nkInfix, p) + addSon(result, newIdentNodeP("div", p), left) + addSon(result, expression(p, 140)) + of pxMod: # 140 + result = newNodeP(nkInfix, p) + addSon(result, newIdentNodeP("mod", p), left) + addSon(result, expression(p, 140)) + # .* ->* == 150 + of pxPlusPlus: # 160 + result = newNodeP(nkCall, p) + addSon(result, newIdentNodeP("inc", p), left) + of pxMinusMinus: # 160 + result = newNodeP(nkCall, p) + addSon(result, newIdentNodeP("dec", p), left) + of pxParLe: # 160 + result = newNodeP(nkCall, p) + addSon(result, left) + while p.tok.xkind != pxParRi: + var a = expression(p, 29) + addSon(result, a) + while p.tok.xkind == pxComma: + getTok(p, a) + a = expression(p, 29) + addSon(result, a) + eat(p, pxParRi, result) + of pxDot: # 160 + result = newNodeP(nkDotExpr, p) + addSon(result, left) + addSon(result, skipIdent(p)) + of pxArrow: # 160 + result = newNodeP(nkDotExpr, p) + addSon(result, left) + addSon(result, skipIdent(p)) + of pxBracketLe: # 160 + result = newNodeP(nkBracketExpr, p) + addSon(result, left, expression(p)) + eat(p, pxBracketRi, result) + # :: == 170 else: - backtrackContext(p) - result = conditionalExpression(p) - -proc shiftExpression(p: var TParser): PNode = - result = additiveExpression(p) - while p.tok.xkind in {pxShl, pxShr}: - var op = if p.tok.xkind == pxShl: "shl" else: "shr" - getTok(p, result) - var a = result - var b = additiveExpression(p) - result = newBinary(op, a, b, p) - -proc relationalExpression(p: var TParser): PNode = - result = shiftExpression(p) - # Nimrod uses ``<`` and ``<=``, etc. too: - while p.tok.xkind in {pxLt, pxLe, pxGt, pxGe}: - var op = tokKindToStr(p.tok.xkind) - getTok(p, result) - var a = result - var b = shiftExpression(p) - result = newBinary(op, a, b, p) - -proc equalityExpression(p: var TParser): PNode = - result = relationalExpression(p) - # Nimrod uses ``==`` and ``!=`` too: - while p.tok.xkind in {pxEquals, pxNeq}: - var op = tokKindToStr(p.tok.xkind) - getTok(p, result) - var a = result - var b = relationalExpression(p) - result = newBinary(op, a, b, p) + result = left -proc andExpression(p: var TParser): PNode = - result = equalityExpression(p) - while p.tok.xkind == pxAmp: - getTok(p, result) - var a = result - var b = equalityExpression(p) - result = newBinary("and", a, b, p) +proc expression*(p : var TParser, rbp : int = 0) : PNode = + var tok : TToken -proc exclusiveOrExpression(p: var TParser): PNode = - result = andExpression(p) - while p.tok.xkind == pxHat: - getTok(p, result) - var a = result - var b = andExpression(p) - result = newBinary("^", a, b, p) + tok = p.tok[] + getTok(p, result) -proc inclusiveOrExpression(p: var TParser): PNode = - result = exclusiveOrExpression(p) - while p.tok.xkind == pxBar: - getTok(p, result) - var a = result - var b = exclusiveOrExpression(p) - result = newBinary("or", a, b, p) - -proc logicalAndExpression(p: var TParser): PNode = - result = inclusiveOrExpression(p) - while p.tok.xkind == pxAmpAmp: - getTok(p, result) - var a = result - var b = inclusiveOrExpression(p) - result = newBinary("and", a, b, p) + result = startExpression(p, tok) -proc logicalOrExpression(p: var TParser): PNode = - result = logicalAndExpression(p) - while p.tok.xkind == pxBarBar: + while rbp < leftBindingPower(p, p.tok): + tok = p.tok[] getTok(p, result) - var a = result - var b = logicalAndExpression(p) - result = newBinary("or", a, b, p) - -proc conditionalExpression(p: var TParser): PNode = - result = logicalOrExpression(p) - if p.tok.xkind == pxConditional: - getTok(p, result) # skip '?' - var a = result - var b = expression(p) - eat(p, pxColon, b) - var c = conditionalExpression(p) - result = newNodeP(nkIfExpr, p) - var branch = newNodeP(nkElifExpr, p) - addSon(branch, a, b) - addSon(result, branch) - branch = newNodeP(nkElseExpr, p) - addSon(branch, c) - addSon(result, branch) + result = leftExpression(p, tok, result) # Statements @@ -1549,12 +1509,12 @@ proc parseIf(p: var TParser): PNode = while true: getTok(p) # skip ``if`` var branch = newNodeP(nkElifBranch, p) - skipCom(p, branch) eat(p, pxParLe, branch) addSon(branch, expression(p)) eat(p, pxParRi, branch) addSon(branch, nestedStatement(p)) addSon(result, branch) + skipCom(p, branch) if p.tok.s == "else": getTok(p, result) if p.tok.s != "if": @@ -1574,19 +1534,51 @@ proc parseWhile(p: var TParser): PNode = eat(p, pxParRi, result) addSon(result, nestedStatement(p)) +proc embedStmts(sl, a: PNode) + proc parseDoWhile(p: var TParser): PNode = - # we only support ``do stmt while (0)`` as an idiom for - # ``block: stmt`` - result = newNodeP(nkBlockStmt, p) - getTok(p, result) # skip "do" - addSon(result, ast.emptyNode, nestedStatement(p)) + # parsing + result = newNodeP(nkWhileStmt, p) + getTok(p, result) + var stm = nestedStatement(p) eat(p, "while", result) eat(p, pxParLe, result) - if p.tok.xkind == pxIntLit and p.tok.iNumber == 0: getTok(p, result) - else: parMessage(p, errTokenExpected, "0") + var exp = expression(p) eat(p, pxParRi, result) if p.tok.xkind == pxSemicolon: getTok(p) + # while true: + # stmt + # if not expr: + # break + addSon(result, newIdentNodeP("true", p)) + + stm = buildStmtList(stm) + + # get the last exp if it is a stmtlist + var cleanedExp = exp + if exp.kind == nkStmtList: + cleanedExp = exp.sons[exp.len-1] + exp.sons = exp.sons[0..exp.len-2] + embedStmts(stm, exp) + + var notExp = newNodeP(nkPrefix, p) + addSon(notExp, newIdentNodeP("not", p)) + addSon(notExp, cleanedExp) + + var brkStm = newNodeP(nkBreakStmt, p) + addSon(brkStm, ast.emptyNode) + + var ifStm = newNodeP(nkIfStmt, p) + var ifBranch = newNodeP(nkElifBranch, p) + addSon(ifBranch, notExp) + addSon(ifBranch, brkStm) + addSon(ifStm, ifBranch) + + embedStmts(stm, ifStm) + + addSon(result, stm) + proc declarationOrStatement(p: var TParser): PNode = if p.tok.xkind != pxSymbol: result = expressionStatement(p) @@ -1666,7 +1658,7 @@ proc parseFor(p: var TParser, result: PNode) = eat(p, pxParLe, result) var initStmt = declarationOrStatement(p) if initStmt.kind != nkEmpty: - addSon(result, initStmt) + embedStmts(result, initStmt) var w = newNodeP(nkWhileStmt, p) var condition = expressionStatement(p) if condition.kind == nkEmpty: condition = newIdentNodeP("true", p) @@ -1676,7 +1668,7 @@ proc parseFor(p: var TParser, result: PNode) = var loopBody = nestedStatement(p) if step.kind != nkEmpty: loopBody = buildStmtList(loopBody) - addSon(loopBody, step) + embedStmts(loopBody, step) addSon(w, loopBody) addSon(result, w) @@ -2048,6 +2040,10 @@ proc parseStandaloneClass(p: var TParser, isStruct: bool): PNode = result = declaration(p) p.currentClass = oldClass +proc unwrap(a: PNode): PNode = + if a.kind == nkPar: + return a.sons[0] + return a include cpp @@ -2082,16 +2078,10 @@ proc statement(p: var TParser): PNode = of "return": result = newNodeP(nkReturnStmt, p) getTok(p) - # special case for ``return (expr)`` because I hate the redundant - # parenthesis ;-) - if p.tok.xkind == pxParLe: - getTok(p, result) - addSon(result, expression(p)) - eat(p, pxParRi, result) - elif p.tok.xkind != pxSemicolon: - addSon(result, expression(p)) - else: + if p.tok.xkind == pxSemicolon: addSon(result, ast.emptyNode) + else: + addSon(result, unwrap(expression(p))) eat(p, pxSemicolon) of "enum": result = enumSpecifier(p) of "typedef": result = parseTypeDef(p) @@ -2140,9 +2130,12 @@ proc statement(p: var TParser): PNode = assert result != nil proc parseUnit(p: var TParser): PNode = - result = newNodeP(nkStmtList, p) - getTok(p) # read first token - while p.tok.xkind != pxEof: - var s = statement(p) - if s.kind != nkEmpty: embedStmts(result, s) + try: + result = newNodeP(nkStmtList, p) + getTok(p) # read first token + while p.tok.xkind != pxEof: + var s = statement(p) + if s.kind != nkEmpty: embedStmts(result, s) + except ERetryParsing: + parMessage(p, errGenerated, "Uncaught parsing exception raised") diff --git a/compiler/c2nim/tests/vincent.c b/compiler/c2nim/tests/vincent.c new file mode 100644 index 000000000..24c6d6425 --- /dev/null +++ b/compiler/c2nim/tests/vincent.c @@ -0,0 +1,33 @@ +#include <stdlib.h> +#include <stdio.h> + +int rand(void); + +int id2(void) { + return (int *)1; +} + +int id(void (*f)(void)) { + f(); + ((void (*)(int))f)(10); + return 10; + return (20+1); + return (int *)id; +} + +int main() { + float f = .2, + g = 2., + h = 1.0+rand(), + i = 1.0e+3; + int j, a; + for(j = 0, a = 10; j < 0; j++, a++) ; + do { + printf("howdy"); + } while(--i, 0); + if(1) + printf("1"); // error from this comment + else + printf("2"); + return '\x00'; +} diff --git a/compiler/c2nim/tests/vincent.h b/compiler/c2nim/tests/vincent.h new file mode 100644 index 000000000..b4e761ee1 --- /dev/null +++ b/compiler/c2nim/tests/vincent.h @@ -0,0 +1,3 @@ +struct foo { + int x,y,z; +}; |