strutils.parseHexInt added

This commit is contained in:
Andreas Rumpf
2010-01-18 17:06:43 +01:00
parent 8259d9d15a
commit b50133b50f
11 changed files with 352 additions and 534 deletions

View File

@@ -15,7 +15,6 @@ cc = gcc
@end
path="$lib/pure"
path="$lib/devel"
path="$lib/impure"
path="$lib/wrappers"
path="$lib/wrappers/cairo"

View File

@@ -326,6 +326,10 @@ proc ParseFloat*(s: string): float {.noSideEffect, procvar.}
## a valid floating point number, `EInvalidValue` is raised. ``NAN``,
## ``INF``, ``-INF`` are also supported (case insensitive comparison).
proc ParseHexInt*(s: string): int {.noSideEffect, procvar.}
## Parses a hexadecimal integer value contained in `s`. If `s` is not
## a valid integer, `EInvalidValue` is raised.
# the stringify and format operators:
proc toString*[Ty](x: Ty): string {.deprecated.}
## This generic proc is the same as the stringify operator `$`.
@@ -731,6 +735,25 @@ proc ParseBiggestInt(s: string): biggestInt =
if index == -1:
raise newException(EInvalidValue, "invalid integer: " & s)
proc ParseHexInt(s: string): int =
var i = 0
if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
while true:
case s[i]
of '_': inc(i)
of '0'..'9':
result = result shl 4 or (ord(s[i]) - ord('0'))
inc(i)
of 'a'..'f':
result = result shl 4 or (ord(s[i]) - ord('a') + 10)
inc(i)
of 'A'..'F':
result = result shl 4 or (ord(s[i]) - ord('A') + 10)
inc(i)
of '\0': break
else: raise newException(EInvalidValue, "invalid integer: " & s)
proc ParseFloat(s: string): float =
var
esign = 1.0

View File

@@ -232,7 +232,9 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of wPath, wP:
expectArg(switch, arg, pass, info)
path = processPath(arg)
discard lists.IncludeStr(options.searchPaths, path)
if not contains(options.searchPaths, path):
lists.PrependStr(options.searchPaths, path)
#discard lists.IncludeStr(options.searchPaths, path)
of wOut, wO:
expectArg(switch, arg, pass, info)
options.outFile = arg

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2008 Andreas Rumpf
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -60,15 +60,16 @@ proc AppendStr(list: var TLinkedList, data: string) =
proc PrependStr(list: var TLinkedList, data: string) =
prepend(list, newStrEntry(data))
proc IncludeStr(list: var TLinkedList, data: string): bool =
var it: PListEntry
it = list.head
proc Contains*(list: TLinkedList, data: string): bool =
var it = list.head
while it != nil:
if PStrEntry(it).data == data:
return true # already in list
return true
it = it.next
proc IncludeStr(list: var TLinkedList, data: string): bool =
if Contains(list, data): return true
AppendStr(list, data) # else: add to list
result = false
proc InsertBefore(list: var TLinkedList, pos, entry: PListEntry) =
assert(pos != nil)

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -12,7 +12,7 @@
import
llstream, strutils, ast, astalgo, scanner, syntaxes, rnimsyn, options, msgs,
os, lists, condsyms, paslex, pasparse, rodread, rodwrite, ropes, trees,
os, lists, condsyms, rodread, rodwrite, ropes, trees,
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, ecmasgen,
platform, interact, nimconf, importer, passaux, depends, transf, evals, types
@@ -47,7 +47,6 @@ proc getModule(filename: string): PSym =
for i in countup(0, high(compMods)):
if sameFile(compMods[i].filename, filename):
return compMods[i].module
result = nil
proc newModule(filename: string): PSym =
# We cannot call ``newSym`` here, because we have to circumvent the ID
@@ -152,61 +151,11 @@ proc CommandInteractive() =
incl(m.flags, sfMainModule)
processModule(m, "stdin", LLStreamOpenStdIn(), nil)
proc exSymbols(n: PNode) =
case n.kind
of nkEmpty..nkNilLit: nil
of nkProcDef..nkIteratorDef: exSymbol(n.sons[namePos])
of nkWhenStmt, nkStmtList:
for i in countup(0, sonsLen(n) - 1): exSymbols(n.sons[i])
of nkVarSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1): exSymbol(n.sons[i].sons[0])
of nkTypeSection:
for i in countup(0, sonsLen(n) - 1):
exSymbol(n.sons[i].sons[0])
if (n.sons[i].sons[2] != nil) and
(n.sons[i].sons[2].kind == nkObjectTy):
fixRecordDef(n.sons[i].sons[2])
else: nil
proc CommandExportSymbols(filename: string) =
# now unused!
var module = parseFile(addFileExt(filename, NimExt))
if module != nil:
exSymbols(module)
renderModule(module, getOutFile(filename, "pretty." & NimExt))
proc CommandPretty(filename: string) =
var module = parseFile(addFileExt(filename, NimExt))
if module != nil:
renderModule(module, getOutFile(filename, "pretty." & NimExt))
proc CommandLexPas(filename: string) =
var f = addFileExt(filename, "pas")
var stream = LLStreamOpen(f, fmRead)
if stream != nil:
var
L: TPasLex
tok: TPasTok
OpenLexer(L, f, stream)
getPasTok(L, tok)
while tok.xkind != pxEof:
printPasTok(tok)
getPasTok(L, tok)
closeLexer(L)
else: rawMessage(errCannotOpenFile, f)
proc CommandPas(filename: string) =
var f = addFileExt(filename, "pas")
var stream = LLStreamOpen(f, fmRead)
if stream != nil:
var p: TPasParser
OpenPasParser(p, f, stream)
var module = parseUnit(p)
closePasParser(p)
renderModule(module, getOutFile(filename, NimExt))
else:
rawMessage(errCannotOpenFile, f)
proc CommandScan(filename: string) =
var f = addFileExt(filename, nimExt)
var stream = LLStreamOpen(f, fmRead)
@@ -274,14 +223,6 @@ proc MainCommand(cmd, filename: string) =
LoadSpecialConfig(DocTexConfig)
wantFile(filename)
CommandRst2TeX(filename)
of wPas:
gCmd = cmdPas
wantFile(filename)
CommandPas(filename)
of wBoot:
gCmd = cmdBoot
wantFile(filename)
CommandPas(filename)
of wGenDepend:
gCmd = cmdGenDepend
wantFile(filename)
@@ -306,4 +247,4 @@ proc MainCommand(cmd, filename: string) =
gCmd = cmdInteractive
CommandInteractive()
else: rawMessage(errInvalidCommandX, cmd)

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -41,7 +41,7 @@ type # please make sure we have under 32 options
TGlobalOptions* = set[TGlobalOption]
TCommands* = enum # Nimrod's commands
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToEcmaScript,
cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc, cmdPas, cmdBoot,
cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
cmdGenDepend, cmdListDef, cmdCheck, # semantic checking for whole project
cmdParse, # parse a single file (for debugging)
cmdScan, # scan a single file (for debugging)

67
rod/pas2nim/pas2nim.nim Executable file
View File

