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.nim2272
1 files changed, 0 insertions, 2272 deletions
diff --git a/compiler/c2nim/cparse.nim b/compiler/c2nim/cparse.nim
deleted file mode 100644
index 2e31af528..000000000
--- a/compiler/c2nim/cparse.nim
+++ /dev/null
@@ -1,2272 +0,0 @@
-#
-#
-#      c2nim - C to Nimrod source converter
-#        (c) Copyright 2013 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module implements an Ansi C parser.
-## It translates a C source file into a Nimrod AST. Then the renderer can be
-## used to convert the AST to its text representation.
-
-# TODO
-# - document 'cpp' mode
-# - implement handling of '::': function declarations
-# - C++'s "operator" still needs some love
-# - support '#if' in classes
-
-import 
-  os, llstream, renderer, clex, idents, strutils, pegs, ast, astalgo, msgs,
-  options, strtabs, hashes, algorithm
-
-type 
-  TParserFlag = enum
-    pfRefs,             ## use "ref" instead of "ptr" for C's typ*
-    pfCDecl,            ## annotate procs with cdecl
-    pfStdCall,          ## annotate procs with stdcall
-    pfSkipInclude,      ## skip all ``#include``
-    pfTypePrefixes,     ## all generated types start with 'T' or 'P'
-    pfSkipComments,     ## do not generate comments
-    pfCpp,              ## process C++
-    pfIgnoreRValueRefs, ## transform C++'s 'T&&' to 'T'
-    pfKeepBodies        ## do not skip C++ method bodies
-  
-  TMacro = object
-    name: string
-    params: int           # number of parameters
-    body: seq[ref TToken] # can contain pxMacroParam tokens
-  
-  TParserOptions = object
-    flags: set[TParserFlag]
-    prefixes, suffixes: seq[string]
-    mangleRules: seq[tuple[pattern: TPeg, frmt: string]]
-    privateRules: seq[TPeg]
-    dynlibSym, header: string
-    macros: seq[TMacro]
-    toMangle: PStringTable
-    classes: PStringTable
-  PParserOptions* = ref TParserOptions
-  
-  TParser* = object
-    lex: TLexer
-    tok: ref TToken       # current token
-    options: PParserOptions
-    backtrack: seq[ref TToken]
-    inTypeDef: int
-    scopeCounter: int
-    hasDeadCodeElimPragma: bool
-    currentClass: PNode   # type that needs to be added as 'this' parameter
-  
-  TReplaceTuple* = array[0..1, string]
-
-  ERetryParsing = object of ESynch
-
-
-
-proc addTypeDef(section, name, t: PNode)
-proc parseStruct(p: var TParser, stmtList: PNode, isUnion: bool): PNode
-proc parseStructBody(p: var TParser, stmtList: PNode, isUnion: bool,
-                     kind: TNodeKind = nkRecList): PNode
-
-
-
-proc newParserOptions*(): PParserOptions = 
-  new(result)
-  result.prefixes = @[]
-  result.suffixes = @[]
-  result.macros = @[]
-  result.mangleRules = @[]
-  result.privateRules = @[]
-  result.flags = {}
-  result.dynlibSym = ""
-  result.header = ""
-  result.toMangle = newStringTable(modeCaseSensitive)
-  result.classes = newStringTable(modeCaseSensitive)
-
-proc setOption*(parserOptions: PParserOptions, key: string, val=""): bool = 
-  result = true
-  case key.normalize
-  of "ref": incl(parserOptions.flags, pfRefs)
-  of "dynlib": parserOptions.dynlibSym = val
-  of "header": parserOptions.header = val
-  of "cdecl": incl(parserOptions.flags, pfCdecl)
-  of "stdcall": incl(parserOptions.flags, pfStdCall)
-  of "prefix": parserOptions.prefixes.add(val)
-  of "suffix": parserOptions.suffixes.add(val)
-  of "skipinclude": incl(parserOptions.flags, pfSkipInclude)
-  of "typeprefixes": incl(parserOptions.flags, pfTypePrefixes)
-  of "skipcomments": incl(parserOptions.flags, pfSkipComments)
-  of "cpp": incl(parserOptions.flags, pfCpp)
-  of "keepbodies": incl(parserOptions.flags, pfKeepBodies)
-  of "ignorervaluerefs": incl(parserOptions.flags, pfIgnoreRValueRefs)
-  of "class": parserOptions.classes[val] = "true"
-  else: result = false
-
-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, 
-                inputStream: PLLStream, options = newParserOptions()) = 
-  openLexer(p.lex, filename, inputStream)
-  p.options = options
-  p.backtrack = @[]
-  new(p.tok)
-
-proc parMessage(p: TParser, msg: TMsgKind, arg = "") = 
-  #assert false
-  lexMessage(p.lex, msg, arg)
-
-proc closeParser(p: var TParser) = closeLexer(p.lex)
-proc 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()
-
-proc rawGetTok(p: var TParser) = 
-  if p.tok.next != nil:
-    p.tok = p.tok.next
-  elif p.backtrack.len == 0: 
-    p.tok.next = nil
-    getTok(p.lex, p.tok[])
-  else: 
-    # We need the next token and must be able to backtrack. So we need to 
-    # allocate a new token.
-    var t: ref TToken
-    new(t)
-    getTok(p.lex, t[])
-    p.tok.next = t
-    p.tok = t
-
-proc insertAngleRi(currentToken: ref TToken) = 
-  var t: ref TToken
-  new(t)
-  t.xkind = pxAngleRi
-  t.next = currentToken.next
-  currentToken.next = t
-
-proc findMacro(p: TParser): int =
-  for i in 0..high(p.options.macros):
-    if p.tok.s == p.options.macros[i].name: return i
-  return -1
-
-proc rawEat(p: var TParser, xkind: TTokKind) = 
-  if p.tok.xkind == xkind: rawGetTok(p)
-  else: parMessage(p, errTokenExpected, tokKindToStr(xkind))
-
-proc parseMacroArguments(p: var TParser): seq[seq[ref TToken]] = 
-  result = @[]
-  result.add(@[])
-  var i: array[pxParLe..pxCurlyLe, int]
-  var L = 0
-  saveContext(p)
-  while true:
-    var kind = p.tok.xkind
-    case kind
-    of pxEof: rawEat(p, pxParRi)
-    of pxParLe, pxBracketLe, pxCurlyLe: 
-      inc(i[kind])
-      result[L].add(p.tok)
-    of pxParRi:
-      # end of arguments?
-      if i[pxParLe] == 0 and i[pxBracketLe] == 0 and i[pxCurlyLe] == 0: break
-      if i[pxParLe] > 0: dec(i[pxParLe])
-      result[L].add(p.tok)
-    of pxBracketRi, pxCurlyRi:
-      kind = pred(kind, 3)
-      if i[kind] > 0: dec(i[kind])
-      result[L].add(p.tok)
-    of pxComma: 
-      if i[pxParLe] == 0 and i[pxBracketLe] == 0 and i[pxCurlyLe] == 0:
-        # next argument: comma is not part of the argument
-        result.add(@[])
-        inc(L)
-      else: 
-        # comma does not separate different arguments:
-        result[L].add(p.tok)
-    else:
-      result[L].add(p.tok)
-    rawGetTok(p)
-  closeContext(p)
-
-proc expandMacro(p: var TParser, m: TMacro) = 
-  rawGetTok(p) # skip macro name
-  var arguments: seq[seq[ref TToken]]
-  if m.params > 0:
-    rawEat(p, pxParLe)
-    arguments = parseMacroArguments(p)
-    if arguments.len != m.params: parMessage(p, errWrongNumberOfArguments)
-    rawEat(p, pxParRi)
-  # insert into the token list:
-  if m.body.len > 0:
-    var newList: ref TToken
-    new(newList)
-    var lastTok = newList
-    for tok in items(m.body): 
-      if tok.xkind == pxMacroParam: 
-        for t in items(arguments[int(tok.iNumber)]):
-          #echo "t: ", t^
-          lastTok.next = t
-          lastTok = t
-      else:
-        #echo "tok: ", tok^
-        lastTok.next = tok
-        lastTok = tok
-    lastTok.next = p.tok
-    p.tok = newList.next
-
-proc getTok(p: var TParser) = 
-  rawGetTok(p)
-  if p.tok.xkind == pxSymbol:
-    var idx = findMacro(p)
-    if idx >= 0: 
-      expandMacro(p, p.options.macros[idx])
-
-proc parLineInfo(p: TParser): TLineInfo = 
-  result = getLineInfo(p.lex)
-
-proc skipComAux(p: var TParser, n: PNode) =
-  if n != nil and n.kind != nkEmpty: 
-    if pfSkipComments notin p.options.flags:
-      if n.comment == nil: n.comment = p.tok.s
-      else: add(n.comment, "\n" & p.tok.s)
-  else: 
-    parMessage(p, warnCommentXIgnored, p.tok.s)
-  getTok(p)
-
-proc skipCom(p: var TParser, n: PNode) = 
-  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)
-
-proc getTok(p: var TParser, n: PNode) =
-  getTok(p)
-  skipCom(p, n)
-
-proc expectIdent(p: TParser) = 
-  if p.tok.xkind != pxSymbol: parMessage(p, errIdentifierExpected, $(p.tok[]))
-  
-proc eat(p: var TParser, xkind: TTokKind, n: PNode) = 
-  if p.tok.xkind == xkind: getTok(p, n)
-  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))
-  
-proc eat(p: var TParser, tok: string, n: PNode) = 
-  if p.tok.s == tok: getTok(p, n)
-  else: parMessage(p, errTokenExpected, tok)
-  
-proc opt(p: var TParser, xkind: TTokKind, n: PNode) = 
-  if p.tok.xkind == xkind: getTok(p, n)
-  
-proc addSon(father, a, b: PNode) = 
-  addSon(father, a)
-  addSon(father, b)
-
-proc addSon(father, a, b, c: PNode) = 
-  addSon(father, a)
-  addSon(father, b)
-  addSon(father, c)
-  
-proc newNodeP(kind: TNodeKind, p: TParser): PNode = 
-  result = newNodeI(kind, getLineInfo(p.lex))
-
-proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode = 
-  result = newNodeP(kind, p)
-  result.intVal = intVal
-
-proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat, 
-                   p: TParser): PNode = 
-  result = newNodeP(kind, p)
-  result.floatVal = floatVal
-
-proc newStrNodeP(kind: TNodeKind, strVal: string, p: TParser): PNode = 
-  result = newNodeP(kind, p)
-  result.strVal = strVal
-
-proc newIdentNodeP(ident: PIdent, p: TParser): PNode = 
-  result = newNodeP(nkIdent, p)
-  result.ident = ident
-
-proc newIdentNodeP(ident: string, p: TParser): PNode =
-  result = newIdentNodeP(getIdent(ident), p)
-
-proc mangleRules(s: string, p: TParser): string = 
-  block mangle:
-    for pattern, frmt in items(p.options.mangleRules):
-      if s.match(pattern):
-        result = s.replacef(pattern, frmt)
-        break mangle
-    block prefixes:
-      for prefix in items(p.options.prefixes): 
-        if s.startsWith(prefix): 
-          result = s.substr(prefix.len)
-          break prefixes
-      result = s
-    block suffixes:
-      for suffix in items(p.options.suffixes):
-        if result.endsWith(suffix):
-          setLen(result, result.len - suffix.len)
-          break suffixes
-
-proc mangleName(s: string, p: TParser): string = 
-  if p.options.toMangle.hasKey(s): result = p.options.toMangle[s]
-  else: result = mangleRules(s, p)
-
-proc isPrivate(s: string, p: TParser): bool = 
-  for pattern in items(p.options.privateRules): 
-    if s.match(pattern): return true
-
-proc mangledIdent(ident: string, p: TParser): PNode = 
-  result = newNodeP(nkIdent, p)
-  result.ident = getIdent(mangleName(ident, p))
-
-proc newIdentPair(a, b: string, p: TParser): PNode = 
-  result = newNodeP(nkExprColonExpr, p)
-  addSon(result, newIdentNodeP(a, p))
-  addSon(result, newIdentNodeP(b, p))
-
-proc newIdentStrLitPair(a, b: string, p: TParser): PNode =
-  result = newNodeP(nkExprColonExpr, p)
-  addSon(result, newIdentNodeP(a, p))
-  addSon(result, newStrNodeP(nkStrLit, b, p))
-
-proc addImportToPragma(pragmas: PNode, ident: string, p: TParser) =
-  addSon(pragmas, newIdentStrLitPair("importc", ident, p))
-  if p.options.dynlibSym.len > 0:
-    addSon(pragmas, newIdentPair("dynlib", p.options.dynlibSym, p))
-  else:
-    addSon(pragmas, newIdentStrLitPair("header", p.options.header, p))
-
-proc exportSym(p: TParser, i: PNode, origName: string): PNode = 
-  assert i.kind == nkIdent
-  if p.scopeCounter == 0 and not isPrivate(origName, p):
-    result = newNodeI(nkPostfix, i.info)
-    addSon(result, newIdentNode(getIdent("*"), i.info), i)
-  else:
-    result = i
-
-proc varIdent(ident: string, p: TParser): PNode = 
-  result = exportSym(p, mangledIdent(ident, p), ident)
-  if p.scopeCounter > 0: return
-  if p.options.dynlibSym.len > 0 or p.options.header.len > 0: 
-    var a = result
-    result = newNodeP(nkPragmaExpr, p)
-    var pragmas = newNodeP(nkPragma, p)
-    addSon(result, a)
-    addSon(result, pragmas)
-    addImportToPragma(pragmas, ident, p)
-
-proc fieldIdent(ident: string, p: TParser): PNode = 
-  result = exportSym(p, mangledIdent(ident, p), ident)
-  if p.scopeCounter > 0: return
-  if p.options.header.len > 0: 
-    var a = result
-    result = newNodeP(nkPragmaExpr, p)
-    var pragmas = newNodeP(nkPragma, p)
-    addSon(result, a)
-    addSon(result, pragmas)
-    addSon(pragmas, newIdentStrLitPair("importc", ident, p))
-
-proc doImport(ident: string, pragmas: PNode, p: TParser) = 
-  if p.options.dynlibSym.len > 0 or p.options.header.len > 0: 
-    addImportToPragma(pragmas, ident, p)
-
-proc doImportCpp(ident: string, pragmas: PNode, p: TParser) = 
-  if p.options.dynlibSym.len > 0 or p.options.header.len > 0:
-    addSon(pragmas, newIdentStrLitPair("importcpp", ident, p))
-    if p.options.dynlibSym.len > 0:
-      addSon(pragmas, newIdentPair("dynlib", p.options.dynlibSym, p))
-    else:
-      addSon(pragmas, newIdentStrLitPair("header", p.options.header, p))
-
-proc newBinary(opr: string, a, b: PNode, p: TParser): PNode =
-  result = newNodeP(nkInfix, p)
-  addSon(result, newIdentNodeP(getIdent(opr), p))
-  addSon(result, a)
-  addSon(result, b)
-
-proc skipIdent(p: var TParser): PNode = 
-  expectIdent(p)
-  result = mangledIdent(p.tok.s, p)
-  getTok(p, result)
-
-proc skipIdentExport(p: var TParser): PNode = 
-  expectIdent(p)
-  result = exportSym(p, mangledIdent(p.tok.s, p), p.tok.s)
-  getTok(p, result)
-
-proc skipTypeIdentExport(p: var TParser, prefix='T'): PNode = 
-  expectIdent(p)
-  var n = prefix & mangleName(p.tok.s, p)
-  p.options.toMangle[p.tok.s] = n
-  var i = newNodeP(nkIdent, p)
-  i.ident = getIdent(n)
-  result = exportSym(p, i, p.tok.s)
-  getTok(p, result)
-
-proc markTypeIdent(p: var TParser, typ: PNode) = 
-  if pfTypePrefixes in p.options.flags:
-    var prefix = ""
-    if typ == nil or typ.kind == nkEmpty: 
-      prefix = "T"
-    else: 
-      var t = typ
-      while t != nil and t.kind in {nkVarTy, nkPtrTy, nkRefTy}: 
-        prefix.add('P')
-        t = t.sons[0]
-      if prefix.len == 0: prefix.add('T')
-    expectIdent(p)
-    p.options.toMangle[p.tok.s] = prefix & mangleRules(p.tok.s, p)
-  
-# --------------- parser -----------------------------------------------------
-# We use this parsing rule: If it looks like a declaration, it is one. This
-# avoids to build a symbol table, which can't be done reliably anyway for our
-# purposes.
-
-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
-
-proc declKeyword(p: TParser, s: string): bool = 
-  # returns true if it is a keyword that introduces a declaration
-  case s
-  of  "extern", "static", "auto", "register", "const", "volatile", "restrict",
-      "inline", "__inline", "__cdecl", "__stdcall", "__syscall", "__fastcall",
-      "__safecall", "void", "struct", "union", "enum", "typedef",
-      "short", "int", "long", "float", "double", "signed", "unsigned", "char": 
-    result = true
-  of "class":
-    result = p.options.flags.contains(pfCpp)
-
-proc stmtKeyword(s: string): bool =
-  case s
-  of  "if", "for", "while", "do", "switch", "break", "continue", "return",
-      "goto":
-    result = true
-
-# ------------------- type desc -----------------------------------------------
-
-proc isIntType(s: string): bool =
-  case s
-  of "short", "int", "long", "float", "double", "signed", "unsigned":
-    result = true
-
-proc skipConst(p: var TParser) = 
-  while p.tok.xkind == pxSymbol and
-      (p.tok.s == "const" or p.tok.s == "volatile" or p.tok.s == "restrict"): 
-    getTok(p, nil)
-
-proc isTemplateAngleBracket(p: var TParser): bool =
-  if pfCpp notin p.options.flags: return false
-  saveContext(p)
-  getTok(p, nil) # skip "<"
-  var i: array[pxParLe..pxCurlyLe, int]
-  var angles = 0
-  while true:
-    let kind = p.tok.xkind
-    case kind
-    of pxEof: break
-    of pxParLe, pxBracketLe, pxCurlyLe: inc(i[kind])
-    of pxGt, pxAngleRi:
-      # end of arguments?
-      if i[pxParLe] == 0 and i[pxBracketLe] == 0 and i[pxCurlyLe] == 0 and
-          angles == 0:
-        # mark as end token:
-        p.tok.xkind = pxAngleRi
-        result = true; 
-        break
-      if angles > 0: dec(angles)
-    of pxShr:
-      # >> can end a template too:
-      if i[pxParLe] == 0 and i[pxBracketLe] == 0 and i[pxCurlyLe] == 0 and
-          angles == 1:
-        p.tok.xkind = pxAngleRi
-        insertAngleRi(p.tok)
-        result = true
-        break
-      if angles > 1: dec(angles, 2)
-    of pxLt: inc(angles)
-    of pxParRi, pxBracketRi, pxCurlyRi:
-      let kind = pred(kind, 3)
-      if i[kind] > 0: dec(i[kind])
-      else: break
-    of pxSemicolon: break
-    else: discard
-    getTok(p, nil)
-  backtrackContext(p)
-
-proc optAngle(p: var TParser, n: PNode): PNode =
-  if p.tok.xkind == pxLt and isTemplateAngleBracket(p):
-    getTok(p)
-    result = newNodeP(nkBracketExpr, p)
-    result.add(n)
-    while true:
-      let a = assignmentExpression(p)
-      if not a.isNil: result.add(a)
-      if p.tok.xkind != pxComma: break
-      getTok(p)
-    eat(p, pxAngleRi)
-  else:
-    result = n
-
-proc optScope(p: var TParser, n: PNode): PNode =
-  result = n
-  if pfCpp in p.options.flags:
-    while p.tok.xkind == pxScope:
-      let a = result
-      result = newNodeP(nkDotExpr, p)
-      result.add(a)
-      getTok(p, result)
-      expectIdent(p)
-      result.add(mangledIdent(p.tok.s, p))
-      getTok(p, result)
-
-proc typeAtom(p: var TParser): PNode = 
-  skipConst(p)
-  expectIdent(p)
-  case p.tok.s
-  of "void": 
-    result = newNodeP(nkNilLit, p) # little hack
-    getTok(p, nil)
-  of "struct", "union", "enum": 
-    getTok(p, nil)
-    result = skipIdent(p)
-  elif isIntType(p.tok.s):
-    var x = ""
-    #getTok(p, nil)
-    var isUnsigned = false
-    while p.tok.xkind == pxSymbol and (isIntType(p.tok.s) or p.tok.s == "char"):
-      if p.tok.s == "unsigned":
-        isUnsigned = true
-      elif p.tok.s == "signed" or p.tok.s == "int":
-        discard
-      else:
-        add(x, p.tok.s)
-      getTok(p, nil)
-    if x.len == 0: x = "int"
-    let xx = if isUnsigned: "cu" & x else: "c" & x
-    result = mangledIdent(xx, p)
-  else:
-    result = mangledIdent(p.tok.s, p)
-    getTok(p, result)
-    result = optScope(p, result)
-    result = optAngle(p, result)
-    
-proc newPointerTy(p: TParser, typ: PNode): PNode =
-  if pfRefs in p.options.flags: 
-    result = newNodeP(nkRefTy, p)
-  else:
-    result = newNodeP(nkPtrTy, p)
-  result.addSon(typ)
-
-proc pointer(p: var TParser, a: PNode): PNode = 
-  result = a
-  var i = 0
-  skipConst(p)
-  while true:
-    if p.tok.xkind == pxStar:
-      inc(i)
-      getTok(p, result)
-      skipConst(p)
-      result = newPointerTy(p, result)
-    elif p.tok.xkind == pxAmp and pfCpp in p.options.flags:
-      getTok(p, result)
-      skipConst(p)
-      let b = result
-      result = newNodeP(nkVarTy, p)
-      result.add(b)
-    elif p.tok.xkind == pxAmpAmp and pfCpp in p.options.flags:
-      getTok(p, result)
-      skipConst(p)
-      if pfIgnoreRvalueRefs notin p.options.flags:
-        let b = result
-        result = newNodeP(nkVarTy, p)
-        result.add(b)
-    else: break
-  if a.kind == nkIdent and a.ident.s == "char": 
-    if i >= 2: 
-      result = newIdentNodeP("cstringArray", p)
-      for j in 1..i-2: result = newPointerTy(p, result)
-    elif i == 1: result = newIdentNodeP("cstring", p)
-  elif a.kind == nkNilLit and i > 0:
-    result = newIdentNodeP("pointer", p)
-    for j in 1..i-1: result = newPointerTy(p, result)
-
-proc newProcPragmas(p: TParser): PNode =
-  result = newNodeP(nkPragma, p)
-  if pfCDecl in p.options.flags: 
-    addSon(result, newIdentNodeP("cdecl", p))
-  elif pfStdCall in p.options.flags:
-    addSon(result, newIdentNodeP("stdcall", p))
-
-proc addPragmas(father, pragmas: PNode) =
-  if sonsLen(pragmas) > 0: addSon(father, pragmas)
-  else: addSon(father, ast.emptyNode)
-
-proc addReturnType(params, rettyp: PNode) =
-  if rettyp == nil: addSon(params, ast.emptyNode)
-  elif rettyp.kind != nkNilLit: addSon(params, rettyp)
-  else: addSon(params, ast.emptyNode)
-
-proc parseFormalParams(p: var TParser, params, pragmas: PNode)
-
-proc parseTypeSuffix(p: var TParser, typ: PNode): PNode = 
-  result = typ
-  while true:
-    case p.tok.xkind 
-    of pxBracketLe:
-      getTok(p, result)
-      skipConst(p) # POSIX contains: ``int [restrict]``
-      if p.tok.xkind != pxBracketRi:
-        var tmp = result
-        var index = expression(p)
-        # 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)
-        addSon(result, index)
-        addSon(result, tmp)
-      else:
-        # pointer type:
-        var tmp = result
-        if pfRefs in p.options.flags: 
-          result = newNodeP(nkRefTy, p)
-        else:
-          result = newNodeP(nkPtrTy, p)
-        result.addSon(tmp)
-      eat(p, pxBracketRi, result)
-    of pxParLe:
-      # function pointer:
-      var procType = newNodeP(nkProcTy, p)
-      var pragmas = newProcPragmas(p)
-      var params = newNodeP(nkFormalParams, p)
-      addReturnType(params, result)
-      parseFormalParams(p, params, pragmas)
-      addSon(procType, params)
-      addPragmas(procType, pragmas)
-      result = procType
-    else: break
-
-proc typeDesc(p: var TParser): PNode = 
-  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)
-    while p.tok.xkind == pxStar: getTok(p, nil)
-    result = parseField(p, kind)
-    eat(p, pxParRi, result)
-  else: 
-    expectIdent(p)
-    if kind == nkRecList: result = fieldIdent(p.tok.s, p) 
-    else: result = mangledIdent(p.tok.s, p)
-    getTok(p, result)
-
-proc 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))
-  if p.options.header.len > 0:
-    addSon(pragmas, newIdentStrLitPair("importc", origName, p),
-                    newIdentStrLitPair("header", p.options.header, p))
-  if pragmas.len > 0: addSon(result, pragmas)
-  else: addSon(result, ast.emptyNode)
-
-proc hashPosition(p: TParser): string =
-  let lineInfo = parLineInfo(p)
-  let fileInfo = fileInfos[lineInfo.fileIndex]
-  result = $hash(fileInfo.shortName & "_" & $lineInfo.line & "_" & $lineInfo.col).uint
-
-proc parseInnerStruct(p: var TParser, stmtList: PNode, isUnion: bool): PNode =
-  getTok(p, nil)
-  if p.tok.xkind != pxCurlyLe:
-    parMessage(p, errUser, "Expected '{' but found '" & $(p.tok[]) & "'")
-  
-  let structName =  if isUnion: "INNER_C_UNION_" & p.hashPosition
-                    else: "INNER_C_STRUCT_" & p.hashPosition
-  let typeSection = newNodeP(nkTypeSection, p)
-  let newStruct = newNodeP(nkObjectTy, p)
-  var pragmas = ast.emptyNode
-  if isUnion:
-    pragmas = newNodeP(nkPragma, p)
-    addSon(pragmas, newIdentNodeP("union", p))
-  addSon(newStruct, pragmas, ast.emptyNode) # no inheritance 
-  result = newNodeP(nkIdent, p)
-  result.ident = getIdent(structName)
-  let struct = parseStructBody(p, stmtList, isUnion)
-  let defName = newNodeP(nkIdent, p)
-  defName.ident = getIdent(structName)
-  addSon(newStruct, struct)
-  addTypeDef(typeSection, structPragmas(p, defName, "no_name"), newStruct)
-  addSon(stmtList, typeSection)
-
-proc parseStructBody(p: var TParser, stmtList: PNode, isUnion: bool,
-                     kind: TNodeKind = nkRecList): PNode =
-  result = newNodeP(kind, p)
-  eat(p, pxCurlyLe, result)
-  while p.tok.xkind notin {pxEof, pxCurlyRi}:
-    skipConst(p)
-    var baseTyp: PNode
-    if p.tok.xkind == pxSymbol and (p.tok.s == "struct" or p.tok.s == "union"):
-      let gotUnion = if p.tok.s == "union": true   else: false
-      saveContext(p)
-      getTok(p, nil)
-      if p.tok.xkind == pxSymbol:
-        backtrackContext(p)
-        baseTyp = typeAtom(p)
-      else:
-        backtrackContext(p)
-        baseTyp = parseInnerStruct(p, stmtList, gotUnion)
-        if p.tok.xkind == pxSemiColon:
-          let def = newNodeP(nkIdentDefs, p)
-          var t = pointer(p, baseTyp)
-          let i = fieldIdent("ano_" & p.hashPosition, p)
-          t = parseTypeSuffix(p, t)
-          addSon(def, i, t, ast.emptyNode)
-          addSon(result, def)
-          getTok(p, nil)
-          continue
-    else:
-      baseTyp = typeAtom(p)
-    
-    while true:
-      var def = newNodeP(nkIdentDefs, p)
-      var t = pointer(p, baseTyp)
-      var i = parseField(p, kind)
-      t = parseTypeSuffix(p, t)
-      addSon(def, i, t, ast.emptyNode)
-      addSon(result, def)
-      if p.tok.xkind != pxComma: break
-      getTok(p, def)
-    eat(p, pxSemicolon, lastSon(result))
-  eat(p, pxCurlyRi, result)
-
-proc enumPragmas(p: TParser, name: PNode): PNode =
-  result = newNodeP(nkPragmaExpr, 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, stmtList: PNode, isUnion: bool): PNode =
-  result = newNodeP(nkObjectTy, p)
-  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, stmtList, 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
-  typ = declarator(p, typ, addr name)
-  if name == nil:
-    var idx = sonsLen(params)+1
-    name = newIdentNodeP("a" & $idx, p)
-  var x = newNodeP(nkIdentDefs, p)
-  addSon(x, name, typ)
-  if p.tok.xkind == pxAsgn: 
-    # we support default parameters for C++:
-    getTok(p, x)
-    addSon(x, assignmentExpression(p))
-  else:
-    addSon(x, ast.emptyNode)
-  addSon(params, x)
-
-proc parseFormalParams(p: var TParser, params, pragmas: PNode) = 
-  eat(p, pxParLe, params)
-  while p.tok.xkind notin {pxEof, pxParRi}:
-    if p.tok.xkind == pxDotDotDot:  
-      addSon(pragmas, newIdentNodeP("varargs", p))
-      getTok(p, pragmas)
-      break
-    parseParam(p, params)
-    if p.tok.xkind != pxComma: break
-    getTok(p, params)
-  eat(p, pxParRi, params)
-
-proc parseCallConv(p: var TParser, pragmas: PNode) = 
-  while p.tok.xkind == pxSymbol:
-    case p.tok.s
-    of "inline", "__inline": addSon(pragmas, newIdentNodeP("inline", p))
-    of "__cdecl": addSon(pragmas, newIdentNodeP("cdecl", p))
-    of "__stdcall": addSon(pragmas, newIdentNodeP("stdcall", p))
-    of "__syscall": addSon(pragmas, newIdentNodeP("syscall", p))
-    of "__fastcall": addSon(pragmas, newIdentNodeP("fastcall", p))
-    of "__safecall": addSon(pragmas, newIdentNodeP("safecall", p))
-    else: break
-    getTok(p, nil)
-
-proc parseFunctionPointerDecl(p: var TParser, rettyp: PNode): PNode = 
-  var procType = newNodeP(nkProcTy, p)
-  var pragmas = newProcPragmas(p)
-  var params = newNodeP(nkFormalParams, p)
-  eat(p, pxParLe, params)
-  addReturnType(params, rettyp)
-  parseCallConv(p, pragmas)
-  if p.tok.xkind == pxStar: getTok(p, params)
-  else: parMessage(p, errTokenExpected, "*")
-  if p.inTypeDef > 0: markTypeIdent(p, nil)
-  var name = skipIdentExport(p)
-  eat(p, pxParRi, name)
-  parseFormalParams(p, params, pragmas)
-  addSon(procType, params)
-  addPragmas(procType, pragmas)
-  
-  if p.inTypeDef == 0:
-    result = newNodeP(nkVarSection, p)
-    var def = newNodeP(nkIdentDefs, p)
-    addSon(def, name, procType, ast.emptyNode)
-    addSon(result, def)    
-  else:
-    result = newNodeP(nkTypeDef, p)
-    addSon(result, name, ast.emptyNode, procType)
-  assert result != nil
-  
-proc addTypeDef(section, name, t: PNode) = 
-  var def = newNodeI(nkTypeDef, name.info)
-  addSon(def, name, ast.emptyNode, t)
-  addSon(section, def)
-  
-proc otherTypeDef(p: var TParser, section, typ: PNode) = 
-  var name: PNode
-  var t = typ
-  if p.tok.xkind in {pxStar, pxAmp, pxAmpAmp}:
-    t = pointer(p, t)
-  if p.tok.xkind == pxParLe: 
-    # function pointer: typedef typ (*name)();
-    var x = parseFunctionPointerDecl(p, t)
-    name = x[0]
-    t = x[2]
-  else: 
-    # typedef typ name;
-    markTypeIdent(p, t)
-    name = skipIdentExport(p)
-  t = parseTypeSuffix(p, t)
-  addTypeDef(section, name, t)
-
-proc parseTrailingDefinedTypes(p: var TParser, section, typ: PNode) = 
-  while p.tok.xkind == pxComma:
-    getTok(p, nil)
-    var newTyp = pointer(p, typ)
-    markTypeIdent(p, newTyp)
-    var newName = skipIdentExport(p)
-    newTyp = parseTypeSuffix(p, newTyp)
-    addTypeDef(section, newName, newTyp)
-
-proc createConst(name, typ, val: PNode, p: TParser): PNode =
-  result = newNodeP(nkConstDef, p)
-  addSon(result, name, typ, val)
-
-proc exprToNumber(n: PNode not nil): tuple[succ: bool, val: BiggestInt] =
-  result = (false, 0.BiggestInt)
-  case n.kind:
-  of nkPrefix:
-    # Check for negative/positive numbers  -3  or  +6
-    if n.sons.len == 2 and n.sons[0].kind == nkIdent and n.sons[1].kind == nkIntLit:
-      let pre = n.sons[0]
-      let num = n.sons[1]
-      if pre.ident.s == "-": result = (true, - num.intVal)
-      elif pre.ident.s == "+": result = (true, num.intVal)
-  else: discard
-
-proc enumFields(p: var TParser, constList: PNode): PNode = 
-  result = newNodeP(nkEnumTy, p)
-  addSon(result, ast.emptyNode) # enum does not inherit from anything
-  var i: BiggestInt = 0
-  var field: tuple[id: BiggestInt, isNumber: bool, node: PNode]
-  var fields = newSeq[type(field)]()
-  while true:
-    var e = skipIdent(p)
-    if p.tok.xkind == pxAsgn: 
-      getTok(p, e)
-      var c = constantExpression(p)
-      var a = e
-      e = newNodeP(nkEnumFieldDef, p)
-      addSon(e, a, c)
-      skipCom(p, e)
-      if c.kind == nkIntLit:
-        i = c.intVal
-        field.isNumber = true
-      else:
-        var (success, number) = exprToNumber(c)
-        if success:
-          i = number
-          field.isNumber = true
-        else:
-          field.isNumber = false
-    else:
-      inc(i)
-      field.isNumber = true
-    field.id = i
-    field.node = e
-    fields.add(field)
-    if p.tok.xkind != pxComma: break
-    getTok(p, e)
-    # allow trailing comma:
-    if p.tok.xkind == pxCurlyRi: break
-  fields.sort do (x, y: type(field)) -> int:
-    cmp(x.id, y.id)
-  var lastId: BiggestInt
-  var lastIdent: PNode
-  for count, f in fields:
-    if not f.isNumber:
-      addSon(result, f.node)
-    elif f.id == lastId and count > 0:
-      var currentIdent: PNode
-      case f.node.kind:
-      of nkEnumFieldDef:
-        if f.node.sons.len > 0 and f.node.sons[0].kind == nkIdent:
-          currentIdent = f.node.sons[0]
-        else: parMessage(p, errGenerated, "Warning: When sorting enum fields an expected nkIdent was not found. Check the fields!")
-      of nkIdent: currentIdent = f.node
-      else: parMessage(p, errGenerated, "Warning: When sorting enum fields an expected nkIdent was not found. Check the fields!")
-      var constant = createConst( currentIdent, ast.emptyNode, lastIdent, p)
-      constList.addSon(constant)
-    else:
-      addSon(result, f.node)
-      lastId = f.id
-      case f.node.kind:
-      of nkEnumFieldDef:
-        if f.node.sons.len > 0 and f.node.sons[0].kind == nkIdent:
-          lastIdent = f.node.sons[0]
-        else: parMessage(p, errGenerated, "Warning: When sorting enum fields an expected nkIdent was not found. Check the fields!")
-      of nkIdent: lastIdent = f.node
-      else: parMessage(p, errGenerated, "Warning: When sorting enum fields an expected nkIdent was not found. Check the fields!")
-
-proc parseTypedefStruct(p: var TParser, result: PNode, stmtList: PNode, isUnion: bool) = 
-  getTok(p, result)
-  if p.tok.xkind == pxCurlyLe:
-    var t = parseStruct(p, stmtList, isUnion)
-    var origName = p.tok.s
-    markTypeIdent(p, nil)
-    var name = skipIdent(p)
-    addTypeDef(result, structPragmas(p, name, origName), t)
-    parseTrailingDefinedTypes(p, result, name)
-  elif p.tok.xkind == pxSymbol: 
-    # name to be defined or type "struct a", we don't know yet:
-    markTypeIdent(p, nil)
-    var origName = p.tok.s
-    var nameOrType = skipIdent(p)
-    case p.tok.xkind 
-    of pxCurlyLe:
-      var t = parseStruct(p, stmtList, isUnion)
-      if p.tok.xkind == pxSymbol: 
-        # typedef struct tagABC {} abc, *pabc;
-        # --> abc is a better type name than tagABC!
-        markTypeIdent(p, nil)
-        var origName = p.tok.s
-        var name = skipIdent(p)
-        addTypeDef(result, structPragmas(p, name, origName), t)
-        parseTrailingDefinedTypes(p, result, name)
-      else:
-        addTypeDef(result, structPragmas(p, nameOrType, origName), t)
-    of pxSymbol: 
-      # typedef struct a a?
-      if mangleName(p.tok.s, p) == nameOrType.ident.s:
-        # ignore the declaration:
-        getTok(p, nil)
-      else:
-        # typedef struct a b; or typedef struct a b[45];
-        otherTypeDef(p, result, nameOrType)
-    else: 
-      otherTypeDef(p, result, nameOrType)
-  else:
-    expectIdent(p)
-
-proc parseTypedefEnum(p: var TParser, result, constSection: PNode) = 
-  getTok(p, result)
-  if p.tok.xkind == pxCurlyLe:
-    getTok(p, result)
-    var t = enumFields(p, constSection)
-    eat(p, pxCurlyRi, t)
-    var origName = p.tok.s
-    markTypeIdent(p, nil)
-    var name = skipIdent(p)
-    addTypeDef(result, enumPragmas(p, exportSym(p, name, origName)), t)
-    parseTrailingDefinedTypes(p, result, name)
-  elif p.tok.xkind == pxSymbol: 
-    # name to be defined or type "enum a", we don't know yet:
-    markTypeIdent(p, nil)
-    var origName = p.tok.s
-    var nameOrType = skipIdent(p)
-    case p.tok.xkind 
-    of pxCurlyLe:
-      getTok(p, result)
-      var t = enumFields(p, constSection)
-      eat(p, pxCurlyRi, t)
-      if p.tok.xkind == pxSymbol: 
-        # typedef enum tagABC {} abc, *pabc;
-        # --> abc is a better type name than tagABC!
-        markTypeIdent(p, nil)
-        var origName = p.tok.s
-        var name = skipIdent(p)
-        addTypeDef(result, enumPragmas(p, exportSym(p, name, origName)), t)
-        parseTrailingDefinedTypes(p, result, name)
-      else:
-        addTypeDef(result, 
-                   enumPragmas(p, exportSym(p, nameOrType, origName)), t)
-    of pxSymbol: 
-      # typedef enum a a?
-      if mangleName(p.tok.s, p) == nameOrType.ident.s:
-        # ignore the declaration:
-        getTok(p, nil)
-      else:
-        # typedef enum a b; or typedef enum a b[45];
-        otherTypeDef(p, result, nameOrType)
-    else: 
-      otherTypeDef(p, result, nameOrType)
-  else:
-    expectIdent(p)
-
-proc parseTypeDef(p: var TParser): PNode =  
-  result = newNodeP(nkStmtList, p)
-  var typeSection = newNodeP(nkTypeSection, p)
-  var afterStatements = newNodeP(nkStmtList, p)
-  while p.tok.xkind == pxSymbol and p.tok.s == "typedef":
-    getTok(p, typeSection)
-    inc(p.inTypeDef)
-    expectIdent(p)
-    case p.tok.s
-    of "struct": parseTypedefStruct(p, typeSection, result, isUnion=false)
-    of "union": parseTypedefStruct(p, typeSection, result, isUnion=true)
-    of "enum":
-      var constSection = newNodeP(nkConstSection, p)
-      parseTypedefEnum(p, typeSection, constSection)
-      addSon(afterStatements, constSection)
-    of "class":
-      if pfCpp in p.options.flags:
-        parseTypedefStruct(p, typeSection, result, isUnion=false)
-      else:
-        var t = typeAtom(p)
-        otherTypeDef(p, typeSection, t)
-    else: 
-      var t = typeAtom(p)
-      otherTypeDef(p, typeSection, t)
-    eat(p, pxSemicolon)
-    dec(p.inTypeDef)
-  
-  addSon(result, typeSection)
-  for s in afterStatements:
-    addSon(result, s)
-  
-proc skipDeclarationSpecifiers(p: var TParser) =
-  while p.tok.xkind == pxSymbol:
-    case p.tok.s
-    of "extern", "static", "auto", "register", "const", "volatile": 
-      getTok(p, nil)
-    else: break
-
-proc parseInitializer(p: var TParser): PNode = 
-  if p.tok.xkind == pxCurlyLe: 
-    result = newNodeP(nkBracket, p)
-    getTok(p, result)
-    while p.tok.xkind notin {pxEof, pxCurlyRi}: 
-      addSon(result, parseInitializer(p))
-      opt(p, pxComma, nil)
-    eat(p, pxCurlyRi, result)
-  else:
-    result = assignmentExpression(p)
-
-proc addInitializer(p: var TParser, def: PNode) = 
-  if p.tok.xkind == pxAsgn:
-    getTok(p, def)
-    addSon(def, parseInitializer(p))
-  else:
-    addSon(def, ast.emptyNode)  
-
-proc parseVarDecl(p: var TParser, baseTyp, typ: PNode, 
-                  origName: string): PNode =  
-  result = newNodeP(nkVarSection, p)
-  var def = newNodeP(nkIdentDefs, p)
-  addSon(def, varIdent(origName, p))
-  addSon(def, parseTypeSuffix(p, typ))
-  addInitializer(p, def)
-  addSon(result, def)
-    
-  while p.tok.xkind == pxComma: 
-    getTok(p, def)
-    var t = pointer(p, baseTyp)
-    expectIdent(p)
-    def = newNodeP(nkIdentDefs, p)
-    addSon(def, varIdent(p.tok.s, p))
-    getTok(p, def)
-    addSon(def, parseTypeSuffix(p, t))
-    addInitializer(p, def)
-    addSon(result, def)
-  eat(p, pxSemicolon)
-
-proc declarationName(p: var TParser): string =
-  expectIdent(p)
-  result = p.tok.s
-  getTok(p) # skip identifier
-  while p.tok.xkind == pxScope and pfCpp in p.options.flags:
-    getTok(p) # skip "::"
-    expectIdent(p)
-    result.add("::")
-    result.add(p.tok.s)
-    getTok(p)
-
-proc declaration(p: var TParser): PNode = 
-  result = newNodeP(nkProcDef, p)
-  var pragmas = newNodeP(nkPragma, p)
-  
-  skipDeclarationSpecifiers(p)
-  parseCallConv(p, pragmas)
-  skipDeclarationSpecifiers(p)
-  expectIdent(p)
-  var baseTyp = typeAtom(p)
-  var rettyp = pointer(p, baseTyp)
-  skipDeclarationSpecifiers(p)
-  parseCallConv(p, pragmas)
-  skipDeclarationSpecifiers(p)
-  
-  if p.tok.xkind == pxParLe: 
-    # Function pointer declaration: This is of course only a heuristic, but the
-    # best we can do here.
-    result = parseFunctionPointerDecl(p, rettyp)
-    eat(p, pxSemicolon)
-    return
-  var origName = declarationName(p)
-  case p.tok.xkind
-  of pxParLe:
-    # really a function!
-    var name = mangledIdent(origName, p)
-    var params = newNodeP(nkFormalParams, p)
-    addReturnType(params, rettyp)
-    parseFormalParams(p, params, pragmas)
-    if pfCpp in p.options.flags and p.tok.xkind == pxSymbol and
-        p.tok.s == "const":
-      addSon(pragmas, newIdentNodeP("noSideEffect", p))
-      getTok(p)
-    if pfCDecl in p.options.flags:
-      addSon(pragmas, newIdentNodeP("cdecl", p))
-    elif pfStdcall in p.options.flags:
-      addSon(pragmas, newIdentNodeP("stdcall", p))
-    # no pattern, no exceptions:
-    addSon(result, exportSym(p, name, origName), ast.emptyNode, ast.emptyNode)
-    addSon(result, params, pragmas, ast.emptyNode) # no exceptions
-    case p.tok.xkind 
-    of pxSemicolon: 
-      getTok(p)
-      addSon(result, ast.emptyNode) # nobody
-      if p.scopeCounter == 0: doImport(origName, pragmas, p)
-    of pxCurlyLe:
-      addSon(result, compoundStatement(p))
-    else:
-      parMessage(p, errTokenExpected, ";")
-    if sonsLen(result.sons[pragmasPos]) == 0: 
-      result.sons[pragmasPos] = ast.emptyNode
-  else:
-    result = parseVarDecl(p, baseTyp, rettyp, origName)
-  assert result != nil
-
-proc enumSpecifier(p: var TParser): PNode =  
-  saveContext(p)
-  getTok(p, nil) # skip "enum"
-  case p.tok.xkind
-  of pxCurlyLe: 
-    closeContext(p)
-    # make a const section out of it:
-    result = newNodeP(nkConstSection, p)
-    getTok(p, result)
-    var i = 0
-    var hasUnknown = false
-    while true:
-      var name = skipIdentExport(p)
-      var val: PNode
-      if p.tok.xkind == pxAsgn: 
-        getTok(p, name)
-        val = constantExpression(p)
-        if val.kind == nkIntLit:  
-          i = int(val.intVal)+1
-          hasUnknown = false
-        else:
-          hasUnknown = true
-      else:
-        if hasUnknown:
-          parMessage(p, warnUser, "computed const value may be wrong: " &
-            name.renderTree)
-        val = newIntNodeP(nkIntLit, i, p)
-        inc(i)
-      var c = createConst(name, ast.emptyNode, val, p)
-      addSon(result, c)
-      if p.tok.xkind != pxComma: break
-      getTok(p, c)
-      # allow trailing comma:
-      if p.tok.xkind == pxCurlyRi: break
-    eat(p, pxCurlyRi, result)
-    eat(p, pxSemicolon)
-  of pxSymbol: 
-    var origName = p.tok.s
-    markTypeIdent(p, nil)
-    result = skipIdent(p)
-    case p.tok.xkind 
-    of pxCurlyLe: 
-      closeContext(p)
-      var name = result
-      # create a type section containing the enum
-      result = newNodeP(nkStmtList, p)
-      var tSection = newNodeP(nkTypeSection, p)
-      var t = newNodeP(nkTypeDef, p)
-      getTok(p, t)
-      var constSection = newNodeP(nkConstSection, p)
-      var e = enumFields(p, constSection)
-      addSon(t, exportSym(p, name, origName), ast.emptyNode, e)
-      addSon(tSection, t)
-      addSon(result, tSection)
-      addSon(result, constSection)
-      eat(p, pxCurlyRi, result)
-      eat(p, pxSemicolon)
-    of pxSemicolon:
-      # just ignore ``enum X;`` for now.
-      closeContext(p)
-      getTok(p, nil)
-    else: 
-      backtrackContext(p)
-      result = declaration(p)
-  else:
-    closeContext(p)
-    parMessage(p, errTokenExpected, "{")
-    result = ast.emptyNode
-    
-# Expressions
-
-proc setBaseFlags(n: PNode, base: TNumericalBase) = 
-  case base
-  of base10: discard
-  of base2: incl(n.flags, nfBase2)
-  of base8: incl(n.flags, nfBase8)
-  of base16: incl(n.flags, nfBase16)
-
-proc startExpression(p : var TParser, tok : TToken) : PNode =
-  #echo "nud ", $tok
-  case tok.xkind:
-  of pxSymbol:
-    if tok.s == "NULL":
-      result = newNodeP(nkNilLit, p)
-    elif tok.s == "sizeof":
-      result = newNodeP(nkCall, p)
-      addSon(result, newIdentNodeP("sizeof", p))
-      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)
-      if p.tok.xkind == pxBracketLe:
-        getTok(p)
-        eat(p, pxBracketRi)
-        opr.add("Array")
-      addSon(result, newIdentNodeP(opr, p))
-      if p.tok.xkind == pxParLe:
-        getTok(p, result)
-        addSon(result, typeDesc(p))
-        eat(p, pxParRi, result)
-      else:
-        addSon(result, expression(p, 139))
-    else:
-      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)
-    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:
-    result = left
-
-proc expression*(p : var TParser, rbp : int = 0) : PNode =
-  var tok : TToken
-
-  tok = p.tok[]
-  getTok(p, result)
-
-  result = startExpression(p, tok)
-
-  while rbp < leftBindingPower(p, p.tok):
-    tok = p.tok[]
-    getTok(p, result)
-    result = leftExpression(p, tok, result)
-    
-# Statements
-
-proc buildStmtList(a: PNode): PNode = 
-  if a.kind == nkStmtList: result = a
-  else:
-    result = newNodeI(nkStmtList, a.info)
-    addSon(result, a)
-
-proc nestedStatement(p: var TParser): PNode =
-  # careful: We need to translate:
-  # if (x) if (y) stmt;
-  # into:
-  # if x:
-  #   if x:
-  #     stmt
-  # 
-  # Nimrod requires complex statements to be nested in whitespace!
-  const
-    complexStmt = {nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef,
-      nkTemplateDef, nkIteratorDef, nkIfStmt,
-      nkWhenStmt, nkForStmt, nkWhileStmt, nkCaseStmt, nkVarSection, 
-      nkConstSection, nkTypeSection, nkTryStmt, nkBlockStmt, nkStmtList,
-      nkCommentStmt, nkStmtListExpr, nkBlockExpr, nkStmtListType, nkBlockType}
-  result = statement(p)
-  if result.kind in complexStmt:
-    result = buildStmtList(result)
-
-proc expressionStatement(p: var TParser): PNode = 
-  # do not skip the comment after a semicolon to make a new nkCommentStmt
-  if p.tok.xkind == pxSemicolon: 
-    getTok(p)
-    result = ast.emptyNode
-  else:
-    result = expression(p)
-    if p.tok.xkind == pxSemicolon: getTok(p)
-    else: parMessage(p, errTokenExpected, ";")
-  assert result != nil
-
-proc parseIf(p: var TParser): PNode = 
-  # we parse additional "else if"s too here for better Nimrod code
-  result = newNodeP(nkIfStmt, p)
-  while true: 
-    getTok(p) # skip ``if``
-    var branch = newNodeP(nkElifBranch, p)
-    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": 
-        # ordinary else part:
-        branch = newNodeP(nkElse, p)
-        addSon(branch, nestedStatement(p))
-        addSon(result, branch)
-        break 
-    else: 
-      break 
-  
-proc parseWhile(p: var TParser): PNode = 
-  result = newNodeP(nkWhileStmt, p)
-  getTok(p, result)
-  eat(p, pxParLe, result)
-  addSon(result, expression(p))
-  eat(p, pxParRi, result)
-  addSon(result, nestedStatement(p))
-
-proc embedStmts(sl, a: PNode)
-
-proc parseDoWhile(p: var TParser): PNode =  
-  # parsing
-  result = newNodeP(nkWhileStmt, p)
-  getTok(p, result)
-  var stm = nestedStatement(p)
-  eat(p, "while", result)
-  eat(p, pxParLe, result)
-  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)
-  elif declKeyword(p, p.tok.s): 
-    result = declaration(p)
-  else:
-    # ordinary identifier:
-    saveContext(p)
-    getTok(p) # skip identifier to look ahead
-    case p.tok.xkind
-    of pxSymbol, pxStar, pxLt, pxAmp, pxAmpAmp:
-      # we parse 
-      # a b
-      # a * b
-      # always as declarations! This is of course not correct, but good
-      # enough for most real world C code out there.
-      backtrackContext(p)
-      result = declaration(p)
-    of pxColon: 
-      # it is only a label:
-      closeContext(p)
-      getTok(p)
-      result = statement(p)
-    else: 
-      backtrackContext(p)
-      result = expressionStatement(p)
-  assert result != nil
-
-proc parseTuple(p: var TParser, statements: PNode, isUnion: bool): PNode = 
-  parseStructBody(p, statements, isUnion, nkTupleTy)
-
-proc parseTrailingDefinedIdents(p: var TParser, result, baseTyp: PNode) =
-  var varSection = newNodeP(nkVarSection, p)
-  while p.tok.xkind notin {pxEof, pxSemicolon}:
-    var t = pointer(p, baseTyp)
-    expectIdent(p)
-    var def = newNodeP(nkIdentDefs, p)
-    addSon(def, varIdent(p.tok.s, p))
-    getTok(p, def)
-    addSon(def, parseTypeSuffix(p, t))
-    addInitializer(p, def)
-    addSon(varSection, def)
-    if p.tok.xkind != pxComma: break
-    getTok(p, def)
-  eat(p, pxSemicolon)
-  if sonsLen(varSection) > 0:
-    addSon(result, varSection)
-
-proc parseStandaloneStruct(p: var TParser, isUnion: bool): PNode =
-  result = newNodeP(nkStmtList, p)
-  saveContext(p)
-  getTok(p, result) # skip "struct" or "union"
-  var origName = ""
-  if p.tok.xkind == pxSymbol: 
-    markTypeIdent(p, nil)
-    origName = p.tok.s
-    getTok(p, result)
-  if p.tok.xkind in {pxCurlyLe, pxSemiColon}:
-    if origName.len > 0: 
-      var name = mangledIdent(origName, p)
-      var t = parseStruct(p, result, isUnion)
-      var typeSection = newNodeP(nkTypeSection, p)
-      addTypeDef(typeSection, structPragmas(p, name, origName), t)
-      addSon(result, typeSection)
-      parseTrailingDefinedIdents(p, result, name)
-    else:
-      var t = parseTuple(p, result, isUnion)
-      parseTrailingDefinedIdents(p, result, t)
-  else:
-    backtrackContext(p)
-    result = declaration(p)
-
-proc parseFor(p: var TParser, result: PNode) = 
-  # 'for' '(' expression_statement expression_statement expression? ')'
-  #   statement
-  getTok(p, result)
-  eat(p, pxParLe, result)
-  var initStmt = declarationOrStatement(p)
-  if initStmt.kind != nkEmpty:
-    embedStmts(result, initStmt)
-  var w = newNodeP(nkWhileStmt, p)
-  var condition = expressionStatement(p)
-  if condition.kind == nkEmpty: condition = newIdentNodeP("true", p)
-  addSon(w, condition)
-  var step = if p.tok.xkind != pxParRi: expression(p) else: ast.emptyNode
-  eat(p, pxParRi, step)
-  var loopBody = nestedStatement(p)
-  if step.kind != nkEmpty:
-    loopBody = buildStmtList(loopBody)
-    embedStmts(loopBody, step)
-  addSon(w, loopBody)
-  addSon(result, w)
-  
-proc switchStatement(p: var TParser): PNode = 
-  result = newNodeP(nkStmtList, p)
-  while true:
-    if p.tok.xkind in {pxEof, pxCurlyRi}: break
-    case p.tok.s 
-    of "break":
-      getTok(p, result)
-      eat(p, pxSemicolon, result)
-      break
-    of "return", "continue", "goto": 
-      addSon(result, statement(p))
-      break
-    of "case", "default":
-      break
-    else: discard
-    addSon(result, statement(p))
-  if sonsLen(result) == 0:
-    # translate empty statement list to Nimrod's ``nil`` statement
-    result = newNodeP(nkNilLit, p)
-
-proc rangeExpression(p: var TParser): PNode =
-  # We support GCC's extension: ``case expr...expr:`` 
-  result = constantExpression(p)
-  if p.tok.xkind == pxDotDotDot:
-    getTok(p, result)
-    var a = result
-    var b = constantExpression(p)
-    result = newNodeP(nkRange, p)
-    addSon(result, a)
-    addSon(result, b)
-
-proc parseSwitch(p: var TParser): PNode = 
-  # We cannot support Duff's device or C's crazy switch syntax. We just support
-  # sane usages of switch. ;-)
-  result = newNodeP(nkCaseStmt, p)
-  getTok(p, result)
-  eat(p, pxParLe, result)
-  addSon(result, expression(p))
-  eat(p, pxParRi, result)
-  eat(p, pxCurlyLe, result)
-  var b: PNode
-  while (p.tok.xkind != pxCurlyRi) and (p.tok.xkind != pxEof): 
-    case p.tok.s 
-    of "default": 
-      b = newNodeP(nkElse, p)
-      getTok(p, b)
-      eat(p, pxColon, b)
-    of "case": 
-      b = newNodeP(nkOfBranch, p)
-      while p.tok.xkind == pxSymbol and p.tok.s == "case":
-        getTok(p, b)
-        addSon(b, rangeExpression(p))
-        eat(p, pxColon, b)
-    else:
-      parMessage(p, errXExpected, "case")
-    addSon(b, switchStatement(p))
-    addSon(result, b)
-    if b.kind == nkElse: break 
-  eat(p, pxCurlyRi)
-
-proc addStmt(sl, a: PNode) = 
-  # merge type sections if possible:
-  if a.kind != nkTypeSection or sonsLen(sl) == 0 or
-      lastSon(sl).kind != nkTypeSection:
-    addSon(sl, a)
-  else:
-    var ts = lastSon(sl)
-    for i in 0..sonsLen(a)-1: addSon(ts, a.sons[i])
-
-proc embedStmts(sl, a: PNode) = 
-  if a.kind != nkStmtList:
-    addStmt(sl, a)
-  else:
-    for i in 0..sonsLen(a)-1: 
-      if a[i].kind != nkEmpty: addStmt(sl, a[i])
-
-proc compoundStatement(p: var TParser): PNode = 
-  result = newNodeP(nkStmtList, p)
-  eat(p, pxCurlyLe)
-  inc(p.scopeCounter)
-  while p.tok.xkind notin {pxEof, pxCurlyRi}: 
-    var a = statement(p)
-    if a.kind == nkEmpty: break
-    embedStmts(result, a)
-  if sonsLen(result) == 0:
-    # translate ``{}`` to Nimrod's ``discard`` statement
-    result = newNodeP(nkDiscardStmt, p)
-    result.add(ast.emptyNode)
-  dec(p.scopeCounter)
-  eat(p, pxCurlyRi)
-
-proc skipInheritKeyw(p: var TParser) =
-  if p.tok.xkind == pxSymbol and (p.tok.s == "private" or 
-                                  p.tok.s == "protected" or
-                                  p.tok.s == "public"):
-    getTok(p)
-
-proc parseConstructor(p: var TParser, pragmas: PNode, 
-                      isDestructor=false): PNode =
-  var origName = p.tok.s
-  getTok(p)
-  
-  result = newNodeP(nkProcDef, p)
-  var rettyp = if isDestructor: newNodeP(nkNilLit, p)
-               else: mangledIdent(origName, p)
-  
-  let oname = if isDestructor: "destroy" & origName
-              else: "construct" & origName
-  var name = mangledIdent(oname, p)
-  var params = newNodeP(nkFormalParams, p)
-  addReturnType(params, rettyp)
-  if p.tok.xkind == pxParLe:
-    parseFormalParams(p, params, pragmas)
-  if p.tok.xkind == pxSymbol and p.tok.s == "const":
-    addSon(pragmas, newIdentNodeP("noSideEffect", p))
-  if pfCDecl in p.options.flags:
-    addSon(pragmas, newIdentNodeP("cdecl", p))
-  elif pfStdcall in p.options.flags:
-    addSon(pragmas, newIdentNodeP("stdcall", p))
-  if p.tok.xkind == pxColon:
-    # skip initializer list:
-    while true:
-      getTok(p)
-      discard expression(p)
-      if p.tok.xkind != pxComma: break
-  # no pattern, no exceptions:
-  addSon(result, exportSym(p, name, origName), ast.emptyNode, ast.emptyNode)
-  addSon(result, params, pragmas, ast.emptyNode) # no exceptions
-  addSon(result, ast.emptyNode) # no body
-  case p.tok.xkind 
-  of pxSemicolon: getTok(p)
-  of pxCurlyLe:
-    let body = compoundStatement(p)
-    if pfKeepBodies in p.options.flags:
-      result.sons[bodyPos] = body
-  else:
-    parMessage(p, errTokenExpected, ";")
-  if result.sons[bodyPos].kind == nkEmpty:
-    doImport((if isDestructor: "~" else: "") & origName, pragmas, p)
-  elif isDestructor:
-    addSon(pragmas, newIdentNodeP("destructor", p))
-  if sonsLen(result.sons[pragmasPos]) == 0:
-    result.sons[pragmasPos] = ast.emptyNode
-
-proc parseMethod(p: var TParser, origName: string, rettyp, pragmas: PNode,
-                 isStatic: bool): PNode =
-  result = newNodeP(nkProcDef, p)
-  var params = newNodeP(nkFormalParams, p)
-  addReturnType(params, rettyp)
-  var thisDef = newNodeP(nkIdentDefs, p)
-  if not isStatic:
-    # declare 'this':
-    var t = newNodeP(nkVarTy, p)
-    t.add(p.currentClass)
-    addSon(thisDef, newIdentNodeP("this", p), t, ast.emptyNode)
-    params.add(thisDef)
-  parseFormalParams(p, params, pragmas)
-  if p.tok.xkind == pxSymbol and p.tok.s == "const":
-    addSon(pragmas, newIdentNodeP("noSideEffect", p))
-    getTok(p, result)
-    if not isStatic:
-      # fix the type of the 'this' parameter:
-      thisDef.sons[1] = thisDef.sons[1].sons[0]
-  if pfCDecl in p.options.flags:
-    addSon(pragmas, newIdentNodeP("cdecl", p))
-  elif pfStdcall in p.options.flags:
-    addSon(pragmas, newIdentNodeP("stdcall", p))
-  # no pattern, no exceptions:
-  let methodName = newIdentNodeP(origName, p)
-  addSon(result, exportSym(p, methodName, origName),
-         ast.emptyNode, ast.emptyNode)
-  addSon(result, params, pragmas, ast.emptyNode) # no exceptions
-  addSon(result, ast.emptyNode) # no body
-  case p.tok.xkind
-  of pxSemicolon: getTok(p)
-  of pxCurlyLe:
-    let body = compoundStatement(p)
-    if pfKeepBodies in p.options.flags:
-      result.sons[bodyPos] = body
-  else:
-    parMessage(p, errTokenExpected, ";")
-  if result.sons[bodyPos].kind == nkEmpty:
-    if isStatic: doImport(origName, pragmas, p)
-    else: doImportCpp(origName, pragmas, p)
-  if sonsLen(result.sons[pragmasPos]) == 0:
-    result.sons[pragmasPos] = ast.emptyNode
-
-proc parseStandaloneClass(p: var TParser, isStruct: bool): PNode
-
-proc followedByParLe(p: var TParser): bool =
-  saveContext(p)
-  getTok(p) # skip Identifier
-  result = p.tok.xkind == pxParLe
-  backtrackContext(p)
-
-proc parseOperator(p: var TParser, origName: var string): bool =
-  getTok(p) # skip 'operator' keyword
-  case p.tok.xkind
-  of pxAmp..pxArrow:
-    # ordinary operator symbol:
-    origName.add(tokKindToStr(p.tok.xkind))
-    getTok(p)
-  of pxSymbol:
-    if p.tok.s == "new" or p.tok.s == "delete":
-      origName.add(p.tok.s)
-      getTok(p)
-      if p.tok.xkind == pxBracketLe:
-        getTok(p)
-        eat(p, pxBracketRi)
-        origName.add("[]")
-    else:
-      # type converter
-      let x = typeAtom(p)
-      if x.kind == nkIdent:
-        origName.add(x.ident.s)
-      else:
-        parMessage(p, errGenerated, "operator symbol expected")
-      result = true
-  of pxParLe:
-    getTok(p)
-    eat(p, pxParRi)
-    origName.add("()")
-  of pxBracketLe:
-    getTok(p)
-    eat(p, pxBracketRi)
-    origName.add("[]")
-  else:
-    parMessage(p, errGenerated, "operator symbol expected")
-
-proc parseClass(p: var TParser; isStruct: bool; stmtList: PNode): PNode =
-  result = newNodeP(nkObjectTy, p)
-  addSon(result, ast.emptyNode, ast.emptyNode) # no pragmas, no inheritance 
-  
-  var recList = newNodeP(nkRecList, p)
-  addSon(result, recList)
-  if p.tok.xkind == pxColon:
-    getTok(p, result)
-    skipInheritKeyw(p)
-    var baseTyp = typeAtom(p)
-    var inh = newNodeP(nkOfInherit, p)
-    inh.add(baseTyp)
-    if p.tok.xkind == pxComma:
-      parMessage(p, errGenerated, "multiple inheritance is not supported")
-      while p.tok.xkind == pxComma:
-        getTok(p)
-        skipInheritKeyw(p)
-        discard typeAtom(p)
-    result.sons[0] = inh
-    
-  eat(p, pxCurlyLe, result)
-  var private = not isStruct
-  var pragmas = newNodeP(nkPragma, p)
-  while p.tok.xkind notin {pxEof, pxCurlyRi}:
-    skipCom(p, stmtList)
-    if p.tok.xkind == pxSymbol and (p.tok.s == "private" or 
-                                    p.tok.s == "protected"):
-      getTok(p, result)
-      eat(p, pxColon, result)
-      private = true
-    elif p.tok.xkind == pxSymbol and p.tok.s == "public":
-      getTok(p, result)
-      eat(p, pxColon, result)
-      private = false
-    if p.tok.xkind == pxSymbol and (p.tok.s == "friend" or p.tok.s == "using"):
-      # we skip friend declarations:
-      while p.tok.xkind notin {pxEof, pxSemicolon}: getTok(p)
-      eat(p, pxSemicolon)
-    elif p.tok.xkind == pxSymbol and p.tok.s == "enum":
-      let x = enumSpecifier(p)
-      if not private or pfKeepBodies in p.options.flags: stmtList.add(x)
-    elif p.tok.xkind == pxSymbol and p.tok.s == "typedef":
-      let x = parseTypeDef(p)
-      if not private or pfKeepBodies in p.options.flags: stmtList.add(x)
-    elif p.tok.xkind == pxSymbol and(p.tok.s == "struct" or p.tok.s == "class"):
-      let x = parseStandaloneClass(p, isStruct=p.tok.s == "struct")
-      if not private or pfKeepBodies in p.options.flags: stmtList.add(x)
-    elif p.tok.xkind == pxSymbol and p.tok.s == "union":
-      let x = parseStandaloneStruct(p, isUnion=true)
-      if not private or pfKeepBodies in p.options.flags: stmtList.add(x)
-    else:
-      if pragmas.len != 0: pragmas = newNodeP(nkPragma, p)
-      parseCallConv(p, pragmas)
-      var isStatic = false
-      if p.tok.xkind == pxSymbol and p.tok.s == "virtual":
-        getTok(p, stmtList)
-      if p.tok.xkind == pxSymbol and p.tok.s == "explicit":
-        getTok(p, stmtList)
-      if p.tok.xkind == pxSymbol and p.tok.s == "static":
-        getTok(p, stmtList)
-        isStatic = true
-      parseCallConv(p, pragmas)
-      if p.tok.xkind == pxSymbol and p.tok.s == p.currentClass.ident.s and 
-          followedByParLe(p):
-        # constructor
-        let cons = parseConstructor(p, pragmas)
-        if not private or pfKeepBodies in p.options.flags: stmtList.add(cons)
-      elif p.tok.xkind == pxTilde:
-        # destructor
-        getTok(p, stmtList)
-        if p.tok.xkind == pxSymbol and p.tok.s == p.currentClass.ident.s:
-          let des = parseConstructor(p, pragmas, isDestructor=true)
-          if not private or pfKeepBodies in p.options.flags: stmtList.add(des)
-        else:
-          parMessage(p, errGenerated, "invalid destructor")
-      else:
-        # field declaration or method:
-        var baseTyp = typeAtom(p)
-        while true:
-          var def = newNodeP(nkIdentDefs, p)
-          var t = pointer(p, baseTyp)
-          let canBeMethod = p.tok.xkind != pxParLe
-          var origName: string
-          if p.tok.xkind == pxSymbol:
-            origName = p.tok.s
-            if p.tok.s == "operator":
-              var isConverter = parseOperator(p, origName)
-              let meth = parseMethod(p, origName, t, pragmas, isStatic)
-              if not private or pfKeepBodies in p.options.flags:
-                if isConverter: meth.kind = nkConverterDef
-                stmtList.add(meth)
-              break
-          var i = parseField(p, nkRecList)
-          if canBeMethod and p.tok.xkind == pxParLe:
-            let meth = parseMethod(p, origName, t, pragmas, isStatic)
-            if not private or pfKeepBodies in p.options.flags:
-              stmtList.add(meth)
-          else:
-            t = parseTypeSuffix(p, t)
-            addSon(def, i, t, ast.emptyNode)
-            if not isStatic: addSon(recList, def)
-          if p.tok.xkind != pxComma: break
-          getTok(p, def)
-        if p.tok.xkind == pxSemicolon:
-          getTok(p, lastSon(recList))
-  eat(p, pxCurlyRi, result)
-
-proc parseStandaloneClass(p: var TParser, isStruct: bool): PNode =
-  result = newNodeP(nkStmtList, p)
-  saveContext(p)
-  getTok(p, result) # skip "class" or "struct"
-  var origName = ""
-  let oldClass = p.currentClass
-  if p.tok.xkind == pxSymbol: 
-    markTypeIdent(p, nil)
-    origName = p.tok.s
-    getTok(p, result)
-    p.currentClass = mangledIdent(origName, p)
-  else:
-    p.currentClass = nil
-  if p.tok.xkind in {pxCurlyLe, pxSemiColon, pxColon}:
-    if origName.len > 0:
-      p.options.classes[origName] = "true"
-
-      var typeSection = newNodeP(nkTypeSection, p)
-      addSon(result, typeSection)
-      
-      var name = mangledIdent(origName, p)
-      var t = parseClass(p, isStruct, result)
-      addTypeDef(typeSection, structPragmas(p, name, origName), t)
-      parseTrailingDefinedIdents(p, result, name)
-    else:
-      var t = parseTuple(p, result, isUnion=false)
-      parseTrailingDefinedIdents(p, result, t)
-  else:
-    backtrackContext(p)
-    result = declaration(p)
-  p.currentClass = oldClass
-
-proc unwrap(a: PNode): PNode =
-  if a.kind == nkPar:
-    return a.sons[0]
-  return a
-
-include cpp
-
-proc statement(p: var TParser): PNode = 
-  case p.tok.xkind 
-  of pxSymbol: 
-    case p.tok.s
-    of "if": result = parseIf(p)
-    of "switch": result = parseSwitch(p)
-    of "while": result = parseWhile(p)
-    of "do": result = parseDoWhile(p)
-    of "for": 
-      result = newNodeP(nkStmtList, p)
-      parseFor(p, result)
-    of "goto": 
-      # we cannot support "goto"; in hand-written C, "goto" is most often used
-      # to break a block, so we convert it to a break statement with label.
-      result = newNodeP(nkBreakStmt, p)
-      getTok(p)
-      addSon(result, skipIdent(p))
-      eat(p, pxSemicolon)
-    of "continue":
-      result = newNodeP(nkContinueStmt, p)
-      getTok(p)
-      eat(p, pxSemicolon)
-      addSon(result, ast.emptyNode)
-    of "break":
-      result = newNodeP(nkBreakStmt, p)
-      getTok(p)
-      eat(p, pxSemicolon)
-      addSon(result, ast.emptyNode)
-    of "return":
-      result = newNodeP(nkReturnStmt, p)
-      getTok(p)
-      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)
-    of "union": result = parseStandaloneStruct(p, isUnion=true)
-    of "struct":
-      if pfCpp in p.options.flags:
-        result = parseStandaloneClass(p, isStruct=true)
-      else:
-        result = parseStandaloneStruct(p, isUnion=false)
-    of "class":
-      if pfCpp in p.options.flags:
-        result = parseStandaloneClass(p, isStruct=false)
-      else:
-        result = declarationOrStatement(p)
-    of "namespace":
-      if pfCpp in p.options.flags:
-        while p.tok.xkind notin {pxEof, pxCurlyLe}: getTok(p)
-        result = compoundStatement(p)
-      else:
-        result = declarationOrStatement(p)
-    of "using":
-      if pfCpp in p.options.flags:
-        while p.tok.xkind notin {pxEof, pxSemicolon}: getTok(p)
-        eat(p, pxSemicolon)
-        result = newNodeP(nkNilLit, p)
-      else:
-        result = declarationOrStatement(p)
-    else: result = declarationOrStatement(p)
-  of pxCurlyLe:
-    result = compoundStatement(p)
-  of pxDirective, pxDirectiveParLe:
-    result = parseDir(p)
-  of pxLineComment, pxStarComment:
-    result = newNodeP(nkCommentStmt, p)
-    skipCom(p, result)
-  of pxSemicolon:
-    # empty statement:
-    getTok(p)
-    if p.tok.xkind in {pxLineComment, pxStarComment}:
-      result = newNodeP(nkCommentStmt, p)
-      skipCom(p, result)
-    else:
-      result = newNodeP(nkNilLit, p)
-  else:
-    result = expressionStatement(p)
-  assert result != nil
-
-proc parseUnit(p: var TParser): PNode =
-  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")
-