diff options
author | Andreas Rumpf <ar@kimeta.de> | 2014-04-10 01:47:20 +0200 |
---|---|---|
committer | Andreas Rumpf <ar@kimeta.de> | 2014-04-10 01:47:20 +0200 |
commit | dcfc7a8896166563f6fd80fbab81bc50e0b5a217 (patch) | |
tree | 4a247ec2d64bafec53e5ab24b0fda89642908a07 /compiler/c2nim/cparse.nim | |
parent | a86c774932afd8b6782df1925837df9df04ef381 (diff) | |
parent | 8b82004359b8d852fa0107d79cc78b21eb35c028 (diff) | |
download | Nim-dcfc7a8896166563f6fd80fbab81bc50e0b5a217.tar.gz |
resolved conflict
Diffstat (limited to 'compiler/c2nim/cparse.nim')
-rw-r--r-- | compiler/c2nim/cparse.nim | 826 |
1 files changed, 410 insertions, 416 deletions
diff --git a/compiler/c2nim/cparse.nim b/compiler/c2nim/cparse.nim index 44be556db..52d50ca39 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 = @[] @@ -93,16 +95,16 @@ proc setOption*(parserOptions: PParserOptions, key: string, val=""): bool = of "class": parserOptions.classes[val] = "true" else: result = false -proc ParseUnit*(p: var TParser): PNode +proc parseUnit*(p: var TParser): PNode proc openParser*(p: var TParser, filename: string, inputStream: PLLStream, options = newParserOptions()) proc closeParser*(p: var TParser) # implementation -proc OpenParser(p: var TParser, filename: string, +proc openParser(p: var TParser, filename: string, inputStream: PLLStream, options = newParserOptions()) = - OpenLexer(p.lex, filename, inputStream) + openLexer(p.lex, filename, inputStream) p.options = options p.backtrack = @[] new(p.tok) @@ -111,7 +113,7 @@ proc parMessage(p: TParser, msg: TMsgKind, arg = "") = #assert false lexMessage(p.lex, msg, arg) -proc CloseParser(p: var TParser) = CloseLexer(p.lex) +proc closeParser(p: var TParser) = closeLexer(p.lex) proc saveContext(p: var TParser) = p.backtrack.add(p.tok) proc closeContext(p: var TParser) = discard p.backtrack.pop() proc backtrackContext(p: var TParser) = p.tok = p.backtrack.pop() @@ -145,7 +147,7 @@ proc findMacro(p: TParser): int = proc rawEat(p: var TParser, xkind: TTokKind) = if p.tok.xkind == xkind: rawGetTok(p) - else: parMessage(p, errTokenExpected, TokKindToStr(xkind)) + else: parMessage(p, errTokenExpected, tokKindToStr(xkind)) proc parseMacroArguments(p: var TParser): seq[seq[ref TToken]] = result = @[] @@ -228,7 +230,7 @@ proc skipComAux(p: var TParser, n: PNode) = getTok(p) proc skipCom(p: var TParser, n: PNode) = - while p.tok.xkind in {pxLineComment, pxStarComment}: skipcomAux(p, n) + while p.tok.xkind in {pxLineComment, pxStarComment}: skipComAux(p, n) proc skipStarCom(p: var TParser, n: PNode) = while p.tok.xkind == pxStarComment: skipComAux(p, n) @@ -242,11 +244,11 @@ proc expectIdent(p: TParser) = proc eat(p: var TParser, xkind: TTokKind, n: PNode) = if p.tok.xkind == xkind: getTok(p, n) - else: parMessage(p, errTokenExpected, TokKindToStr(xkind)) + else: parMessage(p, errTokenExpected, tokKindToStr(xkind)) proc eat(p: var TParser, xkind: TTokKind) = if p.tok.xkind == xkind: getTok(p) - else: parMessage(p, errTokenExpected, TokKindToStr(xkind)) + else: parMessage(p, errTokenExpected, tokKindToStr(xkind)) proc eat(p: var TParser, tok: string, n: PNode) = if p.tok.s == tok: getTok(p, n) @@ -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 @@ -538,7 +540,7 @@ proc typeAtom(p: var TParser): PNode = if p.tok.s == "unsigned": isUnsigned = true elif p.tok.s == "signed" or p.tok.s == "int": - nil + discard else: add(x, p.tok.s) getTok(p, nil) @@ -605,7 +607,7 @@ proc addPragmas(father, pragmas: PNode) = proc addReturnType(params, rettyp: PNode) = if rettyp == nil: addSon(params, ast.emptyNode) elif rettyp.kind != nkNilLit: addSon(params, rettyp) - else: addson(params, ast.emptyNode) + else: addSon(params, ast.emptyNode) proc parseFormalParams(p: var TParser, params, pragmas: PNode) @@ -622,10 +624,11 @@ proc parseTypeSuffix(p: var TParser, typ: PNode): PNode = # array type: result = newNodeP(nkBracketExpr, p) addSon(result, newIdentNodeP("array", p)) - var r = newNodeP(nkRange, p) - addSon(r, newIntNodeP(nkIntLit, 0, p)) - addSon(r, newBinary("-", index, newIntNodeP(nkIntLit, 1, p), p)) - addSon(result, r) + #var r = newNodeP(nkRange, p) + #addSon(r, newIntNodeP(nkIntLit, 0, p)) + #addSon(r, newBinary("-", index, newIntNodeP(nkIntLit, 1, p), p)) + #addSon(result, r) + addSon(result, index) addSon(result, tmp) else: # pointer type: @@ -651,6 +654,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) @@ -663,11 +682,6 @@ proc parseField(p: var TParser, kind: TNodeKind): PNode = 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) @@ -680,8 +694,7 @@ proc parseStructBody(p: var TParser, isUnion: bool, var i = parseField(p, kind) t = parseTypeSuffix(p, t) addSon(def, i, t, ast.emptyNode) - if not takeOnlyFirstField(p, isUnion) or sonsLen(result) < 1: - addSon(result, def) + addSon(result, def) if p.tok.xkind != pxComma: break getTok(p, def) eat(p, pxSemicolon, lastSon(result)) @@ -690,44 +703,67 @@ proc parseStructBody(p: var TParser, isUnion: bool, proc structPragmas(p: TParser, name: PNode, origName: string): PNode = assert name.kind == nkIdent result = newNodeP(nkPragmaExpr, p) - addson(result, exportSym(p, name, origName)) - var pragmas = newNodep(nkPragma, p) - addSon(pragmas, newIdentNodeP("pure", p), newIdentNodeP("final", p)) + addSon(result, exportSym(p, name, origName)) + var pragmas = newNodeP(nkPragma, p) + #addSon(pragmas, newIdentNodeP("pure", p), newIdentNodeP("final", p)) if p.options.header.len > 0: addSon(pragmas, newIdentStrLitPair("importc", origName, p), newIdentStrLitPair("header", p.options.header, p)) - addSon(result, pragmas) + if pragmas.len > 0: addSon(result, pragmas) + else: addSon(result, ast.emptyNode) proc enumPragmas(p: TParser, name: PNode): PNode = result = newNodeP(nkPragmaExpr, p) - addson(result, name) - var pragmas = newNodep(nkPragma, p) + addSon(result, name) + var pragmas = newNodeP(nkPragma, p) var e = newNodeP(nkExprColonExpr, p) # HACK: sizeof(cint) should be constructed as AST addSon(e, newIdentNodeP("size", p), newIdentNodeP("sizeof(cint)", p)) addSon(pragmas, e) addSon(result, pragmas) -proc parseStruct(p: var TParser, isUnion: bool): PNode = +proc parseStruct(p: var TParser, isUnion: bool): PNode = result = newNodeP(nkObjectTy, p) - addSon(result, ast.emptyNode, ast.emptyNode) # no pragmas, no inheritance + var pragmas = ast.emptyNode + if isUnion: + pragmas = newNodeP(nkPragma, p) + addSon(pragmas, newIdentNodeP("union", p)) + addSon(result, pragmas, ast.emptyNode) # no inheritance if p.tok.xkind == pxCurlyLe: addSon(result, parseStructBody(p, isUnion)) 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: + discard + 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: @@ -1045,7 +1081,7 @@ proc declaration(p: var TParser): PNode = of pxSemicolon: getTok(p) addSon(result, ast.emptyNode) # nobody - if p.scopeCounter == 0: DoImport(origName, pragmas, p) + if p.scopeCounter == 0: doImport(origName, pragmas, p) of pxCurlyLe: addSon(result, compoundStatement(p)) else: @@ -1129,229 +1165,32 @@ proc enumSpecifier(p: var TParser): PNode = proc setBaseFlags(n: PNode, base: TNumericalBase) = case base - of base10: nil + of base10: discard of base2: incl(n.flags, nfBase2) 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,270 @@ 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) + var right = expression(p, 29) + addSon(result, left, newBinary("xor", copyTree(left), right, p)) + of pxBarAsgn: # 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("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 +1510,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 +1535,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 +1659,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 +1669,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) @@ -1694,7 +1687,7 @@ proc switchStatement(p: var TParser): PNode = break of "case", "default": break - else: nil + else: discard addSon(result, statement(p)) if sonsLen(result) == 0: # translate empty statement list to Nimrod's ``nil`` statement @@ -1818,7 +1811,7 @@ proc parseConstructor(p: var TParser, pragmas: PNode, else: parMessage(p, errTokenExpected, ";") if result.sons[bodyPos].kind == nkEmpty: - DoImport((if isDestructor: "~" else: "") & origName, pragmas, p) + doImport((if isDestructor: "~" else: "") & origName, pragmas, p) elif isDestructor: addSon(pragmas, newIdentNodeP("destructor", p)) if sonsLen(result.sons[pragmasPos]) == 0: @@ -1862,8 +1855,8 @@ proc parseMethod(p: var TParser, origName: string, rettyp, pragmas: PNode, else: parMessage(p, errTokenExpected, ";") if result.sons[bodyPos].kind == nkEmpty: - if isStatic: DoImport(origName, pragmas, p) - else: DoImportCpp(origName, pragmas, p) + if isStatic: doImport(origName, pragmas, p) + else: doImportCpp(origName, pragmas, p) if sonsLen(result.sons[pragmasPos]) == 0: result.sons[pragmasPos] = ast.emptyNode @@ -1880,7 +1873,7 @@ proc parseOperator(p: var TParser, origName: var string): bool = case p.tok.xkind of pxAmp..pxArrow: # ordinary operator symbol: - origName.add(TokKindToStr(p.tok.xkind)) + origName.add(tokKindToStr(p.tok.xkind)) getTok(p) of pxSymbol: if p.tok.s == "new" or p.tok.s == "delete": @@ -2048,6 +2041,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 +2079,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 +2131,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") |