diff options
Diffstat (limited to 'tools/grammar_nanny.nim')
-rw-r--r-- | tools/grammar_nanny.nim | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/tools/grammar_nanny.nim b/tools/grammar_nanny.nim new file mode 100644 index 000000000..cbdc51efc --- /dev/null +++ b/tools/grammar_nanny.nim @@ -0,0 +1,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()) |