c2nim tool added

This commit is contained in:
Andreas Rumpf 2010-07-21 09:44:47 +02:00
commit d10973adb0
28 changed files with 3498 additions and 66 deletions

231
rod/c2nim/cpp.nim Executable file
View file

@ -0,0 +1,231 @@
# Preprocessor support
const
c2nimSymbol = "C2NIM"
proc eatNewLine(p: var TParser, n: PNode) =
if p.tok.xkind == pxLineComment:
skipCom(p, n)
if p.tok.xkind == pxNewLine: getTok(p)
else:
eat(p, pxNewLine)
proc parseDefineBody(p: var TParser, tmplDef: PNode): string =
if p.tok.xkind == pxCurlyLe or
(p.tok.xkind == pxSymbol and (declKeyword(p.tok.s) or stmtKeyword(p.tok.s))):
addSon(tmplDef, statement(p))
result = "stmt"
elif p.tok.xkind in {pxLineComment, pxNewLine}:
addSon(tmplDef, buildStmtList(newNodeP(nkNilLit, p)))
result = "stmt"
else:
addSon(tmplDef, buildStmtList(expression(p)))
result = "expr"
proc parseDefine(p: var TParser): PNode =
if p.tok.xkind == pxDirectiveParLe:
# a macro with parameters:
result = newNodeP(nkTemplateDef, p)
getTok(p)
addSon(result, skipIdent(p))
eat(p, pxParLe)
var params = newNodeP(nkFormalParams, p)
# return type; not known yet:
addSon(params, nil)
var identDefs = newNodeP(nkIdentDefs, p)
while p.tok.xkind != pxParRi:
addSon(identDefs, skipIdent(p))
skipStarCom(p, nil)
if p.tok.xkind != pxComma: break
getTok(p)
addSon(identDefs, newIdentNodeP("expr", p))
addSon(identDefs, nil)
addSon(params, identDefs)
eat(p, pxParRi)
addSon(result, nil) # no generic parameters
addSon(result, params)
addSon(result, nil) # no pragmas
var kind = parseDefineBody(p, result)
params.sons[0] = newIdentNodeP(kind, p)
eatNewLine(p, result)
else:
# a macro without parameters:
result = newNodeP(nkConstSection, p)
while p.tok.xkind == pxDirective and p.tok.s == "define":
getTok(p) # skip #define
var c = newNodeP(nkConstDef, p)
addSon(c, skipIdent(p))
addSon(c, nil)
skipStarCom(p, c)
if p.tok.xkind in {pxLineComment, pxNewLine, pxEof}:
addSon(c, newIdentNodeP("true", p))
else:
addSon(c, expression(p))
addSon(result, c)
eatNewLine(p, c)
proc isDir(p: TParser, dir: string): bool =
result = p.tok.xkind in {pxDirectiveParLe, pxDirective} and p.tok.s == dir
proc parseInclude(p: var TParser): PNode =
result = newNodeP(nkImportStmt, p)
while isDir(p, "include"):
getTok(p) # skip "include"
if p.tok.xkind == pxStrLit:
var file = newStrNodeP(nkStrLit, p.tok.s, p)
addSon(result, file)
getTok(p)
skipStarCom(p, file)
elif p.tok.xkind == pxLt:
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p)
else:
parMessage(p, errXExpected, "string literal")
eatNewLine(p, nil)
if sonsLen(result) == 0:
# we only parsed includes that we chose to ignore:
result = nil
proc definedExprAux(p: var TParser): PNode =
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP("defined", p))
addSon(result, skipIdent(p))
proc parseStmtList(p: var TParser): PNode =
result = newNodeP(nkStmtList, p)
while true:
case p.tok.xkind
of pxEof: break
of pxDirectiveParLe, pxDirective:
case p.tok.s
of "else", "endif", "elif": break
else: nil
addSon(result, statement(p))
proc parseIfDirAux(p: var TParser, result: PNode) =
addSon(result.sons[0], parseStmtList(p))
while isDir(p, "elif"):
var b = newNodeP(nkElifBranch, p)
getTok(p)
addSon(b, expression(p))
eatNewLine(p, nil)
addSon(b, parseStmtList(p))
addSon(result, b)
if isDir(p, "else"):
var s = newNodeP(nkElse, p)
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p)
eatNewLine(p, nil)
addSon(s, parseStmtList(p))
addSon(result, s)
if isDir(p, "endif"):
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p)
eatNewLine(p, nil)
else:
parMessage(p, errXExpected, "#endif")
proc specialIf(p: TParser): bool =
ExpectIdent(p)
result = p.tok.s == c2nimSymbol
proc chooseBranch(whenStmt: PNode, branch: int): PNode =
var L = sonsLen(whenStmt)
if branch < L:
if L == 2 and whenStmt[1].kind == nkElse or branch == 0:
result = lastSon(whenStmt[branch])
else:
var b = whenStmt[branch]
assert(b.kind == nkElifBranch)
result = newNodeI(nkWhenStmt, whenStmt.info)
for i in branch .. L-1:
addSon(result, whenStmt[i])
proc skipIfdefCPlusPlus(p: var TParser): PNode =
while p.tok.xkind != pxEof:
if isDir(p, "endif"):
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p)
eatNewLine(p, nil)
return
getTok(p)
parMessage(p, errXExpected, "#endif")
proc parseIfdefDir(p: var TParser): PNode =
result = newNodeP(nkWhenStmt, p)
addSon(result, newNodeP(nkElifBranch, p))
getTok(p)
var special = specialIf(p)
if p.tok.s == "__cplusplus":
return skipIfdefCPlusPlus(p)
addSon(result.sons[0], definedExprAux(p))
eatNewLine(p, nil)
parseIfDirAux(p, result)
if special:
result = chooseBranch(result, 0)
proc parseIfndefDir(p: var TParser): PNode =
result = newNodeP(nkWhenStmt, p)
addSon(result, newNodeP(nkElifBranch, p))
getTok(p)
var special = specialIf(p)
var e = newNodeP(nkCall, p)
addSon(e, newIdentNodeP("not", p))
addSon(e, definedExprAux(p))
eatNewLine(p, nil)
addSon(result.sons[0], e)
parseIfDirAux(p, result)
if special:
result = chooseBranch(result, 1)
proc parseIfDir(p: var TParser): PNode =
result = newNodeP(nkWhenStmt, p)
addSon(result, newNodeP(nkElifBranch, p))
getTok(p)
addSon(result.sons[0], expression(p))
eatNewLine(p, nil)
parseIfDirAux(p, result)
proc parseMangleDir(p: var TParser) =
var col = getColumn(p.lex) + 2
getTok(p)
if p.tok.xkind != pxStrLit: ExpectIdent(p)
try:
var pattern = parsePeg(
input = p.tok.s,
filename = p.lex.filename,
line = p.lex.linenumber,
col = col)
getTok(p)
if p.tok.xkind != pxStrLit: ExpectIdent(p)
p.options.mangleRules.add((pattern, p.tok.s))
getTok(p)
except EInvalidPeg:
parMessage(p, errUser, getCurrentExceptionMsg())
eatNewLine(p, nil)
proc parseDir(p: var TParser): PNode =
assert(p.tok.xkind in {pxDirective, pxDirectiveParLe})
case p.tok.s
of "define": result = parseDefine(p)
of "include": result = parseInclude(p)
of "ifdef": result = parseIfdefDir(p)
of "ifndef": result = parseIfndefDir(p)
of "if": result = parseIfDir(p)
of "cdecl", "stdcall", "ref":
discard setOption(p.options, p.tok.s)
getTok(p)
eatNewLine(p, nil)
of "dynlib", "header", "prefix", "suffix", "skip":
var key = p.tok.s
getTok(p)
if p.tok.xkind != pxStrLit: ExpectIdent(p)
discard setOption(p.options, key, p.tok.s)
getTok(p)
eatNewLine(p, nil)
of "mangle":
parseMangleDir(p)
else:
# ignore unimportant/unknown directive ("undef", "pragma", "error")
while true:
getTok(p)
if p.tok.xkind in {pxEof, pxNewLine, pxLineComment}: break
eatNewLine(p, nil)