summary refs log tree commit diff stats
path: root/compiler/c2nim/cparse.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/c2nim/cparse.nim')
-rw-r--r--compiler/c2nim/cparse.nim826
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")