├── .gitignore ├── 01-Hello ├── 01-Hello.iml ├── Hello.g4 ├── input.txt └── test_hello.py ├── 03-Array ├── 03-Array.iml ├── ArrayInit.g4 ├── README.md ├── input.txt ├── rewriter.py └── test_array.py ├── 04-Calc ├── 04-Calc.iml ├── LabeledExpr.g4 ├── MyVisitor.py ├── README.md ├── calc.py └── t.expr ├── 04-Expr ├── 04-Expr.iml ├── Expr.g4 ├── MyListener.py ├── README.md ├── t.expr └── test_Expr.py ├── 04-ExtractInterface ├── 04-ExtractInterface.iml ├── Demo.java ├── ExtractInterfaceListener.py ├── Java.g4 ├── README.md └── test_extract.py ├── 04-Rows-visitor ├── 04-Rows-visitor.iml ├── README.md ├── Rows.g4 ├── col.py └── t.rows ├── 04-modechange ├── 04-modechange.iml ├── README.md ├── XMLLexer.g4 ├── t.xml └── test.py ├── 04-sempred ├── 04-sempred.iml ├── Data.g4 ├── Readme.md ├── t.data └── test_data.py ├── 07-LableRule ├── 07-LableRule.iml ├── LExpr.g4 ├── README.md ├── t.expr ├── test_EvalContext.py ├── test_EvalListener.py └── test_EvalVistor.py ├── 07-Property ├── 07-Property.iml ├── PropertyFile.g4 ├── README.md ├── t.properties ├── test_as_loader.py ├── test_as_print.py ├── test_listener.py └── test_visitor.py ├── 08-CSV ├── 08-CSV.iml ├── CSV.g4 ├── CSV_Loader.py ├── README.md └── t.csv ├── 08-CallGraph ├── 08-CallGraph.iml ├── CallGraph.py ├── CheckSymbols.py ├── Cymbol.g4 ├── Readme.md ├── SymbolScope.py ├── output.dot ├── t.cymbol ├── vars.cymbol └── vars2.cymbol ├── 08-JSON ├── 08-JSON.iml ├── JSON.g4 ├── README.md ├── json2xml.py └── t.json ├── 09-simple ├── README.md ├── Simple.g4 ├── TestE_Listener.py ├── in1.txt ├── in2.txt ├── in3.txt ├── in4.txt ├── in5.txt ├── in6.txt └── in7.txt ├── 10-CSV ├── 10-CSV.iml ├── CSV.g4 ├── README.md ├── test_csv.py └── users.csv ├── 10-Keyword ├── 10-Keyword.iml ├── Keywords.g4 ├── input1.txt ├── input2.txt ├── input3.txt └── test_Keyword.py ├── 10-calc ├── 10-calc.iml ├── Expr.g4 ├── README.md └── calc.py ├── 11-CppState ├── 11-CppState.iml ├── CppStat.g4 ├── PredCppStat.g4 ├── input.cpp └── input2.cpp ├── 11-predicate_lexer ├── 11-predicate_lexer.iml ├── Enum2.g4 ├── README.md ├── Temp.java └── test_EnumLexer.py ├── 11-predicate_parser ├── 11-predicate_parser.iml ├── Enum.g4 ├── README.md └── Temp.java ├── 12-channel ├── 12-channel.iml ├── Cymbol.g4 ├── README.md ├── shift_var_comments.py └── t.cym ├── 12-id_as_keyword ├── IDKeyword.g4 ├── PredKeyword.g4 ├── input.txt └── run.bat ├── 12-sea_of_text ├── Mode.txt ├── ModeTagsLexer.g4 ├── ModeTagsParser.g4 └── Tags.g4 ├── README.md ├── antlr.jar ├── antlr4module ├── bin ├── antlr-4.7.2-complete.jar ├── antlr4env.bat └── pygrun ├── img └── IDEA.png └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | __pycache__/ 3 | *.tokens 4 | *.swp 5 | 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | pip-wheel-metadata/ 29 | share/python-wheels/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | MANIFEST 34 | 35 | # PyInstaller 36 | # Usually these files are written by a python script from a template 37 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 38 | *.manifest 39 | *.spec 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .nox/ 49 | .coverage 50 | .coverage.* 51 | .cache 52 | nosetests.xml 53 | coverage.xml 54 | *.cover 55 | *.py,cover 56 | .hypothesis/ 57 | .pytest_cache/ 58 | cover/ 59 | 60 | # Translations 61 | *.mo 62 | *.pot 63 | 64 | # Django stuff: 65 | *.log 66 | local_settings.py 67 | db.sqlite3 68 | db.sqlite3-journal 69 | 70 | # Flask stuff: 71 | instance/ 72 | .webassets-cache 73 | 74 | # Scrapy stuff: 75 | .scrapy 76 | 77 | # Sphinx documentation 78 | docs/_build/ 79 | 80 | # PyBuilder 81 | .pybuilder/ 82 | target/ 83 | 84 | # Jupyter Notebook 85 | .ipynb_checkpoints 86 | 87 | # IPython 88 | profile_default/ 89 | ipython_config.py 90 | 91 | # pyenv 92 | # For a library or package, you might want to ignore these files since the code is 93 | # intended to run in multiple environments; otherwise, check them in: 94 | # .python-version 95 | 96 | # pipenv 97 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 98 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 99 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 100 | # install all needed dependencies. 101 | #Pipfile.lock 102 | 103 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 104 | __pypackages__/ 105 | 106 | # Celery stuff 107 | celerybeat-schedule 108 | celerybeat.pid 109 | 110 | # SageMath parsed files 111 | *.sage.py 112 | 113 | # Environments 114 | .env 115 | .venv 116 | env/ 117 | venv/ 118 | ENV/ 119 | env.bak/ 120 | venv.bak/ 121 | 122 | # Spyder project settings 123 | .spyderproject 124 | .spyproject 125 | 126 | # Rope project settings 127 | .ropeproject 128 | 129 | # mkdocs documentation 130 | /site 131 | 132 | # mypy 133 | .mypy_cache/ 134 | .dmypy.json 135 | dmypy.json 136 | 137 | # Pyre type checker 138 | .pyre/ 139 | 140 | # pytype static type analyzer 141 | .pytype/ 142 | 143 | # Cython debug symbols 144 | cython_debug/ 145 | 146 | # static files generated from Django application using `collectstatic` 147 | media 148 | static 149 | -------------------------------------------------------------------------------- /01-Hello/01-Hello.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /01-Hello/Hello.g4: -------------------------------------------------------------------------------- 1 | grammar Hello; // Define a grammar called Hello 2 | r : 'hello' ID ; // match keyword hello followed by an identifier 3 | ID : [a-z]+ ; // match lower-case identifiers 4 | WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines, \r (Windows) 5 | -------------------------------------------------------------------------------- /01-Hello/input.txt: -------------------------------------------------------------------------------- 1 | hello world -------------------------------------------------------------------------------- /01-Hello/test_hello.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from antlr4 import * 3 | from HelloLexer import HelloLexer 4 | from HelloParser import HelloParser 5 | 6 | 7 | def main(argv): 8 | input = FileStream(argv[1]) 9 | lexer = HelloLexer(input) 10 | stream = CommonTokenStream(lexer) 11 | parser = HelloParser(stream) 12 | tree = parser.r() 13 | print(tree.toStringTree(recog=parser)) 14 | 15 | if __name__ == '__main__': 16 | main(sys.argv) 17 | -------------------------------------------------------------------------------- /03-Array/03-Array.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /03-Array/ArrayInit.g4: -------------------------------------------------------------------------------- 1 | /** Grammars always start with a grammar header. This grammar is called 2 | * ArrayInit and must match the filename: ArrayInit.g4 3 | */ 4 | grammar ArrayInit; 5 | 6 | /** A rule called init that matches comma-separated values between {...}. */ 7 | init : '{' value (',' value)* '}' ; // must match at least one value 8 | 9 | /** A value can be either a nested array/struct or a simple integer (INT) */ 10 | value : init 11 | | INT 12 | ; 13 | 14 | // parser rules start with lowercase letters, lexer rules with uppercase 15 | INT : [0-9]+ ; // Define token INT as one or more digits 16 | WS : [ \t\r\n]+ -> skip ; // Define whitespace rule, toss it out 17 | -------------------------------------------------------------------------------- /03-Array/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | This example shows how to use listener to do simple translation of input array. 3 | 4 | # How to run 5 | ``` 6 | % antlr4py3 ArrayInit.g4 7 | % pygrun ArrayInit init --tree input.txt 8 | [@0,0:0='{',<1>,1:0] 9 | [@1,1:2='99',<4>,1:1] 10 | [@2,3:3=',',<2>,1:3] 11 | [@3,5:5='3',<4>,1:5] 12 | [@4,6:6=',',<2>,1:6] 13 | [@5,8:10='451',<4>,1:8] 14 | [@6,11:11='}',<3>,1:11] 15 | [@7,12:11='',<-1>,1:12] 16 | 17 | % pygrun ArrayInit init --tokens input.txt 18 | (init { 19 | (value 99) , 20 | (value 3) , 21 | (value 451) }) 22 | 23 | % python test_array.py input.txt 24 | (init { (value 99) , (value 3) , (value 451) }) 25 | "\u0063\u0003\u01c3" 26 | 27 | ``` -------------------------------------------------------------------------------- /03-Array/input.txt: -------------------------------------------------------------------------------- 1 | {99, 3, 451} -------------------------------------------------------------------------------- /03-Array/rewriter.py: -------------------------------------------------------------------------------- 1 | from ArrayInitListener import ArrayInitListener 2 | 3 | 4 | class RewriteListener(ArrayInitListener): 5 | # Enter a parse tree produced by ArrayInitParser#init. 6 | def enterInit(self, ctx): 7 | print("\"", end='') 8 | 9 | # Exit a parse tree produced by ArrayInitParser#init. 10 | def exitInit(self, ctx): 11 | print("\"", end='') 12 | 13 | # Enter a parse tree produced by ArrayInitParser#value. 14 | def enterValue(self, ctx): 15 | pass 16 | 17 | # Exit a parse tree produced by ArrayInitParser#value. 18 | def exitValue(self, ctx): 19 | data = ctx.INT().getText() 20 | print('\\u%04x' % int(data), end='') -------------------------------------------------------------------------------- /03-Array/test_array.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from antlr4 import * 3 | from ArrayInitLexer import ArrayInitLexer 4 | from ArrayInitParser import ArrayInitParser 5 | from rewriter import RewriteListener 6 | 7 | def main(argv): 8 | istream = FileStream(argv[1]) 9 | lexer = ArrayInitLexer(istream) 10 | stream = CommonTokenStream(lexer) 11 | parser = ArrayInitParser(stream) 12 | tree = parser.init() 13 | print(tree.toStringTree(recog=parser)) 14 | 15 | walker = ParseTreeWalker() 16 | walker.walk(RewriteListener(), tree) 17 | print() 18 | 19 | if __name__ == '__main__': 20 | main(sys.argv) 21 | -------------------------------------------------------------------------------- /04-Calc/04-Calc.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /04-Calc/LabeledExpr.g4: -------------------------------------------------------------------------------- 1 | grammar LabeledExpr; // rename to distinguish from Expr.g4 2 | 3 | prog: stat+ ; 4 | 5 | stat: expr NEWLINE # printExpr 6 | | ID '=' expr NEWLINE # assign 7 | | NEWLINE # blank 8 | ; 9 | 10 | expr: expr op=('*'|'/') expr # MulDiv 11 | | expr op=('+'|'-') expr # AddSub 12 | | INT # int 13 | | ID # id 14 | | '(' expr ')' # parens 15 | ; 16 | 17 | MUL : '*' ; // assigns token name to '*' used above in grammar 18 | DIV : '/' ; 19 | ADD : '+' ; 20 | SUB : '-' ; 21 | ID : [a-zA-Z]+ ; // match identifiers 22 | INT : [0-9]+ ; // match integers 23 | NEWLINE:'\r'? '\n' ; // return newlines to parser (is end-statement signal) 24 | WS : [ \t]+ -> skip ; // toss out whitespace 25 | -------------------------------------------------------------------------------- /04-Calc/MyVisitor.py: -------------------------------------------------------------------------------- 1 | __author__ = 'jszheng' 2 | 3 | from LabeledExprVisitor import LabeledExprVisitor 4 | from LabeledExprParser import LabeledExprParser 5 | 6 | 7 | class MyVisitor(LabeledExprVisitor): 8 | def __init__(self): 9 | self.memory = {} 10 | 11 | def visitAssign(self, ctx): 12 | name = ctx.ID().getText() 13 | value = self.visit(ctx.expr()) 14 | self.memory[name] = value 15 | return value 16 | 17 | def visitPrintExpr(self, ctx): 18 | value = self.visit(ctx.expr()) 19 | print(value) 20 | return 0 21 | 22 | def visitInt(self, ctx): 23 | return ctx.INT().getText() 24 | 25 | def visitId(self, ctx): 26 | name = ctx.ID().getText() 27 | if name in self.memory: 28 | return self.memory[name] 29 | return 0 30 | 31 | def visitMulDiv(self, ctx): 32 | left = int(self.visit(ctx.expr(0))) 33 | right = int(self.visit(ctx.expr(1))) 34 | if ctx.op.type == LabeledExprParser.MUL: 35 | return left * right 36 | return left / right 37 | 38 | def visitAddSub(self, ctx): 39 | left = int(self.visit(ctx.expr(0))) 40 | right = int(self.visit(ctx.expr(1))) 41 | if ctx.op.type == LabeledExprParser.ADD: 42 | return left + right 43 | return left - right 44 | 45 | def visitParens(self, ctx): 46 | return self.visit(ctx.expr()) 47 | -------------------------------------------------------------------------------- /04-Calc/README.md: -------------------------------------------------------------------------------- 1 | # Calculator 2 | This example shows 3 | - Visitor Pattern 4 | - Use of Alternative Label 5 | 6 | # How to run 7 | ``` 8 | % antlr4py3 -visitor -no-listener LabeledExpr.g4 9 | % type t.expr 10 | 193 11 | a = 5 12 | b = 6 13 | a+b*2 14 | (1+2)*3 15 | 16 | % python calc.py t.expr 17 | 193 18 | 17 19 | 9 20 | ``` -------------------------------------------------------------------------------- /04-Calc/calc.py: -------------------------------------------------------------------------------- 1 | __author__ = 'jszheng' 2 | 3 | import sys 4 | from antlr4 import * 5 | from antlr4.InputStream import InputStream 6 | from LabeledExprLexer import LabeledExprLexer 7 | from LabeledExprParser import LabeledExprParser 8 | from MyVisitor import MyVisitor 9 | 10 | if __name__ == '__main__': 11 | if len(sys.argv) > 1: 12 | input_stream = FileStream(sys.argv[1]) 13 | else: 14 | input_stream = InputStream(sys.stdin.readline()) 15 | 16 | lexer = LabeledExprLexer(input_stream) 17 | token_stream = CommonTokenStream(lexer) 18 | parser = LabeledExprParser(token_stream) 19 | tree = parser.prog() 20 | 21 | #lisp_tree_str = tree.toStringTree(recog=parser) 22 | #print(lisp_tree_str) 23 | 24 | visitor = MyVisitor() 25 | visitor.visit(tree) 26 | -------------------------------------------------------------------------------- /04-Calc/t.expr: -------------------------------------------------------------------------------- 1 | 193 2 | a = 5 3 | b = 6 4 | a+b*2 5 | (1+2)*3 6 | -------------------------------------------------------------------------------- /04-Expr/04-Expr.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /04-Expr/Expr.g4: -------------------------------------------------------------------------------- 1 | grammar Expr; 2 | 3 | /** The start rule; begin parsing here. */ 4 | prog: stat+ ; 5 | 6 | stat: expr NEWLINE 7 | | ID '=' expr NEWLINE 8 | | NEWLINE 9 | ; 10 | 11 | expr: expr ('*'|'/') expr 12 | | expr ('+'|'-') expr 13 | | INT 14 | | ID 15 | | '(' expr ')' 16 | ; 17 | 18 | ID : [a-zA-Z]+ ; // match identifiers