grammar_nanny.nim 1.4 KB

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