strutils.parseHexInt added

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

View file

@ -15,7 +15,6 @@ cc = gcc
@end @end
path="$lib/pure" path="$lib/pure"
path="$lib/devel"
path="$lib/impure" path="$lib/impure"
path="$lib/wrappers" path="$lib/wrappers"
path="$lib/wrappers/cairo" 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``, ## a valid floating point number, `EInvalidValue` is raised. ``NAN``,
## ``INF``, ``-INF`` are also supported (case insensitive comparison). ## ``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: # the stringify and format operators:
proc toString*[Ty](x: Ty): string {.deprecated.} proc toString*[Ty](x: Ty): string {.deprecated.}
## This generic proc is the same as the stringify operator `$`. ## This generic proc is the same as the stringify operator `$`.
@ -731,6 +735,25 @@ proc ParseBiggestInt(s: string): biggestInt =
if index == -1: if index == -1:
raise newException(EInvalidValue, "invalid integer: " & s) 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 = proc ParseFloat(s: string): float =
var var
esign = 1.0 esign = 1.0

View file

@ -232,7 +232,9 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of wPath, wP: of wPath, wP:
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
path = processPath(arg) 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: of wOut, wO:
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
options.outFile = arg options.outFile = arg

View file

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

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf # (c) Copyright 2010 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -12,7 +12,7 @@
import import
llstream, strutils, ast, astalgo, scanner, syntaxes, rnimsyn, options, msgs, 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, wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, ecmasgen, cgen, ecmasgen,
platform, interact, nimconf, importer, passaux, depends, transf, evals, types 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)): for i in countup(0, high(compMods)):
if sameFile(compMods[i].filename, filename): if sameFile(compMods[i].filename, filename):
return compMods[i].module return compMods[i].module
result = nil
proc newModule(filename: string): PSym = proc newModule(filename: string): PSym =
# We cannot call ``newSym`` here, because we have to circumvent the ID # We cannot call ``newSym`` here, because we have to circumvent the ID
@ -152,61 +151,11 @@ proc CommandInteractive() =
incl(m.flags, sfMainModule) incl(m.flags, sfMainModule)
processModule(m, "stdin", LLStreamOpenStdIn(), nil) 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) = proc CommandPretty(filename: string) =
var module = parseFile(addFileExt(filename, NimExt)) var module = parseFile(addFileExt(filename, NimExt))
if module != nil: if module != nil:
renderModule(module, getOutFile(filename, "pretty." & NimExt)) 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) = proc CommandScan(filename: string) =
var f = addFileExt(filename, nimExt) var f = addFileExt(filename, nimExt)
var stream = LLStreamOpen(f, fmRead) var stream = LLStreamOpen(f, fmRead)
@ -274,14 +223,6 @@ proc MainCommand(cmd, filename: string) =
LoadSpecialConfig(DocTexConfig) LoadSpecialConfig(DocTexConfig)
wantFile(filename) wantFile(filename)
CommandRst2TeX(filename) CommandRst2TeX(filename)
of wPas:
gCmd = cmdPas
wantFile(filename)
CommandPas(filename)
of wBoot:
gCmd = cmdBoot
wantFile(filename)
CommandPas(filename)
of wGenDepend: of wGenDepend:
gCmd = cmdGenDepend gCmd = cmdGenDepend
wantFile(filename) wantFile(filename)
@ -306,4 +247,4 @@ proc MainCommand(cmd, filename: string) =
gCmd = cmdInteractive gCmd = cmdInteractive
CommandInteractive() CommandInteractive()
else: rawMessage(errInvalidCommandX, cmd) else: rawMessage(errInvalidCommandX, cmd)

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf # (c) Copyright 2010 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -41,7 +41,7 @@ type # please make sure we have under 32 options
TGlobalOptions* = set[TGlobalOption] TGlobalOptions* = set[TGlobalOption]
TCommands* = enum # Nimrod's commands TCommands* = enum # Nimrod's commands
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToEcmaScript, cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToEcmaScript,
cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc, cmdPas, cmdBoot, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
cmdGenDepend, cmdListDef, cmdCheck, # semantic checking for whole project cmdGenDepend, cmdListDef, cmdCheck, # semantic checking for whole project
cmdParse, # parse a single file (for debugging) cmdParse, # parse a single file (for debugging)
cmdScan, # scan 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 # Pas2nim - Pascal to Nimrod source converter
# (c) Copyright 2009 Andreas Rumpf # (c) Copyright 2010 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # 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. # the scanner module.
import import
nhashes, options, msgs, strutils, platform, idents, lexbase, wordrecg, scanner nhashes, options, msgs, strutils, platform, idents, lexbase
const const
MaxLineLength* = 80 # lines longer than this lead to a warning 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'} SymChars*: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
SymStartChars*: TCharSet = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'} SymStartChars*: TCharSet = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
OpChars*: TCharSet = {'+', '-', '*', '/', '<', '>', '!', '?', '^', '.', '|', OpChars*: TCharSet = {'+', '-', '*', '/', '<', '>', '!', '?', '^', '.', '|',
'=', ':', '%', '&', '$', '@', '~', '\x80'..'\xFF'} '=', ':', '%', '&', '$', '@', '~', '\x80'..'\xFF'}
type # order is important for TPasTokKind # keywords are sorted!
type
TPasTokKind* = enum TPasTokKind* = enum
pxInvalid, pxEof, # keywords: pxInvalid, pxEof,
#[[[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)
#]]]
pxAnd, pxArray, pxAs, pxAsm, pxBegin, pxCase, pxClass, pxConst, pxAnd, pxArray, pxAs, pxAsm, pxBegin, pxCase, pxClass, pxConst,
pxConstructor, pxDestructor, pxDiv, pxDo, pxDownto, pxElse, pxEnd, pxExcept, pxConstructor, pxDestructor, pxDiv, pxDo, pxDownto, pxElse, pxEnd, pxExcept,
pxExports, pxFinalization, pxFinally, pxFor, pxFunction, pxGoto, pxIf, pxExports, pxFinalization, pxFinally, pxFor, pxFunction, pxGoto, pxIf,
@ -47,13 +34,13 @@ type # order is important for TPasTokKind
pxOr, pxOut, pxPacked, pxProcedure, pxProgram, pxProperty, pxRaise, pxOr, pxOut, pxPacked, pxProcedure, pxProgram, pxProperty, pxRaise,
pxRecord, pxRepeat, pxResourcestring, pxSet, pxShl, pxShr, pxThen, pxRecord, pxRepeat, pxResourcestring, pxSet, pxShl, pxShr, pxThen,
pxThreadvar, pxTo, pxTry, pxType, pxUnit, pxUntil, pxUses, pxVar, pxWhile, pxThreadvar, pxTo, pxTry, pxType, pxUnit, pxUntil, pxUses, pxVar, pxWhile,
pxWith, pxXor, #[[[end]]] pxWith, pxXor,
pxComment, # ordinary comment pxComment, # ordinary comment
pxCommand, # {@} pxCommand, # {@}
pxAmp, # {&} pxAmp, # {&}
pxPer, # {%} pxPer, # {%}
pxStrLit, pxSymbol, # a symbol 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, pxFloatLit, pxParLe, pxParRi, pxBracketLe, pxBracketRi, pxComma,
pxSemiColon, pxColon, # operators pxSemiColon, pxColon, # operators
pxAsgn, pxEquals, pxDot, pxDotDot, pxHat, pxPlus, pxMinus, pxStar, pxSlash, pxAsgn, pxEquals, pxDot, pxDotDot, pxHat, pxPlus, pxMinus, pxStar, pxSlash,
@ -62,10 +49,7 @@ type # order is important for TPasTokKind
TPasTokKinds* = set[TPasTokKind] TPasTokKinds* = set[TPasTokKind]
const const
PasTokKindToStr*: array[TPasTokKind, string] = ["pxInvalid", "[EOF]", #[[[cog Keywords = ["and", "array", "as", "asm", "begin", "case", "class", "const",
#cog.out(strings)
#]]]
"and", "array", "as", "asm", "begin", "case", "class", "const",
"constructor", "destructor", "div", "do", "downto", "else", "end", "except", "constructor", "destructor", "div", "do", "downto", "else", "end", "except",
"exports", "finalization", "finally", "for", "function", "goto", "if", "exports", "finalization", "finally", "for", "function", "goto", "if",
"implementation", "in", "inherited", "initialization", "inline", "implementation", "in", "inherited", "initialization", "inline",
@ -73,23 +57,74 @@ const
"or", "out", "packed", "procedure", "program", "property", "raise", "or", "out", "packed", "procedure", "program", "property", "raise",
"record", "repeat", "resourcestring", "set", "shl", "shr", "then", "record", "repeat", "resourcestring", "set", "shl", "shr", "then",
"threadvar", "to", "try", "type", "unit", "until", "uses", "var", "while", "threadvar", "to", "try", "type", "unit", "until", "uses", "var", "while",
"with", "xor", #[[[end]]] "with", "xor"]
"pxComment", "pxCommand", "{&}", "{%}", "pxStrLit", "[IDENTIFIER]",
"pxIntLit", "pxInt64Lit", "pxFloatLit", "(", ")", "[", "]", ",", ";", ":", firstKeyword = pxAnd
":=", "=", ".", "..", "^", "+", "-", "*", "/", "<=", "<", ">=", ">", "<>", lastKeyword = pxXor
"@", "(*$", "*)", "{$", "}"]
type type
TPasTok* = object of TToken # a Pascal token TPasTok* = object
xkind*: TPasTokKind # the type of the token 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 getPasTok*(L: var TPasLex, tok: var TPasTok)
proc PrintPasTok*(tok: TPasTok) proc PrintPasTok*(tok: TPasTok)
proc pasTokToStr*(tok: TPasTok): string proc pasTokToStr*(tok: TPasTok): string
# implementation # 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 = proc pastokToStr(tok: TPasTok): string =
case tok.xkind case tok.xkind
of pxIntLit, pxInt64Lit: result = $(tok.iNumber) of pxIntLit, pxInt64Lit: result = $(tok.iNumber)
@ -105,144 +140,14 @@ proc PrintPasTok(tok: TPasTok) =
writeln(stdout, pastokToStr(tok)) writeln(stdout, pastokToStr(tok))
proc setKeyword(L: var TPasLex, tok: var TPasTok) = proc setKeyword(L: var TPasLex, tok: var TPasTok) =
case tok.ident.id #[[[cog var x = binaryStrSearch(keywords, toLower(tok.ident.s))
#for k in keywords: if x < 0: tok.xkind = pxSymbol
# m = capitalize(k) else: tok.xKind = TPasTokKind(x + ord(firstKeyword))
# 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
proc matchUnderscoreChars(L: var TPasLex, tok: var TPasTok, chars: TCharSet) = proc matchUnderscoreChars(L: var TPasLex, tok: var TPasTok, chars: TCharSet) =
# matches ([chars]_)* # matches ([chars]_)*
var var pos = L.bufpos # use registers for pos, buf
pos: int var buf = L.buf
buf: cstring
pos = L.bufpos # use registers for pos, buf
buf = L.buf
while true: while true:
if buf[pos] in chars: if buf[pos] in chars:
add(tok.literal, buf[pos]) add(tok.literal, buf[pos])
@ -255,16 +160,12 @@ proc matchUnderscoreChars(L: var TPasLex, tok: var TPasTok, chars: TCharSet) =
L.bufPos = pos L.bufPos = pos
proc isFloatLiteral(s: string): bool = 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'}: if s[i] in {'.', 'e', 'E'}:
return true return true
result = false
proc getNumber2(L: var TPasLex, tok: var TPasTok) = proc getNumber2(L: var TPasLex, tok: var TPasTok) =
var var pos = L.bufpos + 1 # skip %
pos, bits: int
xi: biggestInt
pos = L.bufpos + 1 # skip %
if not (L.buf[pos] in {'0'..'1'}): if not (L.buf[pos] in {'0'..'1'}):
# BUGFIX for %date% # BUGFIX for %date%
tok.xkind = pxInvalid tok.xkind = pxInvalid
@ -272,8 +173,8 @@ proc getNumber2(L: var TPasLex, tok: var TPasTok) =
inc(L.bufpos) inc(L.bufpos)
return return
tok.base = base2 tok.base = base2
xi = 0 var xi: biggestInt = 0
bits = 0 var bits = 0
while true: while true:
case L.buf[pos] case L.buf[pos]
of 'A'..'Z', 'a'..'z', '2'..'9', '.': of 'A'..'Z', 'a'..'z', '2'..'9', '.':
@ -287,27 +188,21 @@ proc getNumber2(L: var TPasLex, tok: var TPasTok) =
inc(bits) inc(bits)
else: break else: break
tok.iNumber = xi tok.iNumber = xi
if (bits > 32): if (bits > 32): tok.xkind = pxInt64Lit
tok.xkind = pxInt64Lit else: tok.xkind = pxIntLit
else:
tok.xkind = pxIntLit
L.bufpos = pos L.bufpos = pos
proc getNumber16(L: var TPasLex, tok: var TPasTok) = proc getNumber16(L: var TPasLex, tok: var TPasTok) =
var var pos = L.bufpos + 1 # skip $
pos, bits: int
xi: biggestInt
pos = L.bufpos + 1 # skip $
tok.base = base16 tok.base = base16
xi = 0 var xi: biggestInt = 0
bits = 0 var bits = 0
while true: while true:
case L.buf[pos] case L.buf[pos]
of 'G'..'Z', 'g'..'z', '.': of 'G'..'Z', 'g'..'z', '.':
lexMessage(L, errInvalidNumber) lexMessage(L, errInvalidNumber)
inc(pos) inc(pos)
of '_': of '_': inc(pos)
inc(pos)
of '0'..'9': of '0'..'9':
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0')) xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0'))
inc(pos) inc(pos)
@ -357,11 +252,9 @@ proc HandleCRLF(L: var TLexer, pos: int): int =
else: result = pos else: result = pos
proc getString(L: var TPasLex, tok: var TPasTok) = proc getString(L: var TPasLex, tok: var TPasTok) =
var var xi: int
pos, xi: int var pos = L.bufPos
buf: cstring var buf = L.buf
pos = L.bufPos
buf = L.buf
while true: while true:
if buf[pos] == '\'': if buf[pos] == '\'':
inc(pos) inc(pos)
@ -408,16 +301,11 @@ proc getString(L: var TPasLex, tok: var TPasTok) =
L.bufpos = pos L.bufpos = pos
proc getSymbol(L: var TPasLex, tok: var TPasTok) = proc getSymbol(L: var TPasLex, tok: var TPasTok) =
var var h: THash = 0
pos: int var pos = L.bufpos
c: Char var buf = L.buf
buf: cstring
h: THash # hashing algorithm inlined
h = 0
pos = L.bufpos
buf = L.buf
while true: while true:
c = buf[pos] var c = buf[pos]
case c case c
of 'a'..'z', '0'..'9', '\x80'..'\xFF': of 'a'..'z', '0'..'9', '\x80'..'\xFF':
h = h +% Ord(c) h = h +% Ord(c)
@ -428,8 +316,7 @@ proc getSymbol(L: var TPasLex, tok: var TPasTok) =
h = h +% Ord(c) h = h +% Ord(c)
h = h +% h shl 10 h = h +% h shl 10
h = h xor (h shr 6) h = h xor (h shr 6)
of '_': of '_': nil
nil
else: break else: break
Inc(pos) Inc(pos)
h = h +% h shl 3 h = h +% h shl 3
@ -440,15 +327,12 @@ proc getSymbol(L: var TPasLex, tok: var TPasTok) =
setKeyword(L, tok) setKeyword(L, tok)
proc scanLineComment(L: var TPasLex, tok: var TPasTok) = proc scanLineComment(L: var TPasLex, tok: var TPasTok) =
var var pos = L.bufpos
buf: cstring var buf = L.buf
pos, col: int # a comment ends if the next line does not start with the // on the same
indent: int # column after only whitespace
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
tok.xkind = pxComment tok.xkind = pxComment
col = getColNumber(L, pos) var col = getColNumber(L, pos)
while true: while true:
inc(pos, 2) # skip // inc(pos, 2) # skip //
add(tok.literal, '#') add(tok.literal, '#')
@ -457,7 +341,7 @@ proc scanLineComment(L: var TPasLex, tok: var TPasTok) =
inc(pos) inc(pos)
pos = handleCRLF(L, pos) pos = handleCRLF(L, pos)
buf = L.buf buf = L.buf
indent = 0 var indent = 0
while buf[pos] == ' ': while buf[pos] == ' ':
inc(pos) inc(pos)
inc(indent) inc(indent)
@ -468,11 +352,8 @@ proc scanLineComment(L: var TPasLex, tok: var TPasTok) =
L.bufpos = pos L.bufpos = pos
proc scanCurlyComment(L: var TPasLex, tok: var TPasTok) = proc scanCurlyComment(L: var TPasLex, tok: var TPasTok) =
var var pos = L.bufpos
buf: cstring var buf = L.buf
pos: int
pos = L.bufpos
buf = L.buf
tok.literal = "#" tok.literal = "#"
tok.xkind = pxComment tok.xkind = pxComment
while true: while true:
@ -480,23 +361,19 @@ proc scanCurlyComment(L: var TPasLex, tok: var TPasTok) =
of CR, LF: of CR, LF:
pos = HandleCRLF(L, pos) pos = HandleCRLF(L, pos)
buf = L.buf buf = L.buf
tok.literal = tok.literal & "\n" & '#' add(tok.literal, "\n#")
of '}': of '}':
inc(pos) inc(pos)
break break
of lexbase.EndOfFile: of lexbase.EndOfFile: lexMessage(L, errTokenExpected, "}")
lexMessage(L, errTokenExpected, "}")
else: else:
add(tok.literal, buf[pos]) add(tok.literal, buf[pos])
inc(pos) inc(pos)
L.bufpos = pos L.bufpos = pos
proc scanStarComment(L: var TPasLex, tok: var TPasTok) = proc scanStarComment(L: var TPasLex, tok: var TPasTok) =
var var pos = L.bufpos
buf: cstring var buf = L.buf
pos: int
pos = L.bufpos
buf = L.buf
tok.literal = "#" tok.literal = "#"
tok.xkind = pxComment tok.xkind = pxComment
while true: while true:
@ -504,7 +381,7 @@ proc scanStarComment(L: var TPasLex, tok: var TPasTok) =
of CR, LF: of CR, LF:
pos = HandleCRLF(L, pos) pos = HandleCRLF(L, pos)
buf = L.buf buf = L.buf
tok.literal = tok.literal & "\n" & '#' add(tok.literal, "\n#")
of '*': of '*':
inc(pos) inc(pos)
if buf[pos] == ')': if buf[pos] == ')':
@ -520,11 +397,8 @@ proc scanStarComment(L: var TPasLex, tok: var TPasTok) =
L.bufpos = pos L.bufpos = pos
proc skip(L: var TPasLex, tok: var TPasTok) = proc skip(L: var TPasLex, tok: var TPasTok) =
var var pos = L.bufpos
buf: cstring var buf = L.buf
pos: int
pos = L.bufpos
buf = L.buf
while true: while true:
case buf[pos] case buf[pos]
of ' ', Tabulator: of ' ', Tabulator:
@ -537,11 +411,10 @@ proc skip(L: var TPasLex, tok: var TPasTok) =
L.bufpos = pos L.bufpos = pos
proc getPasTok(L: var TPasLex, tok: var TPasTok) = proc getPasTok(L: var TPasLex, tok: var TPasTok) =
var c: Char
tok.xkind = pxInvalid tok.xkind = pxInvalid
fillToken(tok) fillToken(tok)
skip(L, tok) skip(L, tok)
c = L.buf[L.bufpos] var c = L.buf[L.bufpos]
if c in SymStartChars: if c in SymStartChars:
getSymbol(L, tok) getSymbol(L, tok)
elif c in {'0'..'9'}: elif c in {'0'..'9'}:

