1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
## Simple tool to check for obvious mistakes in Nim's
## grammar.txt file.
import std / [strutils, sets]
when defined(nimPreviewSlimSystem):
import std/syncio
import ".." / compiler / [
llstream, lexer, options, msgs, idents,
lineinfos, pathutils]
proc checkGrammarFileImpl(cache: IdentCache, config: ConfigRef) =
var f = AbsoluteFile"doc/grammar.txt"
let data = readFile(f.string).multiReplace({"IND{=}": "SAME_IND", "'": "\""})
var stream = llStreamOpen(data)
var declaredSyms = initHashSet[string]()
var usedSyms = initHashSet[string]()
usedSyms.incl "module" # 'module' is the start rule.
if stream != nil:
declaredSyms.incl "section" # special case for 'section(RULE)' in the grammar
var
L: Lexer
tok: Token
openLexer(L, f, stream, cache, config)
# load the first token:
rawGetTok(L, tok)
var word = ""
while tok.tokType != tkEof:
#printTok(config, tok)
if isKeyword(tok.tokType) or tok.tokType == tkSymbol:
word = tok.ident.s
rawGetTok(L, tok)
if tok.tokType == tkEquals:
declaredSyms.incl word
rawGetTok(L, tok)
elif not allCharsInSet(word, {'A'..'Z', '0'..'9', '_'}):
usedSyms.incl word
else:
rawGetTok(L, tok)
for u in declaredSyms:
if u notin usedSyms:
echo "Unused non-terminal: ", u
for u in usedSyms:
if u notin declaredSyms:
echo "Undeclared non-terminal: ", u
closeLexer(L)
else:
rawMessage(config, errGenerated, "cannot open file: " & f.string)
proc checkGrammarFile* =
checkGrammarFileImpl(newIdentCache(), newConfigRef())
|