@@ -0,0 +1,67 @@
#
#
# Pas2nim - Pascal to Nimrod source converter
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
#
import
llstream, strutils, os, ast, rnimsyn, options, msgs,
paslex, pasparse
proc exSymbols(n: PNode) =
case n.kind
of nkEmpty..nkNilLit: nil
of nkProcDef..nkIteratorDef: exSymbol(n.sons[namePos])
of nkWhenStmt, nkStmtList:
for i in countup(0, sonsLen(n) - 1): exSymbols(n.sons[i])
of nkVarSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1): exSymbol(n.sons[i].sons[0])
of nkTypeSection:
for i in countup(0, sonsLen(n) - 1):
exSymbol(n.sons[i].sons[0])
if (n.sons[i].sons[2] != nil) and
(n.sons[i].sons[2].kind == nkObjectTy):
fixRecordDef(n.sons[i].sons[2])
else: nil
proc CommandExportSymbols(filename: string) =
# now unused!
var module = parseFile(addFileExt(filename, NimExt))
if module != nil:
exSymbols(module)
renderModule(module, getOutFile(filename, "pretty." & NimExt))
proc CommandLexPas(filename: string) =
var f = addFileExt(filename, "pas")
var stream = LLStreamOpen(f, fmRead)
if stream != nil:
var
L: TPasLex
tok: TPasTok
OpenLexer(L, f, stream)
getPasTok(L, tok)
while tok.xkind != pxEof:
printPasTok(tok)
getPasTok(L, tok)
closeLexer(L)
else: rawMessage(errCannotOpenFile, f)
proc CommandPas(filename: string) =
var f = addFileExt(filename, "pas")
var stream = LLStreamOpen(f, fmRead)
if stream != nil:
var p: TPasParser
OpenPasParser(p, f, stream)
var module = parseUnit(p)
closePasParser(p)
renderModule(module, getOutFile(filename, NimExt))
else:
rawMessage(errCannotOpenFile, f)

View File