View file

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

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf # (c) Copyright 2010 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -16,33 +16,21 @@
import import
nhashes, strutils, idents nhashes, strutils, idents
# Keywords must be kept sorted and within a range
type type
TSpecialWord* = enum TSpecialWord* = enum
wInvalid, # these are mapped to Nimrod keywords: wInvalid,
#[[[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)
#]]]
wAddr, wAnd, wAs, wAsm, wBind, wBlock, wBreak, wCase, wCast, wConst, wAddr, wAnd, wAs, wAsm, wBind, wBlock, wBreak, wCase, wCast, wConst,
wContinue, wConverter, wDiscard, wDistinct, wDiv, wElif, wElse, wEnd, wEnum, wContinue, wConverter, wDiscard, wDistinct, wDiv, wElif, wElse, wEnd, wEnum,
wExcept, wFinally, wFor, wFrom, wGeneric, wIf, wImplies, wImport, wIn, wExcept, wFinally, wFor, wFrom, wGeneric, wIf, wImplies, wImport, wIn,
wInclude, wIs, wIsnot, wIterator, wLambda, wMacro, wMethod, wMod, wNil, wInclude, wIs, wIsnot, wIterator, wLambda, wMacro, wMethod, wMod, wNil,
wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn, wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn,
wShl, wShr, wTemplate, wTry, wTuple, wType, wVar, wWhen, wWhile, wWith, wShl, wShr, wTemplate, wTry, wTuple, wType, wVar, wWhen, wWhile, wWith,
wWithout, wXor, wYield, #[[[end]]] wWithout, wXor, wYield,
# other special tokens:
wColon, wEquals, wDot, wDotDot, wHat, wStar, wMinus, # pragmas and command line options: wColon, wEquals, wDot, wDotDot, wHat, wStar, wMinus,
wMagic, wTypeCheck, wFinal, wProfiler, wObjChecks, wImportc, wExportc, wMagic, wTypeCheck, wFinal, wProfiler, wObjChecks, wImportc, wExportc,
wAlign, wNodecl, wPure, wVolatile, wRegister, wSideeffect, wHeader, wAlign, wNodecl, wPure, wVolatile, wRegister, wSideeffect, wHeader,
wNosideeffect, wNoreturn, wMerge, wLib, wDynlib, wCompilerproc, wProcVar, wNosideeffect, wNoreturn, wMerge, wLib, wDynlib, wCompilerproc, wProcVar,
@ -60,39 +48,30 @@ type
wPassc, wT, wPassl, wL, wListcmd, wGendoc, wGenmapping, wOs, wCpu, wPassc, wT, wPassl, wL, wListcmd, wGendoc, wGenmapping, wOs, wCpu,
wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH, wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH,
wSymbolFiles, wFieldChecks, wX, wVersion, wAdvanced, wSkipcfg, wSkipProjCfg, wSymbolFiles, wFieldChecks, wX, wVersion, wAdvanced, wSkipcfg, wSkipProjCfg,
wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar, wAcyclic, wIndex, # wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar,
# commands: wAcyclic, wIndex,
wCompileToC, wCompileToCpp, wCompileToEcmaScript, wCompileToLLVM, wPretty, wCompileToC, wCompileToCpp, wCompileToEcmaScript, wCompileToLLVM, wPretty,
wDoc, wPas, wGenDepend, wListDef, wCheck, wParse, wScan, wBoot, wLazy, wDoc, wPas, wGenDepend, wListDef, wCheck, wParse, wScan, wBoot, wLazy,
wRst2html, wRst2tex, wI, # special for the preprocessor of configuration files: wRst2html, wRst2tex, wI,
wWrite, wPutEnv, wPrependEnv, wAppendEnv, # additional Pascal keywords: wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar
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
TSpecialWords* = set[TSpecialWord] TSpecialWords* = set[TSpecialWord]
const const
oprLow* = ord(wColon) oprLow* = ord(wColon)
oprHigh* = ord(wHat) oprHigh* = ord(wHat)
specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["", # specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["",
# keywords:
#
#[[[cog
#
#cog.out(strings)
#]]]
"addr", "and", "as", "asm", "bind", "block", "break", "case", "cast", "addr", "and", "as", "asm", "bind", "block", "break", "case", "cast",
"const", "continue", "converter", "discard", "distinct", "div", "elif", "const", "continue", "converter", "discard", "distinct", "div", "elif",
"else", "end", "enum", "except", "finally", "for", "from", "generic", "if", "else", "end", "enum", "except", "finally", "for", "from", "generic", "if",
"implies", "import", "in", "include", "is", "isnot", "iterator", "lambda", "implies", "import", "in", "include", "is", "isnot", "iterator", "lambda",
"macro", "method", "mod", "nil", "not", "notin", "object", "of", "or", "macro", "method", "mod", "nil", "not", "notin", "object", "of", "or",
"out", "proc", "ptr", "raise", "ref", "return", "shl", "shr", "template", "out", "proc", "ptr", "raise", "ref", "return", "shl", "shr", "template",
"try", "tuple", "type", "var", "when", "while", "with", "without", "xor", "yield", #[[[end]]] "try", "tuple", "type", "var", "when", "while", "with", "without", "xor",
# other special tokens: "yield",
":", "=", ".", "..", "^", "*", "-", # pragmas and command line options:
":", "=", ".", "..", "^", "*", "-",
"magic", "typecheck", "final", "profiler", "objchecks", "importc", "magic", "typecheck", "final", "profiler", "objchecks", "importc",
"exportc", "align", "nodecl", "pure", "volatile", "register", "sideeffect", "exportc", "align", "nodecl", "pure", "volatile", "register", "sideeffect",
"header", "nosideeffect", "noreturn", "merge", "lib", "dynlib", "header", "nosideeffect", "noreturn", "merge", "lib", "dynlib",
@ -113,18 +92,11 @@ const
"cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v", "cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v",
"help", "h", "symbolfiles", "fieldchecks", "x", "version", "advanced", "help", "h", "symbolfiles", "fieldchecks", "x", "version", "advanced",
"skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints", "skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints",
"nomain", "subschar", "acyclic", "index", # commands: "nomain", "subschar", "acyclic", "index",
"compiletoc", "compiletocpp", "compiletoecmascript", "compiletollvm", "compiletoc", "compiletocpp", "compiletoecmascript", "compiletollvm",
"pretty", "doc", "pas", "gendepend", "listdef", "check", "parse", "scan", "pretty", "doc", "pas", "gendepend", "listdef", "check", "parse", "scan",
"boot", "lazy", "rst2html", "rst2tex", "i", # special for the preprocessor of configuration files: "boot", "lazy", "rst2html", "rst2tex", "i",
"write", "putenv", "prependenv", "appendenv", "array", "begin", "class", "write", "putenv", "prependenv", "appendenv", "threadvar"]
"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"]
proc whichKeyword*(id: PIdent): TSpecialWord proc whichKeyword*(id: PIdent): TSpecialWord
proc whichKeyword*(id: String): TSpecialWord proc whichKeyword*(id: String): TSpecialWord
@ -149,4 +121,4 @@ proc initSpecials() =
for s in countup(succ(low(specialWords)), high(specialWords)): for s in countup(succ(low(specialWords)), high(specialWords)):
getIdent(specialWords[s], getNormalizedHash(specialWords[s])).id = ord(s) 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 2010-XX-XX Version 0.8.8 released
================================= =================================
Version 0.8.8 has been released! Get it `here <download.html>`_.
Bugfixes Bugfixes
-------- --------
- The Posix version of ``os.copyFile`` has better error handling. - 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 - Overloading of the subscript operator only works if the type does not provide
a built-in one. 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 2009-12-21 Version 0.8.6 released
================================= =================================
Version 0.8.6 has been released! Get it `here <download.html>`_. The version The version jump from 0.8.2 to 0.8.6 acknowledges the fact that all development
jump from 0.8.2 to 0.8.6 acknowledges the fact that all development of the of the compiler is now done in Nimrod.
compiler is now done in Nimrod.
Bugfixes Bugfixes