# # # The Nimrod Compiler # (c) Copyright 2008 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # This module handles the reading of the config file. import llstream, nversion, commands, os, strutils, msgs, platform, condsyms, scanner, options, idents, wordrecg proc LoadConfig*(project: string) proc LoadSpecialConfig*(configfilename: string) # implementation # ---------------- configuration file parser ----------------------------- # we use Nimrod's scanner here to safe space and work proc ppGetTok(L: var TLexer, tok: PToken) = # simple filter rawGetTok(L, tok^ ) while (tok.tokType == tkInd) or (tok.tokType == tkSad) or (tok.tokType == tkDed) or (tok.tokType == tkComment): rawGetTok(L, tok^ ) proc parseExpr(L: var TLexer, tok: PToken): bool proc parseAtom(L: var TLexer, tok: PToken): bool = if tok.tokType == tkParLe: ppGetTok(L, tok) result = parseExpr(L, tok) if tok.tokType == tkParRi: ppGetTok(L, tok) else: lexMessage(L, errTokenExpected, "\')\'") elif tok.ident.id == ord(wNot): ppGetTok(L, tok) result = not parseAtom(L, tok) else: result = isDefined(tok.ident) #condsyms.listSymbols(); #writeln(tok.ident.s + ' has the value: ', result); ppGetTok(L, tok) proc parseAndExpr(L: var TLexer, tok: PToken): bool = var b: bool result = parseAtom(L, tok) while tok.ident.id == ord(wAnd): ppGetTok(L, tok) # skip "and" b = parseAtom(L, tok) result = result and b proc parseExpr(L: var TLexer, tok: PToken): bool = var b: bool result = parseAndExpr(L, tok) while tok.ident.id == ord(wOr): ppGetTok(L, tok) # skip "or" b = parseAndExpr(L, tok) result = result or b proc EvalppIf(L: var TLexer, tok: PToken): bool = ppGetTok(L, tok) # skip 'if' or 'elif' result = parseExpr(L, tok) if tok.tokType == tkColon: ppGetTok(L, tok) else: lexMessage(L, errTokenExpected, "\':\'") var condStack: seq[bool] condStack = @ [] proc doEnd(L: var TLexer, tok: PToken) = if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if") ppGetTok(L, tok) # skip 'end' setlen(condStack, high(condStack)) type TJumpDest = enum jdEndif, jdElseEndif proc jumpToDirective(L: var TLexer, tok: PToken, dest: TJumpDest) proc doElse(L: var TLexer, tok: PToken) = if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if") ppGetTok(L, tok) if tok.tokType == tkColon: ppGetTok(L, tok) if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif) proc doElif(L: var TLexer, tok: PToken) = var res: bool if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if") res = EvalppIf(L, tok) if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif) else: condStack[high(condStack)] = true proc jumpToDirective(L: var TLexer, tok: PToken, dest: TJumpDest) = var nestedIfs: int nestedIfs = 0 while True: if (tok.ident != nil) and (tok.ident.s == "@"): ppGetTok(L, tok) case whichKeyword(tok.ident) of wIf: Inc(nestedIfs) of wElse: if (dest == jdElseEndif) and (nestedIfs == 0): doElse(L, tok) break of wElif: if (dest == jdElseEndif) and (nestedIfs == 0): doElif(L, tok) break of wEnd: if nestedIfs == 0: doEnd(L, tok) break if nestedIfs > 0: Dec(nestedIfs) else: nil ppGetTok(L, tok) elif tok.tokType == tkEof: lexMessage(L, errTokenExpected, "@end") else: ppGetTok(L, tok) proc parseDirective(L: var TLexer, tok: PToken) = var res: bool key: string ppGetTok(L, tok) # skip @ case whichKeyword(tok.ident) of wIf: setlen(condStack, len(condStack) + 1) res = EvalppIf(L, tok) condStack[high(condStack)] = res if not res: jumpToDirective(L, tok, jdElseEndif) of wElif: doElif(L, tok) of wElse: doElse(L, tok) of wEnd: doEnd(L, tok) of wWrite: ppGetTok(L, tok) msgs.MessageOut(tokToStr(tok)) ppGetTok(L, tok) of wPutEnv: ppGetTok(L, tok) key = tokToStr(tok) ppGetTok(L, tok) os.putEnv(key, tokToStr(tok)) ppGetTok(L, tok) of wPrependEnv: ppGetTok(L, tok) key = tokToStr(tok) ppGetTok(L, tok) os.putEnv(key, tokToStr(tok) & os.getenv(key)) ppGetTok(L, tok) of wAppendenv: ppGetTok(L, tok) key = tokToStr(tok) ppGetTok(L, tok) os.putEnv(key, os.getenv(key) & tokToStr(tok))