@@ -1,44 +1,31 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf
# Pas2nim - Pascal to Nimrod source converter
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This module implements a FreePascal scanner. This is a adaption from
# This module implements a FreePascal scanner. This is an adaption from
# the scanner module.
import
nhashes, options, msgs, strutils, platform, idents, lexbase, wordrecg, scanner
nhashes, options, msgs, strutils, platform, idents, lexbase
const
MaxLineLength* = 80 # lines longer than this lead to a warning
numChars*: TCharSet = {'0'..'9', 'a'..'z', 'A'..'Z'} # we support up to base 36
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'}
type # order is important for TPasTokKind
# keywords are sorted!
type
TPasTokKind* = enum
pxInvalid, pxEof, # keywords:
#[[[cog
#from string import capitalize
#keywords = eval(open("data/pas_keyw.yml").read())
#idents = ""
#strings = ""
#i = 1
#for k in keywords:
# idents = idents + "px" + capitalize(k) + ", "
# strings = strings + "'" + k + "', "
# if i % 4 == 0:
# idents = idents + "\n"
# strings = strings + "\n"
# i = i + 1
#cog.out(idents)
#]]]
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,
@@ -47,13 +34,13 @@ type # order is important for TPasTokKind
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, #[[[end]]]
pxWith, pxXor,
pxComment, # ordinary comment
pxCommand, # {@}
pxAmp, # {&}
pxPer, # {%}
pxStrLit, pxSymbol, # a symbol
pxIntLit, pxInt64Lit, # long constant like 0x00000070fffffff or out of int range
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,
@@ -62,10 +49,7 @@ type # order is important for TPasTokKind
TPasTokKinds* = set[TPasTokKind]
const
PasTokKindToStr*: array[TPasTokKind, string] = ["pxInvalid", "[EOF]", #[[[cog
#cog.out(strings)
#]]]
"and", "array", "as", "asm", "begin", "case", "class", "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",
@@ -73,23 +57,74 @@ const
"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", #[[[end]]]
"pxComment", "pxCommand", "{&}", "{%}", "pxStrLit", "[IDENTIFIER]",
"pxIntLit", "pxInt64Lit", "pxFloatLit", "(", ")", "[", "]", ",", ";", ":",
":=", "=", ".", "..", "^", "+", "-", "*", "/", "<=", "<", ">=", ">", "<>",
"@", "(*$", "*)", "{$", "}"]
"with", "xor"]
firstKeyword = pxAnd
lastKeyword = pxXor
type
TPasTok* = object of TToken # a Pascal token
TPasTok* = object
xkind*: TPasTokKind # 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
TPasLex* = object
filename*: string
TPasLex* = object of TLexer
proc getPasTok*(L: var TPasLex, tok: var TPasTok)
proc PrintPasTok*(tok: TPasTok)
proc pasTokToStr*(tok: TPasTok): string
# implementation
var dummyIdent: PIdent
proc fillToken(L: var TToken) =
L.TokType = tkInvalid
L.iNumber = 0
L.Indent = 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.indentStack = @[0]
lex.filename = filename
lex.indentAhead = - 1
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.liMessage(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.liMessage(info, msg, arg)
proc binaryStrSearch(x: openarray[string], y: string): int =
var a = 0
var b = len(x)
while a < b:
var mid = (a + b) div 2
if x[mid] < y: a = mid + 1
else: b = mid
if a < len(x) and x[a] == y: result = a
else: result = -1
proc pastokToStr(tok: TPasTok): string =
case tok.xkind
of pxIntLit, pxInt64Lit: result = $(tok.iNumber)
@@ -105,144 +140,14 @@ proc PrintPasTok(tok: TPasTok) =
writeln(stdout, pastokToStr(tok))
proc setKeyword(L: var TPasLex, tok: var TPasTok) =
case tok.ident.id #[[[cog
#for k in keywords:
# m = capitalize(k)
# cog.outl("ord(w%s):%s tok.xkind := px%s;" % (m, ' '*(18-len(m)), m))
#]]]
of ord(wAnd):
tok.xkind = pxAnd
of ord(wArray):
tok.xkind = pxArray
of ord(wAs):
tok.xkind = pxAs
of ord(wAsm):
tok.xkind = pxAsm
of ord(wBegin):
tok.xkind = pxBegin
of ord(wCase):
tok.xkind = pxCase
of ord(wClass):
tok.xkind = pxClass
of ord(wConst):
tok.xkind = pxConst
of ord(wConstructor):
tok.xkind = pxConstructor
of ord(wDestructor):
tok.xkind = pxDestructor
of ord(wDiv):
tok.xkind = pxDiv
of ord(wDo):
tok.xkind = pxDo
of ord(wDownto):
tok.xkind = pxDownto
of ord(wElse):
tok.xkind = pxElse
of ord(wEnd):
tok.xkind = pxEnd
of ord(wExcept):
tok.xkind = pxExcept
of ord(wExports):
tok.xkind = pxExports
of ord(wFinalization):
tok.xkind = pxFinalization
of ord(wFinally):
tok.xkind = pxFinally
of ord(wFor):
tok.xkind = pxFor
of ord(wFunction):
tok.xkind = pxFunction
of ord(wGoto):
tok.xkind = pxGoto
of ord(wIf):
tok.xkind = pxIf
of ord(wImplementation):
tok.xkind = pxImplementation
of ord(wIn):
tok.xkind = pxIn
of ord(wInherited):
tok.xkind = pxInherited
of ord(wInitialization):
tok.xkind = pxInitialization
of ord(wInline):
tok.xkind = pxInline
of ord(wInterface):
tok.xkind = pxInterface
of ord(wIs):
tok.xkind = pxIs
of ord(wLabel):
tok.xkind = pxLabel
of ord(wLibrary):
tok.xkind = pxLibrary
of ord(wMod):
tok.xkind = pxMod
of ord(wNil):
tok.xkind = pxNil
of ord(wNot):
tok.xkind = pxNot
of ord(wObject):
tok.xkind = pxObject
of ord(wOf):
tok.xkind = pxOf
of ord(wOr):
tok.xkind = pxOr
of ord(wOut):
tok.xkind = pxOut
of ord(wPacked):
tok.xkind = pxPacked
of ord(wProcedure):
tok.xkind = pxProcedure
of ord(wProgram):
tok.xkind = pxProgram
of ord(wProperty):
tok.xkind = pxProperty
of ord(wRaise):
tok.xkind = pxRaise
of ord(wRecord):
tok.xkind = pxRecord
of ord(wRepeat):
tok.xkind = pxRepeat
of ord(wResourcestring):
tok.xkind = pxResourcestring
of ord(wSet):
tok.xkind = pxSet
of ord(wShl):
tok.xkind = pxShl
of ord(wShr):
tok.xkind = pxShr
of ord(wThen):
tok.xkind = pxThen
of ord(wThreadvar):
tok.xkind = pxThreadvar
of ord(wTo):
tok.xkind = pxTo
of ord(wTry):
tok.xkind = pxTry
of ord(wType):
tok.xkind = pxType
of ord(wUnit):
tok.xkind = pxUnit
of ord(wUntil):
tok.xkind = pxUntil
of ord(wUses):
tok.xkind = pxUses
of ord(wVar):
tok.xkind = pxVar
of ord(wWhile):
tok.xkind = pxWhile
of ord(wWith):
tok.xkind = pxWith
of ord(wXor):
tok.xkind = pxXor #[[[end]]]
else: tok.xkind = pxSymbol
var x = binaryStrSearch(keywords, toLower(tok.ident.s))
if x < 0: tok.xkind = pxSymbol
else: tok.xKind = TPasTokKind(x + ord(firstKeyword))
proc matchUnderscoreChars(L: var TPasLex, tok: var TPasTok, chars: TCharSet) =
# matches ([chars]_)*
var
pos: int
buf: cstring
pos = L.bufpos # use registers for pos, buf
buf = L.buf
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])
@@ -255,16 +160,12 @@ proc matchUnderscoreChars(L: var TPasLex, tok: var TPasTok, chars: TCharSet) =
L.bufPos = pos
proc isFloatLiteral(s: string): bool =
for i in countup(0, len(s) + 0 - 1):
for i in countup(0, len(s)-1):
if s[i] in {'.', 'e', 'E'}:
return true
result = false
proc getNumber2(L: var TPasLex, tok: var TPasTok) =
var
pos, bits: int
xi: biggestInt
pos = L.bufpos + 1 # skip %
var pos = L.bufpos + 1 # skip %
if not (L.buf[pos] in {'0'..'1'}):
# BUGFIX for %date%
tok.xkind = pxInvalid
@@ -272,8 +173,8 @@ proc getNumber2(L: var TPasLex, tok: var TPasTok) =
inc(L.bufpos)
return
tok.base = base2
xi = 0
bits = 0
var xi: biggestInt = 0
var bits = 0
while true:
case L.buf[pos]
of 'A'..'Z', 'a'..'z', '2'..'9', '.':
@@ -287,27 +188,21 @@ proc getNumber2(L: var TPasLex, tok: var TPasTok) =
inc(bits)
else: break
tok.iNumber = xi
if (bits > 32):
tok.xkind = pxInt64Lit
else:
tok.xkind = pxIntLit
if (bits > 32): tok.xkind = pxInt64Lit
else: tok.xkind = pxIntLit
L.bufpos = pos
proc getNumber16(L: var TPasLex, tok: var TPasTok) =
var
pos, bits: int
xi: biggestInt
pos = L.bufpos + 1 # skip $
var pos = L.bufpos + 1 # skip $
tok.base = base16
xi = 0
bits = 0
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 '_': inc(pos)
of '0'..'9':
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0'))
inc(pos)
@@ -357,11 +252,9 @@ proc HandleCRLF(L: var TLexer, pos: int): int =
else: result = pos
proc getString(L: var TPasLex, tok: var TPasTok) =
var
pos, xi: int
buf: cstring
pos = L.bufPos
buf = L.buf
var xi: int
var pos = L.bufPos
var buf = L.buf
while true:
if buf[pos] == '\'':
inc(pos)
@@ -408,16 +301,11 @@ proc getString(L: var TPasLex, tok: var TPasTok) =
L.bufpos = pos
proc getSymbol(L: var TPasLex, tok: var TPasTok) =
var
pos: int
c: Char
buf: cstring
h: THash # hashing algorithm inlined
h = 0
pos = L.bufpos
buf = L.buf
var h: THash = 0
var pos = L.bufpos
var buf = L.buf
while true:
c = buf[pos]
var c = buf[pos]
case c
of 'a'..'z', '0'..'9', '\x80'..'\xFF':
h = h +% Ord(c)
@@ -428,8 +316,7 @@ proc getSymbol(L: var TPasLex, tok: var TPasTok) =
h = h +% Ord(c)
h = h +% h shl 10
h = h xor (h shr 6)
of '_':
nil
of '_': nil
else: break
Inc(pos)
h = h +% h shl 3
@@ -440,15 +327,12 @@ proc getSymbol(L: var TPasLex, tok: var TPasTok) =
setKeyword(L, tok)
proc scanLineComment(L: var TPasLex, tok: var TPasTok) =
var
buf: cstring
pos, col: int
indent: int
pos = L.bufpos
buf = L.buf # a comment ends if the next line does not start with the // on the same
# column after only whitespace
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
col = getColNumber(L, pos)
var col = getColNumber(L, pos)
while true:
inc(pos, 2) # skip //
add(tok.literal, '#')
@@ -457,7 +341,7 @@ proc scanLineComment(L: var TPasLex, tok: var TPasTok) =
inc(pos)
pos = handleCRLF(L, pos)
buf = L.buf
indent = 0
var indent = 0
while buf[pos] == ' ':
inc(pos)
inc(indent)
@@ -468,11 +352,8 @@ proc scanLineComment(L: var TPasLex, tok: var TPasTok) =
L.bufpos = pos
proc scanCurlyComment(L: var TPasLex, tok: var TPasTok) =
var
buf: cstring
pos: int
pos = L.bufpos
buf = L.buf
var pos = L.bufpos
var buf = L.buf
tok.literal = "#"
tok.xkind = pxComment
while true:
@@ -480,23 +361,19 @@ proc scanCurlyComment(L: var TPasLex, tok: var TPasTok) =
of CR, LF:
pos = HandleCRLF(L, pos)
buf = L.buf
tok.literal = tok.literal & "\n" & '#'
add(tok.literal, "\n#")
of '}':
inc(pos)
break
of lexbase.EndOfFile:
lexMessage(L, errTokenExpected, "}")
of lexbase.EndOfFile: lexMessage(L, errTokenExpected, "}")
else:
add(tok.literal, buf[pos])
inc(pos)
L.bufpos = pos
proc scanStarComment(L: var TPasLex, tok: var TPasTok) =
var
buf: cstring
pos: int
pos = L.bufpos
buf = L.buf
var pos = L.bufpos
var buf = L.buf
tok.literal = "#"
tok.xkind = pxComment
while true:
@@ -504,7 +381,7 @@ proc scanStarComment(L: var TPasLex, tok: var TPasTok) =
of CR, LF:
pos = HandleCRLF(L, pos)
buf = L.buf
tok.literal = tok.literal & "\n" & '#'
add(tok.literal, "\n#")
of '*':
inc(pos)
if buf[pos] == ')':
@@ -520,11 +397,8 @@ proc scanStarComment(L: var TPasLex, tok: var TPasTok) =
L.bufpos = pos
proc skip(L: var TPasLex, tok: var TPasTok) =
var
buf: cstring
pos: int
pos = L.bufpos
buf = L.buf
var pos = L.bufpos
var buf = L.buf
while true:
case buf[pos]
of ' ', Tabulator:
@@ -537,11 +411,10 @@ proc skip(L: var TPasLex, tok: var TPasTok) =
L.bufpos = pos
proc getPasTok(L: var TPasLex, tok: var TPasTok) =
var c: Char
tok.xkind = pxInvalid
fillToken(tok)
skip(L, tok)
c = L.buf[L.bufpos]
var c = L.buf[L.bufpos]
if c in SymStartChars:
getSymbol(L, tok)
elif c in {'0'..'9'}:

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf
# Pas2nim - Pascal to Nimrod source converter
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -9,11 +9,10 @@
# This module implements the parser of the Pascal variant Nimrod is written in.
# It transfers a Pascal module into a Nimrod AST. Then the renderer can be
# used to generate the Nimrod version of the compiler.
# used to convert the AST to its text representation.
import
os, llstream, scanner, paslex, idents, wordrecg, strutils, ast, astalgo, msgs,
options
os, llstream, paslex, idents, strutils, ast, astalgo, msgs, options
type
TPasSection* = enum
@@ -96,7 +95,7 @@ proc skipCom(p: var TPasParser, n: PNode) =
while p.tok.xkind == pxComment:
if (n != nil):
if n.comment == nil: n.comment = p.tok.literal
else: n.comment = n.comment & "\n" & p.tok.literal
else: add(n.comment, "\n" & p.tok.literal)
else:
parMessage(p, warnCommentXIgnored, p.tok.literal)
getTok(p)
@@ -119,7 +118,8 @@ proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TPasParser): PNode =
result = newNodeP(kind, p)
result.intVal = intVal
proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat, p: TPasParser): PNode =
proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat,
p: TPasParser): PNode =
result = newNodeP(kind, p)
result.floatVal = floatVal
@@ -132,17 +132,16 @@ proc newIdentNodeP(ident: PIdent, p: TPasParser): PNode =
result.ident = ident
proc createIdentNodeP(ident: PIdent, p: TPasParser): PNode =
var x: PIdent
result = newNodeP(nkIdent, p)
x = PIdent(IdTableGet(p.repl, ident))
var x = PIdent(IdTableGet(p.repl, ident))
if x != nil: result.ident = x
else: result.ident = ident
proc parseExpr(p: var TPasParser): PNode
proc parseStmt(p: var TPasParser): PNode
proc parseTypeDesc(p: var TPasParser, definition: PNode = nil): PNode
proc parseEmit(p: var TPasParser, definition: PNode): PNode =
var a: PNode
getTok(p) # skip 'emit'
result = nil
if p.tok.xkind != pxCurlyDirRi:
@@ -152,7 +151,7 @@ proc parseEmit(p: var TPasParser, definition: PNode): PNode =
of conStmt:
result = parseStmt(p)
if p.tok.xkind != pxCurlyDirRi:
a = result
var a = result
result = newNodeP(nkStmtList, p)
addSon(result, a)
while p.tok.xkind != pxCurlyDirRi:
@@ -162,7 +161,6 @@ proc parseEmit(p: var TPasParser, definition: PNode): PNode =
eat(p, pxCurlyDirRi)
proc parseCommand(p: var TPasParser, definition: PNode = nil): PNode =
var a: PNode
result = nil
getTok(p)
if p.tok.ident.id == getIdent("discard").id:
@@ -179,7 +177,7 @@ proc parseCommand(p: var TPasParser, definition: PNode = nil): PNode =
elif p.tok.ident.id == getIdent("cast").id:
getTok(p)
eat(p, pxCurlyDirRi)
a = parseExpr(p)
var a = parseExpr(p)
if (a.kind == nkCall) and (sonsLen(a) == 2):
result = newNodeP(nkCast, p)
addSon(result, a.sons[0])
@@ -230,16 +228,15 @@ proc parseCommand(p: var TPasParser, definition: PNode = nil): PNode =
proc getPrecedence(kind: TPasTokKind): int =
case kind
of pxDiv, pxMod, pxStar, pxSlash, pxShl, pxShr, pxAnd:
result = 5 # highest
result = 5
of pxPlus, pxMinus, pxOr, pxXor:
result = 4
of pxIn, pxEquals, pxLe, pxLt, pxGe, pxGt, pxNeq, pxIs:
result = 3
else: result = - 1
else: result = -1
proc rangeExpr(p: var TPasParser): PNode =
var a: PNode
a = parseExpr(p)
var a = parseExpr(p)
if p.tok.xkind == pxDotDot:
result = newNodeP(nkRange, p)
addSon(result, a)
@@ -250,7 +247,6 @@ proc rangeExpr(p: var TPasParser): PNode =
result = a
proc bracketExprList(p: var TPasParser, first: PNode): PNode =
var a: PNode
result = newNodeP(nkBracketExpr, p)
addSon(result, first)
getTok(p)
@@ -262,16 +258,16 @@ proc bracketExprList(p: var TPasParser, first: PNode): PNode =
if p.tok.xkind == pxEof:
parMessage(p, errTokenExpected, PasTokKindToStr[pxBracketRi])
break
a = rangeExpr(p)
var a = rangeExpr(p)
skipCom(p, a)
if p.tok.xkind == pxComma:
getTok(p)
skipCom(p, a)
addSon(result, a)
proc exprColonEqExpr(p: var TPasParser, kind: TNodeKind, tok: TPasTokKind): PNode =
var a: PNode
a = parseExpr(p)
proc exprColonEqExpr(p: var TPasParser, kind: TNodeKind,
tok: TPasTokKind): PNode =
var a = parseExpr(p)
if p.tok.xkind == tok:
result = newNodeP(kind, p)
getTok(p)
@@ -283,7 +279,6 @@ proc exprColonEqExpr(p: var TPasParser, kind: TNodeKind, tok: TPasTokKind): PNod
proc exprListAux(p: var TPasParser, elemKind: TNodeKind,
endTok, sepTok: TPasTokKind, result: PNode) =
var a: PNode
getTok(p)
skipCom(p, result)
while true:
@@ -293,7 +288,7 @@ proc exprListAux(p: var TPasParser, elemKind: TNodeKind,
if p.tok.xkind == pxEof:
parMessage(p, errTokenExpected, PasTokKindToStr[endtok])
break
a = exprColonEqExpr(p, elemKind, sepTok)
var a = exprColonEqExpr(p, elemKind, sepTok)
skipCom(p, a)
if (p.tok.xkind == pxComma) or (p.tok.xkind == pxSemicolon):
getTok(p)
@@ -301,7 +296,6 @@ proc exprListAux(p: var TPasParser, elemKind: TNodeKind,
addSon(result, a)
proc qualifiedIdent(p: var TPasParser): PNode =
var a: PNode
if p.tok.xkind == pxSymbol:
result = createIdentNodeP(p.tok.ident, p)
else:
@@ -313,7 +307,7 @@ proc qualifiedIdent(p: var TPasParser): PNode =
getTok(p)
skipCom(p, result)
if p.tok.xkind == pxSymbol:
a = result
var a = result
result = newNodeI(nkDotExpr, a.info)
addSon(result, a)
addSon(result, createIdentNodeP(p.tok.ident, p))
@@ -321,8 +315,8 @@ proc qualifiedIdent(p: var TPasParser): PNode =
else:
parMessage(p, errIdentifierExpected, pasTokToStr(p.tok))
proc qualifiedIdentListAux(p: var TPasParser, endTok: TPasTokKind, result: PNode) =
var a: PNode
proc qualifiedIdentListAux(p: var TPasParser, endTok: TPasTokKind,
result: PNode) =
getTok(p)
skipCom(p, result)
while true:
@@ -332,7 +326,7 @@ proc qualifiedIdentListAux(p: var TPasParser, endTok: TPasTokKind, result: PNode
if p.tok.xkind == pxEof:
parMessage(p, errTokenExpected, PasTokKindToStr[endtok])
break
a = qualifiedIdent(p)
var a = qualifiedIdent(p)
skipCom(p, a)
if p.tok.xkind == pxComma:
getTok(p)
@@ -346,17 +340,12 @@ proc exprColonEqExprList(p: var TPasParser, kind, elemKind: TNodeKind,
proc setBaseFlags(n: PNode, base: TNumericalBase) =
case base
of base10:
nil
of base2:
incl(n.flags, nfBase2)
of base8:
incl(n.flags, nfBase8)
of base16:
incl(n.flags, nfBase16)
of base10: nil
of base2: incl(n.flags, nfBase2)
of base8: incl(n.flags, nfBase8)
of base16: incl(n.flags, nfBase16)
proc identOrLiteral(p: var TPasParser): PNode =
var a: PNode
case p.tok.xkind
of pxSymbol:
result = createIdentNodeP(p.tok.ident, p)
@@ -382,8 +371,9 @@ proc identOrLiteral(p: var TPasParser): PNode =
getTok(p)
of pxParLe:
# () constructor
result = exprColonEqExprList(p, nkPar, nkExprColonExpr, pxParRi, pxColon) #if hasSonWith(result, nkExprColonExpr) then
# replaceSons(result, nkExprColonExpr, nkExprEqExpr)
result = exprColonEqExprList(p, nkPar, nkExprColonExpr, pxParRi, pxColon)
#if hasSonWith(result, nkExprColonExpr) then
# replaceSons(result, nkExprColonExpr, nkExprEqExpr)
if (sonsLen(result) > 1) and not hasSonWith(result, nkExprColonExpr):
result.kind = nkBracket # is an array constructor
of pxBracketLe:
@@ -392,7 +382,7 @@ proc identOrLiteral(p: var TPasParser): PNode =
getTok(p)
skipCom(p, result)
while (p.tok.xkind != pxBracketRi) and (p.tok.xkind != pxEof):
a = rangeExpr(p)
var a = rangeExpr(p)
if a.kind == nkRange:
result.kind = nkCurly # it is definitely a set literal
opt(p, pxComma)
@@ -404,17 +394,16 @@ proc identOrLiteral(p: var TPasParser): PNode =
result = parseCommand(p)
else:
parMessage(p, errExprExpected, pasTokToStr(p.tok))
getTok(p) # we must consume a token here to prevend endless loops!
getTok(p) # we must consume a token here to prevend endless loops!
result = nil
if result != nil: skipCom(p, result)
proc primary(p: var TPasParser): PNode =
var a: PNode
# prefix operator?
if (p.tok.xkind == pxNot) or (p.tok.xkind == pxMinus) or
(p.tok.xkind == pxPlus):
result = newNodeP(nkPrefix, p)
a = newIdentNodeP(getIdent(pasTokToStr(p.tok)), p)
var a = newIdentNodeP(getIdent(pasTokToStr(p.tok)), p)
addSon(result, a)
getTok(p)
skipCom(p, a)
@@ -422,7 +411,7 @@ proc primary(p: var TPasParser): PNode =
return
elif p.tok.xkind == pxAt:
result = newNodeP(nkAddr, p)
a = newIdentNodeP(getIdent(pasTokToStr(p.tok)), p)
var a = newIdentNodeP(getIdent(pasTokToStr(p.tok)), p)
getTok(p)
if p.tok.xkind == pxBracketLe:
result = newNodeP(nkPrefix, p)
@@ -435,12 +424,12 @@ proc primary(p: var TPasParser): PNode =
while true:
case p.tok.xkind
of pxParLe:
a = result
var a = result
result = newNodeP(nkCall, p)
addSon(result, a)
exprListAux(p, nkExprEqExpr, pxParRi, pxEquals, result)
of pxDot:
a = result
var a = result
result = newNodeP(nkDotExpr, p)
addSon(result, a)
getTok(p) # skip '.'
@@ -451,7 +440,7 @@ proc primary(p: var TPasParser): PNode =
else:
parMessage(p, errIdentifierExpected, pasTokToStr(p.tok))
of pxHat:
a = result
var a = result
result = newNodeP(nkDerefExpr, p)
addSon(result, a)
getTok(p)
@@ -461,12 +450,11 @@ proc primary(p: var TPasParser): PNode =
proc lowestExprAux(p: var TPasParser, v: var PNode, limit: int): TPasTokKind =
var
op, nextop: TPasTokKind
opPred: int
nextop: TPasTokKind
v2, node, opNode: PNode
v = primary(p) # expand while operators have priorities higher than 'limit'
op = p.tok.xkind
opPred = getPrecedence(op)
v = primary(p) # expand while operators have priorities higher than 'limit'
var op = p.tok.xkind
var opPred = getPrecedence(op)
while (opPred > limit):
node = newNodeP(nkInfix, p)
opNode = newIdentNodeP(getIdent(pasTokToStr(p.tok)), p) # skip operator:
@@ -530,8 +518,7 @@ proc fixExpr(n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1): result.sons[i] = fixExpr(n.sons[i])
proc parseExpr(p: var TPasParser): PNode =
var oldcontext: TPasContext
oldcontext = p.context
var oldcontext = p.context
p.context = conExpr
if p.tok.xkind == pxCommand:
result = parseCommand(p)
@@ -541,15 +528,12 @@ proc parseExpr(p: var TPasParser): PNode =
p.context = oldcontext
proc parseExprStmt(p: var TPasParser): PNode =
var
a, b: PNode
info: TLineInfo
info = parLineInfo(p)
a = parseExpr(p)
var info = parLineInfo(p)
var a = parseExpr(p)
if p.tok.xkind == pxAsgn:
getTok(p)
skipCom(p, a)
b = parseExpr(p)
var b = parseExpr(p)
result = newNodeI(nkAsgn, info)
addSon(result, a)
addSon(result, b)
@@ -560,7 +544,6 @@ proc inImportBlackList(ident: PIdent): bool =
for i in countup(low(ImportBlackList), high(ImportBlackList)):
if ident.id == getIdent(ImportBlackList[i]).id:
return true
result = false
proc parseUsesStmt(p: var TPasParser): PNode =
var a: PNode
@@ -586,10 +569,9 @@ proc parseUsesStmt(p: var TPasParser): PNode =
if sonsLen(result) == 0: result = nil
proc parseIncludeDir(p: var TPasParser): PNode =
var filename: string
result = newNodeP(nkIncludeStmt, p)
getTok(p) # skip `include`
filename = ""
var filename = ""
while true:
case p.tok.xkind
of pxSymbol, pxDot, pxDotDot, pxSlash:
@@ -635,14 +617,11 @@ proc parseStmtList(p: var TPasParser): PNode =
if sonsLen(result) == 1: result = result.sons[0]
proc parseIfDirAux(p: var TPasParser, result: PNode) =
var
s: PNode
endMarker: TPasTokKind
addSon(result.sons[0], parseStmtList(p))
if p.tok.xkind in {pxCurlyDirLe, pxStarDirLe}:
endMarker = succ(p.tok.xkind)
var endMarker = succ(p.tok.xkind)
if whichKeyword(p.tok.ident) == wElse:
s = newNodeP(nkElse, p)
var s = newNodeP(nkElse, p)
while (p.tok.xkind != pxEof) and (p.tok.xkind != endMarker): getTok(p)
eat(p, endMarker)
addSon(s, parseStmtList(p))
@@ -666,11 +645,10 @@ proc parseIfdefDir(p: var TPasParser, endMarker: TPasTokKind): PNode =
parseIfDirAux(p, result)
proc parseIfndefDir(p: var TPasParser, endMarker: TPasTokKind): PNode =
var e: PNode
result = newNodeP(nkWhenStmt, p)
addSon(result, newNodeP(nkElifBranch, p))
getTok(p)
e = newNodeP(nkCall, p)
var e = newNodeP(nkCall, p)
addSon(e, newIdentNodeP(getIdent("not"), p))
addSon(e, definedExprAux(p))
eat(p, endMarker)
@@ -686,21 +664,17 @@ proc parseIfDir(p: var TPasParser, endMarker: TPasTokKind): PNode =
parseIfDirAux(p, result)
proc parseDirective(p: var TPasParser): PNode =
var endMarker: TPasTokKind
result = nil
if not (p.tok.xkind in {pxCurlyDirLe, pxStarDirLe}): return
endMarker = succ(p.tok.xkind)
var endMarker = succ(p.tok.xkind)
if p.tok.ident != nil:
case whichKeyword(p.tok.ident)
of wInclude:
result = parseIncludeDir(p)
eat(p, endMarker)
of wIf:
result = parseIfDir(p, endMarker)
of wIfdef:
result = parseIfdefDir(p, endMarker)
of wIfndef:
result = parseIfndefDir(p, endMarker)
of wIf: result = parseIfDir(p, endMarker)
of wIfdef: result = parseIfdefDir(p, endMarker)
of wIfndef: result = parseIfndefDir(p, endMarker)
else:
# skip unknown compiler directive
while (p.tok.xkind != pxEof) and (p.tok.xkind != endMarker): getTok(p)
@@ -716,11 +690,10 @@ proc parseRaise(p: var TPasParser): PNode =
else: addSon(result, nil)
proc parseIf(p: var TPasParser): PNode =
var branch: PNode
result = newNodeP(nkIfStmt, p)
while true:
getTok(p) # skip ``if``
branch = newNodeP(nkElifBranch, p)
var branch = newNodeP(nkElifBranch, p)
skipCom(p, branch)
addSon(branch, parseExpr(p))
eat(p, pxThen)
@@ -750,26 +723,24 @@ proc parseWhile(p: var TPasParser): PNode =
addSon(result, parseStmt(p))
proc parseRepeat(p: var TPasParser): PNode =
var a, b, c, s: PNode
result = newNodeP(nkWhileStmt, p)
getTok(p)
skipCom(p, result)
addSon(result, newIdentNodeP(getIdent("true"), p))
s = newNodeP(nkStmtList, p)
var s = newNodeP(nkStmtList, p)
while (p.tok.xkind != pxEof) and (p.tok.xkind != pxUntil):
addSon(s, parseStmt(p))
eat(p, pxUntil)
a = newNodeP(nkIfStmt, p)
var a = newNodeP(nkIfStmt, p)
skipCom(p, a)
b = newNodeP(nkElifBranch, p)
c = newNodeP(nkBreakStmt, p)
var b = newNodeP(nkElifBranch, p)
var c = newNodeP(nkBreakStmt, p)
addSon(c, nil)
addSon(b, parseExpr(p))
skipCom(p, a)
addSon(b, c)
addSon(a, b)
if (b.sons[0].kind == nkIdent) and
(b.sons[0].ident.id == getIdent("false").id):
if b.sons[0].kind == nkIdent and b.sons[0].ident.id == getIdent("false").id:
nil
else:
addSon(s, a)
@@ -800,11 +771,10 @@ proc parseCase(p: var TPasParser): PNode =
eat(p, pxEnd)
proc parseTry(p: var TPasParser): PNode =
var b, e: PNode
result = newNodeP(nkTryStmt, p)
getTok(p)
skipCom(p, result)
b = newNodeP(nkStmtList, p)
var b = newNodeP(nkStmtList, p)
while not (p.tok.xkind in {pxFinally, pxExcept, pxEof, pxEnd}):
addSon(b, parseStmt(p))
addSon(result, b)
@@ -813,7 +783,7 @@ proc parseTry(p: var TPasParser): PNode =
while p.tok.ident.id == getIdent("on").id:
b = newNodeP(nkExceptBranch, p)
getTok(p)
e = qualifiedIdent(p)
var e = qualifiedIdent(p)
if p.tok.xkind == pxColon:
getTok(p)
e = qualifiedIdent(p)
@@ -830,7 +800,7 @@ proc parseTry(p: var TPasParser): PNode =
if p.tok.xkind == pxFinally:
b = newNodeP(nkFinally, p)
getTok(p)
e = newNodeP(nkStmtList, p)
var e = newNodeP(nkStmtList, p)
while (p.tok.xkind != pxEof) and (p.tok.xkind != pxEnd):
addSon(e, parseStmt(p))
if sonsLen(e) == 0: addSon(e, newNodeP(nkNilLit, p))
@@ -1062,8 +1032,7 @@ proc parseEnum(p: var TPasParser): PNode =
proc identVis(p: var TPasParser): PNode =
# identifier with visability
var a: PNode
a = createIdentNodeP(p.tok.ident, p)
var a = createIdentNodeP(p.tok.ident, p)
if p.section == seInterface:
result = newNodeP(nkPostfix, p)
addSon(result, newIdentNodeP(getIdent("*"), p))
@@ -1079,7 +1048,8 @@ proc rawIdent(p: var TPasParser): PNode =
result = createIdentNodeP(p.tok.ident, p)
getTok(p)
proc parseIdentColonEquals(p: var TPasParser, identParser: TSymbolParser): PNode =
proc parseIdentColonEquals(p: var TPasParser,
identParser: TSymbolParser): PNode =
var a: PNode
result = newNodeP(nkIdentDefs, p)
while true:
@@ -1171,41 +1141,38 @@ proc parseRecordPart(p: var TPasParser): PNode =
break
proc exSymbol(n: var PNode) =
var a: PNode
case n.kind
of nkPostfix:
nil
of nkPragmaExpr:
exSymbol(n.sons[0])
of nkIdent, nkAccQuoted:
a = newNodeI(nkPostFix, n.info)
var a = newNodeI(nkPostFix, n.info)
addSon(a, newIdentNode(getIdent("*"), n.info))
addSon(a, n)
n = a
else: internalError(n.info, "exSymbol(): " & $n.kind)
proc fixRecordDef(n: var PNode) =
var length: int
if n == nil: return
case n.kind
of nkRecCase:
fixRecordDef(n.sons[0])
for i in countup(1, sonsLen(n) - 1):
length = sonsLen(n.sons[i])
var length = sonsLen(n.sons[i])
fixRecordDef(n.sons[i].sons[length - 1])
of nkRecList, nkRecWhen, nkElse, nkOfBranch, nkElifBranch, nkObjectTy:
for i in countup(0, sonsLen(n) - 1): fixRecordDef(n.sons[i])
of nkIdentDefs:
for i in countup(0, sonsLen(n) - 3): exSymbol(n.sons[i])
of nkNilLit:
nil
of nkNilLit: nil
else: internalError(n.info, "fixRecordDef(): " & $n.kind)
proc addPragmaToIdent(ident: var PNode, pragma: PNode) =
var e, pragmasNode: PNode
var pragmasNode: PNode
if ident.kind != nkPragmaExpr:
pragmasNode = newNodeI(nkPragma, ident.info)
e = newNodeI(nkPragmaExpr, ident.info)
var e = newNodeI(nkPragmaExpr, ident.info)
addSon(e, ident)
addSon(e, pragmasNode)
ident = e
@@ -1216,9 +1183,8 @@ proc addPragmaToIdent(ident: var PNode, pragma: PNode) =
addSon(pragmasNode, pragma)
proc parseRecordBody(p: var TPasParser, result, definition: PNode) =
var a: PNode
skipCom(p, result)
a = parseRecordPart(p)
var a = parseRecordPart(p)
if result.kind != nkTupleTy: fixRecordDef(a)
addSon(result, a)
eat(p, pxEnd)
@@ -1242,12 +1208,11 @@ proc parseRecordBody(p: var TPasParser, result, definition: PNode) =
proc parseRecordOrObject(p: var TPasParser, kind: TNodeKind,
definition: PNode): PNode =
var a: PNode
result = newNodeP(kind, p)
getTok(p)
addSon(result, nil)
if p.tok.xkind == pxParLe:
a = newNodeP(nkOfInherit, p)
var a = newNodeP(nkOfInherit, p)
getTok(p)
addSon(a, parseTypeDesc(p))
addSon(result, a)
@@ -1257,10 +1222,7 @@ proc parseRecordOrObject(p: var TPasParser, kind: TNodeKind,
parseRecordBody(p, result, definition)
proc parseTypeDesc(p: var TPasParser, definition: PNode = nil): PNode =
var
oldcontext: TPasContext
a, r: PNode
oldcontext = p.context
var oldcontext = p.context
p.context = conTypeDesc
if p.tok.xkind == pxPacked: getTok(p)
case p.tok.xkind
@@ -1274,7 +1236,7 @@ proc parseTypeDesc(p: var TPasParser, definition: PNode = nil): PNode =
result = parseCommand(p)
if result.kind != nkTupleTy: InternalError(result.info, "parseTypeDesc")
parseRecordBody(p, result, definition)
a = lastSon(result) # embed nkRecList directly into nkTupleTy
var a = lastSon(result) # embed nkRecList directly into nkTupleTy
for i in countup(0, sonsLen(a) - 1):
if i == 0: result.sons[sonsLen(result) - 1] = a.sons[0]
else: addSon(result, a.sons[i])
@@ -1287,10 +1249,8 @@ proc parseTypeDesc(p: var TPasParser, definition: PNode = nil): PNode =
addPragmaToIdent(definition.sons[0], newIdentNodeP(getIdent("final"), p))
else:
InternalError(result.info, "anonymous record is not supported")
of pxObject:
result = parseRecordOrObject(p, nkObjectTy, definition)
of pxParLe:
result = parseEnum(p)
of pxObject: result = parseRecordOrObject(p, nkObjectTy, definition)
of pxParLe: result = parseEnum(p)
of pxArray:
result = newNodeP(nkBracketExpr, p)
getTok(p)
@@ -1320,10 +1280,10 @@ proc parseTypeDesc(p: var TPasParser, definition: PNode = nil): PNode =
getTok(p)
result = parseTypeDesc(p)
else:
a = primary(p)
var a = primary(p)
if p.tok.xkind == pxDotDot:
result = newNodeP(nkBracketExpr, p)
r = newNodeP(nkRange, p)
var r = newNodeP(nkRange, p)
addSon(result, newIdentNodeP(getIdent("range"), p))
getTok(p)
addSon(r, a)
@@ -1386,13 +1346,13 @@ proc parseVar(p: var TPasParser): PNode =
result = newNodeP(nkVarSection, p)
getTok(p)
skipCom(p, result)
while p.tok.xkind == pxSymbol:
while p.tok.xkind == pxSymbol:
addSon(result, parseIdentColonEquals(p, identVis))
p.lastVarSection = result
proc parseRoutine(p: var TPasParser): PNode =
var
a, stmts: PNode
stmts: PNode
noBody: bool
result = newNodeP(nkProcDef, p)
getTok(p)
@@ -1417,19 +1377,16 @@ proc parseRoutine(p: var TPasParser): PNode =
else:
parMessage(p, errTokenExpected, "begin")
break
a = parseStmt(p)
var a = parseStmt(p)
for i in countup(0, sonsLen(a) - 1): addSon(stmts, a.sons[i])
addSon(result, stmts)
proc fixExit(p: var TPasParser, n: PNode): bool =
var
length: int
a: PNode
result = false
if (p.tok.ident.id == getIdent("exit").id):
length = sonsLen(n)
var length = sonsLen(n)
if (length <= 0): return
a = n.sons[length - 1]
var a = n.sons[length-1]
if (a.kind == nkAsgn) and (a.sons[0].kind == nkIdent) and
(a.sons[0].ident.id == getIdent("result").id):
delSon(a, 0)
@@ -1440,11 +1397,10 @@ proc fixExit(p: var TPasParser, n: PNode): bool =
skipCom(p, a)
proc fixVarSection(p: var TPasParser, counter: PNode) =
var v: PNode
if p.lastVarSection == nil: return
assert(counter.kind == nkIdent)
for i in countup(0, sonsLen(p.lastVarSection) - 1):
v = p.lastVarSection.sons[i]
var v = p.lastVarSection.sons[i]
for j in countup(0, sonsLen(v) - 3):
if v.sons[j].ident.id == counter.ident.id:
delSon(v, j)
@@ -1456,64 +1412,47 @@ proc parseBegin(p: var TPasParser, result: PNode) =
getTok(p)
while true:
case p.tok.xkind
of pxComment:
addSon(result, parseStmt(p))
of pxComment: addSon(result, parseStmt(p))
of pxSymbol:
if not fixExit(p, result): addSon(result, parseStmt(p))
of pxEnd:
getTok(p)
break
of pxSemicolon:
getTok(p)
of pxEof:
parMessage(p, errExprExpected)
of pxSemicolon: getTok(p)
of pxEof: parMessage(p, errExprExpected)
else: addSonIfNotNil(result, parseStmt(p))
if sonsLen(result) == 0: addSon(result, newNodeP(nkNilLit, p))
proc parseStmt(p: var TPasParser): PNode =
var oldcontext: TPasContext
oldcontext = p.context
var oldcontext = p.context
p.context = conStmt
result = nil
case p.tok.xkind
of pxBegin:
result = newNodeP(nkStmtList, p)
parseBegin(p, result)
of pxCommand:
result = parseCommand(p)
of pxCommand: result = parseCommand(p)
of pxCurlyDirLe, pxStarDirLe:
if isHandledDirective(p): result = parseDirective(p)
of pxIf:
result = parseIf(p)
of pxWhile:
result = parseWhile(p)
of pxRepeat:
result = parseRepeat(p)
of pxCase:
result = parseCase(p)
of pxTry:
result = parseTry(p)
of pxProcedure, pxFunction:
result = parseRoutine(p)
of pxType:
result = parseTypeSection(p)
of pxConst:
result = parseConstSection(p)
of pxVar:
result = parseVar(p)
of pxIf: result = parseIf(p)
of pxWhile: result = parseWhile(p)
of pxRepeat: result = parseRepeat(p)
of pxCase: result = parseCase(p)
of pxTry: result = parseTry(p)
of pxProcedure, pxFunction: result = parseRoutine(p)
of pxType: result = parseTypeSection(p)
of pxConst: result = parseConstSection(p)
of pxVar: result = parseVar(p)
of pxFor:
result = parseFor(p)
fixVarSection(p, result.sons[0])
of pxRaise:
result = parseRaise(p)
of pxUses:
result = parseUsesStmt(p)
of pxRaise: result = parseRaise(p)
of pxUses: result = parseUsesStmt(p)
of pxProgram, pxUnit, pxLibrary:
# skip the pointless header
while not (p.tok.xkind in {pxSemicolon, pxEof}): getTok(p)
getTok(p)
of pxInitialization:
getTok(p) # just skip the token
of pxInitialization: getTok(p) # just skip the token
of pxImplementation:
p.section = seImplementation
result = newNodeP(nkCommentStmt, p)
@@ -1525,8 +1464,7 @@ proc parseStmt(p: var TPasParser): PNode =
of pxComment:
result = newNodeP(nkCommentStmt, p)
skipCom(p, result)
of pxSemicolon:
getTok(p)
of pxSemicolon: getTok(p)
of pxSymbol:
if p.tok.ident.id == getIdent("break").id:
result = newNodeP(nkBreakStmt, p)
@@ -1545,8 +1483,7 @@ proc parseStmt(p: var TPasParser): PNode =
addSon(result, nil)
else:
result = parseExprStmt(p)
of pxDot:
getTok(p) # BUGFIX for ``end.`` in main program
of pxDot: getTok(p) # BUGFIX for ``end.`` in main program
else: result = parseExprStmt(p)
opt(p, pxSemicolon)
if result != nil: skipCom(p, result)
@@ -1557,10 +1494,8 @@ proc parseUnit(p: var TPasParser): PNode =
getTok(p) # read first token
while true:
case p.tok.xkind
of pxEof, pxEnd:
break
of pxBegin:
parseBegin(p, result)
of pxEof, pxEnd: break
of pxBegin: parseBegin(p, result)
of pxCurlyDirLe, pxStarDirLe:
if isHandledDirective(p): addSon(result, parseDirective(p))
else: parMessage(p, errXNotAllowedHere, p.tok.ident.s)

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -16,33 +16,21 @@
import
nhashes, strutils, idents
# Keywords must be kept sorted and within a range
type
TSpecialWord* = enum
wInvalid, # these are mapped to Nimrod keywords:
#[[[cog
#from string import split, capitalize
#keywords = split(open("data/keywords.txt").read())
#idents = ""
#strings = ""
#i = 1
#for k in keywords:
# idents = idents + "w" + capitalize(k) + ", "
# strings = strings + "'" + k + "', "
# if i % 4 == 0:
# idents = idents + "\n"
# strings = strings + "\n"
# i = i + 1
#cog.out(idents)
#]]]
wInvalid,
wAddr, wAnd, wAs, wAsm, wBind, wBlock, wBreak, wCase, wCast, wConst,
wContinue, wConverter, wDiscard, wDistinct, wDiv, wElif, wElse, wEnd, wEnum,
wExcept, wFinally, wFor, wFrom, wGeneric, wIf, wImplies, wImport, wIn,
wInclude, wIs, wIsnot, wIterator, wLambda, wMacro, wMethod, wMod, wNil,
wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn,
wShl, wShr, wTemplate, wTry, wTuple, wType, wVar, wWhen, wWhile, wWith,
wWithout, wXor, wYield, #[[[end]]]
# other special tokens:
wColon, wEquals, wDot, wDotDot, wHat, wStar, wMinus, # pragmas and command line options:
wWithout, wXor, wYield,
wColon, wEquals, wDot, wDotDot, wHat, wStar, wMinus,
wMagic, wTypeCheck, wFinal, wProfiler, wObjChecks, wImportc, wExportc,
wAlign, wNodecl, wPure, wVolatile, wRegister, wSideeffect, wHeader,
wNosideeffect, wNoreturn, wMerge, wLib, wDynlib, wCompilerproc, wProcVar,
@@ -60,39 +48,30 @@ type
wPassc, wT, wPassl, wL, wListcmd, wGendoc, wGenmapping, wOs, wCpu,
wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH,
wSymbolFiles, wFieldChecks, wX, wVersion, wAdvanced, wSkipcfg, wSkipProjCfg,
wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar, wAcyclic, wIndex, #
# commands:
wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar,
wAcyclic, wIndex,
wCompileToC, wCompileToCpp, wCompileToEcmaScript, wCompileToLLVM, wPretty,
wDoc, wPas, wGenDepend, wListDef, wCheck, wParse, wScan, wBoot, wLazy,
wRst2html, wRst2tex, wI, # special for the preprocessor of configuration files:
wWrite, wPutEnv, wPrependEnv, wAppendEnv, # additional Pascal keywords:
wArray, wBegin, wClass, wConstructor, wDestructor, wDo, wDownto, wExports,
wFinalization, wFunction, wGoto, wImplementation, wInherited,
wInitialization, wInterface, wLabel, wLibrary, wPacked, wProcedure,
wProgram, wProperty, wRecord, wRepeat, wResourcestring, wSet, wThen,
wThreadvar, wTo, wUnit, wUntil, wUses, # Pascal special tokens:
wExternal, wOverload, wFar, wAssembler, wForward, wIfdef, wIfndef, wEndif
wRst2html, wRst2tex, wI,
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar
TSpecialWords* = set[TSpecialWord]
const
oprLow* = ord(wColon)
oprHigh* = ord(wHat)
specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["", #
# keywords:
#
#[[[cog
#
#cog.out(strings)
#]]]
specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["",
"addr", "and", "as", "asm", "bind", "block", "break", "case", "cast",
"const", "continue", "converter", "discard", "distinct", "div", "elif",
"else", "end", "enum", "except", "finally", "for", "from", "generic", "if",
"implies", "import", "in", "include", "is", "isnot", "iterator", "lambda",
"macro", "method", "mod", "nil", "not", "notin", "object", "of", "or",
"out", "proc", "ptr", "raise", "ref", "return", "shl", "shr", "template",
"try", "tuple", "type", "var", "when", "while", "with", "without", "xor", "yield", #[[[end]]]
# other special tokens:
":", "=", ".", "..", "^", "*", "-", # pragmas and command line options:
"try", "tuple", "type", "var", "when", "while", "with", "without", "xor",
"yield",
":", "=", ".", "..", "^", "*", "-",
"magic", "typecheck", "final", "profiler", "objchecks", "importc",
"exportc", "align", "nodecl", "pure", "volatile", "register", "sideeffect",
"header", "nosideeffect", "noreturn", "merge", "lib", "dynlib",
@@ -113,18 +92,11 @@ const
"cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v",
"help", "h", "symbolfiles", "fieldchecks", "x", "version", "advanced",
"skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints",
"nomain", "subschar", "acyclic", "index", # commands:
"nomain", "subschar", "acyclic", "index",
"compiletoc", "compiletocpp", "compiletoecmascript", "compiletollvm",
"pretty", "doc", "pas", "gendepend", "listdef", "check", "parse", "scan",
"boot", "lazy", "rst2html", "rst2tex", "i", # special for the preprocessor of configuration files:
"write", "putenv", "prependenv", "appendenv", "array", "begin", "class",
"constructor", "destructor", "do", "downto", "exports", "finalization",
"function", "goto", "implementation", "inherited", "initialization",
"interface", "label", "library", "packed", "procedure", "program",
"property", "record", "repeat", "resourcestring", "set", "then",
"threadvar", "to", "unit", "until", "uses", # Pascal special tokens
"external", "overload", "far", "assembler", "forward", "ifdef", "ifndef",
"endif"]
"boot", "lazy", "rst2html", "rst2tex", "i",
"write", "putenv", "prependenv", "appendenv", "threadvar"]
proc whichKeyword*(id: PIdent): TSpecialWord
proc whichKeyword*(id: String): TSpecialWord
@@ -149,4 +121,4 @@ proc initSpecials() =
for s in countup(succ(low(specialWords)), high(specialWords)):
getIdent(specialWords[s], getNormalizedHash(specialWords[s])).id = ord(s)
initSpecials()
initSpecials()

View File

@@ -5,6 +5,9 @@ News
2010-XX-XX Version 0.8.8 released
=================================
Version 0.8.8 has been released! Get it `here <download.html>`_.
Bugfixes
--------
- The Posix version of ``os.copyFile`` has better error handling.
@@ -33,16 +36,18 @@ Changes affecting backwards compatibility
- Overloading of the subscript operator only works if the type does not provide
a built-in one.
- The search order for libraries which is affected by the ``path`` option
has been reversed, so that the project's path is searched before
the standard library's path.
- The compiler does not include a Pascal parser for bootstrapping purposes any
more. Instead there is a ``pas2nim`` tool that contains the old functionality.
2009-12-21 Version 0.8.6 released
=================================
Version 0.8.6 has been released! Get it `here <download.html>`_. The version
jump from 0.8.2 to 0.8.6 acknowledges the fact that all development of the
compiler is now done in Nimrod.
The version jump from 0.8.2 to 0.8.6 acknowledges the fact that all development
of the compiler is now done in Nimrod.
Bugfixes