mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 22:10:33 +00:00
c2nim is not part of the compiler anymore
This commit is contained in:
@@ -1,92 +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.
|
||||
#
|
||||
|
||||
import
|
||||
strutils, os, times, parseopt, llstream, ast, renderer, options, msgs,
|
||||
clex, cparse
|
||||
|
||||
const
|
||||
Version = NimrodVersion
|
||||
Usage = """
|
||||
c2nim - C to Nimrod source converter
|
||||
(c) 2013 Andreas Rumpf
|
||||
Usage: c2nim [options] inputfile [options]
|
||||
Options:
|
||||
-o, --out:FILE set output filename
|
||||
--cpp process C++ input file
|
||||
--dynlib:SYMBOL import from dynlib: SYMBOL will be used for the import
|
||||
--header:HEADER_FILE import from a HEADER_FILE (discouraged!)
|
||||
--cdecl annotate procs with ``{.cdecl.}``
|
||||
--stdcall annotate procs with ``{.stdcall.}``
|
||||
--ref convert typ* to ref typ (default: ptr typ)
|
||||
--prefix:PREFIX strip prefix for the generated Nimrod identifiers
|
||||
(multiple --prefix options are supported)
|
||||
--suffix:SUFFIX strip suffix for the generated Nimrod identifiers
|
||||
(multiple --suffix options are supported)
|
||||
--skipinclude do not convert ``#include`` to ``import``
|
||||
--typeprefixes generate ``T`` and ``P`` type prefixes
|
||||
--skipcomments do not copy comments
|
||||
--ignoreRValueRefs translate C++'s ``T&&`` to ``T`` instead ``of var T``
|
||||
--keepBodies keep C++'s method bodies
|
||||
--spliceHeader parse and emit header before source file
|
||||
-v, --version write c2nim's version
|
||||
-h, --help show this help
|
||||
"""
|
||||
|
||||
proc parse(infile: string, options: PParserOptions): PNode =
|
||||
var stream = llStreamOpen(infile, fmRead)
|
||||
if stream == nil: rawMessage(errCannotOpenFile, infile)
|
||||
var p: TParser
|
||||
openParser(p, infile, stream, options)
|
||||
result = parseUnit(p)
|
||||
closeParser(p)
|
||||
|
||||
proc main(infile, outfile: string, options: PParserOptions, spliceHeader: bool) =
|
||||
var start = getTime()
|
||||
if spliceHeader and infile.splitFile.ext == ".c" and existsFile(infile.changeFileExt(".h")):
|
||||
var header_module = parse(infile.changeFileExt(".h"), options)
|
||||
var source_module = parse(infile, options)
|
||||
for n in source_module:
|
||||
addson(header_module, n)
|
||||
renderModule(header_module, outfile)
|
||||
else:
|
||||
renderModule(parse(infile, options), outfile)
|
||||
rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start),
|
||||
formatSize(getTotalMem())])
|
||||
|
||||
var
|
||||
infile = ""
|
||||
outfile = ""
|
||||
spliceHeader = false
|
||||
parserOptions = newParserOptions()
|
||||
for kind, key, val in getopt():
|
||||
case kind
|
||||
of cmdArgument: infile = key
|
||||
of cmdLongOption, cmdShortOption:
|
||||
case key.toLower
|
||||
of "help", "h":
|
||||
stdout.write(Usage)
|
||||
quit(0)
|
||||
of "version", "v":
|
||||
stdout.write(Version & "\n")
|
||||
quit(0)
|
||||
of "o", "out": outfile = val
|
||||
of "spliceheader": spliceHeader = true
|
||||
else:
|
||||
if not parserOptions.setOption(key, val):
|
||||
stdout.writeln("[Error] unknown option: " & key)
|
||||
of cmdEnd: assert(false)
|
||||
if infile.len == 0:
|
||||
# no filename has been given, so we show the help:
|
||||
stdout.write(Usage)
|
||||
else:
|
||||
if outfile.len == 0:
|
||||
outfile = changeFileExt(infile, "nim")
|
||||
infile = addFileExt(infile, "h")
|
||||
main(infile, outfile, parserOptions, spliceHeader)
|
||||
@@ -1,787 +0,0 @@
|
||||
#
|
||||
#
|
||||
# c2nim - C to Nimrod source converter
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# This module implements an Ansi C scanner. This is an adaption from
|
||||
# the scanner module. Keywords are not handled here, but in the parser to make
|
||||
# it more flexible.
|
||||
|
||||
|
||||
import
|
||||
options, msgs, strutils, platform, nimlexbase, llstream
|
||||
|
||||
const
|
||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
||||
numChars*: TCharSet = {'0'..'9', 'a'..'z', 'A'..'Z'}
|
||||
SymChars*: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'}
|
||||
SymStartChars*: TCharSet = {'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF'}
|
||||
|
||||
type
|
||||
TTokKind* = enum
|
||||
pxInvalid, pxEof,
|
||||
pxMacroParam, # fake token: macro parameter (with its index)
|
||||
pxStarComment, # /* */ comment
|
||||
pxLineComment, # // comment
|
||||
pxDirective, # #define, etc.
|
||||
pxDirectiveParLe, # #define m( with parle (yes, C is that ugly!)
|
||||
pxDirConc, # ##
|
||||
pxNewLine, # newline: end of directive
|
||||
pxAmp, # &
|
||||
pxAmpAmp, # &&
|
||||
pxAmpAsgn, # &=
|
||||
pxAmpAmpAsgn, # &&=
|
||||
pxBar, # |
|
||||
pxBarBar, # ||
|
||||
pxBarAsgn, # |=
|
||||
pxBarBarAsgn, # ||=
|
||||
pxNot, # !
|
||||
pxPlusPlus, # ++
|
||||
pxMinusMinus, # --
|
||||
pxPlus, # +
|
||||
pxPlusAsgn, # +=
|
||||
pxMinus, # -
|
||||
pxMinusAsgn, # -=
|
||||
pxMod, # %
|
||||
pxModAsgn, # %=
|
||||
pxSlash, # /
|
||||
pxSlashAsgn, # /=
|
||||
pxStar, # *
|
||||
pxStarAsgn, # *=
|
||||
pxHat, # ^
|
||||
pxHatAsgn, # ^=
|
||||
pxAsgn, # =
|
||||
pxEquals, # ==
|
||||
pxDot, # .
|
||||
pxDotDotDot, # ...
|
||||
pxLe, # <=
|
||||
pxLt, # <
|
||||
pxGe, # >=
|
||||
pxGt, # >
|
||||
pxNeq, # !=
|
||||
pxConditional, # ?
|
||||
pxShl, # <<
|
||||
pxShlAsgn, # <<=
|
||||
pxShr, # >>
|
||||
pxShrAsgn, # >>=
|
||||
pxTilde, # ~
|
||||
pxTildeAsgn, # ~=
|
||||
pxArrow, # ->
|
||||
pxScope, # ::
|
||||
|
||||
pxStrLit,
|
||||
pxCharLit,
|
||||
pxSymbol, # a symbol
|
||||
pxIntLit,
|
||||
pxInt64Lit, # long constant like 0x70fffffff or out of int range
|
||||
pxFloatLit,
|
||||
pxParLe, pxBracketLe, pxCurlyLe, # this order is important
|
||||
pxParRi, pxBracketRi, pxCurlyRi, # for macro argument parsing!
|
||||
pxComma, pxSemiColon, pxColon,
|
||||
pxAngleRi # '>' but determined to be the end of a
|
||||
# template's angle bracket
|
||||
TTokKinds* = set[TTokKind]
|
||||
|
||||
type
|
||||
TNumericalBase* = enum base10, base2, base8, base16
|
||||
TToken* = object
|
||||
xkind*: TTokKind # the type of the token
|
||||
s*: string # parsed symbol, char or string literal
|
||||
iNumber*: BiggestInt # the parsed integer literal;
|
||||
# if xkind == pxMacroParam: parameter's position
|
||||
fNumber*: BiggestFloat # the parsed floating point literal
|
||||
base*: TNumericalBase # the numerical base; only valid for int
|
||||
# or float literals
|
||||
next*: ref TToken # for C we need arbitrary look-ahead :-(
|
||||
|
||||
TLexer* = object of TBaseLexer
|
||||
fileIdx*: int32
|
||||
inDirective: bool
|
||||
|
||||
proc getTok*(L: var TLexer, tok: var TToken)
|
||||
proc printTok*(tok: TToken)
|
||||
proc `$`*(tok: TToken): string
|
||||
# implementation
|
||||
|
||||
var
|
||||
gLinesCompiled*: int
|
||||
|
||||
proc fillToken(L: var TToken) =
|
||||
L.xkind = pxInvalid
|
||||
L.iNumber = 0
|
||||
L.s = ""
|
||||
L.fNumber = 0.0
|
||||
L.base = base10
|
||||
|
||||
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
||||
openBaseLexer(lex, inputstream)
|
||||
lex.fileIdx = filename.fileInfoIdx
|
||||
|
||||
proc closeLexer*(lex: var TLexer) =
|
||||
inc(gLinesCompiled, lex.LineNumber)
|
||||
closeBaseLexer(lex)
|
||||
|
||||
proc getColumn*(L: TLexer): int =
|
||||
result = getColNumber(L, L.bufPos)
|
||||
|
||||
proc getLineInfo*(L: TLexer): TLineInfo =
|
||||
result = newLineInfo(L.fileIdx, L.linenumber, getColNumber(L, L.bufpos))
|
||||
|
||||
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
|
||||
msgs.GlobalError(getLineInfo(L), msg, arg)
|
||||
|
||||
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||
var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
|
||||
msgs.GlobalError(info, msg, arg)
|
||||
|
||||
proc tokKindToStr*(k: TTokKind): string =
|
||||
case k
|
||||
of pxEof: result = "[EOF]"
|
||||
of pxInvalid: result = "[invalid]"
|
||||
of pxMacroParam: result = "[macro param]"
|
||||
of pxStarComment, pxLineComment: result = "[comment]"
|
||||
of pxStrLit: result = "[string literal]"
|
||||
of pxCharLit: result = "[char literal]"
|
||||
|
||||
of pxDirective, pxDirectiveParLe: result = "#" # #define, etc.
|
||||
of pxDirConc: result = "##"
|
||||
of pxNewLine: result = "[NewLine]"
|
||||
of pxAmp: result = "&" # &
|
||||
of pxAmpAmp: result = "&&" # &&
|
||||
of pxAmpAsgn: result = "&=" # &=
|
||||
of pxAmpAmpAsgn: result = "&&=" # &&=
|
||||
of pxBar: result = "|" # |
|
||||
of pxBarBar: result = "||" # ||
|
||||
of pxBarAsgn: result = "|=" # |=
|
||||
of pxBarBarAsgn: result = "||=" # ||=
|
||||
of pxNot: result = "!" # !
|
||||
of pxPlusPlus: result = "++" # ++
|
||||
of pxMinusMinus: result = "--" # --
|
||||
of pxPlus: result = "+" # +
|
||||
of pxPlusAsgn: result = "+=" # +=
|
||||
of pxMinus: result = "-" # -
|
||||
of pxMinusAsgn: result = "-=" # -=
|
||||
of pxMod: result = "%" # %
|
||||
of pxModAsgn: result = "%=" # %=
|
||||
of pxSlash: result = "/" # /
|
||||
of pxSlashAsgn: result = "/=" # /=
|
||||
of pxStar: result = "*" # *
|
||||
of pxStarAsgn: result = "*=" # *=
|
||||
of pxHat: result = "^" # ^
|
||||
of pxHatAsgn: result = "^=" # ^=
|
||||
of pxAsgn: result = "=" # =
|
||||
of pxEquals: result = "==" # ==
|
||||
of pxDot: result = "." # .
|
||||
of pxDotDotDot: result = "..." # ...
|
||||
of pxLe: result = "<=" # <=
|
||||
of pxLt: result = "<" # <
|
||||
of pxGe: result = ">=" # >=
|
||||
of pxGt: result = ">" # >
|
||||
of pxNeq: result = "!=" # !=
|
||||
of pxConditional: result = "?"
|
||||
of pxShl: result = "<<"
|
||||
of pxShlAsgn: result = "<<="
|
||||
of pxShr: result = ">>"
|
||||
of pxShrAsgn: result = ">>="
|
||||
of pxTilde: result = "~"
|
||||
of pxTildeAsgn: result = "~="
|
||||
of pxArrow: result = "->"
|
||||
of pxScope: result = "::"
|
||||
|
||||
of pxSymbol: result = "[identifier]"
|
||||
of pxIntLit, pxInt64Lit: result = "[integer literal]"
|
||||
of pxFloatLit: result = "[floating point literal]"
|
||||
of pxParLe: result = "("
|
||||
of pxParRi: result = ")"
|
||||
of pxBracketLe: result = "["
|
||||
of pxBracketRi: result = "]"
|
||||
of pxComma: result = ","
|
||||
of pxSemiColon: result = ";"
|
||||
of pxColon: result = ":"
|
||||
of pxCurlyLe: result = "{"
|
||||
of pxCurlyRi: result = "}"
|
||||
of pxAngleRi: result = "> [end of template]"
|
||||
|
||||
proc `$`(tok: TToken): string =
|
||||
case tok.xkind
|
||||
of pxSymbol, pxInvalid, pxStarComment, pxLineComment, pxStrLit: result = tok.s
|
||||
of pxIntLit, pxInt64Lit: result = $tok.iNumber
|
||||
of pxFloatLit: result = $tok.fNumber
|
||||
else: result = tokKindToStr(tok.xkind)
|
||||
|
||||
proc printTok(tok: TToken) =
|
||||
writeln(stdout, $tok)
|
||||
|
||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
||||
# matches ([chars]_)*
|
||||
var pos = L.bufpos # use registers for pos, buf
|
||||
var buf = L.buf
|
||||
while true:
|
||||
if buf[pos] in chars:
|
||||
add(tok.s, buf[pos])
|
||||
inc(pos)
|
||||
else:
|
||||
break
|
||||
if buf[pos] == '_':
|
||||
add(tok.s, '_')
|
||||
inc(pos)
|
||||
L.bufPos = pos
|
||||
|
||||
proc isFloatLiteral(s: string): bool =
|
||||
for i in countup(0, len(s)-1):
|
||||
if s[i] in {'.', 'e', 'E'}:
|
||||
return true
|
||||
|
||||
proc getNumber2(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 2 # skip 0b
|
||||
tok.base = base2
|
||||
var xi: BiggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
of 'A'..'Z', 'a'..'z':
|
||||
# ignore type suffix:
|
||||
inc(pos)
|
||||
of '2'..'9', '.':
|
||||
lexMessage(L, errInvalidNumber)
|
||||
inc(pos)
|
||||
of '_':
|
||||
inc(pos)
|
||||
of '0', '1':
|
||||
xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
inc(bits)
|
||||
else: break
|
||||
tok.iNumber = xi
|
||||
if (bits > 32): tok.xkind = pxInt64Lit
|
||||
else: tok.xkind = pxIntLit
|
||||
L.bufpos = pos
|
||||
|
||||
proc getNumber8(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 1 # skip 0
|
||||
tok.base = base8
|
||||
var xi: BiggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
of 'A'..'Z', 'a'..'z':
|
||||
# ignore type suffix:
|
||||
inc(pos)
|
||||
of '8'..'9', '.':
|
||||
lexMessage(L, errInvalidNumber)
|
||||
inc(pos)
|
||||
of '_':
|
||||
inc(pos)
|
||||
of '0'..'7':
|
||||
xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
inc(bits)
|
||||
else: break
|
||||
tok.iNumber = xi
|
||||
if (bits > 12): tok.xkind = pxInt64Lit
|
||||
else: tok.xkind = pxIntLit
|
||||
L.bufpos = pos
|
||||
|
||||
proc getNumber16(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 2 # skip 0x
|
||||
tok.base = base16
|
||||
var xi: BiggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
of 'G'..'Z', 'g'..'z':
|
||||
# ignore type suffix:
|
||||
inc(pos)
|
||||
of '_': inc(pos)
|
||||
of '0'..'9':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
inc(bits, 4)
|
||||
of 'a'..'f':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('a') + 10)
|
||||
inc(pos)
|
||||
inc(bits, 4)
|
||||
of 'A'..'F':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
|
||||
inc(pos)
|
||||
inc(bits, 4)
|
||||
else: break
|
||||
tok.iNumber = xi
|
||||
if bits > 32: tok.xkind = pxInt64Lit
|
||||
else: tok.xkind = pxIntLit
|
||||
L.bufpos = pos
|
||||
|
||||
proc getFloating(L: var TLexer, tok: var TToken) =
|
||||
matchUnderscoreChars(L, tok, {'0'..'9'})
|
||||
if L.buf[L.bufpos] in {'e', 'E'}:
|
||||
add(tok.s, L.buf[L.bufpos])
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] in {'+', '-'}:
|
||||
add(tok.s, L.buf[L.bufpos])
|
||||
inc(L.bufpos)
|
||||
matchUnderscoreChars(L, tok, {'0'..'9'})
|
||||
|
||||
proc getNumber(L: var TLexer, tok: var TToken) =
|
||||
tok.base = base10
|
||||
if L.buf[L.bufpos] == '.':
|
||||
add(tok.s, "0.")
|
||||
inc(L.bufpos)
|
||||
getFloating(L, tok)
|
||||
else:
|
||||
matchUnderscoreChars(L, tok, {'0'..'9'})
|
||||
if L.buf[L.bufpos] == '.':
|
||||
add(tok.s, '.')
|
||||
inc(L.bufpos)
|
||||
getFloating(L, tok)
|
||||
try:
|
||||
if isFloatLiteral(tok.s):
|
||||
tok.fnumber = parseFloat(tok.s)
|
||||
tok.xkind = pxFloatLit
|
||||
else:
|
||||
tok.iNumber = parseInt(tok.s)
|
||||
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)):
|
||||
tok.xkind = pxInt64Lit
|
||||
else:
|
||||
tok.xkind = pxIntLit
|
||||
except EInvalidValue:
|
||||
lexMessage(L, errInvalidNumber, tok.s)
|
||||
except EOverflow:
|
||||
lexMessage(L, errNumberOutOfRange, tok.s)
|
||||
# ignore type suffix:
|
||||
while L.buf[L.bufpos] in {'A'..'Z', 'a'..'z'}: inc(L.bufpos)
|
||||
|
||||
proc handleCRLF(L: var TLexer, pos: int): int =
|
||||
case L.buf[pos]
|
||||
of CR: result = nimlexbase.handleCR(L, pos)
|
||||
of LF: result = nimlexbase.handleLF(L, pos)
|
||||
else: result = pos
|
||||
|
||||
proc escape(L: var TLexer, tok: var TToken, allowEmpty=false) =
|
||||
inc(L.bufpos) # skip \
|
||||
case L.buf[L.bufpos]
|
||||
of 'b', 'B':
|
||||
add(tok.s, '\b')
|
||||
inc(L.bufpos)
|
||||
of 't', 'T':
|
||||
add(tok.s, '\t')
|
||||
inc(L.bufpos)
|
||||
of 'n', 'N':
|
||||
add(tok.s, '\L')
|
||||
inc(L.bufpos)
|
||||
of 'f', 'F':
|
||||
add(tok.s, '\f')
|
||||
inc(L.bufpos)
|
||||
of 'r', 'R':
|
||||
add(tok.s, '\r')
|
||||
inc(L.bufpos)
|
||||
of '\'':
|
||||
add(tok.s, '\'')
|
||||
inc(L.bufpos)
|
||||
of '"':
|
||||
add(tok.s, '"')
|
||||
inc(L.bufpos)
|
||||
of '\\':
|
||||
add(tok.s, '\b')
|
||||
inc(L.bufpos)
|
||||
of '0'..'7':
|
||||
var xi = ord(L.buf[L.bufpos]) - ord('0')
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] in {'0'..'7'}:
|
||||
xi = (xi shl 3) or (ord(L.buf[L.bufpos]) - ord('0'))
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] in {'0'..'7'}:
|
||||
xi = (xi shl 3) or (ord(L.buf[L.bufpos]) - ord('0'))
|
||||
inc(L.bufpos)
|
||||
add(tok.s, chr(xi))
|
||||
of 'x':
|
||||
var xi = 0
|
||||
inc(L.bufpos)
|
||||
while true:
|
||||
case L.buf[L.bufpos]
|
||||
of '0'..'9':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('0'))
|
||||
inc(L.bufpos)
|
||||
of 'a'..'f':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('a') + 10)
|
||||
inc(L.bufpos)
|
||||
of 'A'..'F':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('A') + 10)
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
break
|
||||
add(tok.s, chr(xi))
|
||||
elif not allowEmpty:
|
||||
lexMessage(L, errInvalidCharacterConstant)
|
||||
|
||||
proc getCharLit(L: var TLexer, tok: var TToken) =
|
||||
inc(L.bufpos) # skip '
|
||||
if L.buf[L.bufpos] == '\\':
|
||||
escape(L, tok)
|
||||
else:
|
||||
add(tok.s, L.buf[L.bufpos])
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '\'':
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
lexMessage(L, errMissingFinalQuote)
|
||||
tok.xkind = pxCharLit
|
||||
|
||||
proc getString(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufPos + 1 # skip "
|
||||
var buf = L.buf # put `buf` in a register
|
||||
var line = L.linenumber # save linenumber for better error message
|
||||
while true:
|
||||
case buf[pos]
|
||||
of '\"':
|
||||
inc(pos)
|
||||
break
|
||||
of CR:
|
||||
pos = nimlexbase.HandleCR(L, pos)
|
||||
buf = L.buf
|
||||
of LF:
|
||||
pos = nimlexbase.HandleLF(L, pos)
|
||||
buf = L.buf
|
||||
of nimlexbase.EndOfFile:
|
||||
var line2 = L.linenumber
|
||||
L.LineNumber = line
|
||||
lexMessagePos(L, errClosingQuoteExpected, L.lineStart)
|
||||
L.LineNumber = line2
|
||||
break
|
||||
of '\\':
|
||||
# we allow an empty \ for line concatenation, but we don't require it
|
||||
# for line concatenation
|
||||
L.bufpos = pos
|
||||
escape(L, tok, allowEmpty=true)
|
||||
pos = L.bufpos
|
||||
else:
|
||||
add(tok.s, buf[pos])
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
tok.xkind = pxStrLit
|
||||
|
||||
proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
while true:
|
||||
var c = buf[pos]
|
||||
if c notin SymChars: break
|
||||
add(tok.s, c)
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
tok.xkind = pxSymbol
|
||||
|
||||
proc scanLineComment(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
# a comment ends if the next line does not start with the // on the same
|
||||
# column after only whitespace
|
||||
tok.xkind = pxLineComment
|
||||
var col = getColNumber(L, pos)
|
||||
while true:
|
||||
inc(pos, 2) # skip //
|
||||
add(tok.s, '#')
|
||||
while not (buf[pos] in {CR, LF, nimlexbase.EndOfFile}):
|
||||
add(tok.s, buf[pos])
|
||||
inc(pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
var indent = 0
|
||||
while buf[pos] == ' ':
|
||||
inc(pos)
|
||||
inc(indent)
|
||||
if (col == indent) and (buf[pos] == '/') and (buf[pos + 1] == '/'):
|
||||
add(tok.s, "\n")
|
||||
else:
|
||||
break
|
||||
L.bufpos = pos
|
||||
|
||||
proc scanStarComment(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
tok.s = "#"
|
||||
tok.xkind = pxStarComment
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR, LF:
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
add(tok.s, "\n#")
|
||||
# skip annoying stars as line prefix: (eg.
|
||||
# /*
|
||||
# * ugly comment <-- this star
|
||||
# */
|
||||
while buf[pos] in {' ', '\t'}:
|
||||
add(tok.s, ' ')
|
||||
inc(pos)
|
||||
if buf[pos] == '*' and buf[pos+1] != '/': inc(pos)
|
||||
of '*':
|
||||
inc(pos)
|
||||
if buf[pos] == '/':
|
||||
inc(pos)
|
||||
break
|
||||
else:
|
||||
add(tok.s, '*')
|
||||
of nimlexbase.EndOfFile:
|
||||
lexMessage(L, errTokenExpected, "*/")
|
||||
else:
|
||||
add(tok.s, buf[pos])
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
|
||||
proc skip(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
while true:
|
||||
case buf[pos]
|
||||
of '\\':
|
||||
# Ignore \ line continuation characters when not inDirective
|
||||
inc(pos)
|
||||
if L.inDirective:
|
||||
while buf[pos] in {' ', '\t'}: inc(pos)
|
||||
if buf[pos] in {CR, LF}:
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
of ' ', Tabulator:
|
||||
inc(pos) # newline is special:
|
||||
of CR, LF:
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
if L.inDirective:
|
||||
tok.xkind = pxNewLine
|
||||
L.inDirective = false
|
||||
else:
|
||||
break # EndOfFile also leaves the loop
|
||||
L.bufpos = pos
|
||||
|
||||
proc getDirective(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 1
|
||||
var buf = L.buf
|
||||
while buf[pos] in {' ', '\t'}: inc(pos)
|
||||
while buf[pos] in SymChars:
|
||||
add(tok.s, buf[pos])
|
||||
inc(pos)
|
||||
# a HACK: we need to distinguish
|
||||
# #define x (...)
|
||||
# from:
|
||||
# #define x(...)
|
||||
#
|
||||
L.bufpos = pos
|
||||
# look ahead:
|
||||
while buf[pos] in {' ', '\t'}: inc(pos)
|
||||
while buf[pos] in SymChars: inc(pos)
|
||||
if buf[pos] == '(': tok.xkind = pxDirectiveParLe
|
||||
else: tok.xkind = pxDirective
|
||||
L.inDirective = true
|
||||
|
||||
proc getTok(L: var TLexer, tok: var TToken) =
|
||||
tok.xkind = pxInvalid
|
||||
fillToken(tok)
|
||||
skip(L, tok)
|
||||
if tok.xkind == pxNewLine: return
|
||||
var c = L.buf[L.bufpos]
|
||||
if c in SymStartChars:
|
||||
getSymbol(L, tok)
|
||||
elif c == '0':
|
||||
case L.buf[L.bufpos+1]
|
||||
of 'x', 'X': getNumber16(L, tok)
|
||||
of 'b', 'B': getNumber2(L, tok)
|
||||
of '1'..'7': getNumber8(L, tok)
|
||||
else: getNumber(L, tok)
|
||||
elif c in {'1'..'9'} or (c == '.' and L.buf[L.bufpos+1] in {'0'..'9'}):
|
||||
getNumber(L, tok)
|
||||
else:
|
||||
case c
|
||||
of ';':
|
||||
tok.xkind = pxSemicolon
|
||||
inc(L.bufpos)
|
||||
of '/':
|
||||
if L.buf[L.bufpos + 1] == '/':
|
||||
scanLineComment(L, tok)
|
||||
elif L.buf[L.bufpos+1] == '*':
|
||||
inc(L.bufpos, 2)
|
||||
scanStarComment(L, tok)
|
||||
elif L.buf[L.bufpos+1] == '=':
|
||||
inc(L.bufpos, 2)
|
||||
tok.xkind = pxSlashAsgn
|
||||
else:
|
||||
tok.xkind = pxSlash
|
||||
inc(L.bufpos)
|
||||
of ',':
|
||||
tok.xkind = pxComma
|
||||
inc(L.bufpos)
|
||||
of '(':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxParLe
|
||||
of '*':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxStarAsgn
|
||||
else:
|
||||
tok.xkind = pxStar
|
||||
of ')':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxParRi
|
||||
of '[':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxBracketLe
|
||||
of ']':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxBracketRi
|
||||
of '.':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] == '.':
|
||||
tok.xkind = pxDotDotDot
|
||||
inc(L.bufpos, 2)
|
||||
else:
|
||||
tok.xkind = pxDot
|
||||
of '{':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxCurlyLe
|
||||
of '}':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxCurlyRi
|
||||
of '+':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxPlusAsgn
|
||||
inc(L.bufpos)
|
||||
elif L.buf[L.bufpos] == '+':
|
||||
tok.xkind = pxPlusPlus
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxPlus
|
||||
of '-':
|
||||
inc(L.bufpos)
|
||||
case L.buf[L.bufpos]
|
||||
of '>':
|
||||
tok.xkind = pxArrow
|
||||
inc(L.bufpos)
|
||||
of '=':
|
||||
tok.xkind = pxMinusAsgn
|
||||
inc(L.bufpos)
|
||||
of '-':
|
||||
tok.xkind = pxMinusMinus
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxMinus
|
||||
of '?':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxConditional
|
||||
of ':':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == ':':
|
||||
tok.xkind = pxScope
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxColon
|
||||
of '!':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxNeq
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxNot
|
||||
of '<':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxLe
|
||||
elif L.buf[L.bufpos] == '<':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxShlAsgn
|
||||
else:
|
||||
tok.xkind = pxShl
|
||||
else:
|
||||
tok.xkind = pxLt
|
||||
of '>':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxGe
|
||||
elif L.buf[L.bufpos] == '>':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxShrAsgn
|
||||
else:
|
||||
tok.xkind = pxShr
|
||||
else:
|
||||
tok.xkind = pxGt
|
||||
of '=':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxEquals
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxAsgn
|
||||
of '&':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxAmpAsgn
|
||||
inc(L.bufpos)
|
||||
elif L.buf[L.bufpos] == '&':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxAmpAmpAsgn
|
||||
else:
|
||||
tok.xkind = pxAmpAmp
|
||||
else:
|
||||
tok.xkind = pxAmp
|
||||
of '|':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxBarAsgn
|
||||
inc(L.bufpos)
|
||||
elif L.buf[L.bufpos] == '|':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxBarBarAsgn
|
||||
else:
|
||||
tok.xkind = pxBarBar
|
||||
else:
|
||||
tok.xkind = pxBar
|
||||
of '^':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxHatAsgn
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxHat
|
||||
of '%':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxModAsgn
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxMod
|
||||
of '~':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
tok.xkind = pxTildeAsgn
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxTilde
|
||||
of '#':
|
||||
if L.buf[L.bufpos+1] == '#':
|
||||
inc(L.bufpos, 2)
|
||||
tok.xkind = pxDirConc
|
||||
else:
|
||||
getDirective(L, tok)
|
||||
of '"': getString(L, tok)
|
||||
of '\'': getCharLit(L, tok)
|
||||
of nimlexbase.EndOfFile:
|
||||
tok.xkind = pxEof
|
||||
else:
|
||||
tok.s = $c
|
||||
tok.xkind = pxInvalid
|
||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
||||
inc(L.bufpos)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,347 +0,0 @@
|
||||
#
|
||||
#
|
||||
# c2nim - C to Nimrod source converter
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# 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)
|
||||
elif p.tok.xkind == pxNewLine:
|
||||
eat(p, pxNewLine)
|
||||
|
||||
proc skipLine(p: var TParser) =
|
||||
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}: getTok(p)
|
||||
eatNewLine(p, nil)
|
||||
|
||||
proc parseDefineBody(p: var TParser, tmplDef: PNode): string =
|
||||
if p.tok.xkind == pxCurlyLe or
|
||||
(p.tok.xkind == pxSymbol and (
|
||||
declKeyword(p, 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, skipIdentExport(p))
|
||||
addSon(result, ast.emptyNode)
|
||||
eat(p, pxParLe)
|
||||
var params = newNodeP(nkFormalParams, p)
|
||||
# return type; not known yet:
|
||||
addSon(params, ast.emptyNode)
|
||||
if p.tok.xkind != pxParRi:
|
||||
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, ast.emptyNode)
|
||||
addSon(params, identDefs)
|
||||
eat(p, pxParRi)
|
||||
|
||||
addSon(result, ast.emptyNode) # no generic parameters
|
||||
addSon(result, params)
|
||||
addSon(result, ast.emptyNode) # no pragmas
|
||||
addSon(result, ast.emptyNode)
|
||||
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, skipIdentExport(p))
|
||||
addSon(c, ast.emptyNode)
|
||||
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)
|
||||
assert result != nil
|
||||
|
||||
proc parseDefBody(p: var TParser, m: var TMacro, params: seq[string]) =
|
||||
m.body = @[]
|
||||
# A little hack: We safe the context, so that every following token will be
|
||||
# put into a newly allocated TToken object. Thus we can just save a
|
||||
# reference to the token in the macro's body.
|
||||
saveContext(p)
|
||||
while p.tok.xkind notin {pxEof, pxNewLine, pxLineComment}:
|
||||
case p.tok.xkind
|
||||
of pxSymbol:
|
||||
# is it a parameter reference?
|
||||
var tok = p.tok
|
||||
for i in 0..high(params):
|
||||
if params[i] == p.tok.s:
|
||||
new(tok)
|
||||
tok.xkind = pxMacroParam
|
||||
tok.iNumber = i
|
||||
break
|
||||
m.body.add(tok)
|
||||
of pxDirConc:
|
||||
# just ignore this token: this implements token merging correctly
|
||||
discard
|
||||
else:
|
||||
m.body.add(p.tok)
|
||||
# we do not want macro expansion here:
|
||||
rawGetTok(p)
|
||||
eatNewLine(p, nil)
|
||||
closeContext(p)
|
||||
# newline token might be overwritten, but this is not
|
||||
# part of the macro body, so it is safe.
|
||||
|
||||
proc parseDef(p: var TParser, m: var TMacro) =
|
||||
var hasParams = p.tok.xkind == pxDirectiveParLe
|
||||
getTok(p)
|
||||
expectIdent(p)
|
||||
m.name = p.tok.s
|
||||
getTok(p)
|
||||
var params: seq[string] = @[]
|
||||
# parse parameters:
|
||||
if hasParams:
|
||||
eat(p, pxParLe)
|
||||
while p.tok.xkind != pxParRi:
|
||||
expectIdent(p)
|
||||
params.add(p.tok.s)
|
||||
getTok(p)
|
||||
skipStarCom(p, nil)
|
||||
if p.tok.xkind != pxComma: break
|
||||
getTok(p)
|
||||
eat(p, pxParRi)
|
||||
m.params = params.len
|
||||
parseDefBody(p, m, params)
|
||||
|
||||
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 and pfSkipInclude notin p.options.flags:
|
||||
var file = newStrNodeP(nkStrLit, changeFileExt(p.tok.s, ""), p)
|
||||
addSon(result, file)
|
||||
getTok(p)
|
||||
skipStarCom(p, file)
|
||||
eatNewLine(p, nil)
|
||||
else:
|
||||
skipLine(p)
|
||||
if sonsLen(result) == 0:
|
||||
# we only parsed includes that we chose to ignore:
|
||||
result = ast.emptyNode
|
||||
|
||||
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: discard
|
||||
addSon(result, statement(p))
|
||||
|
||||
proc eatEndif(p: var TParser) =
|
||||
if isDir(p, "endif"):
|
||||
skipLine(p)
|
||||
else:
|
||||
parMessage(p, errXExpected, "#endif")
|
||||
|
||||
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)
|
||||
skipLine(p)
|
||||
addSon(s, parseStmtList(p))
|
||||
addSon(result, s)
|
||||
eatEndif(p)
|
||||
|
||||
proc skipUntilEndif(p: var TParser) =
|
||||
var nested = 1
|
||||
while p.tok.xkind != pxEof:
|
||||
if isDir(p, "ifdef") or isDir(p, "ifndef") or isDir(p, "if"):
|
||||
inc(nested)
|
||||
elif isDir(p, "endif"):
|
||||
dec(nested)
|
||||
if nested <= 0:
|
||||
skipLine(p)
|
||||
return
|
||||
getTok(p)
|
||||
parMessage(p, errXExpected, "#endif")
|
||||
|
||||
type
|
||||
TEndifMarker = enum
|
||||
emElif, emElse, emEndif
|
||||
|
||||
proc skipUntilElifElseEndif(p: var TParser): TEndifMarker =
|
||||
var nested = 1
|
||||
while p.tok.xkind != pxEof:
|
||||
if isDir(p, "ifdef") or isDir(p, "ifndef") or isDir(p, "if"):
|
||||
inc(nested)
|
||||
elif isDir(p, "elif") and nested <= 1:
|
||||
return emElif
|
||||
elif isDir(p, "else") and nested <= 1:
|
||||
return emElse
|
||||
elif isDir(p, "endif"):
|
||||
dec(nested)
|
||||
if nested <= 0:
|
||||
return emEndif
|
||||
getTok(p)
|
||||
parMessage(p, errXExpected, "#endif")
|
||||
|
||||
proc parseIfdef(p: var TParser): PNode =
|
||||
getTok(p) # skip #ifdef
|
||||
expectIdent(p)
|
||||
case p.tok.s
|
||||
of "__cplusplus":
|
||||
skipUntilEndif(p)
|
||||
result = ast.emptyNode
|
||||
of c2nimSymbol:
|
||||
skipLine(p)
|
||||
result = parseStmtList(p)
|
||||
skipUntilEndif(p)
|
||||
else:
|
||||
result = newNodeP(nkWhenStmt, p)
|
||||
addSon(result, newNodeP(nkElifBranch, p))
|
||||
addSon(result.sons[0], definedExprAux(p))
|
||||
eatNewLine(p, nil)
|
||||
parseIfDirAux(p, result)
|
||||
|
||||
proc parseIfndef(p: var TParser): PNode =
|
||||
result = ast.emptyNode
|
||||
getTok(p) # skip #ifndef
|
||||
expectIdent(p)
|
||||
if p.tok.s == c2nimSymbol:
|
||||
skipLine(p)
|
||||
case skipUntilElifElseEndif(p)
|
||||
of emElif:
|
||||
result = newNodeP(nkWhenStmt, p)
|
||||
addSon(result, newNodeP(nkElifBranch, p))
|
||||
getTok(p)
|
||||
addSon(result.sons[0], expression(p))
|
||||
eatNewLine(p, nil)
|
||||
parseIfDirAux(p, result)
|
||||
of emElse:
|
||||
skipLine(p)
|
||||
result = parseStmtList(p)
|
||||
eatEndif(p)
|
||||
of emEndif: skipLine(p)
|
||||
else:
|
||||
result = newNodeP(nkWhenStmt, p)
|
||||
addSon(result, newNodeP(nkElifBranch, 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)
|
||||
|
||||
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 parsePegLit(p: var TParser): TPeg =
|
||||
var col = getColumn(p.lex) + 2
|
||||
getTok(p)
|
||||
if p.tok.xkind != pxStrLit: expectIdent(p)
|
||||
try:
|
||||
result = parsePeg(
|
||||
pattern = if p.tok.xkind == pxStrLit: p.tok.s else: escapePeg(p.tok.s),
|
||||
filename = p.lex.fileIdx.toFilename,
|
||||
line = p.lex.linenumber,
|
||||
col = col)
|
||||
getTok(p)
|
||||
except EInvalidPeg:
|
||||
parMessage(p, errUser, getCurrentExceptionMsg())
|
||||
|
||||
proc parseMangleDir(p: var TParser) =
|
||||
var pattern = parsePegLit(p)
|
||||
if p.tok.xkind != pxStrLit: expectIdent(p)
|
||||
p.options.mangleRules.add((pattern, p.tok.s))
|
||||
getTok(p)
|
||||
eatNewLine(p, nil)
|
||||
|
||||
proc modulePragmas(p: var TParser): PNode =
|
||||
if p.options.dynlibSym.len > 0 and not p.hasDeadCodeElimPragma:
|
||||
p.hasDeadCodeElimPragma = true
|
||||
result = newNodeP(nkPragma, p)
|
||||
var e = newNodeP(nkExprColonExpr, p)
|
||||
addSon(e, newIdentNodeP("deadCodeElim", p), newIdentNodeP("on", p))
|
||||
addSon(result, e)
|
||||
else:
|
||||
result = ast.emptyNode
|
||||
|
||||
proc parseDir(p: var TParser): PNode =
|
||||
result = ast.emptyNode
|
||||
assert(p.tok.xkind in {pxDirective, pxDirectiveParLe})
|
||||
case p.tok.s
|
||||
of "define": result = parseDefine(p)
|
||||
of "include": result = parseInclude(p)
|
||||
of "ifdef": result = parseIfdef(p)
|
||||
of "ifndef": result = parseIfndef(p)
|
||||
of "if": result = parseIfDir(p)
|
||||
of "cdecl", "stdcall", "ref", "skipinclude", "typeprefixes", "skipcomments":
|
||||
discard setOption(p.options, p.tok.s)
|
||||
getTok(p)
|
||||
eatNewLine(p, nil)
|
||||
of "dynlib", "header", "prefix", "suffix", "class":
|
||||
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)
|
||||
result = modulePragmas(p)
|
||||
of "mangle":
|
||||
parseMangleDir(p)
|
||||
of "def":
|
||||
var L = p.options.macros.len
|
||||
setLen(p.options.macros, L+1)
|
||||
parseDef(p, p.options.macros[L])
|
||||
of "private":
|
||||
var pattern = parsePegLit(p)
|
||||
p.options.privateRules.add(pattern)
|
||||
eatNewLine(p, nil)
|
||||
else:
|
||||
# ignore unimportant/unknown directive ("undef", "pragma", "error")
|
||||
skipLine(p)
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# Use the modules of the compiler
|
||||
|
||||
path: "$nimrod/compiler"
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
|
||||
enum vehicles
|
||||
{
|
||||
car = 0x10,
|
||||
truck,
|
||||
boat = 0x01,
|
||||
ship = 1,
|
||||
speedboat = 1,
|
||||
bicycle = 4,
|
||||
bobycar
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
red = 4,
|
||||
green = 2,
|
||||
blue
|
||||
};
|
||||
|
||||
typedef enum food
|
||||
{
|
||||
bread = 4,
|
||||
toast = 4,
|
||||
bun = 0x04,
|
||||
cucumber = 2,
|
||||
chocolate = 6
|
||||
};
|
||||
|
||||
typedef enum numbers
|
||||
{
|
||||
one = 1,
|
||||
two,
|
||||
nten = - 10,
|
||||
nnine,
|
||||
four = 4,
|
||||
three = + 3,
|
||||
positivenine = + 9,
|
||||
nfour = - 4,
|
||||
negativeten = -10
|
||||
};
|
||||
@@ -1,240 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/matrix.h
|
||||
// Purpose: wxTransformMatrix class. NOT YET USED
|
||||
// Author: Chris Breeze, Julian Smart
|
||||
// Modified by: Klaas Holwerda
|
||||
// Created: 01/02/97
|
||||
// RCS-ID: $Id$
|
||||
// Copyright: (c) Julian Smart, Chris Breeze
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WX_MATRIXH__
|
||||
#define _WX_MATRIXH__
|
||||
|
||||
//! headerfiles="matrix.h wx/object.h"
|
||||
#include "wx/object.h"
|
||||
#include "wx/math.h"
|
||||
|
||||
//! codefiles="matrix.cpp"
|
||||
|
||||
// A simple 3x3 matrix. This may be replaced by a more general matrix
|
||||
// class some day.
|
||||
//
|
||||
// Note: this is intended to be used in wxDC at some point to replace
|
||||
// the current system of scaling/translation. It is not yet used.
|
||||
|
||||
#def WXDLLIMPEXP_CORE
|
||||
#header "wxmatrix.h"
|
||||
|
||||
//:definition
|
||||
// A 3x3 matrix to do 2D transformations.
|
||||
// It can be used to map data to window coordinates,
|
||||
// and also for manipulating your own data.
|
||||
// For example drawing a picture (composed of several primitives)
|
||||
// at a certain coordinate and angle within another parent picture.
|
||||
// At all times m_isIdentity is set if the matrix itself is an Identity matrix.
|
||||
// It is used where possible to optimize calculations.
|
||||
class WXDLLIMPEXP_CORE wxTransformMatrix: public wxObject<string, string<ubyte>>
|
||||
{
|
||||
public:
|
||||
wxTransformMatrix(void);
|
||||
wxTransformMatrix(const wxTransformMatrix& mat);
|
||||
|
||||
~wxTransformMatrix(void);
|
||||
|
||||
//get the value in the matrix at col,row
|
||||
//rows are horizontal (second index of m_matrix member)
|
||||
//columns are vertical (first index of m_matrix member)
|
||||
double GetValue(int col, int row) const;
|
||||
|
||||
//set the value in the matrix at col,row
|
||||
//rows are horizontal (second index of m_matrix member)
|
||||
//columns are vertical (first index of m_matrix member)
|
||||
void SetValue(int col, int row, double value);
|
||||
|
||||
void operator = (const wxTransformMatrix& mat);
|
||||
bool operator == (const wxTransformMatrix& mat) const;
|
||||
bool operator != (const module::gah::wxTransformMatrix& mat) const;
|
||||
|
||||
//multiply every element by t
|
||||
wxTransformMatrix& operator*=(const double& t);
|
||||
//divide every element by t
|
||||
wxTransformMatrix& operator/=(const double& t);
|
||||
//add matrix m to this t
|
||||
wxTransformMatrix& operator+=(const wxTransformMatrix& m);
|
||||
//subtract matrix m from this
|
||||
wxTransformMatrix& operator-=(const wxTransformMatrix& m);
|
||||
//multiply matrix m with this
|
||||
wxTransformMatrix& operator*=(const wxTransformMatrix& m);
|
||||
|
||||
// constant operators
|
||||
|
||||
//multiply every element by t and return result
|
||||
wxTransformMatrix operator*(const double& t) const;
|
||||
//divide this matrix by t and return result
|
||||
wxTransformMatrix operator/(const double& t) const;
|
||||
//add matrix m to this and return result
|
||||
wxTransformMatrix operator+(const wxTransformMatrix& m) const;
|
||||
//subtract matrix m from this and return result
|
||||
wxTransformMatrix operator-(const wxTransformMatrix& m) const;
|
||||
//multiply this by matrix m and return result
|
||||
wxTransformMatrix operator*(const wxTransformMatrix& m) const;
|
||||
wxTransformMatrix operator-() const;
|
||||
|
||||
//rows are horizontal (second index of m_matrix member)
|
||||
//columns are vertical (first index of m_matrix member)
|
||||
double& operator()(int col, int row);
|
||||
|
||||
//rows are horizontal (second index of m_matrix member)
|
||||
//columns are vertical (first index of m_matrix member)
|
||||
double operator()(int col, int row) const;
|
||||
|
||||
// Invert matrix
|
||||
bool Invert(void);
|
||||
|
||||
// Make into identity matrix
|
||||
bool Identity(void);
|
||||
|
||||
// Is the matrix the identity matrix?
|
||||
// Only returns a flag, which is set whenever an operation
|
||||
// is done.
|
||||
inline bool IsIdentity(void) const { return m_isIdentity; }
|
||||
|
||||
// This does an actual check.
|
||||
inline bool IsIdentity1(void) const ;
|
||||
|
||||
//Scale by scale (isotropic scaling i.e. the same in x and y):
|
||||
//!ex:
|
||||
//!code: | scale 0 0 |
|
||||
//!code: matrix' = | 0 scale 0 | x matrix
|
||||
//!code: | 0 0 scale |
|
||||
bool Scale(double scale);
|
||||
|
||||
//Scale with center point and x/y scale
|
||||
//
|
||||
//!ex:
|
||||
//!code: | xs 0 xc(1-xs) |
|
||||
//!code: matrix' = | 0 ys yc(1-ys) | x matrix
|
||||
//!code: | 0 0 1 |
|
||||
wxTransformMatrix& Scale(const double &xs, const double &ys,const double &xc, const double &yc);
|
||||
|
||||
// mirror a matrix in x, y
|
||||
//!ex:
|
||||
//!code: | -1 0 0 |
|
||||
//!code: matrix' = | 0 -1 0 | x matrix
|
||||
//!code: | 0 0 1 |
|
||||
wxTransformMatrix<float>& Mirror(bool x=true, bool y=false);
|
||||
// Translate by dx, dy:
|
||||
//!ex:
|
||||
//!code: | 1 0 dx |
|
||||
//!code: matrix' = | 0 1 dy | x matrix
|
||||
//!code: | 0 0 1 |
|
||||
bool Translate(double x, double y);
|
||||
|
||||
// Rotate clockwise by the given number of degrees:
|
||||
//!ex:
|
||||
//!code: | cos sin 0 |
|
||||
//!code: matrix' = | -sin cos 0 | x matrix
|
||||
//!code: | 0 0 1 |
|
||||
bool Rotate(double angle);
|
||||
|
||||
//Rotate counter clockwise with point of rotation
|
||||
//
|
||||
//!ex:
|
||||
//!code: | cos(r) -sin(r) x(1-cos(r))+y(sin(r)|
|
||||
//!code: matrix' = | sin(r) cos(r) y(1-cos(r))-x(sin(r)| x matrix
|
||||
//!code: | 0 0 1 |
|
||||
wxTransformMatrix& Rotate(const double &r, const double &x, const double &y);
|
||||
|
||||
// Transform X value from logical to device
|
||||
inline double TransformX(double x) const;
|
||||
|
||||
// Transform Y value from logical to device
|
||||
inline double TransformY(double y) const;
|
||||
|
||||
// Transform a point from logical to device coordinates
|
||||
bool TransformPoint(double x, double y, double& tx, double& ty) const;
|
||||
|
||||
// Transform a point from device to logical coordinates.
|
||||
// Example of use:
|
||||
// wxTransformMatrix mat = dc.GetTransformation();
|
||||
// mat.Invert();
|
||||
// mat.InverseTransformPoint(x, y, x1, y1);
|
||||
// OR (shorthand:)
|
||||
// dc.LogicalToDevice(x, y, x1, y1);
|
||||
// The latter is slightly less efficient if we're doing several
|
||||
// conversions, since the matrix is inverted several times.
|
||||
// N.B. 'this' matrix is the inverse at this point
|
||||
bool InverseTransformPoint(double x, double y, double& tx, double& ty) const;
|
||||
|
||||
double Get_scaleX();
|
||||
double Get_scaleY();
|
||||
double GetRotation();
|
||||
void SetRotation(double rotation);
|
||||
|
||||
|
||||
public:
|
||||
double m_matrix[3][3];
|
||||
bool m_isIdentity;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Chris Breeze reported, that
|
||||
some functions of wxTransformMatrix cannot work because it is not
|
||||
known if he matrix has been inverted. Be careful when using it.
|
||||
*/
|
||||
|
||||
// Transform X value from logical to device
|
||||
// warning: this function can only be used for this purpose
|
||||
// because no rotation is involved when mapping logical to device coordinates
|
||||
// mirror and scaling for x and y will be part of the matrix
|
||||
// if you have a matrix that is rotated, eg a shape containing a matrix to place
|
||||
// it in the logical coordinate system, use TransformPoint
|
||||
inline double wxTransformMatrix::TransformX(double x) const
|
||||
{
|
||||
//normally like this, but since no rotation is involved (only mirror and scale)
|
||||
//we can do without Y -> m_matrix[1]{0] is -sin(rotation angle) and therefore zero
|
||||
//(x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0]))
|
||||
return (m_isIdentity ? x : (x * m_matrix[0][0] + m_matrix[2][0]));
|
||||
}
|
||||
|
||||
// Transform Y value from logical to device
|
||||
// warning: this function can only be used for this purpose
|
||||
// because no rotation is involved when mapping logical to device coordinates
|
||||
// mirror and scaling for x and y will be part of the matrix
|
||||
// if you have a matrix that is rotated, eg a shape containing a matrix to place
|
||||
// it in the logical coordinate system, use TransformPoint
|
||||
inline double wxTransformMatrix::TransformY(double y) const
|
||||
{
|
||||
//normally like this, but since no rotation is involved (only mirror and scale)
|
||||
//we can do without X -> m_matrix[0]{1] is sin(rotation angle) and therefore zero
|
||||
//(x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1]))
|
||||
return (m_isIdentity ? y : (y * m_matrix[1][1] + m_matrix[2][1]));
|
||||
}
|
||||
|
||||
|
||||
// Is the matrix the identity matrix?
|
||||
// Each operation checks whether the result is still the identity matrix and sets a flag.
|
||||
inline bool wxTransformMatrix::IsIdentity1(void) const
|
||||
{
|
||||
return
|
||||
( wxIsSameDouble(m_matrix[0][0], 1.0) &&
|
||||
wxIsSameDouble(m_matrix[1][1], 1.0) &&
|
||||
wxIsSameDouble(m_matrix[2][2], 1.0) &&
|
||||
wxIsSameDouble(m_matrix[1][0], 0.0) &&
|
||||
wxIsSameDouble(m_matrix[2][0], 0.0) &&
|
||||
wxIsSameDouble(m_matrix[0][1], 0.0) &&
|
||||
wxIsSameDouble(m_matrix[2][1], 0.0) &&
|
||||
wxIsSameDouble(m_matrix[0][2], 0.0) &&
|
||||
wxIsSameDouble(m_matrix[1][2], 0.0) );
|
||||
}
|
||||
|
||||
// Calculates the determinant of a 2 x 2 matrix
|
||||
inline double wxCalculateDet(double a11, double a21, double a12, double a22)
|
||||
{
|
||||
return a11 * a22 - a12 * a21;
|
||||
}
|
||||
|
||||
#endif // _WX_MATRIXH__
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
struct normal{
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
typedef struct outerStruct {
|
||||
struct normal a_nomal_one;
|
||||
|
||||
int a;
|
||||
|
||||
struct {
|
||||
union {
|
||||
int b;
|
||||
} a_union_in_the_struct;
|
||||
|
||||
int c;
|
||||
};
|
||||
|
||||
union {
|
||||
int d;
|
||||
|
||||
struct {
|
||||
int e;
|
||||
} a_struct_in_the_union;
|
||||
} a_union;
|
||||
};
|
||||
@@ -1,622 +0,0 @@
|
||||
/* This file has been written by Blablub.
|
||||
*
|
||||
* Another comment line.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
# ifdef __SOME_OTHER_CRAP
|
||||
extern "C" {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define interrupts() sei()
|
||||
|
||||
enum
|
||||
{
|
||||
/* 8bit, color or not */
|
||||
CV_LOAD_IMAGE_UNCHANGED =-1,
|
||||
/* 8bit, gray */
|
||||
CV_LOAD_IMAGE_GRAYSCALE =0,
|
||||
/* ?, color */
|
||||
CV_LOAD_IMAGE_COLOR =1,
|
||||
/* any depth, ? */
|
||||
CV_LOAD_IMAGE_ANYDEPTH =2,
|
||||
/* ?, any color */
|
||||
CV_LOAD_IMAGE_ANYCOLOR =4
|
||||
};
|
||||
|
||||
typedef void (*callback_t) (int rc);
|
||||
typedef const char* (*callback2)(int rc, long L, const char* buffer);
|
||||
|
||||
int aw_callback_set (AW_CALLBACK c, callback_t callback );
|
||||
int aw_instance_callback_set (AW_CALLBACK c, callback_t callback);
|
||||
|
||||
unsigned long int wawa;
|
||||
|
||||
#define MAX(x, y) ((x) < (y)? (y) : (x))
|
||||
|
||||
#define AW_BUILD 85 // AW 5.0
|
||||
// Limits
|
||||
#define AW_MAX_AVCHANGE_PER_SECOND 10
|
||||
|
||||
#private expatDll
|
||||
|
||||
#if !defined(expatDll)
|
||||
# if defined(windows)
|
||||
# define expatDll "expat.dll"
|
||||
# elif defined(macosx)
|
||||
# define expatDll "libexpat.dynlib"
|
||||
# else
|
||||
# define expatDll "libexpat.so(.1|)"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#mangle "'XML_'{.*}" "$1"
|
||||
#private "'XML_ParserStruct'"
|
||||
|
||||
#mangle cuint cint
|
||||
|
||||
unsigned int uiVar;
|
||||
|
||||
#private "@('_'!.)"
|
||||
unsigned int myPrivateVar__;
|
||||
|
||||
|
||||
struct XML_ParserStruct;
|
||||
|
||||
#def XMLCALL __cdecl
|
||||
|
||||
typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData,
|
||||
const XML_Char *name,
|
||||
XML_Content *model);
|
||||
|
||||
|
||||
void* x;
|
||||
void* fn(void);
|
||||
void (*fn)(void);
|
||||
void* (*fn)(void);
|
||||
void* (*fn)(void*);
|
||||
|
||||
/*
|
||||
* Very ugly real world code ahead:
|
||||
*/
|
||||
|
||||
#def JMETHOD(rettype, name, params) rettype (*name) params
|
||||
|
||||
typedef struct cjpeg_source_struct * cjpeg_source_ptr;
|
||||
|
||||
struct cjpeg_source_struct {
|
||||
JMETHOD(void, start_input, (j_compress_ptr cinfo,
|
||||
cjpeg_source_ptr sinfo));
|
||||
JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,
|
||||
cjpeg_source_ptr sinfo));
|
||||
JMETHOD(void, finish_input, (j_compress_ptr cinfo,
|
||||
cjpeg_source_ptr sinfo));
|
||||
|
||||
FILE *input_file;
|
||||
|
||||
JSAMPARRAY buffer;
|
||||
JDIMENSION buffer_height;
|
||||
};
|
||||
|
||||
// Test standalone structs:
|
||||
|
||||
union myunion {
|
||||
char x, y, *z;
|
||||
myint a, b;
|
||||
} u;
|
||||
|
||||
struct mystruct {
|
||||
char x, y, *z;
|
||||
myint a, b;
|
||||
};
|
||||
|
||||
struct mystruct fn(i32 x, i64 y);
|
||||
|
||||
struct mystruct {
|
||||
char x, y, *z;
|
||||
myint a, b;
|
||||
} *myvar = NULL, **myvar2 = NULL;
|
||||
|
||||
// anonymous struct:
|
||||
|
||||
struct {
|
||||
char x, y, *z;
|
||||
myint a, b;
|
||||
} varX, **varY;
|
||||
|
||||
// empty anonymous struct:
|
||||
|
||||
struct {
|
||||
|
||||
} varX, **varY;
|
||||
|
||||
// Test C2NIM skipping:
|
||||
|
||||
#define MASK(x) ((x) & 0xff)
|
||||
#define CAST1(x) ((int) &x)
|
||||
#define CAST2(x) (typ*) &x
|
||||
#define CAST3(x) ((const unsigned char**) &x)
|
||||
|
||||
#ifndef C2NIM
|
||||
#if someNestedCond
|
||||
This is an invalid text that should generate a parser error, if not
|
||||
#endif
|
||||
skipped correctly.
|
||||
#endif
|
||||
|
||||
#ifndef C2NIM
|
||||
#if someNestedCond
|
||||
This is an invalid text that should generate a parser error, if not
|
||||
#endif
|
||||
skipped correctly.
|
||||
#else
|
||||
typedef char gchar;
|
||||
typedef unsigned int gunsignedint;
|
||||
typedef unsigned char guchar;
|
||||
#endif
|
||||
|
||||
#ifdef C2NIM
|
||||
# mangle "'those'" "these"
|
||||
int those;
|
||||
#elif abc
|
||||
#if someNestedCond
|
||||
This is an invalid text that should generate a parser error, if not
|
||||
#else
|
||||
skipped correctly.
|
||||
#endif
|
||||
#else
|
||||
Another crappy input line.
|
||||
#endif
|
||||
|
||||
point* newPoint(void) {
|
||||
for (int i = 0; i < 89; ++i) echo("test" " string " "concatenation");
|
||||
for (; j < 54; j++) {}
|
||||
for (;; j--) ;
|
||||
for (;;) {}
|
||||
mytype * x = y * z;
|
||||
|
||||
if (**p == ' ') {
|
||||
--p;
|
||||
} else if (**p == '\t') {
|
||||
p += 3;
|
||||
} else {
|
||||
p = 45 + (mytype*)45;
|
||||
p = 45 + ((mytype*)45);
|
||||
p = 45 + ((mytype)45);
|
||||
// BUG: This does not parse:
|
||||
// p = 45 + (mytype)45;
|
||||
}
|
||||
|
||||
while (x >= 6 && x <= 20)
|
||||
--x;
|
||||
|
||||
switch (*p) {
|
||||
case 'A'...'Z':
|
||||
case 'a'...'z':
|
||||
++p;
|
||||
break;
|
||||
case '0':
|
||||
++p;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
a1, a2 = 4, a3
|
||||
};
|
||||
|
||||
typedef enum crazyTAG {
|
||||
x1, x2, x3 = 8, x4, x5
|
||||
} myEnum, *pMyEnum;
|
||||
|
||||
typedef enum {
|
||||
x1, x2, x3 = 8, x4, x5
|
||||
} myEnum, *pMyEnum;
|
||||
|
||||
// Test multi-line macro:
|
||||
|
||||
#define MUILTILINE "abc" \
|
||||
"xyz" \
|
||||
"def"
|
||||
|
||||
#define MULTILINE(x, y) do { \
|
||||
++y; ++x; \
|
||||
} while (0)
|
||||
|
||||
#ifdef C2NIM
|
||||
# dynlib iupdll
|
||||
# cdecl
|
||||
# mangle "'GTK_'{.*}" "TGtk$1"
|
||||
# mangle "'PGTK_'{.*}" "PGtk$1"
|
||||
# if defined(windows)
|
||||
# define iupdll "iup.dll"
|
||||
# elif defined(macosx)
|
||||
# define iupdll "libiup.dynlib"
|
||||
# else
|
||||
# define iupdll "libiup.so"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef struct stupidTAG {
|
||||
mytype a, b;
|
||||
} GTK_MyStruct, *PGTK_MyStruct;
|
||||
|
||||
typedef struct {
|
||||
mytype a, b;
|
||||
} GTK_MyStruct, *PGTK_MyStruct;
|
||||
|
||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
||||
|
||||
#ifdef DEBUG
|
||||
# define OUT(x) printf("%s\n", x)
|
||||
#else
|
||||
# define OUT(x)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef C2NIM
|
||||
# def EXTERN(x) static x
|
||||
# def TWO_ARGS(x, y) x* y
|
||||
#endif
|
||||
// parses now!
|
||||
EXTERN(int) f(void);
|
||||
EXTERN(int) g(void);
|
||||
|
||||
|
||||
#def EXPORT
|
||||
// does parse now!
|
||||
EXPORT int f(void);
|
||||
EXPORT int g(void);
|
||||
|
||||
static TWO_ARGS(int, x) = TWO_ARGS(56, 45);
|
||||
|
||||
|
||||
# define abc 34
|
||||
# define xyz 42
|
||||
|
||||
# define wuseldusel "my string\nconstant"
|
||||
|
||||
#undef ignoreThis
|
||||
|
||||
char* x;
|
||||
|
||||
typedef struct {
|
||||
char x, y, *z;
|
||||
} point;
|
||||
|
||||
char* __stdcall printf(char* frmt, const char* const** ptrToStrArray,
|
||||
const int* const dummy, ...);
|
||||
|
||||
inline char* myinlineProc(char* frmt, const char* const* strArray,
|
||||
const int* const dummy, ...);
|
||||
|
||||
// Test void parameter list:
|
||||
void myVoidProc(void);
|
||||
|
||||
void emptyReturn(void) { return; }
|
||||
|
||||
// POSIX stuff:
|
||||
|
||||
#ifdef C2NIM
|
||||
#prefix posix_
|
||||
int c2nimBranch;
|
||||
#elif defined(MACOSX)
|
||||
int* x, y, z;
|
||||
#else
|
||||
int dummy;
|
||||
#endif
|
||||
|
||||
#ifndef C2NIM
|
||||
int dontTranslateThis;
|
||||
#elif defined(Windows)
|
||||
int WindowsTrue = true;
|
||||
#endif
|
||||
|
||||
int posix_spawn(pid_t *restrict, const char *restrict,
|
||||
const posix_spawn_file_actions_t *,
|
||||
const posix_spawnattr_t *restrict, char *const [restrict],
|
||||
char *const [restrict]);
|
||||
int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *,
|
||||
int);
|
||||
int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *,
|
||||
int, int);
|
||||
int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *restrict,
|
||||
int, const char *restrict, int, mode_t);
|
||||
int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *);
|
||||
int posix_spawn_file_actions_init(posix_spawn_file_actions_t *);
|
||||
int posix_spawnattr_destroy(posix_spawnattr_t *);
|
||||
int posix_spawnattr_getsigdefault(const posix_spawnattr_t *restrict,
|
||||
sigset_t *restrict);
|
||||
int posix_spawnattr_getflags(const posix_spawnattr_t *restrict,
|
||||
short *restrict);
|
||||
int posix_spawnattr_getpgroup(const posix_spawnattr_t *restrict,
|
||||
pid_t *restrict);
|
||||
int posix_spawnattr_getschedparam(const posix_spawnattr_t *restrict,
|
||||
struct sched_param *restrict);
|
||||
int posix_spawnattr_getschedpolicy(const posix_spawnattr_t *restrict,
|
||||
int *restrict);
|
||||
int posix_spawnattr_getsigmask(const posix_spawnattr_t *restrict,
|
||||
sigset_t *restrict);
|
||||
int posix_spawnattr_init(posix_spawnattr_t *);
|
||||
int posix_spawnattr_setsigdefault(posix_spawnattr_t *restrict,
|
||||
const sigset_t *restrict);
|
||||
int posix_spawnattr_setflags(posix_spawnattr_t *, short);
|
||||
int posix_spawnattr_setpgroup(posix_spawnattr_t *, pid_t);
|
||||
|
||||
|
||||
int posix_spawnattr_setschedparam(posix_spawnattr_t *restrict,
|
||||
const struct sched_param *restrict);
|
||||
int posix_spawnattr_setschedpolicy(posix_spawnattr_t *, int);
|
||||
int posix_spawnattr_setsigmask(posix_spawnattr_t *restrict,
|
||||
const sigset_t *restrict);
|
||||
int posix_spawnp(pid_t *restrict, const char *restrict,
|
||||
const posix_spawn_file_actions_t *,
|
||||
const posix_spawnattr_t *restrict,
|
||||
char *const [restrict], char *const [restrict]);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float R, G, B;
|
||||
}
|
||||
RGBType;
|
||||
typedef struct
|
||||
{
|
||||
float H, W, B;
|
||||
}
|
||||
HWBType;
|
||||
|
||||
static HWBType *
|
||||
RGB_to_HWB (RGBType RGB, HWBType * HWB)
|
||||
{
|
||||
HWBType* myArray[20];
|
||||
/*
|
||||
* RGB are each on [0, 1]. W and B are returned on [0, 1] and H is
|
||||
* returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.
|
||||
*/
|
||||
|
||||
float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
|
||||
int i;
|
||||
|
||||
w = MIN3 (R, G, B);
|
||||
v = MAX3 (R, G, B);
|
||||
b &= 1 - v;
|
||||
if (v == w)
|
||||
RETURN_HWB (HWB_UNDEFINED, w, b);
|
||||
f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
|
||||
i = (R == w) ? 3 : ((G == w) ? 5 : 1);
|
||||
RETURN_HWB (i - f / (v - w), w, b);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
clip_1d (int *x0, int *y0, int *x1, int *y1, int mindim, int maxdim)
|
||||
{
|
||||
double m; // gradient of line
|
||||
if (*x0 < mindim)
|
||||
{ // start of line is left of window
|
||||
if (*x1 < mindim) // as is the end, so the line never cuts the window
|
||||
return 0;
|
||||
m = (*y1 - *y0) / (double) (*x1 - *x0); // calculate the slope of the line
|
||||
// adjust x0 to be on the left boundary (ie to be zero), and y0 to match
|
||||
*y0 -= m * (*x0 - mindim);
|
||||
*x0 = mindim;
|
||||
// now, perhaps, adjust the far end of the line as well
|
||||
if (*x1 > maxdim)
|
||||
{
|
||||
*y1 += m * (maxdim - *x1);
|
||||
*x1 = maxdim;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (*x0 > maxdim)
|
||||
{ // start of line is right of window - complement of above
|
||||
if (*x1 > maxdim) // as is the end, so the line misses the window
|
||||
return 0;
|
||||
m = (*y1 - *y0) / (double) (*x1 - *x0); // calculate the slope of the line
|
||||
*y0 += m * (maxdim - *x0); // adjust so point is on the right
|
||||
// boundary
|
||||
*x0 = maxdim;
|
||||
// now, perhaps, adjust the end of the line
|
||||
if (*x1 < mindim)
|
||||
{
|
||||
*y1 -= m * (*x1 - mindim);
|
||||
*x1 = mindim;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// the final case - the start of the line is inside the window
|
||||
if (*x1 > maxdim)
|
||||
{ // other end is outside to the right
|
||||
m = (*y1 - *y0) / (double) (*x1 - *x0); // calculate the slope of the line
|
||||
*y1 += m * (maxdim - *x1);
|
||||
*x1 = maxdim;
|
||||
return 1;
|
||||
}
|
||||
if (*x1 < mindim)
|
||||
{ // other end is outside to the left
|
||||
m = (*y1 - *y0) / (double) (*x1 - *x0); // calculate the slope of line
|
||||
*y1 -= m * (*x1 - mindim);
|
||||
*x1 = mindim;
|
||||
return 1;
|
||||
}
|
||||
// only get here if both points are inside the window
|
||||
return 1;
|
||||
}
|
||||
|
||||
// end of line clipping code
|
||||
|
||||
static void
|
||||
gdImageBrushApply (gdImagePtr im, int x, int y)
|
||||
{
|
||||
int lx, ly;
|
||||
int hy;
|
||||
int hx;
|
||||
int x1, y1, x2, y2;
|
||||
int srcx, srcy;
|
||||
if (!im->brush)
|
||||
{
|
||||
return;
|
||||
}
|
||||
hy = gdImageSY (im->brush) / 2;
|
||||
y1 = y - hy;
|
||||
y2 = y1 + gdImageSY (im->brush);
|
||||
hx = gdImageSX (im->brush) / 2;
|
||||
x1 = x - hx;
|
||||
x2 = x1 + gdImageSX (im->brush);
|
||||
srcy = 0;
|
||||
if (im->trueColor)
|
||||
{
|
||||
if (im->brush->trueColor)
|
||||
{
|
||||
for (ly = y1; (ly < y2); ly++)
|
||||
{
|
||||
srcx = 0;
|
||||
for (lx = x1; (lx < x2); lx++)
|
||||
{
|
||||
int p;
|
||||
p = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
|
||||
// 2.0.9, Thomas Winzig: apply simple full transparency
|
||||
if (p != gdImageGetTransparent (im->brush))
|
||||
{
|
||||
gdImageSetPixel (im, lx, ly, p);
|
||||
}
|
||||
srcx++;
|
||||
}
|
||||
srcy++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger
|
||||
// for pointing out the issue)
|
||||
for (ly = y1; (ly < y2); ly++)
|
||||
{
|
||||
srcx = 0;
|
||||
for (lx = x1; (lx < x2); lx++)
|
||||
{
|
||||
int p, tc;
|
||||
p = gdImageGetPixel (im->brush, srcx, srcy);
|
||||
tc = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
|
||||
// 2.0.9, Thomas Winzig: apply simple full transparency
|
||||
if (p != gdImageGetTransparent (im->brush))
|
||||
{
|
||||
gdImageSetPixel (im, lx, ly, tc);
|
||||
}
|
||||
srcx++;
|
||||
}
|
||||
srcy++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (ly = y1; (ly < y2); ly++)
|
||||
{
|
||||
srcx = 0;
|
||||
for (lx = x1; (lx < x2); lx++)
|
||||
{
|
||||
int p;
|
||||
p = gdImageGetPixel (im->brush, srcx, srcy);
|
||||
// Allow for non-square brushes!
|
||||
if (p != gdImageGetTransparent (im->brush))
|
||||
{
|
||||
// Truecolor brush. Very slow
|
||||
// on a palette destination.
|
||||
if (im->brush->trueColor)
|
||||
{
|
||||
gdImageSetPixel (im, lx, ly,
|
||||
gdImageColorResolveAlpha(im,
|
||||
gdTrueColorGetRed(p),
|
||||
gdTrueColorGetGreen(p),
|
||||
gdTrueColorGetBlue(p),
|
||||
gdTrueColorGetAlpha(p)));
|
||||
}
|
||||
else
|
||||
{
|
||||
gdImageSetPixel (im, lx, ly, im->brushColorMap[p]);
|
||||
}
|
||||
}
|
||||
srcx++;
|
||||
}
|
||||
srcy++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void gdImageSetPixel (gdImagePtr im, int x, int y, int color)
|
||||
{
|
||||
int p;
|
||||
switch (color)
|
||||
{
|
||||
case gdStyled:
|
||||
if (!im->style)
|
||||
{
|
||||
// Refuse to draw if no style is set.
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = im->style[im->stylePos++];
|
||||
}
|
||||
if (p != (gdTransparent))
|
||||
{
|
||||
gdImageSetPixel (im, x, y, p);
|
||||
}
|
||||
im->stylePos = im->stylePos % im->styleLength;
|
||||
break;
|
||||
case gdStyledBrushed:
|
||||
if (!im->style)
|
||||
{
|
||||
// Refuse to draw if no style is set.
|
||||
return;
|
||||
}
|
||||
p = im->style[im->stylePos++];
|
||||
if ((p != gdTransparent) && (p != 0))
|
||||
{
|
||||
gdImageSetPixel (im, x, y, gdBrushed);
|
||||
}
|
||||
im->stylePos = im->stylePos % im->styleLength;
|
||||
break;
|
||||
case gdBrushed:
|
||||
gdImageBrushApply (im, x, y);
|
||||
break;
|
||||
case gdTiled:
|
||||
gdImageTileApply (im, x, y);
|
||||
break;
|
||||
case gdAntiAliased:
|
||||
// This shouldn't happen (2.0.26) because we just call
|
||||
// gdImageAALine now, but do something sane.
|
||||
gdImageSetPixel(im, x, y, im->AA_color);
|
||||
break;
|
||||
default:
|
||||
if (gdImageBoundsSafeMacro (im, x, y))
|
||||
{
|
||||
if (im->trueColor)
|
||||
{
|
||||
if (im->alphaBlendingFlag)
|
||||
{
|
||||
im->tpixels[y][x] = gdAlphaBlend (im->tpixels[y][x], color);
|
||||
}
|
||||
else
|
||||
{
|
||||
im->tpixels[y][x] = color;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
im->pixels[y][x] = color;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#ifdef C2NIM
|
||||
# header "iup.h"
|
||||
# cdecl
|
||||
# mangle "'GTK_'{.*}" "TGtk$1"
|
||||
# mangle "'PGTK_'{.*}" "PGtk$1"
|
||||
#endif
|
||||
|
||||
typedef struct stupidTAG {
|
||||
mytype a, b;
|
||||
} GTK_MyStruct, *PGTK_MyStruct;
|
||||
|
||||
typedef struct {
|
||||
mytype a, b;
|
||||
} GTK_MyStruct, *PGTK_MyStruct;
|
||||
|
||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int rand(void);
|
||||
|
||||
int id2(void) {
|
||||
return (int *)1;
|
||||
}
|
||||
|
||||
int id(void (*f)(void)) {
|
||||
f();
|
||||
((void (*)(int))f)(10);
|
||||
return 10;
|
||||
return (20+1);
|
||||
return (int *)id;
|
||||
}
|
||||
|
||||
int main() {
|
||||
float f = .2,
|
||||
g = 2.,
|
||||
h = 1.0+rand(),
|
||||
i = 1.0e+3;
|
||||
int j, a;
|
||||
for(j = 0, a = 10; j < 0; j++, a++) ;
|
||||
do {
|
||||
printf("howdy");
|
||||
} while(--i, 0);
|
||||
if(1)
|
||||
printf("1"); // error from this comment
|
||||
else
|
||||
printf("2");
|
||||
return '\x00';
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
struct foo {
|
||||
int x,y,z;
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
# Use the modules of the compiler
|
||||
|
||||
path: "$nimrod/compiler"
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
#
|
||||
#
|
||||
# Pas2nim - Pascal to Nimrod source converter
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import
|
||||
strutils, os, parseopt, llstream, ast, renderer, options, msgs,
|
||||
paslex, pasparse
|
||||
|
||||
const
|
||||
Version = "0.8"
|
||||
Usage = """
|
||||
pas2nim - Pascal to Nimrod source converter
|
||||
(c) 2012 Andreas Rumpf
|
||||
Usage: pas2nim [options] inputfile [options]
|
||||
Options:
|
||||
-o, --out:FILE set output filename
|
||||
--ref convert ^typ to ref typ (default: ptr typ)
|
||||
--boot use special translation rules for the Nimrod compiler
|
||||
-v, --version write pas2nim's version
|
||||
-h, --help show this help
|
||||
"""
|
||||
|
||||
proc main(infile, outfile: string, flags: set[TParserFlag]) =
|
||||
var stream = llStreamOpen(infile, fmRead)
|
||||
if stream == nil: rawMessage(errCannotOpenFile, infile)
|
||||
var p: TParser
|
||||
openParser(p, infile, stream, flags)
|
||||
var module = parseUnit(p)
|
||||
closeParser(p)
|
||||
renderModule(module, outfile)
|
||||
|
||||
var
|
||||
infile = ""
|
||||
outfile = ""
|
||||
flags: set[TParserFlag] = {}
|
||||
for kind, key, val in getopt():
|
||||
case kind
|
||||
of cmdArgument: infile = key
|
||||
of cmdLongOption, cmdShortOption:
|
||||
case key
|
||||
of "help", "h":
|
||||
stdout.write(Usage)
|
||||
quit(0)
|
||||
of "version", "v":
|
||||
stdout.write(Version & "\n")
|
||||
quit(0)
|
||||
of "o", "out": outfile = val
|
||||
of "ref": incl(flags, pfRefs)
|
||||
of "boot": flags = flags + {pfRefs, pfMoreReplacements, pfImportBlackList}
|
||||
else: stdout.writeln("[Error] unknown option: " & key)
|
||||
of cmdEnd: assert(false)
|
||||
if infile.len == 0:
|
||||
# no filename has been given, so we show the help:
|
||||
stdout.write(Usage)
|
||||
else:
|
||||
if outfile.len == 0:
|
||||
outfile = changeFileExt(infile, "nim")
|
||||
infile = addFileExt(infile, "pas")
|
||||
main(infile, outfile, flags)
|
||||
@@ -1,570 +0,0 @@
|
||||
#
|
||||
#
|
||||
# Pas2nim - Pascal to Nimrod source converter
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# This module implements a FreePascal scanner. This is an adaption from
|
||||
# the scanner module.
|
||||
|
||||
import
|
||||
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream
|
||||
|
||||
const
|
||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
||||
numChars*: TCharSet = {'0'..'9', 'a'..'z', 'A'..'Z'}
|
||||
SymChars*: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
|
||||
SymStartChars*: TCharSet = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
|
||||
OpChars*: TCharSet = {'+', '-', '*', '/', '<', '>', '!', '?', '^', '.', '|',
|
||||
'=', ':', '%', '&', '$', '@', '~', '\x80'..'\xFF'}
|
||||
|
||||
# keywords are sorted!
|
||||
|
||||
type
|
||||
TTokKind* = enum
|
||||
pxInvalid, pxEof,
|
||||
pxAnd, pxArray, pxAs, pxAsm, pxBegin, pxCase, pxClass, pxConst,
|
||||
pxConstructor, pxDestructor, pxDiv, pxDo, pxDownto, pxElse, pxEnd, pxExcept,
|
||||
pxExports, pxFinalization, pxFinally, pxFor, pxFunction, pxGoto, pxIf,
|
||||
pxImplementation, pxIn, pxInherited, pxInitialization, pxInline,
|
||||
pxInterface, pxIs, pxLabel, pxLibrary, pxMod, pxNil, pxNot, pxObject, pxOf,
|
||||
pxOr, pxOut, pxPacked, pxProcedure, pxProgram, pxProperty, pxRaise,
|
||||
pxRecord, pxRepeat, pxResourcestring, pxSet, pxShl, pxShr, pxThen,
|
||||
pxThreadvar, pxTo, pxTry, pxType, pxUnit, pxUntil, pxUses, pxVar, pxWhile,
|
||||
pxWith, pxXor,
|
||||
pxComment, # ordinary comment
|
||||
pxCommand, # {@}
|
||||
pxAmp, # {&}
|
||||
pxPer, # {%}
|
||||
pxStrLit, pxSymbol, # a symbol
|
||||
pxIntLit, pxInt64Lit, # long constant like 0x70fffffff or out of int range
|
||||
pxFloatLit, pxParLe, pxParRi, pxBracketLe, pxBracketRi, pxComma,
|
||||
pxSemiColon, pxColon, # operators
|
||||
pxAsgn, pxEquals, pxDot, pxDotDot, pxHat, pxPlus, pxMinus, pxStar, pxSlash,
|
||||
pxLe, pxLt, pxGe, pxGt, pxNeq, pxAt, pxStarDirLe, pxStarDirRi, pxCurlyDirLe,
|
||||
pxCurlyDirRi
|
||||
TTokKinds* = set[TTokKind]
|
||||
|
||||
const
|
||||
Keywords = ["and", "array", "as", "asm", "begin", "case", "class", "const",
|
||||
"constructor", "destructor", "div", "do", "downto", "else", "end", "except",
|
||||
"exports", "finalization", "finally", "for", "function", "goto", "if",
|
||||
"implementation", "in", "inherited", "initialization", "inline",
|
||||
"interface", "is", "label", "library", "mod", "nil", "not", "object", "of",
|
||||
"or", "out", "packed", "procedure", "program", "property", "raise",
|
||||
"record", "repeat", "resourcestring", "set", "shl", "shr", "then",
|
||||
"threadvar", "to", "try", "type", "unit", "until", "uses", "var", "while",
|
||||
"with", "xor"]
|
||||
|
||||
firstKeyword = pxAnd
|
||||
lastKeyword = pxXor
|
||||
|
||||
type
|
||||
TNumericalBase* = enum base10, base2, base8, base16
|
||||
TToken* = object
|
||||
xkind*: TTokKind # the type of the token
|
||||
ident*: PIdent # the parsed identifier
|
||||
iNumber*: BiggestInt # the parsed integer literal
|
||||
fNumber*: BiggestFloat # the parsed floating point literal
|
||||
base*: TNumericalBase # the numerical base; only valid for int
|
||||
# or float literals
|
||||
literal*: string # the parsed (string) literal
|
||||
|
||||
TLexer* = object of TBaseLexer
|
||||
filename*: string
|
||||
|
||||
|
||||
proc getTok*(L: var TLexer, tok: var TToken)
|
||||
proc printTok*(tok: TToken)
|
||||
proc `$`*(tok: TToken): string
|
||||
# implementation
|
||||
|
||||
var
|
||||
dummyIdent: PIdent
|
||||
gLinesCompiled: int
|
||||
|
||||
proc fillToken(L: var TToken) =
|
||||
L.xkind = pxInvalid
|
||||
L.iNumber = 0
|
||||
L.literal = ""
|
||||
L.fNumber = 0.0
|
||||
L.base = base10
|
||||
L.ident = dummyIdent # this prevents many bugs!
|
||||
|
||||
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
||||
openBaseLexer(lex, inputstream)
|
||||
lex.filename = filename
|
||||
|
||||
proc closeLexer*(lex: var TLexer) =
|
||||
inc(gLinesCompiled, lex.LineNumber)
|
||||
closeBaseLexer(lex)
|
||||
|
||||
proc getColumn(L: TLexer): int =
|
||||
result = getColNumber(L, L.bufPos)
|
||||
|
||||
proc getLineInfo*(L: TLexer): TLineInfo =
|
||||
result = newLineInfo(L.filename, L.linenumber, getColNumber(L, L.bufpos))
|
||||
|
||||
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
|
||||
msgs.globalError(getLineInfo(L), msg, arg)
|
||||
|
||||
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||
var info = newLineInfo(L.filename, L.linenumber, pos - L.lineStart)
|
||||
msgs.globalError(info, msg, arg)
|
||||
|
||||
proc tokKindToStr*(k: TTokKind): string =
|
||||
case k
|
||||
of pxEof: result = "[EOF]"
|
||||
of firstKeyword..lastKeyword:
|
||||
result = Keywords[ord(k)-ord(firstKeyword)]
|
||||
of pxInvalid, pxComment, pxStrLit: result = "string literal"
|
||||
of pxCommand: result = "{@"
|
||||
of pxAmp: result = "{&"
|
||||
of pxPer: result = "{%"
|
||||
of pxSymbol: result = "identifier"
|
||||
of pxIntLit, pxInt64Lit: result = "integer literal"
|
||||
of pxFloatLit: result = "floating point literal"
|
||||
of pxParLe: result = "("
|
||||
of pxParRi: result = ")"
|
||||
of pxBracketLe: result = "["
|
||||
of pxBracketRi: result = "]"
|
||||
of pxComma: result = ","
|
||||
of pxSemiColon: result = ";"
|
||||
of pxColon: result = ":"
|
||||
of pxAsgn: result = ":="
|
||||
of pxEquals: result = "="
|
||||
of pxDot: result = "."
|
||||
of pxDotDot: result = ".."
|
||||
of pxHat: result = "^"
|
||||
of pxPlus: result = "+"
|
||||
of pxMinus: result = "-"
|
||||
of pxStar: result = "*"
|
||||
of pxSlash: result = "/"
|
||||
of pxLe: result = "<="
|
||||
of pxLt: result = "<"
|
||||
of pxGe: result = ">="
|
||||
of pxGt: result = ">"
|
||||
of pxNeq: result = "<>"
|
||||
of pxAt: result = "@"
|
||||
of pxStarDirLe: result = "(*$"
|
||||
of pxStarDirRi: result = "*)"
|
||||
of pxCurlyDirLe: result = "{$"
|
||||
of pxCurlyDirRi: result = "}"
|
||||
|
||||
proc `$`(tok: TToken): string =
|
||||
case tok.xkind
|
||||
of pxInvalid, pxComment, pxStrLit: result = tok.literal
|
||||
of pxSymbol: result = tok.ident.s
|
||||
of pxIntLit, pxInt64Lit: result = $tok.iNumber
|
||||
of pxFloatLit: result = $tok.fNumber
|
||||
else: result = tokKindToStr(tok.xkind)
|
||||
|
||||
proc printTok(tok: TToken) =
|
||||
writeln(stdout, $tok)
|
||||
|
||||
proc setKeyword(L: var TLexer, tok: var TToken) =
|
||||
var x = binaryStrSearch(keywords, toLower(tok.ident.s))
|
||||
if x < 0: tok.xkind = pxSymbol
|
||||
else: tok.xKind = TTokKind(x + ord(firstKeyword))
|
||||
|
||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
||||
# matches ([chars]_)*
|
||||
var pos = L.bufpos # use registers for pos, buf
|
||||
var buf = L.buf
|
||||
while true:
|
||||
if buf[pos] in chars:
|
||||
add(tok.literal, buf[pos])
|
||||
inc(pos)
|
||||
else:
|
||||
break
|
||||
if buf[pos] == '_':
|
||||
add(tok.literal, '_')
|
||||
inc(pos)
|
||||
L.bufPos = pos
|
||||
|
||||
proc isFloatLiteral(s: string): bool =
|
||||
for i in countup(0, len(s)-1):
|
||||
if s[i] in {'.', 'e', 'E'}:
|
||||
return true
|
||||
|
||||
proc getNumber2(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 1 # skip %
|
||||
if not (L.buf[pos] in {'0'..'1'}):
|
||||
# BUGFIX for %date%
|
||||
tok.xkind = pxInvalid
|
||||
add(tok.literal, '%')
|
||||
inc(L.bufpos)
|
||||
return
|
||||
tok.base = base2
|
||||
var xi: BiggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
of 'A'..'Z', 'a'..'z', '2'..'9', '.':
|
||||
lexMessage(L, errInvalidNumber)
|
||||
inc(pos)
|
||||
of '_':
|
||||
inc(pos)
|
||||
of '0', '1':
|
||||
xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
inc(bits)
|
||||
else: break
|
||||
tok.iNumber = xi
|
||||
if (bits > 32): tok.xkind = pxInt64Lit
|
||||
else: tok.xkind = pxIntLit
|
||||
L.bufpos = pos
|
||||
|
||||
proc getNumber16(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos + 1 # skip $
|
||||
tok.base = base16
|
||||
var xi: BiggestInt = 0
|
||||
var bits = 0
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
of 'G'..'Z', 'g'..'z', '.':
|
||||
lexMessage(L, errInvalidNumber)
|
||||
inc(pos)
|
||||
of '_': inc(pos)
|
||||
of '0'..'9':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
inc(bits, 4)
|
||||
of 'a'..'f':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('a') + 10)
|
||||
inc(pos)
|
||||
inc(bits, 4)
|
||||
of 'A'..'F':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
|
||||
inc(pos)
|
||||
inc(bits, 4)
|
||||
else: break
|
||||
tok.iNumber = xi
|
||||
if (bits > 32):
|
||||
tok.xkind = pxInt64Lit
|
||||
else:
|
||||
tok.xkind = pxIntLit
|
||||
L.bufpos = pos
|
||||
|
||||
proc getNumber10(L: var TLexer, tok: var TToken) =
|
||||
tok.base = base10
|
||||
matchUnderscoreChars(L, tok, {'0'..'9'})
|
||||
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
|
||||
add(tok.literal, '.')
|
||||
inc(L.bufpos)
|
||||
matchUnderscoreChars(L, tok, {'e', 'E', '+', '-', '0'..'9'})
|
||||
try:
|
||||
if isFloatLiteral(tok.literal):
|
||||
tok.fnumber = parseFloat(tok.literal)
|
||||
tok.xkind = pxFloatLit
|
||||
else:
|
||||
tok.iNumber = parseInt(tok.literal)
|
||||
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)):
|
||||
tok.xkind = pxInt64Lit
|
||||
else:
|
||||
tok.xkind = pxIntLit
|
||||
except EInvalidValue:
|
||||
lexMessage(L, errInvalidNumber, tok.literal)
|
||||
except EOverflow:
|
||||
lexMessage(L, errNumberOutOfRange, tok.literal)
|
||||
|
||||
proc handleCRLF(L: var TLexer, pos: int): int =
|
||||
case L.buf[pos]
|
||||
of CR: result = nimlexbase.handleCR(L, pos)
|
||||
of LF: result = nimlexbase.handleLF(L, pos)
|
||||
else: result = pos
|
||||
|
||||
proc getString(L: var TLexer, tok: var TToken) =
|
||||
var xi: int
|
||||
var pos = L.bufPos
|
||||
var buf = L.buf
|
||||
while true:
|
||||
if buf[pos] == '\'':
|
||||
inc(pos)
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR, LF, nimlexbase.EndOfFile:
|
||||
lexMessage(L, errClosingQuoteExpected)
|
||||
break
|
||||
of '\'':
|
||||
inc(pos)
|
||||
if buf[pos] == '\'':
|
||||
inc(pos)
|
||||
add(tok.literal, '\'')
|
||||
else:
|
||||
break
|
||||
else:
|
||||
add(tok.literal, buf[pos])
|
||||
inc(pos)
|
||||
elif buf[pos] == '#':
|
||||
inc(pos)
|
||||
xi = 0
|
||||
case buf[pos]
|
||||
of '$':
|
||||
inc(pos)
|
||||
xi = 0
|
||||
while true:
|
||||
case buf[pos]
|
||||
of '0'..'9': xi = (xi shl 4) or (ord(buf[pos]) - ord('0'))
|
||||
of 'a'..'f': xi = (xi shl 4) or (ord(buf[pos]) - ord('a') + 10)
|
||||
of 'A'..'F': xi = (xi shl 4) or (ord(buf[pos]) - ord('A') + 10)
|
||||
else: break
|
||||
inc(pos)
|
||||
of '0'..'9':
|
||||
xi = 0
|
||||
while buf[pos] in {'0'..'9'}:
|
||||
xi = (xi * 10) + (ord(buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
else: lexMessage(L, errInvalidCharacterConstant)
|
||||
if (xi <= 255): add(tok.literal, chr(xi))
|
||||
else: lexMessage(L, errInvalidCharacterConstant)
|
||||
else:
|
||||
break
|
||||
tok.xkind = pxStrLit
|
||||
L.bufpos = pos
|
||||
|
||||
proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||
var h: THash = 0
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
while true:
|
||||
var c = buf[pos]
|
||||
case c
|
||||
of 'a'..'z', '0'..'9', '\x80'..'\xFF':
|
||||
h = h +% ord(c)
|
||||
h = h +% h shl 10
|
||||
h = h xor (h shr 6)
|
||||
of 'A'..'Z':
|
||||
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
|
||||
h = h +% ord(c)
|
||||
h = h +% h shl 10
|
||||
h = h xor (h shr 6)
|
||||
of '_': discard
|
||||
else: break
|
||||
inc(pos)
|
||||
h = h +% h shl 3
|
||||
h = h xor (h shr 11)
|
||||
h = h +% h shl 15
|
||||
tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
|
||||
L.bufpos = pos
|
||||
setKeyword(L, tok)
|
||||
|
||||
proc scanLineComment(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
# a comment ends if the next line does not start with the // on the same
|
||||
# column after only whitespace
|
||||
tok.xkind = pxComment
|
||||
var col = getColNumber(L, pos)
|
||||
while true:
|
||||
inc(pos, 2) # skip //
|
||||
add(tok.literal, '#')
|
||||
while not (buf[pos] in {CR, LF, nimlexbase.EndOfFile}):
|
||||
add(tok.literal, buf[pos])
|
||||
inc(pos)
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
var indent = 0
|
||||
while buf[pos] == ' ':
|
||||
inc(pos)
|
||||
inc(indent)
|
||||
if (col == indent) and (buf[pos] == '/') and (buf[pos + 1] == '/'):
|
||||
tok.literal = tok.literal & "\n"
|
||||
else:
|
||||
break
|
||||
L.bufpos = pos
|
||||
|
||||
proc scanCurlyComment(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
tok.literal = "#"
|
||||
tok.xkind = pxComment
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR, LF:
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
add(tok.literal, "\n#")
|
||||
of '}':
|
||||
inc(pos)
|
||||
break
|
||||
of nimlexbase.EndOfFile: lexMessage(L, errTokenExpected, "}")
|
||||
else:
|
||||
add(tok.literal, buf[pos])
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
|
||||
proc scanStarComment(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
tok.literal = "#"
|
||||
tok.xkind = pxComment
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR, LF:
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
add(tok.literal, "\n#")
|
||||
of '*':
|
||||
inc(pos)
|
||||
if buf[pos] == ')':
|
||||
inc(pos)
|
||||
break
|
||||
else:
|
||||
add(tok.literal, '*')
|
||||
of nimlexbase.EndOfFile:
|
||||
lexMessage(L, errTokenExpected, "*)")
|
||||
else:
|
||||
add(tok.literal, buf[pos])
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
|
||||
proc skip(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
while true:
|
||||
case buf[pos]
|
||||
of ' ', Tabulator:
|
||||
inc(pos) # newline is special:
|
||||
of CR, LF:
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
else:
|
||||
break # EndOfFile also leaves the loop
|
||||
L.bufpos = pos
|
||||
|
||||
proc getTok(L: var TLexer, tok: var TToken) =
|
||||
tok.xkind = pxInvalid
|
||||
fillToken(tok)
|
||||
skip(L, tok)
|
||||
var c = L.buf[L.bufpos]
|
||||
if c in SymStartChars:
|
||||
getSymbol(L, tok)
|
||||
elif c in {'0'..'9'}:
|
||||
getNumber10(L, tok)
|
||||
else:
|
||||
case c
|
||||
of ';':
|
||||
tok.xkind = pxSemicolon
|
||||
inc(L.bufpos)
|
||||
of '/':
|
||||
if L.buf[L.bufpos + 1] == '/':
|
||||
scanLineComment(L, tok)
|
||||
else:
|
||||
tok.xkind = pxSlash
|
||||
inc(L.bufpos)
|
||||
of ',':
|
||||
tok.xkind = pxComma
|
||||
inc(L.bufpos)
|
||||
of '(':
|
||||
inc(L.bufpos)
|
||||
if (L.buf[L.bufPos] == '*'):
|
||||
if (L.buf[L.bufPos + 1] == '$'):
|
||||
inc(L.bufpos, 2)
|
||||
skip(L, tok)
|
||||
getSymbol(L, tok)
|
||||
tok.xkind = pxStarDirLe
|
||||
else:
|
||||
inc(L.bufpos)
|
||||
scanStarComment(L, tok)
|
||||
else:
|
||||
tok.xkind = pxParLe
|
||||
of '*':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == ')':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxStarDirRi
|
||||
else:
|
||||
tok.xkind = pxStar
|
||||
of ')':
|
||||
tok.xkind = pxParRi
|
||||
inc(L.bufpos)
|
||||
of '[':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxBracketLe
|
||||
of ']':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxBracketRi
|
||||
of '.':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '.':
|
||||
tok.xkind = pxDotDot
|
||||
inc(L.bufpos)
|
||||
else:
|
||||
tok.xkind = pxDot
|
||||
of '{':
|
||||
inc(L.bufpos)
|
||||
case L.buf[L.bufpos]
|
||||
of '$':
|
||||
inc(L.bufpos)
|
||||
skip(L, tok)
|
||||
getSymbol(L, tok)
|
||||
tok.xkind = pxCurlyDirLe
|
||||
of '&':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxAmp
|
||||
of '%':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxPer
|
||||
of '@':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxCommand
|
||||
else: scanCurlyComment(L, tok)
|
||||
of '+':
|
||||
tok.xkind = pxPlus
|
||||
inc(L.bufpos)
|
||||
of '-':
|
||||
tok.xkind = pxMinus
|
||||
inc(L.bufpos)
|
||||
of ':':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxAsgn
|
||||
else:
|
||||
tok.xkind = pxColon
|
||||
of '<':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '>':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxNeq
|
||||
elif L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxLe
|
||||
else:
|
||||
tok.xkind = pxLt
|
||||
of '>':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] == '=':
|
||||
inc(L.bufpos)
|
||||
tok.xkind = pxGe
|
||||
else:
|
||||
tok.xkind = pxGt
|
||||
of '=':
|
||||
tok.xkind = pxEquals
|
||||
inc(L.bufpos)
|
||||
of '@':
|
||||
tok.xkind = pxAt
|
||||
inc(L.bufpos)
|
||||
of '^':
|
||||
tok.xkind = pxHat
|
||||
inc(L.bufpos)
|
||||
of '}':
|
||||
tok.xkind = pxCurlyDirRi
|
||||
inc(L.bufpos)
|
||||
of '\'', '#':
|
||||
getString(L, tok)
|
||||
of '$':
|
||||
getNumber16(L, tok)
|
||||
of '%':
|
||||
getNumber2(L, tok)
|
||||
of nimlexbase.EndOfFile:
|
||||
tok.xkind = pxEof
|
||||
else:
|
||||
tok.literal = c & ""
|
||||
tok.xkind = pxInvalid
|
||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
||||
inc(L.bufpos)
|
||||
File diff suppressed because it is too large
Load Diff
295
doc/c2nim.txt
295
doc/c2nim.txt
@@ -1,295 +0,0 @@
|
||||
=======================
|
||||
c2nim User's manual
|
||||
=======================
|
||||
|
||||
:Author: Andreas Rumpf
|
||||
:Version: |nimrodversion|
|
||||
|
||||
.. contents::
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
"We all make choices. But in the end our choices make us."
|
||||
|
||||
|
||||
c2nim is a tool to translate Ansi C code to Nimrod. The output is
|
||||
human-readable Nimrod code that is meant to be tweaked by hand after the
|
||||
translation process. c2nim is no real compiler!
|
||||
|
||||
c2nim is preliminary meant to translate C header files. Because of this, the
|
||||
preprocessor is part of the parser. For example:
|
||||
|
||||
.. code-block:: C
|
||||
#define abc 123
|
||||
#define xyz 789
|
||||
|
||||
Is translated into:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
const
|
||||
abc* = 123
|
||||
xyz* = 789
|
||||
|
||||
|
||||
c2nim is meant to translate fragments of C code and thus does not follow
|
||||
include files. c2nim cannot parse all of Ansi C and many constructs cannot
|
||||
be represented in Nimrod: for example `duff's device`:idx: cannot be translated
|
||||
to Nimrod.
|
||||
|
||||
|
||||
Preprocessor support
|
||||
====================
|
||||
|
||||
Even though the translation process is not perfect, it is often the case that
|
||||
the translated Nimrod code does not need any tweaking by hand. In other cases
|
||||
it may be preferable to modify the input file instead of the generated Nimrod
|
||||
code so that c2nim can parse it properly. c2nim's preprocessor defines the
|
||||
symbol ``C2NIM`` that can be used to mark code sections:
|
||||
|
||||
.. code-block:: C
|
||||
#ifndef C2NIM
|
||||
// C2NIM should ignore this prototype:
|
||||
int fprintf(FILE* f, const char* frmt, ...);
|
||||
#endif
|
||||
|
||||
The ``C2NIM`` symbol is only recognized in ``#ifdef`` and ``#ifndef``
|
||||
constructs! ``#if defined(C2NIM)`` does **not** work.
|
||||
|
||||
c2nim *processes* ``#ifdef C2NIM`` and ``#ifndef C2NIM`` directives, but other
|
||||
``#if[def]`` directives are *translated* into Nimrod's ``when`` construct:
|
||||
|
||||
.. code-block:: C
|
||||
#ifdef DEBUG
|
||||
# define OUT(x) printf("%s\n", x)
|
||||
#else
|
||||
# define OUT(x)
|
||||
#endif
|
||||
|
||||
Is translated into:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
when defined(debug):
|
||||
template OUT*(x: expr): expr =
|
||||
printf("%s\x0A", x)
|
||||
else:
|
||||
template OUT*(x: expr): stmt =
|
||||
discard
|
||||
|
||||
As can been seen from the example, C's macros with parameters are mapped
|
||||
to Nimrod's templates. This mapping is the best one can do, but it is of course
|
||||
not accurate: Nimrod's templates operate on syntax trees whereas C's
|
||||
macros work on the token level. c2nim cannot translate any macro that contains
|
||||
the ``##`` token concatenation operator.
|
||||
|
||||
c2nim's preprocessor supports special directives that affect how the output
|
||||
is generated. They should be put into a ``#ifdef C2NIM`` section so that
|
||||
ordinary C compilers ignore them.
|
||||
|
||||
|
||||
``#skipinclude`` directive
|
||||
--------------------------
|
||||
**Note**: There is also a ``--skipinclude`` command line option that can be
|
||||
used for the same purpose.
|
||||
|
||||
By default, c2nim translates an ``#include`` that is not followed by ``<``
|
||||
(like in ``#include <stdlib>``) to a Nimrod ``import`` statement. This
|
||||
directive tells c2nim to just skip any ``#include``.
|
||||
|
||||
|
||||
``#stdcall`` and ``#cdecl`` directives
|
||||
--------------------------------------
|
||||
**Note**: There are also ``--stdcall`` and ``--cdecl`` command line options
|
||||
that can be used for the same purpose.
|
||||
|
||||
These directives tell c2nim that it should annotate every proc (or proc type)
|
||||
with the ``stdcall`` / ``cdecl`` calling convention.
|
||||
|
||||
|
||||
``#dynlib`` directive
|
||||
---------------------
|
||||
**Note**: There is also a ``--dynlib`` command line option that can be used for
|
||||
the same purpose.
|
||||
|
||||
This directive tells c2nim that it should annotate every proc that resulted
|
||||
from a C function prototype with the ``dynlib`` pragma:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#ifdef C2NIM
|
||||
# dynlib iupdll
|
||||
# cdecl
|
||||
# if defined(windows)
|
||||
# define iupdll "iup.dll"
|
||||
# elif defined(macosx)
|
||||
# define iupdll "libiup.dylib"
|
||||
# else
|
||||
# define iupdll "libiup.so"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
||||
|
||||
Is translated to:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
when defined(windows):
|
||||
const iupdll* = "iup.dll"
|
||||
elif defined(macosx):
|
||||
const iupdll* = "libiup.dylib"
|
||||
else:
|
||||
const iupdll* = "libiup.so"
|
||||
|
||||
proc IupConvertXYToPos*(ih: PIhandle, x: cint, y: cint): cint {.
|
||||
importc: "IupConvertXYToPos", cdecl, dynlib: iupdll.}
|
||||
|
||||
Note how the example contains extra C code to declare the ``iupdll`` symbol
|
||||
in the generated Nimrod code.
|
||||
|
||||
|
||||
``#header`` directive
|
||||
---------------------
|
||||
**Note**: There is also a ``--header`` command line option that can be used for
|
||||
the same purpose.
|
||||
|
||||
The ``#header`` directive tells c2nim that it should annotate every proc that
|
||||
resulted from a C function prototype and every exported variable and type with
|
||||
the ``header`` pragma:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#ifdef C2NIM
|
||||
# header "iup.h"
|
||||
#endif
|
||||
|
||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
||||
|
||||
Is translated to:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
proc IupConvertXYToPos*(ih: PIhandle, x: cint, y: cint): cint {.
|
||||
importc: "IupConvertXYToPos", header: "iup.h".}
|
||||
|
||||
The ``#header`` and the ``#dynlib`` directives are mutually exclusive.
|
||||
A binding that uses ``dynlib`` is much more preferable over one that uses
|
||||
``header``! The Nimrod compiler might drop support for the ``header`` pragma
|
||||
in the future as it cannot work for backends that do not generate C code.
|
||||
|
||||
|
||||
``#prefix`` and ``#suffix`` directives
|
||||
--------------------------------------
|
||||
|
||||
**Note**: There are also ``--prefix`` and ``--suffix`` command line options
|
||||
that can be used for the same purpose.
|
||||
|
||||
c2nim does not do any name mangling by default. However the
|
||||
``#prefix`` and ``#suffix`` directives can be used to strip prefixes and
|
||||
suffixes from the identifiers in the C code:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#ifdef C2NIM
|
||||
# prefix Iup
|
||||
# dynlib dllname
|
||||
# cdecl
|
||||
#endif
|
||||
|
||||
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
||||
|
||||
Is translated to:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
|
||||
proc ConvertXYToPos*(ih: PIhandle, x: cint, y: cint): cint {.
|
||||
importc: "IupConvertXYToPos", cdecl, dynlib: dllname.}
|
||||
|
||||
|
||||
``#mangle`` directive
|
||||
---------------------
|
||||
|
||||
Even more sophisticated name mangling can be achieved by the ``#mangle``
|
||||
directive: It takes a PEG pattern and format string that specify how the
|
||||
identifier should be converted:
|
||||
|
||||
.. code-block:: C
|
||||
#mangle "'GTK_'{.*}" "TGtk$1"
|
||||
|
||||
For convenience the PEG pattern and the replacement can be single identifiers
|
||||
too, there is no need to quote them:
|
||||
|
||||
.. code-block:: C
|
||||
#mangle ssize_t int
|
||||
// is short for:
|
||||
#mangle "'ssize_t'" "int"
|
||||
|
||||
|
||||
``#private`` directive
|
||||
----------------------
|
||||
|
||||
By default c2nim marks every top level identifier (proc name, variable, etc.)
|
||||
as exported (the export marker is ``*`` in Nimrod). With the ``#private``
|
||||
directive identifiers can be marked as private so that the resulting Nimrod
|
||||
module does not export them. The ``#private`` directive takes a PEG pattern:
|
||||
|
||||
.. code-block:: C
|
||||
#private "@('_'!.)" // all identifiers ending in '_' are private
|
||||
|
||||
Note: The pattern refers to the original C identifiers, not to the resulting
|
||||
identifiers after mangling!
|
||||
|
||||
|
||||
``#skipcomments`` directive
|
||||
---------------------------
|
||||
**Note**: There is also a ``--skipcomments`` command line option that can be
|
||||
used for the same purpose.
|
||||
|
||||
The ``#skipcomments`` directive can be put into the C code to make c2nim
|
||||
ignore comments and not copy them into the generated Nimrod file.
|
||||
|
||||
|
||||
``#typeprefixes`` directive
|
||||
---------------------------
|
||||
**Note**: There is also a ``--typeprefixes`` command line option that can be
|
||||
used for the same purpose.
|
||||
|
||||
The ``#typeprefixes`` directive can be put into the C code to make c2nim
|
||||
generate the ``T`` or ``P`` prefix for every defined type.
|
||||
|
||||
|
||||
``#def`` directive
|
||||
------------------
|
||||
|
||||
Often C code contains special macros that affect the declaration of a function
|
||||
prototype but confuse c2nim's parser:
|
||||
|
||||
.. code-block:: C
|
||||
// does not parse!
|
||||
EXTERN(int) f(void);
|
||||
EXTERN(int) g(void);
|
||||
|
||||
Instead of removing ``EXTERN()`` from the input source file (which cannot be
|
||||
done reliably even with a regular expression!), one can tell c2nim
|
||||
that ``EXPORT`` is a macro that should be expanded by c2nim too:
|
||||
|
||||
.. code-block:: C
|
||||
#ifdef C2NIM
|
||||
# def EXTERN(x) static x
|
||||
#endif
|
||||
// parses now!
|
||||
EXTERN(int) f(void);
|
||||
EXTERN(int) g(void);
|
||||
|
||||
``#def`` is very similar to C's ``#define``, so in general the macro definition
|
||||
can be copied and pasted into a ``#def`` directive.
|
||||
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
||||
* C's ``,`` operator (comma operator) is not supported.
|
||||
* C's ``union`` are translated to Nimrod's objects and only the first field
|
||||
is included in the object type. This way there is a high chance that it is
|
||||
binary compatible to the union.
|
||||
* The condition in a ``do while(condition)`` statement must be ``0``.
|
||||
* Lots of other small issues...
|
||||
|
||||
3
koch.nim
3
koch.nim
@@ -93,10 +93,9 @@ proc buildTool(toolname, args: string) =
|
||||
copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe)
|
||||
|
||||
proc inno(args: string) =
|
||||
# make sure we have generated the c2nim and niminst executables:
|
||||
# make sure we have generated the niminst executables:
|
||||
buildTool("tools/niminst/niminst", args)
|
||||
buildTool("tools/nimgrep", args)
|
||||
buildTool("compiler/c2nim/c2nim", args)
|
||||
exec("tools" / "niminst" / "niminst --var:version=$# inno compiler/nimrod" %
|
||||
NimrodVersion)
|
||||
|
||||
|
||||
2
todo.txt
2
todo.txt
@@ -1,8 +1,6 @@
|
||||
version 0.9.6
|
||||
=============
|
||||
|
||||
- move pas2nim into its own repository
|
||||
- tester: .elf
|
||||
- overloading of '='; general lift mechanism
|
||||
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ UNIX. We don't believe this to be a coincidence. - Jeremy S. Anderson."""
|
||||
|
||||
[Documentation]
|
||||
doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview;filters;trmacros"
|
||||
doc: "tools;c2nim;niminst;nimgrep;gc;estp;idetools;docgen;koch"
|
||||
pdf: "manual;lib;tut1;tut2;nimrodc;c2nim;niminst;gc"
|
||||
doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch"
|
||||
pdf: "manual;lib;tut1;tut2;nimrodc;niminst;gc"
|
||||
srcdoc2: "system.nim;impure/graphics;wrappers/sdl"
|
||||
srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned"
|
||||
srcdoc2: "impure/re;pure/sockets"
|
||||
|
||||
Reference in New Issue
Block a user