From 35d8461e66c1b4b20fdf57de24f325ce8acdc15a Mon Sep 17 00:00:00 2001 From: LSilvaO Date: Wed, 26 Feb 2020 10:55:32 -0500 Subject: [PATCH 01/77] Primera entrega lexer y parser --- doc/Readme.md | 6 +- src/COOL.interp | 111 ++ src/COOL.tokens | 68 + src/COOLCompiler.py | 15 + src/COOLLexer.interp | 178 ++ src/COOLLexer.py | 267 +++ src/COOLLexer.tokens | 68 + src/COOLListener.py | 298 ++++ src/COOLParser.py | 1757 +++++++++++++++++++ src/antlr4/BufferedTokenStream.py | 303 ++++ src/antlr4/CommonTokenFactory.py | 59 + src/antlr4/CommonTokenStream.py | 86 + src/antlr4/FileStream.py | 34 + src/antlr4/InputStream.py | 104 ++ src/antlr4/IntervalSet.py | 282 +++ src/antlr4/LL1Analyzer.py | 172 ++ src/antlr4/Lexer.py | 321 ++++ src/antlr4/ListTokenSource.py | 143 ++ src/antlr4/Parser.py | 572 ++++++ src/antlr4/ParserInterpreter.py | 165 ++ src/antlr4/ParserRuleContext.py | 186 ++ src/antlr4/PredictionContext.py | 623 +++++++ src/antlr4/Recognizer.py | 160 ++ src/antlr4/RuleContext.py | 228 +++ src/antlr4/StdinStream.py | 11 + src/antlr4/Token.py | 155 ++ src/antlr4/TokenStreamRewriter.py | 237 +++ src/antlr4/Utils.py | 33 + src/antlr4/__init__.py | 21 + src/antlr4/atn/ATN.py | 127 ++ src/antlr4/atn/ATNConfig.py | 154 ++ src/antlr4/atn/ATNConfigSet.py | 209 +++ src/antlr4/atn/ATNDeserializationOptions.py | 24 + src/antlr4/atn/ATNDeserializer.py | 528 ++++++ src/antlr4/atn/ATNSimulator.py | 47 + src/antlr4/atn/ATNState.py | 254 +++ src/antlr4/atn/ATNType.py | 17 + src/antlr4/atn/LexerATNSimulator.py | 568 ++++++ src/antlr4/atn/LexerAction.py | 291 +++ src/antlr4/atn/LexerActionExecutor.py | 142 ++ src/antlr4/atn/ParserATNSimulator.py | 1649 +++++++++++++++++ src/antlr4/atn/PredictionMode.py | 499 ++++++ src/antlr4/atn/SemanticContext.py | 320 ++++ src/antlr4/atn/Transition.py | 257 +++ src/antlr4/atn/__init__.py | 1 + src/antlr4/dfa/DFA.py | 133 ++ src/antlr4/dfa/DFASerializer.py | 72 + src/antlr4/dfa/DFAState.py | 120 ++ src/antlr4/dfa/__init__.py | 1 + src/antlr4/error/DiagnosticErrorListener.py | 107 ++ src/antlr4/error/ErrorListener.py | 73 + src/antlr4/error/ErrorStrategy.py | 698 ++++++++ src/antlr4/error/Errors.py | 172 ++ src/antlr4/error/__init__.py | 1 + src/antlr4/tree/Chunk.py | 29 + src/antlr4/tree/ParseTreeMatch.py | 118 ++ src/antlr4/tree/ParseTreePattern.py | 71 + src/antlr4/tree/ParseTreePatternMatcher.py | 373 ++++ src/antlr4/tree/RuleTagToken.py | 49 + src/antlr4/tree/TokenTagToken.py | 47 + src/antlr4/tree/Tree.py | 170 ++ src/antlr4/tree/Trees.py | 111 ++ src/antlr4/tree/__init__.py | 0 src/antlr4/xpath/XPath.py | 343 ++++ src/antlr4/xpath/__init__.py | 1 + src/coolc.sh | 5 +- 66 files changed, 14439 insertions(+), 5 deletions(-) create mode 100644 src/COOL.interp create mode 100644 src/COOL.tokens create mode 100644 src/COOLCompiler.py create mode 100644 src/COOLLexer.interp create mode 100644 src/COOLLexer.py create mode 100644 src/COOLLexer.tokens create mode 100644 src/COOLListener.py create mode 100644 src/COOLParser.py create mode 100644 src/antlr4/BufferedTokenStream.py create mode 100644 src/antlr4/CommonTokenFactory.py create mode 100644 src/antlr4/CommonTokenStream.py create mode 100644 src/antlr4/FileStream.py create mode 100644 src/antlr4/InputStream.py create mode 100644 src/antlr4/IntervalSet.py create mode 100644 src/antlr4/LL1Analyzer.py create mode 100644 src/antlr4/Lexer.py create mode 100644 src/antlr4/ListTokenSource.py create mode 100644 src/antlr4/Parser.py create mode 100644 src/antlr4/ParserInterpreter.py create mode 100644 src/antlr4/ParserRuleContext.py create mode 100644 src/antlr4/PredictionContext.py create mode 100644 src/antlr4/Recognizer.py create mode 100644 src/antlr4/RuleContext.py create mode 100644 src/antlr4/StdinStream.py create mode 100644 src/antlr4/Token.py create mode 100644 src/antlr4/TokenStreamRewriter.py create mode 100644 src/antlr4/Utils.py create mode 100644 src/antlr4/__init__.py create mode 100644 src/antlr4/atn/ATN.py create mode 100644 src/antlr4/atn/ATNConfig.py create mode 100644 src/antlr4/atn/ATNConfigSet.py create mode 100644 src/antlr4/atn/ATNDeserializationOptions.py create mode 100644 src/antlr4/atn/ATNDeserializer.py create mode 100644 src/antlr4/atn/ATNSimulator.py create mode 100644 src/antlr4/atn/ATNState.py create mode 100644 src/antlr4/atn/ATNType.py create mode 100644 src/antlr4/atn/LexerATNSimulator.py create mode 100644 src/antlr4/atn/LexerAction.py create mode 100644 src/antlr4/atn/LexerActionExecutor.py create mode 100644 src/antlr4/atn/ParserATNSimulator.py create mode 100644 src/antlr4/atn/PredictionMode.py create mode 100644 src/antlr4/atn/SemanticContext.py create mode 100644 src/antlr4/atn/Transition.py create mode 100644 src/antlr4/atn/__init__.py create mode 100644 src/antlr4/dfa/DFA.py create mode 100644 src/antlr4/dfa/DFASerializer.py create mode 100644 src/antlr4/dfa/DFAState.py create mode 100644 src/antlr4/dfa/__init__.py create mode 100644 src/antlr4/error/DiagnosticErrorListener.py create mode 100644 src/antlr4/error/ErrorListener.py create mode 100644 src/antlr4/error/ErrorStrategy.py create mode 100644 src/antlr4/error/Errors.py create mode 100644 src/antlr4/error/__init__.py create mode 100644 src/antlr4/tree/Chunk.py create mode 100644 src/antlr4/tree/ParseTreeMatch.py create mode 100644 src/antlr4/tree/ParseTreePattern.py create mode 100644 src/antlr4/tree/ParseTreePatternMatcher.py create mode 100644 src/antlr4/tree/RuleTagToken.py create mode 100644 src/antlr4/tree/TokenTagToken.py create mode 100644 src/antlr4/tree/Tree.py create mode 100644 src/antlr4/tree/Trees.py create mode 100644 src/antlr4/tree/__init__.py create mode 100644 src/antlr4/xpath/XPath.py create mode 100644 src/antlr4/xpath/__init__.py diff --git a/doc/Readme.md b/doc/Readme.md index 402477c8..59c61e34 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -4,9 +4,9 @@ **Nombre** | **Grupo** | **Github** --|--|-- -Nombre1 Apellido1 Apellido2 | C4xx | [@github_user](https://github.com/) -Nombre2 Apellido1 Apellido2 | C4xx | [@github_user](https://github.com/) -Nombre3 Apellido1 Apellido2 | C4xx | [@github_user](https://github.com/) +Liset Silva Oropesa | C411 | [@github_user](https://github.com/) +Pablo Antonio de Armas Suarez | C411 | [@github_user](https://github.com/) +Yenli Gil Machado | C412 | [@github_user](https://github.com/) ## Readme diff --git a/src/COOL.interp b/src/COOL.interp new file mode 100644 index 00000000..f2d42957 --- /dev/null +++ b/src/COOL.interp @@ -0,0 +1,111 @@ +token literal names: +null +';' +'{' +'}' +'(' +',' +')' +':' +'@' +'.' +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +'<-' +'=>' +'+' +'-' +'*' +'/' +'<' +'<=' +'=' +'~' +'(*' +'*)' +null +null +null + +token symbolic names: +null +null +null +null +null +null +null +null +null +null +CLASS +ELSE +FALSE +FI +IF +IN +INHERITS +ISVOID +LET +LOOP +POOL +THEN +WHILE +CASE +ESAC +NEW +OF +NOT +TRUE +STRING +INT +TYPEID +OBJECTID +ASSIGNMENT +CASE_ARROW +ADD +MINUS +MULTIPLY +DIVISION +LESS_THAN +LESS_EQUAL +EQUAL +INTEGER_NEGATIVE +OPEN_COMMENT +CLOSE_COMMENT +COMMENT +ONE_LINE_COMMENT +WHITESPACE + +rule names: +program +programBlocks +classDefine +feature +formal +expression + + +atn: +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 49, 226, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 22, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 28, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 34, 10, 4, 12, 4, 14, 4, 37, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 46, 10, 5, 12, 5, 14, 5, 49, 11, 5, 7, 5, 51, 10, 5, 12, 5, 14, 5, 54, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 68, 10, 5, 5, 5, 70, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 82, 10, 7, 12, 7, 14, 7, 85, 11, 7, 7, 7, 87, 10, 7, 12, 7, 14, 7, 90, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 111, 10, 7, 13, 7, 14, 7, 112, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 123, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 131, 10, 7, 7, 7, 133, 10, 7, 12, 7, 14, 7, 136, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 150, 10, 7, 13, 7, 14, 7, 151, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 176, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 202, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 210, 10, 7, 12, 7, 14, 7, 213, 11, 7, 7, 7, 215, 10, 7, 12, 7, 14, 7, 218, 11, 7, 3, 7, 7, 7, 221, 10, 7, 12, 7, 14, 7, 224, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 260, 2, 14, 3, 2, 2, 2, 4, 21, 3, 2, 2, 2, 6, 23, 3, 2, 2, 2, 8, 69, 3, 2, 2, 2, 10, 71, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 3, 3, 2, 2, 2, 16, 17, 5, 6, 4, 2, 17, 18, 7, 3, 2, 2, 18, 19, 5, 4, 3, 2, 19, 22, 3, 2, 2, 2, 20, 22, 7, 2, 2, 3, 21, 16, 3, 2, 2, 2, 21, 20, 3, 2, 2, 2, 22, 5, 3, 2, 2, 2, 23, 24, 7, 12, 2, 2, 24, 27, 7, 33, 2, 2, 25, 26, 7, 18, 2, 2, 26, 28, 7, 33, 2, 2, 27, 25, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 29, 3, 2, 2, 2, 29, 35, 7, 4, 2, 2, 30, 31, 5, 8, 5, 2, 31, 32, 7, 3, 2, 2, 32, 34, 3, 2, 2, 2, 33, 30, 3, 2, 2, 2, 34, 37, 3, 2, 2, 2, 35, 33, 3, 2, 2, 2, 35, 36, 3, 2, 2, 2, 36, 38, 3, 2, 2, 2, 37, 35, 3, 2, 2, 2, 38, 39, 7, 5, 2, 2, 39, 7, 3, 2, 2, 2, 40, 41, 7, 34, 2, 2, 41, 52, 7, 6, 2, 2, 42, 47, 5, 10, 6, 2, 43, 44, 7, 7, 2, 2, 44, 46, 5, 10, 6, 2, 45, 43, 3, 2, 2, 2, 46, 49, 3, 2, 2, 2, 47, 45, 3, 2, 2, 2, 47, 48, 3, 2, 2, 2, 48, 51, 3, 2, 2, 2, 49, 47, 3, 2, 2, 2, 50, 42, 3, 2, 2, 2, 51, 54, 3, 2, 2, 2, 52, 50, 3, 2, 2, 2, 52, 53, 3, 2, 2, 2, 53, 55, 3, 2, 2, 2, 54, 52, 3, 2, 2, 2, 55, 56, 7, 8, 2, 2, 56, 57, 7, 9, 2, 2, 57, 58, 7, 33, 2, 2, 58, 59, 7, 4, 2, 2, 59, 60, 5, 12, 7, 2, 60, 61, 7, 5, 2, 2, 61, 70, 3, 2, 2, 2, 62, 63, 7, 34, 2, 2, 63, 64, 7, 9, 2, 2, 64, 67, 7, 33, 2, 2, 65, 66, 7, 35, 2, 2, 66, 68, 5, 12, 7, 2, 67, 65, 3, 2, 2, 2, 67, 68, 3, 2, 2, 2, 68, 70, 3, 2, 2, 2, 69, 40, 3, 2, 2, 2, 69, 62, 3, 2, 2, 2, 70, 9, 3, 2, 2, 2, 71, 72, 7, 34, 2, 2, 72, 73, 7, 9, 2, 2, 73, 74, 7, 33, 2, 2, 74, 11, 3, 2, 2, 2, 75, 76, 8, 7, 1, 2, 76, 77, 7, 34, 2, 2, 77, 88, 7, 6, 2, 2, 78, 83, 5, 12, 7, 2, 79, 80, 7, 7, 2, 2, 80, 82, 5, 12, 7, 2, 81, 79, 3, 2, 2, 2, 82, 85, 3, 2, 2, 2, 83, 81, 3, 2, 2, 2, 83, 84, 3, 2, 2, 2, 84, 87, 3, 2, 2, 2, 85, 83, 3, 2, 2, 2, 86, 78, 3, 2, 2, 2, 87, 90, 3, 2, 2, 2, 88, 86, 3, 2, 2, 2, 88, 89, 3, 2, 2, 2, 89, 91, 3, 2, 2, 2, 90, 88, 3, 2, 2, 2, 91, 176, 7, 8, 2, 2, 92, 93, 7, 16, 2, 2, 93, 94, 5, 12, 7, 2, 94, 95, 7, 23, 2, 2, 95, 96, 5, 12, 7, 2, 96, 97, 7, 13, 2, 2, 97, 98, 5, 12, 7, 2, 98, 99, 7, 15, 2, 2, 99, 176, 3, 2, 2, 2, 100, 101, 7, 24, 2, 2, 101, 102, 5, 12, 7, 2, 102, 103, 7, 21, 2, 2, 103, 104, 5, 12, 7, 2, 104, 105, 7, 22, 2, 2, 105, 176, 3, 2, 2, 2, 106, 110, 7, 4, 2, 2, 107, 108, 5, 12, 7, 2, 108, 109, 7, 3, 2, 2, 109, 111, 3, 2, 2, 2, 110, 107, 3, 2, 2, 2, 111, 112, 3, 2, 2, 2, 112, 110, 3, 2, 2, 2, 112, 113, 3, 2, 2, 2, 113, 114, 3, 2, 2, 2, 114, 115, 7, 5, 2, 2, 115, 176, 3, 2, 2, 2, 116, 117, 7, 20, 2, 2, 117, 118, 7, 34, 2, 2, 118, 119, 7, 9, 2, 2, 119, 122, 7, 33, 2, 2, 120, 121, 7, 35, 2, 2, 121, 123, 5, 12, 7, 2, 122, 120, 3, 2, 2, 2, 122, 123, 3, 2, 2, 2, 123, 134, 3, 2, 2, 2, 124, 125, 7, 7, 2, 2, 125, 126, 7, 34, 2, 2, 126, 127, 7, 9, 2, 2, 127, 130, 7, 33, 2, 2, 128, 129, 7, 35, 2, 2, 129, 131, 5, 12, 7, 2, 130, 128, 3, 2, 2, 2, 130, 131, 3, 2, 2, 2, 131, 133, 3, 2, 2, 2, 132, 124, 3, 2, 2, 2, 133, 136, 3, 2, 2, 2, 134, 132, 3, 2, 2, 2, 134, 135, 3, 2, 2, 2, 135, 137, 3, 2, 2, 2, 136, 134, 3, 2, 2, 2, 137, 138, 7, 17, 2, 2, 138, 176, 5, 12, 7, 22, 139, 140, 7, 25, 2, 2, 140, 141, 5, 12, 7, 2, 141, 149, 7, 28, 2, 2, 142, 143, 7, 34, 2, 2, 143, 144, 7, 9, 2, 2, 144, 145, 7, 33, 2, 2, 145, 146, 7, 36, 2, 2, 146, 147, 5, 12, 7, 2, 147, 148, 7, 3, 2, 2, 148, 150, 3, 2, 2, 2, 149, 142, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 149, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 3, 2, 2, 2, 153, 154, 7, 26, 2, 2, 154, 176, 3, 2, 2, 2, 155, 156, 7, 27, 2, 2, 156, 176, 7, 33, 2, 2, 157, 158, 7, 44, 2, 2, 158, 176, 5, 12, 7, 19, 159, 160, 7, 19, 2, 2, 160, 176, 5, 12, 7, 18, 161, 162, 7, 29, 2, 2, 162, 176, 5, 12, 7, 10, 163, 164, 7, 6, 2, 2, 164, 165, 5, 12, 7, 2, 165, 166, 7, 8, 2, 2, 166, 176, 3, 2, 2, 2, 167, 176, 7, 34, 2, 2, 168, 176, 7, 32, 2, 2, 169, 176, 7, 31, 2, 2, 170, 176, 7, 30, 2, 2, 171, 176, 7, 14, 2, 2, 172, 173, 7, 34, 2, 2, 173, 174, 7, 35, 2, 2, 174, 176, 5, 12, 7, 3, 175, 75, 3, 2, 2, 2, 175, 92, 3, 2, 2, 2, 175, 100, 3, 2, 2, 2, 175, 106, 3, 2, 2, 2, 175, 116, 3, 2, 2, 2, 175, 139, 3, 2, 2, 2, 175, 155, 3, 2, 2, 2, 175, 157, 3, 2, 2, 2, 175, 159, 3, 2, 2, 2, 175, 161, 3, 2, 2, 2, 175, 163, 3, 2, 2, 2, 175, 167, 3, 2, 2, 2, 175, 168, 3, 2, 2, 2, 175, 169, 3, 2, 2, 2, 175, 170, 3, 2, 2, 2, 175, 171, 3, 2, 2, 2, 175, 172, 3, 2, 2, 2, 176, 222, 3, 2, 2, 2, 177, 178, 12, 17, 2, 2, 178, 179, 7, 39, 2, 2, 179, 221, 5, 12, 7, 18, 180, 181, 12, 16, 2, 2, 181, 182, 7, 40, 2, 2, 182, 221, 5, 12, 7, 17, 183, 184, 12, 15, 2, 2, 184, 185, 7, 37, 2, 2, 185, 221, 5, 12, 7, 16, 186, 187, 12, 14, 2, 2, 187, 188, 7, 38, 2, 2, 188, 221, 5, 12, 7, 15, 189, 190, 12, 13, 2, 2, 190, 191, 7, 41, 2, 2, 191, 221, 5, 12, 7, 14, 192, 193, 12, 12, 2, 2, 193, 194, 7, 42, 2, 2, 194, 221, 5, 12, 7, 13, 195, 196, 12, 11, 2, 2, 196, 197, 7, 43, 2, 2, 197, 221, 5, 12, 7, 12, 198, 201, 12, 27, 2, 2, 199, 200, 7, 10, 2, 2, 200, 202, 7, 33, 2, 2, 201, 199, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 3, 2, 2, 2, 203, 204, 7, 11, 2, 2, 204, 205, 7, 34, 2, 2, 205, 216, 7, 6, 2, 2, 206, 211, 5, 12, 7, 2, 207, 208, 7, 7, 2, 2, 208, 210, 5, 12, 7, 2, 209, 207, 3, 2, 2, 2, 210, 213, 3, 2, 2, 2, 211, 209, 3, 2, 2, 2, 211, 212, 3, 2, 2, 2, 212, 215, 3, 2, 2, 2, 213, 211, 3, 2, 2, 2, 214, 206, 3, 2, 2, 2, 215, 218, 3, 2, 2, 2, 216, 214, 3, 2, 2, 2, 216, 217, 3, 2, 2, 2, 217, 219, 3, 2, 2, 2, 218, 216, 3, 2, 2, 2, 219, 221, 7, 8, 2, 2, 220, 177, 3, 2, 2, 2, 220, 180, 3, 2, 2, 2, 220, 183, 3, 2, 2, 2, 220, 186, 3, 2, 2, 2, 220, 189, 3, 2, 2, 2, 220, 192, 3, 2, 2, 2, 220, 195, 3, 2, 2, 2, 220, 198, 3, 2, 2, 2, 221, 224, 3, 2, 2, 2, 222, 220, 3, 2, 2, 2, 222, 223, 3, 2, 2, 2, 223, 13, 3, 2, 2, 2, 224, 222, 3, 2, 2, 2, 22, 21, 27, 35, 47, 52, 67, 69, 83, 88, 112, 122, 130, 134, 151, 175, 201, 211, 216, 220, 222] \ No newline at end of file diff --git a/src/COOL.tokens b/src/COOL.tokens new file mode 100644 index 00000000..320277ee --- /dev/null +++ b/src/COOL.tokens @@ -0,0 +1,68 @@ +T__0=1 +T__1=2 +T__2=3 +T__3=4 +T__4=5 +T__5=6 +T__6=7 +T__7=8 +T__8=9 +CLASS=10 +ELSE=11 +FALSE=12 +FI=13 +IF=14 +IN=15 +INHERITS=16 +ISVOID=17 +LET=18 +LOOP=19 +POOL=20 +THEN=21 +WHILE=22 +CASE=23 +ESAC=24 +NEW=25 +OF=26 +NOT=27 +TRUE=28 +STRING=29 +INT=30 +TYPEID=31 +OBJECTID=32 +ASSIGNMENT=33 +CASE_ARROW=34 +ADD=35 +MINUS=36 +MULTIPLY=37 +DIVISION=38 +LESS_THAN=39 +LESS_EQUAL=40 +EQUAL=41 +INTEGER_NEGATIVE=42 +OPEN_COMMENT=43 +CLOSE_COMMENT=44 +COMMENT=45 +ONE_LINE_COMMENT=46 +WHITESPACE=47 +';'=1 +'{'=2 +'}'=3 +'('=4 +','=5 +')'=6 +':'=7 +'@'=8 +'.'=9 +'<-'=33 +'=>'=34 +'+'=35 +'-'=36 +'*'=37 +'/'=38 +'<'=39 +'<='=40 +'='=41 +'~'=42 +'(*'=43 +'*)'=44 diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py new file mode 100644 index 00000000..dd3d486b --- /dev/null +++ b/src/COOLCompiler.py @@ -0,0 +1,15 @@ +import sys +from antlr4 import * +from COOLLexer import COOLLexer +from COOLParser import COOLParser +from COOLListener import COOLListener + +def main(argv): + input = FileStream(argv[1]) + lexer = COOLLexer(input) + stream = CommonTokenStream(lexer) + parser = COOLParser(stream) + tree = parser.program() + +if __name__ == '__main__': + main(sys.argv) diff --git a/src/COOLLexer.interp b/src/COOLLexer.interp new file mode 100644 index 00000000..d78ed196 --- /dev/null +++ b/src/COOLLexer.interp @@ -0,0 +1,178 @@ +token literal names: +null +';' +'{' +'}' +'(' +',' +')' +':' +'@' +'.' +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +'<-' +'=>' +'+' +'-' +'*' +'/' +'<' +'<=' +'=' +'~' +'(*' +'*)' +null +null +null + +token symbolic names: +null +null +null +null +null +null +null +null +null +null +CLASS +ELSE +FALSE +FI +IF +IN +INHERITS +ISVOID +LET +LOOP +POOL +THEN +WHILE +CASE +ESAC +NEW +OF +NOT +TRUE +STRING +INT +TYPEID +OBJECTID +ASSIGNMENT +CASE_ARROW +ADD +MINUS +MULTIPLY +DIVISION +LESS_THAN +LESS_EQUAL +EQUAL +INTEGER_NEGATIVE +OPEN_COMMENT +CLOSE_COMMENT +COMMENT +ONE_LINE_COMMENT +WHITESPACE + +rule names: +T__0 +T__1 +T__2 +T__3 +T__4 +T__5 +T__6 +T__7 +T__8 +CLASS +ELSE +FALSE +FI +IF +IN +INHERITS +ISVOID +LET +LOOP +POOL +THEN +WHILE +CASE +ESAC +NEW +OF +NOT +TRUE +STRING +INT +TYPEID +OBJECTID +ASSIGNMENT +CASE_ARROW +ADD +MINUS +MULTIPLY +DIVISION +LESS_THAN +LESS_EQUAL +EQUAL +INTEGER_NEGATIVE +A +C +D +E +F +H +I +L +N +O +P +R +S +T +U +V +W +ESC +UNICODE +HEX +OPEN_COMMENT +CLOSE_COMMENT +COMMENT +ONE_LINE_COMMENT +WHITESPACE + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN + +mode names: +DEFAULT_MODE + +atn: +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 49, 386, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 7, 30, 252, 10, 30, 12, 30, 14, 30, 255, 11, 30, 3, 30, 3, 30, 3, 31, 6, 31, 260, 10, 31, 13, 31, 14, 31, 261, 3, 32, 3, 32, 7, 32, 266, 10, 32, 12, 32, 14, 32, 269, 11, 32, 3, 33, 3, 33, 7, 33, 273, 10, 33, 12, 33, 14, 33, 276, 11, 33, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 61, 5, 61, 338, 10, 61, 3, 62, 3, 62, 3, 62, 3, 62, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 3, 66, 3, 66, 3, 66, 7, 66, 357, 10, 66, 12, 66, 14, 66, 360, 11, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 67, 3, 67, 7, 67, 370, 10, 67, 12, 67, 14, 67, 373, 11, 67, 3, 67, 5, 67, 376, 10, 67, 3, 67, 3, 67, 3, 68, 6, 68, 381, 10, 68, 13, 68, 14, 68, 382, 3, 68, 3, 68, 3, 358, 2, 69, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 79, 41, 81, 42, 83, 43, 85, 44, 87, 2, 89, 2, 91, 2, 93, 2, 95, 2, 97, 2, 99, 2, 101, 2, 103, 2, 105, 2, 107, 2, 109, 2, 111, 2, 113, 2, 115, 2, 117, 2, 119, 2, 121, 2, 123, 2, 125, 2, 127, 45, 129, 46, 131, 47, 133, 48, 135, 49, 3, 2, 28, 4, 2, 36, 36, 94, 94, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 3, 2, 12, 12, 5, 2, 11, 12, 14, 15, 34, 34, 2, 376, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 127, 3, 2, 2, 2, 2, 129, 3, 2, 2, 2, 2, 131, 3, 2, 2, 2, 2, 133, 3, 2, 2, 2, 2, 135, 3, 2, 2, 2, 3, 137, 3, 2, 2, 2, 5, 139, 3, 2, 2, 2, 7, 141, 3, 2, 2, 2, 9, 143, 3, 2, 2, 2, 11, 145, 3, 2, 2, 2, 13, 147, 3, 2, 2, 2, 15, 149, 3, 2, 2, 2, 17, 151, 3, 2, 2, 2, 19, 153, 3, 2, 2, 2, 21, 155, 3, 2, 2, 2, 23, 161, 3, 2, 2, 2, 25, 166, 3, 2, 2, 2, 27, 172, 3, 2, 2, 2, 29, 175, 3, 2, 2, 2, 31, 178, 3, 2, 2, 2, 33, 181, 3, 2, 2, 2, 35, 190, 3, 2, 2, 2, 37, 197, 3, 2, 2, 2, 39, 201, 3, 2, 2, 2, 41, 206, 3, 2, 2, 2, 43, 211, 3, 2, 2, 2, 45, 216, 3, 2, 2, 2, 47, 222, 3, 2, 2, 2, 49, 227, 3, 2, 2, 2, 51, 232, 3, 2, 2, 2, 53, 236, 3, 2, 2, 2, 55, 239, 3, 2, 2, 2, 57, 243, 3, 2, 2, 2, 59, 248, 3, 2, 2, 2, 61, 259, 3, 2, 2, 2, 63, 263, 3, 2, 2, 2, 65, 270, 3, 2, 2, 2, 67, 277, 3, 2, 2, 2, 69, 280, 3, 2, 2, 2, 71, 283, 3, 2, 2, 2, 73, 285, 3, 2, 2, 2, 75, 287, 3, 2, 2, 2, 77, 289, 3, 2, 2, 2, 79, 291, 3, 2, 2, 2, 81, 293, 3, 2, 2, 2, 83, 296, 3, 2, 2, 2, 85, 298, 3, 2, 2, 2, 87, 300, 3, 2, 2, 2, 89, 302, 3, 2, 2, 2, 91, 304, 3, 2, 2, 2, 93, 306, 3, 2, 2, 2, 95, 308, 3, 2, 2, 2, 97, 310, 3, 2, 2, 2, 99, 312, 3, 2, 2, 2, 101, 314, 3, 2, 2, 2, 103, 316, 3, 2, 2, 2, 105, 318, 3, 2, 2, 2, 107, 320, 3, 2, 2, 2, 109, 322, 3, 2, 2, 2, 111, 324, 3, 2, 2, 2, 113, 326, 3, 2, 2, 2, 115, 328, 3, 2, 2, 2, 117, 330, 3, 2, 2, 2, 119, 332, 3, 2, 2, 2, 121, 334, 3, 2, 2, 2, 123, 339, 3, 2, 2, 2, 125, 345, 3, 2, 2, 2, 127, 347, 3, 2, 2, 2, 129, 350, 3, 2, 2, 2, 131, 353, 3, 2, 2, 2, 133, 365, 3, 2, 2, 2, 135, 380, 3, 2, 2, 2, 137, 138, 7, 61, 2, 2, 138, 4, 3, 2, 2, 2, 139, 140, 7, 125, 2, 2, 140, 6, 3, 2, 2, 2, 141, 142, 7, 127, 2, 2, 142, 8, 3, 2, 2, 2, 143, 144, 7, 42, 2, 2, 144, 10, 3, 2, 2, 2, 145, 146, 7, 46, 2, 2, 146, 12, 3, 2, 2, 2, 147, 148, 7, 43, 2, 2, 148, 14, 3, 2, 2, 2, 149, 150, 7, 60, 2, 2, 150, 16, 3, 2, 2, 2, 151, 152, 7, 66, 2, 2, 152, 18, 3, 2, 2, 2, 153, 154, 7, 48, 2, 2, 154, 20, 3, 2, 2, 2, 155, 156, 5, 89, 45, 2, 156, 157, 5, 101, 51, 2, 157, 158, 5, 87, 44, 2, 158, 159, 5, 111, 56, 2, 159, 160, 5, 111, 56, 2, 160, 22, 3, 2, 2, 2, 161, 162, 5, 93, 47, 2, 162, 163, 5, 101, 51, 2, 163, 164, 5, 111, 56, 2, 164, 165, 5, 93, 47, 2, 165, 24, 3, 2, 2, 2, 166, 167, 7, 104, 2, 2, 167, 168, 5, 87, 44, 2, 168, 169, 5, 101, 51, 2, 169, 170, 5, 111, 56, 2, 170, 171, 5, 93, 47, 2, 171, 26, 3, 2, 2, 2, 172, 173, 5, 95, 48, 2, 173, 174, 5, 99, 50, 2, 174, 28, 3, 2, 2, 2, 175, 176, 5, 99, 50, 2, 176, 177, 5, 95, 48, 2, 177, 30, 3, 2, 2, 2, 178, 179, 5, 99, 50, 2, 179, 180, 5, 103, 52, 2, 180, 32, 3, 2, 2, 2, 181, 182, 5, 99, 50, 2, 182, 183, 5, 103, 52, 2, 183, 184, 5, 97, 49, 2, 184, 185, 5, 93, 47, 2, 185, 186, 5, 109, 55, 2, 186, 187, 5, 99, 50, 2, 187, 188, 5, 113, 57, 2, 188, 189, 5, 111, 56, 2, 189, 34, 3, 2, 2, 2, 190, 191, 5, 99, 50, 2, 191, 192, 5, 111, 56, 2, 192, 193, 5, 117, 59, 2, 193, 194, 5, 105, 53, 2, 194, 195, 5, 99, 50, 2, 195, 196, 5, 91, 46, 2, 196, 36, 3, 2, 2, 2, 197, 198, 5, 101, 51, 2, 198, 199, 5, 93, 47, 2, 199, 200, 5, 113, 57, 2, 200, 38, 3, 2, 2, 2, 201, 202, 5, 101, 51, 2, 202, 203, 5, 105, 53, 2, 203, 204, 5, 105, 53, 2, 204, 205, 5, 107, 54, 2, 205, 40, 3, 2, 2, 2, 206, 207, 5, 107, 54, 2, 207, 208, 5, 105, 53, 2, 208, 209, 5, 105, 53, 2, 209, 210, 5, 101, 51, 2, 210, 42, 3, 2, 2, 2, 211, 212, 5, 113, 57, 2, 212, 213, 5, 97, 49, 2, 213, 214, 5, 93, 47, 2, 214, 215, 5, 103, 52, 2, 215, 44, 3, 2, 2, 2, 216, 217, 5, 119, 60, 2, 217, 218, 5, 97, 49, 2, 218, 219, 5, 99, 50, 2, 219, 220, 5, 101, 51, 2, 220, 221, 5, 93, 47, 2, 221, 46, 3, 2, 2, 2, 222, 223, 5, 89, 45, 2, 223, 224, 5, 87, 44, 2, 224, 225, 5, 111, 56, 2, 225, 226, 5, 93, 47, 2, 226, 48, 3, 2, 2, 2, 227, 228, 5, 93, 47, 2, 228, 229, 5, 111, 56, 2, 229, 230, 5, 87, 44, 2, 230, 231, 5, 89, 45, 2, 231, 50, 3, 2, 2, 2, 232, 233, 5, 103, 52, 2, 233, 234, 5, 93, 47, 2, 234, 235, 5, 119, 60, 2, 235, 52, 3, 2, 2, 2, 236, 237, 5, 105, 53, 2, 237, 238, 5, 95, 48, 2, 238, 54, 3, 2, 2, 2, 239, 240, 5, 103, 52, 2, 240, 241, 5, 105, 53, 2, 241, 242, 5, 113, 57, 2, 242, 56, 3, 2, 2, 2, 243, 244, 7, 118, 2, 2, 244, 245, 5, 109, 55, 2, 245, 246, 5, 115, 58, 2, 246, 247, 5, 93, 47, 2, 247, 58, 3, 2, 2, 2, 248, 253, 7, 36, 2, 2, 249, 252, 5, 121, 61, 2, 250, 252, 10, 2, 2, 2, 251, 249, 3, 2, 2, 2, 251, 250, 3, 2, 2, 2, 252, 255, 3, 2, 2, 2, 253, 251, 3, 2, 2, 2, 253, 254, 3, 2, 2, 2, 254, 256, 3, 2, 2, 2, 255, 253, 3, 2, 2, 2, 256, 257, 7, 36, 2, 2, 257, 60, 3, 2, 2, 2, 258, 260, 9, 3, 2, 2, 259, 258, 3, 2, 2, 2, 260, 261, 3, 2, 2, 2, 261, 259, 3, 2, 2, 2, 261, 262, 3, 2, 2, 2, 262, 62, 3, 2, 2, 2, 263, 267, 9, 4, 2, 2, 264, 266, 9, 5, 2, 2, 265, 264, 3, 2, 2, 2, 266, 269, 3, 2, 2, 2, 267, 265, 3, 2, 2, 2, 267, 268, 3, 2, 2, 2, 268, 64, 3, 2, 2, 2, 269, 267, 3, 2, 2, 2, 270, 274, 9, 6, 2, 2, 271, 273, 9, 5, 2, 2, 272, 271, 3, 2, 2, 2, 273, 276, 3, 2, 2, 2, 274, 272, 3, 2, 2, 2, 274, 275, 3, 2, 2, 2, 275, 66, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 277, 278, 7, 62, 2, 2, 278, 279, 7, 47, 2, 2, 279, 68, 3, 2, 2, 2, 280, 281, 7, 63, 2, 2, 281, 282, 7, 64, 2, 2, 282, 70, 3, 2, 2, 2, 283, 284, 7, 45, 2, 2, 284, 72, 3, 2, 2, 2, 285, 286, 7, 47, 2, 2, 286, 74, 3, 2, 2, 2, 287, 288, 7, 44, 2, 2, 288, 76, 3, 2, 2, 2, 289, 290, 7, 49, 2, 2, 290, 78, 3, 2, 2, 2, 291, 292, 7, 62, 2, 2, 292, 80, 3, 2, 2, 2, 293, 294, 7, 62, 2, 2, 294, 295, 7, 63, 2, 2, 295, 82, 3, 2, 2, 2, 296, 297, 7, 63, 2, 2, 297, 84, 3, 2, 2, 2, 298, 299, 7, 128, 2, 2, 299, 86, 3, 2, 2, 2, 300, 301, 9, 7, 2, 2, 301, 88, 3, 2, 2, 2, 302, 303, 9, 8, 2, 2, 303, 90, 3, 2, 2, 2, 304, 305, 9, 9, 2, 2, 305, 92, 3, 2, 2, 2, 306, 307, 9, 10, 2, 2, 307, 94, 3, 2, 2, 2, 308, 309, 9, 11, 2, 2, 309, 96, 3, 2, 2, 2, 310, 311, 9, 12, 2, 2, 311, 98, 3, 2, 2, 2, 312, 313, 9, 13, 2, 2, 313, 100, 3, 2, 2, 2, 314, 315, 9, 14, 2, 2, 315, 102, 3, 2, 2, 2, 316, 317, 9, 15, 2, 2, 317, 104, 3, 2, 2, 2, 318, 319, 9, 16, 2, 2, 319, 106, 3, 2, 2, 2, 320, 321, 9, 17, 2, 2, 321, 108, 3, 2, 2, 2, 322, 323, 9, 18, 2, 2, 323, 110, 3, 2, 2, 2, 324, 325, 9, 19, 2, 2, 325, 112, 3, 2, 2, 2, 326, 327, 9, 20, 2, 2, 327, 114, 3, 2, 2, 2, 328, 329, 9, 21, 2, 2, 329, 116, 3, 2, 2, 2, 330, 331, 9, 22, 2, 2, 331, 118, 3, 2, 2, 2, 332, 333, 9, 23, 2, 2, 333, 120, 3, 2, 2, 2, 334, 337, 7, 94, 2, 2, 335, 338, 9, 24, 2, 2, 336, 338, 5, 123, 62, 2, 337, 335, 3, 2, 2, 2, 337, 336, 3, 2, 2, 2, 338, 122, 3, 2, 2, 2, 339, 340, 7, 119, 2, 2, 340, 341, 5, 125, 63, 2, 341, 342, 5, 125, 63, 2, 342, 343, 5, 125, 63, 2, 343, 344, 5, 125, 63, 2, 344, 124, 3, 2, 2, 2, 345, 346, 9, 25, 2, 2, 346, 126, 3, 2, 2, 2, 347, 348, 7, 42, 2, 2, 348, 349, 7, 44, 2, 2, 349, 128, 3, 2, 2, 2, 350, 351, 7, 44, 2, 2, 351, 352, 7, 43, 2, 2, 352, 130, 3, 2, 2, 2, 353, 358, 5, 127, 64, 2, 354, 357, 5, 131, 66, 2, 355, 357, 11, 2, 2, 2, 356, 354, 3, 2, 2, 2, 356, 355, 3, 2, 2, 2, 357, 360, 3, 2, 2, 2, 358, 359, 3, 2, 2, 2, 358, 356, 3, 2, 2, 2, 359, 361, 3, 2, 2, 2, 360, 358, 3, 2, 2, 2, 361, 362, 5, 129, 65, 2, 362, 363, 3, 2, 2, 2, 363, 364, 8, 66, 2, 2, 364, 132, 3, 2, 2, 2, 365, 366, 7, 47, 2, 2, 366, 367, 7, 47, 2, 2, 367, 371, 3, 2, 2, 2, 368, 370, 10, 26, 2, 2, 369, 368, 3, 2, 2, 2, 370, 373, 3, 2, 2, 2, 371, 369, 3, 2, 2, 2, 371, 372, 3, 2, 2, 2, 372, 375, 3, 2, 2, 2, 373, 371, 3, 2, 2, 2, 374, 376, 7, 12, 2, 2, 375, 374, 3, 2, 2, 2, 375, 376, 3, 2, 2, 2, 376, 377, 3, 2, 2, 2, 377, 378, 8, 67, 2, 2, 378, 134, 3, 2, 2, 2, 379, 381, 9, 27, 2, 2, 380, 379, 3, 2, 2, 2, 381, 382, 3, 2, 2, 2, 382, 380, 3, 2, 2, 2, 382, 383, 3, 2, 2, 2, 383, 384, 3, 2, 2, 2, 384, 385, 8, 68, 2, 2, 385, 136, 3, 2, 2, 2, 14, 2, 251, 253, 261, 267, 274, 337, 356, 358, 371, 375, 382, 3, 8, 2, 2] \ No newline at end of file diff --git a/src/COOLLexer.py b/src/COOLLexer.py new file mode 100644 index 00000000..d53e933d --- /dev/null +++ b/src/COOLLexer.py @@ -0,0 +1,267 @@ +# Generated from C:\Software\ANTLR\cool\COOL.g4 by ANTLR 4.7.2 +from antlr4 import * +from io import StringIO +from typing.io import TextIO +import sys + + + +def serializedATN(): + with StringIO() as buf: + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\61") + buf.write("\u0182\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7") + buf.write("\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r") + buf.write("\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23") + buf.write("\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30") + buf.write("\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36") + buf.write("\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\4%\t%") + buf.write("\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t,\4-\t-\4.") + buf.write("\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64") + buf.write("\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:") + buf.write("\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\t") + buf.write("C\4D\tD\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\7\3") + buf.write("\7\3\b\3\b\3\t\3\t\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3") + buf.write("\13\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3") + buf.write("\16\3\16\3\17\3\17\3\17\3\20\3\20\3\20\3\21\3\21\3\21") + buf.write("\3\21\3\21\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\22") + buf.write("\3\22\3\22\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24") + buf.write("\3\25\3\25\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3\27") + buf.write("\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3\30\3\31") + buf.write("\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32\3\33\3\33\3\33") + buf.write("\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\35\3\36\3\36") + buf.write("\3\36\7\36\u00fc\n\36\f\36\16\36\u00ff\13\36\3\36\3\36") + buf.write("\3\37\6\37\u0104\n\37\r\37\16\37\u0105\3 \3 \7 \u010a") + buf.write("\n \f \16 \u010d\13 \3!\3!\7!\u0111\n!\f!\16!\u0114\13") + buf.write("!\3\"\3\"\3\"\3#\3#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3") + buf.write("(\3)\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3") + buf.write("\60\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65") + buf.write("\3\66\3\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<\3<\3=") + buf.write("\3=\3=\5=\u0152\n=\3>\3>\3>\3>\3>\3>\3?\3?\3@\3@\3@\3") + buf.write("A\3A\3A\3B\3B\3B\7B\u0165\nB\fB\16B\u0168\13B\3B\3B\3") + buf.write("B\3B\3C\3C\3C\3C\7C\u0172\nC\fC\16C\u0175\13C\3C\5C\u0178") + buf.write("\nC\3C\3C\3D\6D\u017d\nD\rD\16D\u017e\3D\3D\3\u0166\2") + buf.write("E\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31") + buf.write("\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31") + buf.write("\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O") + buf.write(")Q*S+U,W\2Y\2[\2]\2_\2a\2c\2e\2g\2i\2k\2m\2o\2q\2s\2u") + buf.write("\2w\2y\2{\2}\2\177-\u0081.\u0083/\u0085\60\u0087\61\3") + buf.write("\2\34\4\2$$^^\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2") + buf.write("CCcc\4\2EEee\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4") + buf.write("\2NNnn\4\2PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVv") + buf.write("v\4\2WWww\4\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2") + buf.write("\62;CHch\3\2\f\f\5\2\13\f\16\17\"\"\2\u0178\2\3\3\2\2") + buf.write("\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2") + buf.write("\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25") + buf.write("\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3") + buf.write("\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2") + buf.write("\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2") + buf.write("\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\2") + buf.write("9\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2") + buf.write("\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2") + buf.write("\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2") + buf.write("\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085") + buf.write("\3\2\2\2\2\u0087\3\2\2\2\3\u0089\3\2\2\2\5\u008b\3\2\2") + buf.write("\2\7\u008d\3\2\2\2\t\u008f\3\2\2\2\13\u0091\3\2\2\2\r") + buf.write("\u0093\3\2\2\2\17\u0095\3\2\2\2\21\u0097\3\2\2\2\23\u0099") + buf.write("\3\2\2\2\25\u009b\3\2\2\2\27\u00a1\3\2\2\2\31\u00a6\3") + buf.write("\2\2\2\33\u00ac\3\2\2\2\35\u00af\3\2\2\2\37\u00b2\3\2") + buf.write("\2\2!\u00b5\3\2\2\2#\u00be\3\2\2\2%\u00c5\3\2\2\2\'\u00c9") + buf.write("\3\2\2\2)\u00ce\3\2\2\2+\u00d3\3\2\2\2-\u00d8\3\2\2\2") + buf.write("/\u00de\3\2\2\2\61\u00e3\3\2\2\2\63\u00e8\3\2\2\2\65\u00ec") + buf.write("\3\2\2\2\67\u00ef\3\2\2\29\u00f3\3\2\2\2;\u00f8\3\2\2") + buf.write("\2=\u0103\3\2\2\2?\u0107\3\2\2\2A\u010e\3\2\2\2C\u0115") + buf.write("\3\2\2\2E\u0118\3\2\2\2G\u011b\3\2\2\2I\u011d\3\2\2\2") + buf.write("K\u011f\3\2\2\2M\u0121\3\2\2\2O\u0123\3\2\2\2Q\u0125\3") + buf.write("\2\2\2S\u0128\3\2\2\2U\u012a\3\2\2\2W\u012c\3\2\2\2Y\u012e") + buf.write("\3\2\2\2[\u0130\3\2\2\2]\u0132\3\2\2\2_\u0134\3\2\2\2") + buf.write("a\u0136\3\2\2\2c\u0138\3\2\2\2e\u013a\3\2\2\2g\u013c\3") + buf.write("\2\2\2i\u013e\3\2\2\2k\u0140\3\2\2\2m\u0142\3\2\2\2o\u0144") + buf.write("\3\2\2\2q\u0146\3\2\2\2s\u0148\3\2\2\2u\u014a\3\2\2\2") + buf.write("w\u014c\3\2\2\2y\u014e\3\2\2\2{\u0153\3\2\2\2}\u0159\3") + buf.write("\2\2\2\177\u015b\3\2\2\2\u0081\u015e\3\2\2\2\u0083\u0161") + buf.write("\3\2\2\2\u0085\u016d\3\2\2\2\u0087\u017c\3\2\2\2\u0089") + buf.write("\u008a\7=\2\2\u008a\4\3\2\2\2\u008b\u008c\7}\2\2\u008c") + buf.write("\6\3\2\2\2\u008d\u008e\7\177\2\2\u008e\b\3\2\2\2\u008f") + buf.write("\u0090\7*\2\2\u0090\n\3\2\2\2\u0091\u0092\7.\2\2\u0092") + buf.write("\f\3\2\2\2\u0093\u0094\7+\2\2\u0094\16\3\2\2\2\u0095\u0096") + buf.write("\7<\2\2\u0096\20\3\2\2\2\u0097\u0098\7B\2\2\u0098\22\3") + buf.write("\2\2\2\u0099\u009a\7\60\2\2\u009a\24\3\2\2\2\u009b\u009c") + buf.write("\5Y-\2\u009c\u009d\5e\63\2\u009d\u009e\5W,\2\u009e\u009f") + buf.write("\5o8\2\u009f\u00a0\5o8\2\u00a0\26\3\2\2\2\u00a1\u00a2") + buf.write("\5]/\2\u00a2\u00a3\5e\63\2\u00a3\u00a4\5o8\2\u00a4\u00a5") + buf.write("\5]/\2\u00a5\30\3\2\2\2\u00a6\u00a7\7h\2\2\u00a7\u00a8") + buf.write("\5W,\2\u00a8\u00a9\5e\63\2\u00a9\u00aa\5o8\2\u00aa\u00ab") + buf.write("\5]/\2\u00ab\32\3\2\2\2\u00ac\u00ad\5_\60\2\u00ad\u00ae") + buf.write("\5c\62\2\u00ae\34\3\2\2\2\u00af\u00b0\5c\62\2\u00b0\u00b1") + buf.write("\5_\60\2\u00b1\36\3\2\2\2\u00b2\u00b3\5c\62\2\u00b3\u00b4") + buf.write("\5g\64\2\u00b4 \3\2\2\2\u00b5\u00b6\5c\62\2\u00b6\u00b7") + buf.write("\5g\64\2\u00b7\u00b8\5a\61\2\u00b8\u00b9\5]/\2\u00b9\u00ba") + buf.write("\5m\67\2\u00ba\u00bb\5c\62\2\u00bb\u00bc\5q9\2\u00bc\u00bd") + buf.write("\5o8\2\u00bd\"\3\2\2\2\u00be\u00bf\5c\62\2\u00bf\u00c0") + buf.write("\5o8\2\u00c0\u00c1\5u;\2\u00c1\u00c2\5i\65\2\u00c2\u00c3") + buf.write("\5c\62\2\u00c3\u00c4\5[.\2\u00c4$\3\2\2\2\u00c5\u00c6") + buf.write("\5e\63\2\u00c6\u00c7\5]/\2\u00c7\u00c8\5q9\2\u00c8&\3") + buf.write("\2\2\2\u00c9\u00ca\5e\63\2\u00ca\u00cb\5i\65\2\u00cb\u00cc") + buf.write("\5i\65\2\u00cc\u00cd\5k\66\2\u00cd(\3\2\2\2\u00ce\u00cf") + buf.write("\5k\66\2\u00cf\u00d0\5i\65\2\u00d0\u00d1\5i\65\2\u00d1") + buf.write("\u00d2\5e\63\2\u00d2*\3\2\2\2\u00d3\u00d4\5q9\2\u00d4") + buf.write("\u00d5\5a\61\2\u00d5\u00d6\5]/\2\u00d6\u00d7\5g\64\2\u00d7") + buf.write(",\3\2\2\2\u00d8\u00d9\5w<\2\u00d9\u00da\5a\61\2\u00da") + buf.write("\u00db\5c\62\2\u00db\u00dc\5e\63\2\u00dc\u00dd\5]/\2\u00dd") + buf.write(".\3\2\2\2\u00de\u00df\5Y-\2\u00df\u00e0\5W,\2\u00e0\u00e1") + buf.write("\5o8\2\u00e1\u00e2\5]/\2\u00e2\60\3\2\2\2\u00e3\u00e4") + buf.write("\5]/\2\u00e4\u00e5\5o8\2\u00e5\u00e6\5W,\2\u00e6\u00e7") + buf.write("\5Y-\2\u00e7\62\3\2\2\2\u00e8\u00e9\5g\64\2\u00e9\u00ea") + buf.write("\5]/\2\u00ea\u00eb\5w<\2\u00eb\64\3\2\2\2\u00ec\u00ed") + buf.write("\5i\65\2\u00ed\u00ee\5_\60\2\u00ee\66\3\2\2\2\u00ef\u00f0") + buf.write("\5g\64\2\u00f0\u00f1\5i\65\2\u00f1\u00f2\5q9\2\u00f28") + buf.write("\3\2\2\2\u00f3\u00f4\7v\2\2\u00f4\u00f5\5m\67\2\u00f5") + buf.write("\u00f6\5s:\2\u00f6\u00f7\5]/\2\u00f7:\3\2\2\2\u00f8\u00fd") + buf.write("\7$\2\2\u00f9\u00fc\5y=\2\u00fa\u00fc\n\2\2\2\u00fb\u00f9") + buf.write("\3\2\2\2\u00fb\u00fa\3\2\2\2\u00fc\u00ff\3\2\2\2\u00fd") + buf.write("\u00fb\3\2\2\2\u00fd\u00fe\3\2\2\2\u00fe\u0100\3\2\2\2") + buf.write("\u00ff\u00fd\3\2\2\2\u0100\u0101\7$\2\2\u0101<\3\2\2\2") + buf.write("\u0102\u0104\t\3\2\2\u0103\u0102\3\2\2\2\u0104\u0105\3") + buf.write("\2\2\2\u0105\u0103\3\2\2\2\u0105\u0106\3\2\2\2\u0106>") + buf.write("\3\2\2\2\u0107\u010b\t\4\2\2\u0108\u010a\t\5\2\2\u0109") + buf.write("\u0108\3\2\2\2\u010a\u010d\3\2\2\2\u010b\u0109\3\2\2\2") + buf.write("\u010b\u010c\3\2\2\2\u010c@\3\2\2\2\u010d\u010b\3\2\2") + buf.write("\2\u010e\u0112\t\6\2\2\u010f\u0111\t\5\2\2\u0110\u010f") + buf.write("\3\2\2\2\u0111\u0114\3\2\2\2\u0112\u0110\3\2\2\2\u0112") + buf.write("\u0113\3\2\2\2\u0113B\3\2\2\2\u0114\u0112\3\2\2\2\u0115") + buf.write("\u0116\7>\2\2\u0116\u0117\7/\2\2\u0117D\3\2\2\2\u0118") + buf.write("\u0119\7?\2\2\u0119\u011a\7@\2\2\u011aF\3\2\2\2\u011b") + buf.write("\u011c\7-\2\2\u011cH\3\2\2\2\u011d\u011e\7/\2\2\u011e") + buf.write("J\3\2\2\2\u011f\u0120\7,\2\2\u0120L\3\2\2\2\u0121\u0122") + buf.write("\7\61\2\2\u0122N\3\2\2\2\u0123\u0124\7>\2\2\u0124P\3\2") + buf.write("\2\2\u0125\u0126\7>\2\2\u0126\u0127\7?\2\2\u0127R\3\2") + buf.write("\2\2\u0128\u0129\7?\2\2\u0129T\3\2\2\2\u012a\u012b\7\u0080") + buf.write("\2\2\u012bV\3\2\2\2\u012c\u012d\t\7\2\2\u012dX\3\2\2\2") + buf.write("\u012e\u012f\t\b\2\2\u012fZ\3\2\2\2\u0130\u0131\t\t\2") + buf.write("\2\u0131\\\3\2\2\2\u0132\u0133\t\n\2\2\u0133^\3\2\2\2") + buf.write("\u0134\u0135\t\13\2\2\u0135`\3\2\2\2\u0136\u0137\t\f\2") + buf.write("\2\u0137b\3\2\2\2\u0138\u0139\t\r\2\2\u0139d\3\2\2\2\u013a") + buf.write("\u013b\t\16\2\2\u013bf\3\2\2\2\u013c\u013d\t\17\2\2\u013d") + buf.write("h\3\2\2\2\u013e\u013f\t\20\2\2\u013fj\3\2\2\2\u0140\u0141") + buf.write("\t\21\2\2\u0141l\3\2\2\2\u0142\u0143\t\22\2\2\u0143n\3") + buf.write("\2\2\2\u0144\u0145\t\23\2\2\u0145p\3\2\2\2\u0146\u0147") + buf.write("\t\24\2\2\u0147r\3\2\2\2\u0148\u0149\t\25\2\2\u0149t\3") + buf.write("\2\2\2\u014a\u014b\t\26\2\2\u014bv\3\2\2\2\u014c\u014d") + buf.write("\t\27\2\2\u014dx\3\2\2\2\u014e\u0151\7^\2\2\u014f\u0152") + buf.write("\t\30\2\2\u0150\u0152\5{>\2\u0151\u014f\3\2\2\2\u0151") + buf.write("\u0150\3\2\2\2\u0152z\3\2\2\2\u0153\u0154\7w\2\2\u0154") + buf.write("\u0155\5}?\2\u0155\u0156\5}?\2\u0156\u0157\5}?\2\u0157") + buf.write("\u0158\5}?\2\u0158|\3\2\2\2\u0159\u015a\t\31\2\2\u015a") + buf.write("~\3\2\2\2\u015b\u015c\7*\2\2\u015c\u015d\7,\2\2\u015d") + buf.write("\u0080\3\2\2\2\u015e\u015f\7,\2\2\u015f\u0160\7+\2\2\u0160") + buf.write("\u0082\3\2\2\2\u0161\u0166\5\177@\2\u0162\u0165\5\u0083") + buf.write("B\2\u0163\u0165\13\2\2\2\u0164\u0162\3\2\2\2\u0164\u0163") + buf.write("\3\2\2\2\u0165\u0168\3\2\2\2\u0166\u0167\3\2\2\2\u0166") + buf.write("\u0164\3\2\2\2\u0167\u0169\3\2\2\2\u0168\u0166\3\2\2\2") + buf.write("\u0169\u016a\5\u0081A\2\u016a\u016b\3\2\2\2\u016b\u016c") + buf.write("\bB\2\2\u016c\u0084\3\2\2\2\u016d\u016e\7/\2\2\u016e\u016f") + buf.write("\7/\2\2\u016f\u0173\3\2\2\2\u0170\u0172\n\32\2\2\u0171") + buf.write("\u0170\3\2\2\2\u0172\u0175\3\2\2\2\u0173\u0171\3\2\2\2") + buf.write("\u0173\u0174\3\2\2\2\u0174\u0177\3\2\2\2\u0175\u0173\3") + buf.write("\2\2\2\u0176\u0178\7\f\2\2\u0177\u0176\3\2\2\2\u0177\u0178") + buf.write("\3\2\2\2\u0178\u0179\3\2\2\2\u0179\u017a\bC\2\2\u017a") + buf.write("\u0086\3\2\2\2\u017b\u017d\t\33\2\2\u017c\u017b\3\2\2") + buf.write("\2\u017d\u017e\3\2\2\2\u017e\u017c\3\2\2\2\u017e\u017f") + buf.write("\3\2\2\2\u017f\u0180\3\2\2\2\u0180\u0181\bD\2\2\u0181") + buf.write("\u0088\3\2\2\2\16\2\u00fb\u00fd\u0105\u010b\u0112\u0151") + buf.write("\u0164\u0166\u0173\u0177\u017e\3\b\2\2") + return buf.getvalue() + + +class COOLLexer(Lexer): + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] + + T__0 = 1 + T__1 = 2 + T__2 = 3 + T__3 = 4 + T__4 = 5 + T__5 = 6 + T__6 = 7 + T__7 = 8 + T__8 = 9 + CLASS = 10 + ELSE = 11 + FALSE = 12 + FI = 13 + IF = 14 + IN = 15 + INHERITS = 16 + ISVOID = 17 + LET = 18 + LOOP = 19 + POOL = 20 + THEN = 21 + WHILE = 22 + CASE = 23 + ESAC = 24 + NEW = 25 + OF = 26 + NOT = 27 + TRUE = 28 + STRING = 29 + INT = 30 + TYPEID = 31 + OBJECTID = 32 + ASSIGNMENT = 33 + CASE_ARROW = 34 + ADD = 35 + MINUS = 36 + MULTIPLY = 37 + DIVISION = 38 + LESS_THAN = 39 + LESS_EQUAL = 40 + EQUAL = 41 + INTEGER_NEGATIVE = 42 + OPEN_COMMENT = 43 + CLOSE_COMMENT = 44 + COMMENT = 45 + ONE_LINE_COMMENT = 46 + WHITESPACE = 47 + + channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] + + modeNames = [ "DEFAULT_MODE" ] + + literalNames = [ "", + "';'", "'{'", "'}'", "'('", "','", "')'", "':'", "'@'", "'.'", + "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", "'<='", "'='", + "'~'", "'(*'", "'*)'" ] + + symbolicNames = [ "", + "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", + "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", + "OF", "NOT", "TRUE", "STRING", "INT", "TYPEID", "OBJECTID", + "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", + "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_COMMENT", + "CLOSE_COMMENT", "COMMENT", "ONE_LINE_COMMENT", "WHITESPACE" ] + + ruleNames = [ "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", + "T__7", "T__8", "CLASS", "ELSE", "FALSE", "FI", "IF", + "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", + "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", + "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", + "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", + "EQUAL", "INTEGER_NEGATIVE", "A", "C", "D", "E", "F", + "H", "I", "L", "N", "O", "P", "R", "S", "T", "U", "V", + "W", "ESC", "UNICODE", "HEX", "OPEN_COMMENT", "CLOSE_COMMENT", + "COMMENT", "ONE_LINE_COMMENT", "WHITESPACE" ] + + grammarFileName = "COOL.g4" + + def __init__(self, input=None, output:TextIO = sys.stdout): + super().__init__(input, output) + self.checkVersion("4.7.2") + self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) + self._actions = None + self._predicates = None + + diff --git a/src/COOLLexer.tokens b/src/COOLLexer.tokens new file mode 100644 index 00000000..320277ee --- /dev/null +++ b/src/COOLLexer.tokens @@ -0,0 +1,68 @@ +T__0=1 +T__1=2 +T__2=3 +T__3=4 +T__4=5 +T__5=6 +T__6=7 +T__7=8 +T__8=9 +CLASS=10 +ELSE=11 +FALSE=12 +FI=13 +IF=14 +IN=15 +INHERITS=16 +ISVOID=17 +LET=18 +LOOP=19 +POOL=20 +THEN=21 +WHILE=22 +CASE=23 +ESAC=24 +NEW=25 +OF=26 +NOT=27 +TRUE=28 +STRING=29 +INT=30 +TYPEID=31 +OBJECTID=32 +ASSIGNMENT=33 +CASE_ARROW=34 +ADD=35 +MINUS=36 +MULTIPLY=37 +DIVISION=38 +LESS_THAN=39 +LESS_EQUAL=40 +EQUAL=41 +INTEGER_NEGATIVE=42 +OPEN_COMMENT=43 +CLOSE_COMMENT=44 +COMMENT=45 +ONE_LINE_COMMENT=46 +WHITESPACE=47 +';'=1 +'{'=2 +'}'=3 +'('=4 +','=5 +')'=6 +':'=7 +'@'=8 +'.'=9 +'<-'=33 +'=>'=34 +'+'=35 +'-'=36 +'*'=37 +'/'=38 +'<'=39 +'<='=40 +'='=41 +'~'=42 +'(*'=43 +'*)'=44 diff --git a/src/COOLListener.py b/src/COOLListener.py new file mode 100644 index 00000000..50a72320 --- /dev/null +++ b/src/COOLListener.py @@ -0,0 +1,298 @@ +# Generated from C:\Software\ANTLR\cool\COOL.g4 by ANTLR 4.7.2 +from antlr4 import * +if __name__ is not None and "." in __name__: + from .COOLParser import COOLParser +else: + from COOLParser import COOLParser + +# This class defines a complete listener for a parse tree produced by COOLParser. +class COOLListener(ParseTreeListener): + + # Enter a parse tree produced by COOLParser#program. + def enterProgram(self, ctx:COOLParser.ProgramContext): + pass + + # Exit a parse tree produced by COOLParser#program. + def exitProgram(self, ctx:COOLParser.ProgramContext): + pass + + + # Enter a parse tree produced by COOLParser#classes. + def enterClasses(self, ctx:COOLParser.ClassesContext): + pass + + # Exit a parse tree produced by COOLParser#classes. + def exitClasses(self, ctx:COOLParser.ClassesContext): + pass + + + # Enter a parse tree produced by COOLParser#eof. + def enterEof(self, ctx:COOLParser.EofContext): + pass + + # Exit a parse tree produced by COOLParser#eof. + def exitEof(self, ctx:COOLParser.EofContext): + pass + + + # Enter a parse tree produced by COOLParser#classDefine. + def enterClassDefine(self, ctx:COOLParser.ClassDefineContext): + pass + + # Exit a parse tree produced by COOLParser#classDefine. + def exitClassDefine(self, ctx:COOLParser.ClassDefineContext): + pass + + + # Enter a parse tree produced by COOLParser#method. + def enterMethod(self, ctx:COOLParser.MethodContext): + pass + + # Exit a parse tree produced by COOLParser#method. + def exitMethod(self, ctx:COOLParser.MethodContext): + pass + + + # Enter a parse tree produced by COOLParser#property. + def enterProperty(self, ctx:COOLParser.PropertyContext): + pass + + # Exit a parse tree produced by COOLParser#property. + def exitProperty(self, ctx:COOLParser.PropertyContext): + pass + + + # Enter a parse tree produced by COOLParser#formal. + def enterFormal(self, ctx:COOLParser.FormalContext): + pass + + # Exit a parse tree produced by COOLParser#formal. + def exitFormal(self, ctx:COOLParser.FormalContext): + pass + + + # Enter a parse tree produced by COOLParser#letIn. + def enterLetIn(self, ctx:COOLParser.LetInContext): + pass + + # Exit a parse tree produced by COOLParser#letIn. + def exitLetIn(self, ctx:COOLParser.LetInContext): + pass + + + # Enter a parse tree produced by COOLParser#minus. + def enterMinus(self, ctx:COOLParser.MinusContext): + pass + + # Exit a parse tree produced by COOLParser#minus. + def exitMinus(self, ctx:COOLParser.MinusContext): + pass + + + # Enter a parse tree produced by COOLParser#string. + def enterString(self, ctx:COOLParser.StringContext): + pass + + # Exit a parse tree produced by COOLParser#string. + def exitString(self, ctx:COOLParser.StringContext): + pass + + + # Enter a parse tree produced by COOLParser#isvoid. + def enterIsvoid(self, ctx:COOLParser.IsvoidContext): + pass + + # Exit a parse tree produced by COOLParser#isvoid. + def exitIsvoid(self, ctx:COOLParser.IsvoidContext): + pass + + + # Enter a parse tree produced by COOLParser#while. + def enterWhile(self, ctx:COOLParser.WhileContext): + pass + + # Exit a parse tree produced by COOLParser#while. + def exitWhile(self, ctx:COOLParser.WhileContext): + pass + + + # Enter a parse tree produced by COOLParser#division. + def enterDivision(self, ctx:COOLParser.DivisionContext): + pass + + # Exit a parse tree produced by COOLParser#division. + def exitDivision(self, ctx:COOLParser.DivisionContext): + pass + + + # Enter a parse tree produced by COOLParser#negative. + def enterNegative(self, ctx:COOLParser.NegativeContext): + pass + + # Exit a parse tree produced by COOLParser#negative. + def exitNegative(self, ctx:COOLParser.NegativeContext): + pass + + + # Enter a parse tree produced by COOLParser#boolNot. + def enterBoolNot(self, ctx:COOLParser.BoolNotContext): + pass + + # Exit a parse tree produced by COOLParser#boolNot. + def exitBoolNot(self, ctx:COOLParser.BoolNotContext): + pass + + + # Enter a parse tree produced by COOLParser#lessThan. + def enterLessThan(self, ctx:COOLParser.LessThanContext): + pass + + # Exit a parse tree produced by COOLParser#lessThan. + def exitLessThan(self, ctx:COOLParser.LessThanContext): + pass + + + # Enter a parse tree produced by COOLParser#block. + def enterBlock(self, ctx:COOLParser.BlockContext): + pass + + # Exit a parse tree produced by COOLParser#block. + def exitBlock(self, ctx:COOLParser.BlockContext): + pass + + + # Enter a parse tree produced by COOLParser#id. + def enterId(self, ctx:COOLParser.IdContext): + pass + + # Exit a parse tree produced by COOLParser#id. + def exitId(self, ctx:COOLParser.IdContext): + pass + + + # Enter a parse tree produced by COOLParser#multiply. + def enterMultiply(self, ctx:COOLParser.MultiplyContext): + pass + + # Exit a parse tree produced by COOLParser#multiply. + def exitMultiply(self, ctx:COOLParser.MultiplyContext): + pass + + + # Enter a parse tree produced by COOLParser#if. + def enterIf(self, ctx:COOLParser.IfContext): + pass + + # Exit a parse tree produced by COOLParser#if. + def exitIf(self, ctx:COOLParser.IfContext): + pass + + + # Enter a parse tree produced by COOLParser#case. + def enterCase(self, ctx:COOLParser.CaseContext): + pass + + # Exit a parse tree produced by COOLParser#case. + def exitCase(self, ctx:COOLParser.CaseContext): + pass + + + # Enter a parse tree produced by COOLParser#ownMethodCall. + def enterOwnMethodCall(self, ctx:COOLParser.OwnMethodCallContext): + pass + + # Exit a parse tree produced by COOLParser#ownMethodCall. + def exitOwnMethodCall(self, ctx:COOLParser.OwnMethodCallContext): + pass + + + # Enter a parse tree produced by COOLParser#add. + def enterAdd(self, ctx:COOLParser.AddContext): + pass + + # Exit a parse tree produced by COOLParser#add. + def exitAdd(self, ctx:COOLParser.AddContext): + pass + + + # Enter a parse tree produced by COOLParser#new. + def enterNew(self, ctx:COOLParser.NewContext): + pass + + # Exit a parse tree produced by COOLParser#new. + def exitNew(self, ctx:COOLParser.NewContext): + pass + + + # Enter a parse tree produced by COOLParser#parentheses. + def enterParentheses(self, ctx:COOLParser.ParenthesesContext): + pass + + # Exit a parse tree produced by COOLParser#parentheses. + def exitParentheses(self, ctx:COOLParser.ParenthesesContext): + pass + + + # Enter a parse tree produced by COOLParser#assignment. + def enterAssignment(self, ctx:COOLParser.AssignmentContext): + pass + + # Exit a parse tree produced by COOLParser#assignment. + def exitAssignment(self, ctx:COOLParser.AssignmentContext): + pass + + + # Enter a parse tree produced by COOLParser#false. + def enterFalse(self, ctx:COOLParser.FalseContext): + pass + + # Exit a parse tree produced by COOLParser#false. + def exitFalse(self, ctx:COOLParser.FalseContext): + pass + + + # Enter a parse tree produced by COOLParser#int. + def enterInt(self, ctx:COOLParser.IntContext): + pass + + # Exit a parse tree produced by COOLParser#int. + def exitInt(self, ctx:COOLParser.IntContext): + pass + + + # Enter a parse tree produced by COOLParser#equal. + def enterEqual(self, ctx:COOLParser.EqualContext): + pass + + # Exit a parse tree produced by COOLParser#equal. + def exitEqual(self, ctx:COOLParser.EqualContext): + pass + + + # Enter a parse tree produced by COOLParser#true. + def enterTrue(self, ctx:COOLParser.TrueContext): + pass + + # Exit a parse tree produced by COOLParser#true. + def exitTrue(self, ctx:COOLParser.TrueContext): + pass + + + # Enter a parse tree produced by COOLParser#lessEqual. + def enterLessEqual(self, ctx:COOLParser.LessEqualContext): + pass + + # Exit a parse tree produced by COOLParser#lessEqual. + def exitLessEqual(self, ctx:COOLParser.LessEqualContext): + pass + + + # Enter a parse tree produced by COOLParser#methodCall. + def enterMethodCall(self, ctx:COOLParser.MethodCallContext): + pass + + # Exit a parse tree produced by COOLParser#methodCall. + def exitMethodCall(self, ctx:COOLParser.MethodCallContext): + pass + + diff --git a/src/COOLParser.py b/src/COOLParser.py new file mode 100644 index 00000000..d30ff78b --- /dev/null +++ b/src/COOLParser.py @@ -0,0 +1,1757 @@ +# Generated from C:\Software\ANTLR\cool\COOL.g4 by ANTLR 4.7.2 +# encoding: utf-8 +from antlr4 import * +from io import StringIO +from typing.io import TextIO +import sys + + +def serializedATN(): + with StringIO() as buf: + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\61") + buf.write("\u00e2\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") + buf.write("\3\2\3\2\3\3\3\3\3\3\3\3\3\3\5\3\26\n\3\3\4\3\4\3\4\3") + buf.write("\4\5\4\34\n\4\3\4\3\4\3\4\3\4\7\4\"\n\4\f\4\16\4%\13\4") + buf.write("\3\4\3\4\3\5\3\5\3\5\3\5\3\5\7\5.\n\5\f\5\16\5\61\13\5") + buf.write("\7\5\63\n\5\f\5\16\5\66\13\5\3\5\3\5\3\5\3\5\3\5\3\5\3") + buf.write("\5\3\5\3\5\3\5\3\5\3\5\5\5D\n\5\5\5F\n\5\3\6\3\6\3\6\3") + buf.write("\6\3\7\3\7\3\7\3\7\3\7\3\7\7\7R\n\7\f\7\16\7U\13\7\7\7") + buf.write("W\n\7\f\7\16\7Z\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\6\7o\n\7\r") + buf.write("\7\16\7p\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\5\7{\n\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\5\7\u0083\n\7\7\7\u0085\n\7\f\7\16") + buf.write("\7\u0088\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\6\7\u0096\n\7\r\7\16\7\u0097\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\5\7\u00b0\n\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\5\7\u00ca\n\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\7\7\u00d2\n\7\f\7\16\7\u00d5\13\7\7\7\u00d7\n\7\f") + buf.write("\7\16\7\u00da\13\7\3\7\7\7\u00dd\n\7\f\7\16\7\u00e0\13") + buf.write("\7\3\7\2\3\f\b\2\4\6\b\n\f\2\2\2\u0104\2\16\3\2\2\2\4") + buf.write("\25\3\2\2\2\6\27\3\2\2\2\bE\3\2\2\2\nG\3\2\2\2\f\u00af") + buf.write("\3\2\2\2\16\17\5\4\3\2\17\3\3\2\2\2\20\21\5\6\4\2\21\22") + buf.write("\7\3\2\2\22\23\5\4\3\2\23\26\3\2\2\2\24\26\7\2\2\3\25") + buf.write("\20\3\2\2\2\25\24\3\2\2\2\26\5\3\2\2\2\27\30\7\f\2\2\30") + buf.write("\33\7!\2\2\31\32\7\22\2\2\32\34\7!\2\2\33\31\3\2\2\2\33") + buf.write("\34\3\2\2\2\34\35\3\2\2\2\35#\7\4\2\2\36\37\5\b\5\2\37") + buf.write(" \7\3\2\2 \"\3\2\2\2!\36\3\2\2\2\"%\3\2\2\2#!\3\2\2\2") + buf.write("#$\3\2\2\2$&\3\2\2\2%#\3\2\2\2&\'\7\5\2\2\'\7\3\2\2\2") + buf.write("()\7\"\2\2)\64\7\6\2\2*/\5\n\6\2+,\7\7\2\2,.\5\n\6\2-") + buf.write("+\3\2\2\2.\61\3\2\2\2/-\3\2\2\2/\60\3\2\2\2\60\63\3\2") + buf.write("\2\2\61/\3\2\2\2\62*\3\2\2\2\63\66\3\2\2\2\64\62\3\2\2") + buf.write("\2\64\65\3\2\2\2\65\67\3\2\2\2\66\64\3\2\2\2\678\7\b\2") + buf.write("\289\7\t\2\29:\7!\2\2:;\7\4\2\2;<\5\f\7\2<=\7\5\2\2=F") + buf.write("\3\2\2\2>?\7\"\2\2?@\7\t\2\2@C\7!\2\2AB\7#\2\2BD\5\f\7") + buf.write("\2CA\3\2\2\2CD\3\2\2\2DF\3\2\2\2E(\3\2\2\2E>\3\2\2\2F") + buf.write("\t\3\2\2\2GH\7\"\2\2HI\7\t\2\2IJ\7!\2\2J\13\3\2\2\2KL") + buf.write("\b\7\1\2LM\7\"\2\2MX\7\6\2\2NS\5\f\7\2OP\7\7\2\2PR\5\f") + buf.write("\7\2QO\3\2\2\2RU\3\2\2\2SQ\3\2\2\2ST\3\2\2\2TW\3\2\2\2") + buf.write("US\3\2\2\2VN\3\2\2\2WZ\3\2\2\2XV\3\2\2\2XY\3\2\2\2Y[\3") + buf.write("\2\2\2ZX\3\2\2\2[\u00b0\7\b\2\2\\]\7\20\2\2]^\5\f\7\2") + buf.write("^_\7\27\2\2_`\5\f\7\2`a\7\r\2\2ab\5\f\7\2bc\7\17\2\2c") + buf.write("\u00b0\3\2\2\2de\7\30\2\2ef\5\f\7\2fg\7\25\2\2gh\5\f\7") + buf.write("\2hi\7\26\2\2i\u00b0\3\2\2\2jn\7\4\2\2kl\5\f\7\2lm\7\3") + buf.write("\2\2mo\3\2\2\2nk\3\2\2\2op\3\2\2\2pn\3\2\2\2pq\3\2\2\2") + buf.write("qr\3\2\2\2rs\7\5\2\2s\u00b0\3\2\2\2tu\7\24\2\2uv\7\"\2") + buf.write("\2vw\7\t\2\2wz\7!\2\2xy\7#\2\2y{\5\f\7\2zx\3\2\2\2z{\3") + buf.write("\2\2\2{\u0086\3\2\2\2|}\7\7\2\2}~\7\"\2\2~\177\7\t\2\2") + buf.write("\177\u0082\7!\2\2\u0080\u0081\7#\2\2\u0081\u0083\5\f\7") + buf.write("\2\u0082\u0080\3\2\2\2\u0082\u0083\3\2\2\2\u0083\u0085") + buf.write("\3\2\2\2\u0084|\3\2\2\2\u0085\u0088\3\2\2\2\u0086\u0084") + buf.write("\3\2\2\2\u0086\u0087\3\2\2\2\u0087\u0089\3\2\2\2\u0088") + buf.write("\u0086\3\2\2\2\u0089\u008a\7\21\2\2\u008a\u00b0\5\f\7") + buf.write("\26\u008b\u008c\7\31\2\2\u008c\u008d\5\f\7\2\u008d\u0095") + buf.write("\7\34\2\2\u008e\u008f\7\"\2\2\u008f\u0090\7\t\2\2\u0090") + buf.write("\u0091\7!\2\2\u0091\u0092\7$\2\2\u0092\u0093\5\f\7\2\u0093") + buf.write("\u0094\7\3\2\2\u0094\u0096\3\2\2\2\u0095\u008e\3\2\2\2") + buf.write("\u0096\u0097\3\2\2\2\u0097\u0095\3\2\2\2\u0097\u0098\3") + buf.write("\2\2\2\u0098\u0099\3\2\2\2\u0099\u009a\7\32\2\2\u009a") + buf.write("\u00b0\3\2\2\2\u009b\u009c\7\33\2\2\u009c\u00b0\7!\2\2") + buf.write("\u009d\u009e\7,\2\2\u009e\u00b0\5\f\7\23\u009f\u00a0\7") + buf.write("\23\2\2\u00a0\u00b0\5\f\7\22\u00a1\u00a2\7\35\2\2\u00a2") + buf.write("\u00b0\5\f\7\n\u00a3\u00a4\7\6\2\2\u00a4\u00a5\5\f\7\2") + buf.write("\u00a5\u00a6\7\b\2\2\u00a6\u00b0\3\2\2\2\u00a7\u00b0\7") + buf.write("\"\2\2\u00a8\u00b0\7 \2\2\u00a9\u00b0\7\37\2\2\u00aa\u00b0") + buf.write("\7\36\2\2\u00ab\u00b0\7\16\2\2\u00ac\u00ad\7\"\2\2\u00ad") + buf.write("\u00ae\7#\2\2\u00ae\u00b0\5\f\7\3\u00afK\3\2\2\2\u00af") + buf.write("\\\3\2\2\2\u00afd\3\2\2\2\u00afj\3\2\2\2\u00aft\3\2\2") + buf.write("\2\u00af\u008b\3\2\2\2\u00af\u009b\3\2\2\2\u00af\u009d") + buf.write("\3\2\2\2\u00af\u009f\3\2\2\2\u00af\u00a1\3\2\2\2\u00af") + buf.write("\u00a3\3\2\2\2\u00af\u00a7\3\2\2\2\u00af\u00a8\3\2\2\2") + buf.write("\u00af\u00a9\3\2\2\2\u00af\u00aa\3\2\2\2\u00af\u00ab\3") + buf.write("\2\2\2\u00af\u00ac\3\2\2\2\u00b0\u00de\3\2\2\2\u00b1\u00b2") + buf.write("\f\21\2\2\u00b2\u00b3\7\'\2\2\u00b3\u00dd\5\f\7\22\u00b4") + buf.write("\u00b5\f\20\2\2\u00b5\u00b6\7(\2\2\u00b6\u00dd\5\f\7\21") + buf.write("\u00b7\u00b8\f\17\2\2\u00b8\u00b9\7%\2\2\u00b9\u00dd\5") + buf.write("\f\7\20\u00ba\u00bb\f\16\2\2\u00bb\u00bc\7&\2\2\u00bc") + buf.write("\u00dd\5\f\7\17\u00bd\u00be\f\r\2\2\u00be\u00bf\7)\2\2") + buf.write("\u00bf\u00dd\5\f\7\16\u00c0\u00c1\f\f\2\2\u00c1\u00c2") + buf.write("\7*\2\2\u00c2\u00dd\5\f\7\r\u00c3\u00c4\f\13\2\2\u00c4") + buf.write("\u00c5\7+\2\2\u00c5\u00dd\5\f\7\f\u00c6\u00c9\f\33\2\2") + buf.write("\u00c7\u00c8\7\n\2\2\u00c8\u00ca\7!\2\2\u00c9\u00c7\3") + buf.write("\2\2\2\u00c9\u00ca\3\2\2\2\u00ca\u00cb\3\2\2\2\u00cb\u00cc") + buf.write("\7\13\2\2\u00cc\u00cd\7\"\2\2\u00cd\u00d8\7\6\2\2\u00ce") + buf.write("\u00d3\5\f\7\2\u00cf\u00d0\7\7\2\2\u00d0\u00d2\5\f\7\2") + buf.write("\u00d1\u00cf\3\2\2\2\u00d2\u00d5\3\2\2\2\u00d3\u00d1\3") + buf.write("\2\2\2\u00d3\u00d4\3\2\2\2\u00d4\u00d7\3\2\2\2\u00d5\u00d3") + buf.write("\3\2\2\2\u00d6\u00ce\3\2\2\2\u00d7\u00da\3\2\2\2\u00d8") + buf.write("\u00d6\3\2\2\2\u00d8\u00d9\3\2\2\2\u00d9\u00db\3\2\2\2") + buf.write("\u00da\u00d8\3\2\2\2\u00db\u00dd\7\b\2\2\u00dc\u00b1\3") + buf.write("\2\2\2\u00dc\u00b4\3\2\2\2\u00dc\u00b7\3\2\2\2\u00dc\u00ba") + buf.write("\3\2\2\2\u00dc\u00bd\3\2\2\2\u00dc\u00c0\3\2\2\2\u00dc") + buf.write("\u00c3\3\2\2\2\u00dc\u00c6\3\2\2\2\u00dd\u00e0\3\2\2\2") + buf.write("\u00de\u00dc\3\2\2\2\u00de\u00df\3\2\2\2\u00df\r\3\2\2") + buf.write("\2\u00e0\u00de\3\2\2\2\26\25\33#/\64CESXpz\u0082\u0086") + buf.write("\u0097\u00af\u00c9\u00d3\u00d8\u00dc\u00de") + return buf.getvalue() + + +class COOLParser ( Parser ): + + grammarFileName = "COOL.g4" + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] + + sharedContextCache = PredictionContextCache() + + literalNames = [ "", "';'", "'{'", "'}'", "'('", "','", "')'", + "':'", "'@'", "'.'", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", + "'<='", "'='", "'~'", "'(*'", "'*)'" ] + + symbolicNames = [ "", "", "", "", + "", "", "", "", + "", "", "CLASS", "ELSE", "FALSE", + "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", + "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", + "NOT", "TRUE", "STRING", "INT", "TYPEID", "OBJECTID", + "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", + "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", + "OPEN_COMMENT", "CLOSE_COMMENT", "COMMENT", "ONE_LINE_COMMENT", + "WHITESPACE" ] + + RULE_program = 0 + RULE_programBlocks = 1 + RULE_classDefine = 2 + RULE_feature = 3 + RULE_formal = 4 + RULE_expression = 5 + + ruleNames = [ "program", "programBlocks", "classDefine", "feature", + "formal", "expression" ] + + EOF = Token.EOF + T__0=1 + T__1=2 + T__2=3 + T__3=4 + T__4=5 + T__5=6 + T__6=7 + T__7=8 + T__8=9 + CLASS=10 + ELSE=11 + FALSE=12 + FI=13 + IF=14 + IN=15 + INHERITS=16 + ISVOID=17 + LET=18 + LOOP=19 + POOL=20 + THEN=21 + WHILE=22 + CASE=23 + ESAC=24 + NEW=25 + OF=26 + NOT=27 + TRUE=28 + STRING=29 + INT=30 + TYPEID=31 + OBJECTID=32 + ASSIGNMENT=33 + CASE_ARROW=34 + ADD=35 + MINUS=36 + MULTIPLY=37 + DIVISION=38 + LESS_THAN=39 + LESS_EQUAL=40 + EQUAL=41 + INTEGER_NEGATIVE=42 + OPEN_COMMENT=43 + CLOSE_COMMENT=44 + COMMENT=45 + ONE_LINE_COMMENT=46 + WHITESPACE=47 + + def __init__(self, input:TokenStream, output:TextIO = sys.stdout): + super().__init__(input, output) + self.checkVersion("4.7.2") + self._interp = ParserATNSimulator(self, self.atn, self.decisionsToDFA, self.sharedContextCache) + self._predicates = None + + + + + class ProgramContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def programBlocks(self): + return self.getTypedRuleContext(COOLParser.ProgramBlocksContext,0) + + + def getRuleIndex(self): + return COOLParser.RULE_program + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterProgram" ): + listener.enterProgram(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitProgram" ): + listener.exitProgram(self) + + + + + def program(self): + + localctx = COOLParser.ProgramContext(self, self._ctx, self.state) + self.enterRule(localctx, 0, self.RULE_program) + try: + self.enterOuterAlt(localctx, 1) + self.state = 12 + self.programBlocks() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class ProgramBlocksContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return COOLParser.RULE_programBlocks + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) + + + + class ClassesContext(ProgramBlocksContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ProgramBlocksContext + super().__init__(parser) + self.copyFrom(ctx) + + def classDefine(self): + return self.getTypedRuleContext(COOLParser.ClassDefineContext,0) + + def programBlocks(self): + return self.getTypedRuleContext(COOLParser.ProgramBlocksContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterClasses" ): + listener.enterClasses(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitClasses" ): + listener.exitClasses(self) + + + class EofContext(ProgramBlocksContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ProgramBlocksContext + super().__init__(parser) + self.copyFrom(ctx) + + def EOF(self): + return self.getToken(COOLParser.EOF, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterEof" ): + listener.enterEof(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitEof" ): + listener.exitEof(self) + + + + def programBlocks(self): + + localctx = COOLParser.ProgramBlocksContext(self, self._ctx, self.state) + self.enterRule(localctx, 2, self.RULE_programBlocks) + try: + self.state = 19 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [COOLParser.CLASS]: + localctx = COOLParser.ClassesContext(self, localctx) + self.enterOuterAlt(localctx, 1) + self.state = 14 + self.classDefine() + self.state = 15 + self.match(COOLParser.T__0) + self.state = 16 + self.programBlocks() + pass + elif token in [COOLParser.EOF]: + localctx = COOLParser.EofContext(self, localctx) + self.enterOuterAlt(localctx, 2) + self.state = 18 + self.match(COOLParser.EOF) + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class ClassDefineContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def CLASS(self): + return self.getToken(COOLParser.CLASS, 0) + + def TYPEID(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.TYPEID) + else: + return self.getToken(COOLParser.TYPEID, i) + + def INHERITS(self): + return self.getToken(COOLParser.INHERITS, 0) + + def feature(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.FeatureContext) + else: + return self.getTypedRuleContext(COOLParser.FeatureContext,i) + + + def getRuleIndex(self): + return COOLParser.RULE_classDefine + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterClassDefine" ): + listener.enterClassDefine(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitClassDefine" ): + listener.exitClassDefine(self) + + + + + def classDefine(self): + + localctx = COOLParser.ClassDefineContext(self, self._ctx, self.state) + self.enterRule(localctx, 4, self.RULE_classDefine) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 21 + self.match(COOLParser.CLASS) + self.state = 22 + self.match(COOLParser.TYPEID) + self.state = 25 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOLParser.INHERITS: + self.state = 23 + self.match(COOLParser.INHERITS) + self.state = 24 + self.match(COOLParser.TYPEID) + + + self.state = 27 + self.match(COOLParser.T__1) + self.state = 33 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOLParser.OBJECTID: + self.state = 28 + self.feature() + self.state = 29 + self.match(COOLParser.T__0) + self.state = 35 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 36 + self.match(COOLParser.T__2) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class FeatureContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return COOLParser.RULE_feature + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) + + + + class MethodContext(FeatureContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.FeatureContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + def TYPEID(self): + return self.getToken(COOLParser.TYPEID, 0) + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + def formal(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.FormalContext) + else: + return self.getTypedRuleContext(COOLParser.FormalContext,i) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMethod" ): + listener.enterMethod(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMethod" ): + listener.exitMethod(self) + + + class PropertyContext(FeatureContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.FeatureContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + def TYPEID(self): + return self.getToken(COOLParser.TYPEID, 0) + def ASSIGNMENT(self): + return self.getToken(COOLParser.ASSIGNMENT, 0) + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterProperty" ): + listener.enterProperty(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitProperty" ): + listener.exitProperty(self) + + + + def feature(self): + + localctx = COOLParser.FeatureContext(self, self._ctx, self.state) + self.enterRule(localctx, 6, self.RULE_feature) + self._la = 0 # Token type + try: + self.state = 67 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input,6,self._ctx) + if la_ == 1: + localctx = COOLParser.MethodContext(self, localctx) + self.enterOuterAlt(localctx, 1) + self.state = 38 + self.match(COOLParser.OBJECTID) + self.state = 39 + self.match(COOLParser.T__3) + self.state = 50 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOLParser.OBJECTID: + self.state = 40 + self.formal() + self.state = 45 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOLParser.T__4: + self.state = 41 + self.match(COOLParser.T__4) + self.state = 42 + self.formal() + self.state = 47 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 52 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 53 + self.match(COOLParser.T__5) + self.state = 54 + self.match(COOLParser.T__6) + self.state = 55 + self.match(COOLParser.TYPEID) + self.state = 56 + self.match(COOLParser.T__1) + self.state = 57 + self.expression(0) + self.state = 58 + self.match(COOLParser.T__2) + pass + + elif la_ == 2: + localctx = COOLParser.PropertyContext(self, localctx) + self.enterOuterAlt(localctx, 2) + self.state = 60 + self.match(COOLParser.OBJECTID) + self.state = 61 + self.match(COOLParser.T__6) + self.state = 62 + self.match(COOLParser.TYPEID) + self.state = 65 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOLParser.ASSIGNMENT: + self.state = 63 + self.match(COOLParser.ASSIGNMENT) + self.state = 64 + self.expression(0) + + + pass + + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class FormalContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + + def TYPEID(self): + return self.getToken(COOLParser.TYPEID, 0) + + def getRuleIndex(self): + return COOLParser.RULE_formal + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterFormal" ): + listener.enterFormal(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitFormal" ): + listener.exitFormal(self) + + + + + def formal(self): + + localctx = COOLParser.FormalContext(self, self._ctx, self.state) + self.enterRule(localctx, 8, self.RULE_formal) + try: + self.enterOuterAlt(localctx, 1) + self.state = 69 + self.match(COOLParser.OBJECTID) + self.state = 70 + self.match(COOLParser.T__6) + self.state = 71 + self.match(COOLParser.TYPEID) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class ExpressionContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return COOLParser.RULE_expression + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) + + + class LetInContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def LET(self): + return self.getToken(COOLParser.LET, 0) + def OBJECTID(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.OBJECTID) + else: + return self.getToken(COOLParser.OBJECTID, i) + def TYPEID(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.TYPEID) + else: + return self.getToken(COOLParser.TYPEID, i) + def IN(self): + return self.getToken(COOLParser.IN, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def ASSIGNMENT(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.ASSIGNMENT) + else: + return self.getToken(COOLParser.ASSIGNMENT, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterLetIn" ): + listener.enterLetIn(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitLetIn" ): + listener.exitLetIn(self) + + + class MinusContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def MINUS(self): + return self.getToken(COOLParser.MINUS, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMinus" ): + listener.enterMinus(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMinus" ): + listener.exitMinus(self) + + + class StringContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def STRING(self): + return self.getToken(COOLParser.STRING, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterString" ): + listener.enterString(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitString" ): + listener.exitString(self) + + + class IsvoidContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def ISVOID(self): + return self.getToken(COOLParser.ISVOID, 0) + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterIsvoid" ): + listener.enterIsvoid(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitIsvoid" ): + listener.exitIsvoid(self) + + + class WhileContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def WHILE(self): + return self.getToken(COOLParser.WHILE, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def LOOP(self): + return self.getToken(COOLParser.LOOP, 0) + def POOL(self): + return self.getToken(COOLParser.POOL, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterWhile" ): + listener.enterWhile(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitWhile" ): + listener.exitWhile(self) + + + class DivisionContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def DIVISION(self): + return self.getToken(COOLParser.DIVISION, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterDivision" ): + listener.enterDivision(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitDivision" ): + listener.exitDivision(self) + + + class NegativeContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def INTEGER_NEGATIVE(self): + return self.getToken(COOLParser.INTEGER_NEGATIVE, 0) + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterNegative" ): + listener.enterNegative(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitNegative" ): + listener.exitNegative(self) + + + class BoolNotContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def NOT(self): + return self.getToken(COOLParser.NOT, 0) + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterBoolNot" ): + listener.enterBoolNot(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitBoolNot" ): + listener.exitBoolNot(self) + + + class LessThanContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def LESS_THAN(self): + return self.getToken(COOLParser.LESS_THAN, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterLessThan" ): + listener.enterLessThan(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitLessThan" ): + listener.exitLessThan(self) + + + class BlockContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterBlock" ): + listener.enterBlock(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitBlock" ): + listener.exitBlock(self) + + + class IdContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterId" ): + listener.enterId(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitId" ): + listener.exitId(self) + + + class MultiplyContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def MULTIPLY(self): + return self.getToken(COOLParser.MULTIPLY, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMultiply" ): + listener.enterMultiply(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMultiply" ): + listener.exitMultiply(self) + + + class IfContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def IF(self): + return self.getToken(COOLParser.IF, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def THEN(self): + return self.getToken(COOLParser.THEN, 0) + def ELSE(self): + return self.getToken(COOLParser.ELSE, 0) + def FI(self): + return self.getToken(COOLParser.FI, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterIf" ): + listener.enterIf(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitIf" ): + listener.exitIf(self) + + + class CaseContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def CASE(self): + return self.getToken(COOLParser.CASE, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def OF(self): + return self.getToken(COOLParser.OF, 0) + def ESAC(self): + return self.getToken(COOLParser.ESAC, 0) + def OBJECTID(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.OBJECTID) + else: + return self.getToken(COOLParser.OBJECTID, i) + def TYPEID(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.TYPEID) + else: + return self.getToken(COOLParser.TYPEID, i) + def CASE_ARROW(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.CASE_ARROW) + else: + return self.getToken(COOLParser.CASE_ARROW, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterCase" ): + listener.enterCase(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitCase" ): + listener.exitCase(self) + + + class OwnMethodCallContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterOwnMethodCall" ): + listener.enterOwnMethodCall(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitOwnMethodCall" ): + listener.exitOwnMethodCall(self) + + + class AddContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def ADD(self): + return self.getToken(COOLParser.ADD, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterAdd" ): + listener.enterAdd(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitAdd" ): + listener.exitAdd(self) + + + class NewContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def NEW(self): + return self.getToken(COOLParser.NEW, 0) + def TYPEID(self): + return self.getToken(COOLParser.TYPEID, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterNew" ): + listener.enterNew(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitNew" ): + listener.exitNew(self) + + + class ParenthesesContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterParentheses" ): + listener.enterParentheses(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitParentheses" ): + listener.exitParentheses(self) + + + class AssignmentContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + def ASSIGNMENT(self): + return self.getToken(COOLParser.ASSIGNMENT, 0) + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterAssignment" ): + listener.enterAssignment(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitAssignment" ): + listener.exitAssignment(self) + + + class FalseContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def FALSE(self): + return self.getToken(COOLParser.FALSE, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterFalse" ): + listener.enterFalse(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitFalse" ): + listener.exitFalse(self) + + + class IntContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def INT(self): + return self.getToken(COOLParser.INT, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterInt" ): + listener.enterInt(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitInt" ): + listener.exitInt(self) + + + class EqualContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def EQUAL(self): + return self.getToken(COOLParser.EQUAL, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterEqual" ): + listener.enterEqual(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitEqual" ): + listener.exitEqual(self) + + + class TrueContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def TRUE(self): + return self.getToken(COOLParser.TRUE, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterTrue" ): + listener.enterTrue(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitTrue" ): + listener.exitTrue(self) + + + class LessEqualContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def LESS_EQUAL(self): + return self.getToken(COOLParser.LESS_EQUAL, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterLessEqual" ): + listener.enterLessEqual(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitLessEqual" ): + listener.exitLessEqual(self) + + + class MethodCallContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + def TYPEID(self): + return self.getToken(COOLParser.TYPEID, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMethodCall" ): + listener.enterMethodCall(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMethodCall" ): + listener.exitMethodCall(self) + + + + def expression(self, _p:int=0): + _parentctx = self._ctx + _parentState = self.state + localctx = COOLParser.ExpressionContext(self, self._ctx, _parentState) + _prevctx = localctx + _startState = 10 + self.enterRecursionRule(localctx, 10, self.RULE_expression, _p) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 173 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input,14,self._ctx) + if la_ == 1: + localctx = COOLParser.OwnMethodCallContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + + self.state = 74 + self.match(COOLParser.OBJECTID) + self.state = 75 + self.match(COOLParser.T__3) + self.state = 86 + self._errHandler.sync(self) + _la = self._input.LA(1) + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOLParser.T__1) | (1 << COOLParser.T__3) | (1 << COOLParser.FALSE) | (1 << COOLParser.IF) | (1 << COOLParser.ISVOID) | (1 << COOLParser.LET) | (1 << COOLParser.WHILE) | (1 << COOLParser.CASE) | (1 << COOLParser.NEW) | (1 << COOLParser.NOT) | (1 << COOLParser.TRUE) | (1 << COOLParser.STRING) | (1 << COOLParser.INT) | (1 << COOLParser.OBJECTID) | (1 << COOLParser.INTEGER_NEGATIVE))) != 0): + self.state = 76 + self.expression(0) + self.state = 81 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOLParser.T__4: + self.state = 77 + self.match(COOLParser.T__4) + self.state = 78 + self.expression(0) + self.state = 83 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 88 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 89 + self.match(COOLParser.T__5) + pass + + elif la_ == 2: + localctx = COOLParser.IfContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 90 + self.match(COOLParser.IF) + self.state = 91 + self.expression(0) + self.state = 92 + self.match(COOLParser.THEN) + self.state = 93 + self.expression(0) + self.state = 94 + self.match(COOLParser.ELSE) + self.state = 95 + self.expression(0) + self.state = 96 + self.match(COOLParser.FI) + pass + + elif la_ == 3: + localctx = COOLParser.WhileContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 98 + self.match(COOLParser.WHILE) + self.state = 99 + self.expression(0) + self.state = 100 + self.match(COOLParser.LOOP) + self.state = 101 + self.expression(0) + self.state = 102 + self.match(COOLParser.POOL) + pass + + elif la_ == 4: + localctx = COOLParser.BlockContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 104 + self.match(COOLParser.T__1) + self.state = 108 + self._errHandler.sync(self) + _la = self._input.LA(1) + while True: + self.state = 105 + self.expression(0) + self.state = 106 + self.match(COOLParser.T__0) + self.state = 110 + self._errHandler.sync(self) + _la = self._input.LA(1) + if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOLParser.T__1) | (1 << COOLParser.T__3) | (1 << COOLParser.FALSE) | (1 << COOLParser.IF) | (1 << COOLParser.ISVOID) | (1 << COOLParser.LET) | (1 << COOLParser.WHILE) | (1 << COOLParser.CASE) | (1 << COOLParser.NEW) | (1 << COOLParser.NOT) | (1 << COOLParser.TRUE) | (1 << COOLParser.STRING) | (1 << COOLParser.INT) | (1 << COOLParser.OBJECTID) | (1 << COOLParser.INTEGER_NEGATIVE))) != 0)): + break + + self.state = 112 + self.match(COOLParser.T__2) + pass + + elif la_ == 5: + localctx = COOLParser.LetInContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 114 + self.match(COOLParser.LET) + self.state = 115 + self.match(COOLParser.OBJECTID) + self.state = 116 + self.match(COOLParser.T__6) + self.state = 117 + self.match(COOLParser.TYPEID) + self.state = 120 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOLParser.ASSIGNMENT: + self.state = 118 + self.match(COOLParser.ASSIGNMENT) + self.state = 119 + self.expression(0) + + + self.state = 132 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOLParser.T__4: + self.state = 122 + self.match(COOLParser.T__4) + self.state = 123 + self.match(COOLParser.OBJECTID) + self.state = 124 + self.match(COOLParser.T__6) + self.state = 125 + self.match(COOLParser.TYPEID) + self.state = 128 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOLParser.ASSIGNMENT: + self.state = 126 + self.match(COOLParser.ASSIGNMENT) + self.state = 127 + self.expression(0) + + + self.state = 134 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 135 + self.match(COOLParser.IN) + self.state = 136 + self.expression(20) + pass + + elif la_ == 6: + localctx = COOLParser.CaseContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 137 + self.match(COOLParser.CASE) + self.state = 138 + self.expression(0) + self.state = 139 + self.match(COOLParser.OF) + self.state = 147 + self._errHandler.sync(self) + _la = self._input.LA(1) + while True: + self.state = 140 + self.match(COOLParser.OBJECTID) + self.state = 141 + self.match(COOLParser.T__6) + self.state = 142 + self.match(COOLParser.TYPEID) + self.state = 143 + self.match(COOLParser.CASE_ARROW) + self.state = 144 + self.expression(0) + self.state = 145 + self.match(COOLParser.T__0) + self.state = 149 + self._errHandler.sync(self) + _la = self._input.LA(1) + if not (_la==COOLParser.OBJECTID): + break + + self.state = 151 + self.match(COOLParser.ESAC) + pass + + elif la_ == 7: + localctx = COOLParser.NewContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 153 + self.match(COOLParser.NEW) + self.state = 154 + self.match(COOLParser.TYPEID) + pass + + elif la_ == 8: + localctx = COOLParser.NegativeContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 155 + self.match(COOLParser.INTEGER_NEGATIVE) + self.state = 156 + self.expression(17) + pass + + elif la_ == 9: + localctx = COOLParser.IsvoidContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 157 + self.match(COOLParser.ISVOID) + self.state = 158 + self.expression(16) + pass + + elif la_ == 10: + localctx = COOLParser.BoolNotContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 159 + self.match(COOLParser.NOT) + self.state = 160 + self.expression(8) + pass + + elif la_ == 11: + localctx = COOLParser.ParenthesesContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 161 + self.match(COOLParser.T__3) + self.state = 162 + self.expression(0) + self.state = 163 + self.match(COOLParser.T__5) + pass + + elif la_ == 12: + localctx = COOLParser.IdContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 165 + self.match(COOLParser.OBJECTID) + pass + + elif la_ == 13: + localctx = COOLParser.IntContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 166 + self.match(COOLParser.INT) + pass + + elif la_ == 14: + localctx = COOLParser.StringContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 167 + self.match(COOLParser.STRING) + pass + + elif la_ == 15: + localctx = COOLParser.TrueContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 168 + self.match(COOLParser.TRUE) + pass + + elif la_ == 16: + localctx = COOLParser.FalseContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 169 + self.match(COOLParser.FALSE) + pass + + elif la_ == 17: + localctx = COOLParser.AssignmentContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 170 + self.match(COOLParser.OBJECTID) + self.state = 171 + self.match(COOLParser.ASSIGNMENT) + self.state = 172 + self.expression(1) + pass + + + self._ctx.stop = self._input.LT(-1) + self.state = 220 + self._errHandler.sync(self) + _alt = self._interp.adaptivePredict(self._input,19,self._ctx) + while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: + if _alt==1: + if self._parseListeners is not None: + self.triggerExitRuleEvent() + _prevctx = localctx + self.state = 218 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input,18,self._ctx) + if la_ == 1: + localctx = COOLParser.MultiplyContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 175 + if not self.precpred(self._ctx, 15): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 15)") + self.state = 176 + self.match(COOLParser.MULTIPLY) + self.state = 177 + self.expression(16) + pass + + elif la_ == 2: + localctx = COOLParser.DivisionContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 178 + if not self.precpred(self._ctx, 14): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 14)") + self.state = 179 + self.match(COOLParser.DIVISION) + self.state = 180 + self.expression(15) + pass + + elif la_ == 3: + localctx = COOLParser.AddContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 181 + if not self.precpred(self._ctx, 13): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 13)") + self.state = 182 + self.match(COOLParser.ADD) + self.state = 183 + self.expression(14) + pass + + elif la_ == 4: + localctx = COOLParser.MinusContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 184 + if not self.precpred(self._ctx, 12): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 12)") + self.state = 185 + self.match(COOLParser.MINUS) + self.state = 186 + self.expression(13) + pass + + elif la_ == 5: + localctx = COOLParser.LessThanContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 187 + if not self.precpred(self._ctx, 11): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 11)") + self.state = 188 + self.match(COOLParser.LESS_THAN) + self.state = 189 + self.expression(12) + pass + + elif la_ == 6: + localctx = COOLParser.LessEqualContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 190 + if not self.precpred(self._ctx, 10): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 10)") + self.state = 191 + self.match(COOLParser.LESS_EQUAL) + self.state = 192 + self.expression(11) + pass + + elif la_ == 7: + localctx = COOLParser.EqualContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 193 + if not self.precpred(self._ctx, 9): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 9)") + self.state = 194 + self.match(COOLParser.EQUAL) + self.state = 195 + self.expression(10) + pass + + elif la_ == 8: + localctx = COOLParser.MethodCallContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 196 + if not self.precpred(self._ctx, 25): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 25)") + self.state = 199 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOLParser.T__7: + self.state = 197 + self.match(COOLParser.T__7) + self.state = 198 + self.match(COOLParser.TYPEID) + + + self.state = 201 + self.match(COOLParser.T__8) + self.state = 202 + self.match(COOLParser.OBJECTID) + self.state = 203 + self.match(COOLParser.T__3) + self.state = 214 + self._errHandler.sync(self) + _la = self._input.LA(1) + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOLParser.T__1) | (1 << COOLParser.T__3) | (1 << COOLParser.FALSE) | (1 << COOLParser.IF) | (1 << COOLParser.ISVOID) | (1 << COOLParser.LET) | (1 << COOLParser.WHILE) | (1 << COOLParser.CASE) | (1 << COOLParser.NEW) | (1 << COOLParser.NOT) | (1 << COOLParser.TRUE) | (1 << COOLParser.STRING) | (1 << COOLParser.INT) | (1 << COOLParser.OBJECTID) | (1 << COOLParser.INTEGER_NEGATIVE))) != 0): + self.state = 204 + self.expression(0) + self.state = 209 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOLParser.T__4: + self.state = 205 + self.match(COOLParser.T__4) + self.state = 206 + self.expression(0) + self.state = 211 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 216 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 217 + self.match(COOLParser.T__5) + pass + + + self.state = 222 + self._errHandler.sync(self) + _alt = self._interp.adaptivePredict(self._input,19,self._ctx) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.unrollRecursionContexts(_parentctx) + return localctx + + + + def sempred(self, localctx:RuleContext, ruleIndex:int, predIndex:int): + if self._predicates == None: + self._predicates = dict() + self._predicates[5] = self.expression_sempred + pred = self._predicates.get(ruleIndex, None) + if pred is None: + raise Exception("No predicate with index:" + str(ruleIndex)) + else: + return pred(localctx, predIndex) + + def expression_sempred(self, localctx:ExpressionContext, predIndex:int): + if predIndex == 0: + return self.precpred(self._ctx, 15) + + + if predIndex == 1: + return self.precpred(self._ctx, 14) + + + if predIndex == 2: + return self.precpred(self._ctx, 13) + + + if predIndex == 3: + return self.precpred(self._ctx, 12) + + + if predIndex == 4: + return self.precpred(self._ctx, 11) + + + if predIndex == 5: + return self.precpred(self._ctx, 10) + + + if predIndex == 6: + return self.precpred(self._ctx, 9) + + + if predIndex == 7: + return self.precpred(self._ctx, 25) + + + + + diff --git a/src/antlr4/BufferedTokenStream.py b/src/antlr4/BufferedTokenStream.py new file mode 100644 index 00000000..3634f085 --- /dev/null +++ b/src/antlr4/BufferedTokenStream.py @@ -0,0 +1,303 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. + +# This implementation of {@link TokenStream} loads tokens from a +# {@link TokenSource} on-demand, and places the tokens in a buffer to provide +# access to any previous token by index. +# +#

+# This token stream ignores the value of {@link Token#getChannel}. If your +# parser requires the token stream filter tokens to only those on a particular +# channel, such as {@link Token#DEFAULT_CHANNEL} or +# {@link Token#HIDDEN_CHANNEL}, use a filtering token stream such a +# {@link CommonTokenStream}.

+from io import StringIO +from antlr4.Token import Token +from antlr4.error.Errors import IllegalStateException + +# need forward declaration +Lexer = None + +# this is just to keep meaningful parameter types to Parser +class TokenStream(object): + + pass + + +class BufferedTokenStream(TokenStream): + + def __init__(self, tokenSource:Lexer): + # The {@link TokenSource} from which tokens for this stream are fetched. + self.tokenSource = tokenSource + + # A collection of all tokens fetched from the token source. The list is + # considered a complete view of the input once {@link #fetchedEOF} is set + # to {@code true}. + self.tokens = [] + + # The index into {@link #tokens} of the current token (next token to + # {@link #consume}). {@link #tokens}{@code [}{@link #p}{@code ]} should be + # {@link #LT LT(1)}. + # + #

This field is set to -1 when the stream is first constructed or when + # {@link #setTokenSource} is called, indicating that the first token has + # not yet been fetched from the token source. For additional information, + # see the documentation of {@link IntStream} for a description of + # Initializing Methods.

+ self.index = -1 + + # Indicates whether the {@link Token#EOF} token has been fetched from + # {@link #tokenSource} and added to {@link #tokens}. This field improves + # performance for the following cases: + # + #
    + #
  • {@link #consume}: The lookahead check in {@link #consume} to prevent + # consuming the EOF symbol is optimized by checking the values of + # {@link #fetchedEOF} and {@link #p} instead of calling {@link #LA}.
  • + #
  • {@link #fetch}: The check to prevent adding multiple EOF symbols into + # {@link #tokens} is trivial with this field.
  • + #
      + self.fetchedEOF = False + + def mark(self): + return 0 + + def release(self, marker:int): + # no resources to release + pass + + def reset(self): + self.seek(0) + + def seek(self, index:int): + self.lazyInit() + self.index = self.adjustSeekIndex(index) + + def get(self, index:int): + self.lazyInit() + return self.tokens[index] + + def consume(self): + skipEofCheck = False + if self.index >= 0: + if self.fetchedEOF: + # the last token in tokens is EOF. skip check if p indexes any + # fetched token except the last. + skipEofCheck = self.index < len(self.tokens) - 1 + else: + # no EOF token in tokens. skip check if p indexes a fetched token. + skipEofCheck = self.index < len(self.tokens) + else: + # not yet initialized + skipEofCheck = False + + if not skipEofCheck and self.LA(1) == Token.EOF: + raise IllegalStateException("cannot consume EOF") + + if self.sync(self.index + 1): + self.index = self.adjustSeekIndex(self.index + 1) + + # Make sure index {@code i} in tokens has a token. + # + # @return {@code true} if a token is located at index {@code i}, otherwise + # {@code false}. + # @see #get(int i) + #/ + def sync(self, i:int): + n = i - len(self.tokens) + 1 # how many more elements we need? + if n > 0 : + fetched = self.fetch(n) + return fetched >= n + return True + + # Add {@code n} elements to buffer. + # + # @return The actual number of elements added to the buffer. + #/ + def fetch(self, n:int): + if self.fetchedEOF: + return 0 + for i in range(0, n): + t = self.tokenSource.nextToken() + t.tokenIndex = len(self.tokens) + self.tokens.append(t) + if t.type==Token.EOF: + self.fetchedEOF = True + return i + 1 + return n + + + # Get all tokens from start..stop inclusively#/ + def getTokens(self, start:int, stop:int, types:set=None): + if start<0 or stop<0: + return None + self.lazyInit() + subset = [] + if stop >= len(self.tokens): + stop = len(self.tokens)-1 + for i in range(start, stop): + t = self.tokens[i] + if t.type==Token.EOF: + break + if types is None or t.type in types: + subset.append(t) + return subset + + def LA(self, i:int): + return self.LT(i).type + + def LB(self, k:int): + if (self.index-k) < 0: + return None + return self.tokens[self.index-k] + + def LT(self, k:int): + self.lazyInit() + if k==0: + return None + if k < 0: + return self.LB(-k) + i = self.index + k - 1 + self.sync(i) + if i >= len(self.tokens): # return EOF token + # EOF must be last token + return self.tokens[len(self.tokens)-1] + return self.tokens[i] + + # Allowed derived classes to modify the behavior of operations which change + # the current stream position by adjusting the target token index of a seek + # operation. The default implementation simply returns {@code i}. If an + # exception is thrown in this method, the current stream index should not be + # changed. + # + #

      For example, {@link CommonTokenStream} overrides this method to ensure that + # the seek target is always an on-channel token.

      + # + # @param i The target token index. + # @return The adjusted target token index. + + def adjustSeekIndex(self, i:int): + return i + + def lazyInit(self): + if self.index == -1: + self.setup() + + def setup(self): + self.sync(0) + self.index = self.adjustSeekIndex(0) + + # Reset this token stream by setting its token source.#/ + def setTokenSource(self, tokenSource:Lexer): + self.tokenSource = tokenSource + self.tokens = [] + self.index = -1 + self.fetchedEOF = False + + + # Given a starting index, return the index of the next token on channel. + # Return i if tokens[i] is on channel. Return -1 if there are no tokens + # on channel between i and EOF. + #/ + def nextTokenOnChannel(self, i:int, channel:int): + self.sync(i) + if i>=len(self.tokens): + return -1 + token = self.tokens[i] + while token.channel!=channel: + if token.type==Token.EOF: + return -1 + i += 1 + self.sync(i) + token = self.tokens[i] + return i + + # Given a starting index, return the index of the previous token on channel. + # Return i if tokens[i] is on channel. Return -1 if there are no tokens + # on channel between i and 0. + def previousTokenOnChannel(self, i:int, channel:int): + while i>=0 and self.tokens[i].channel!=channel: + i -= 1 + return i + + # Collect all tokens on specified channel to the right of + # the current token up until we see a token on DEFAULT_TOKEN_CHANNEL or + # EOF. If channel is -1, find any non default channel token. + def getHiddenTokensToRight(self, tokenIndex:int, channel:int=-1): + self.lazyInit() + if tokenIndex<0 or tokenIndex>=len(self.tokens): + raise Exception(str(tokenIndex) + " not in 0.." + str(len(self.tokens)-1)) + from antlr4.Lexer import Lexer + nextOnChannel = self.nextTokenOnChannel(tokenIndex + 1, Lexer.DEFAULT_TOKEN_CHANNEL) + from_ = tokenIndex+1 + # if none onchannel to right, nextOnChannel=-1 so set to = last token + to = (len(self.tokens)-1) if nextOnChannel==-1 else nextOnChannel + return self.filterForChannel(from_, to, channel) + + + # Collect all tokens on specified channel to the left of + # the current token up until we see a token on DEFAULT_TOKEN_CHANNEL. + # If channel is -1, find any non default channel token. + def getHiddenTokensToLeft(self, tokenIndex:int, channel:int=-1): + self.lazyInit() + if tokenIndex<0 or tokenIndex>=len(self.tokens): + raise Exception(str(tokenIndex) + " not in 0.." + str(len(self.tokens)-1)) + from antlr4.Lexer import Lexer + prevOnChannel = self.previousTokenOnChannel(tokenIndex - 1, Lexer.DEFAULT_TOKEN_CHANNEL) + if prevOnChannel == tokenIndex - 1: + return None + # if none on channel to left, prevOnChannel=-1 then from=0 + from_ = prevOnChannel+1 + to = tokenIndex-1 + return self.filterForChannel(from_, to, channel) + + + def filterForChannel(self, left:int, right:int, channel:int): + hidden = [] + for i in range(left, right+1): + t = self.tokens[i] + if channel==-1: + from antlr4.Lexer import Lexer + if t.channel!= Lexer.DEFAULT_TOKEN_CHANNEL: + hidden.append(t) + elif t.channel==channel: + hidden.append(t) + if len(hidden)==0: + return None + return hidden + + def getSourceName(self): + return self.tokenSource.getSourceName() + + # Get the text of all tokens in this buffer.#/ + def getText(self, interval:tuple=None): + self.lazyInit() + self.fill() + if interval is None: + interval = (0, len(self.tokens)-1) + start = interval[0] + if isinstance(start, Token): + start = start.tokenIndex + stop = interval[1] + if isinstance(stop, Token): + stop = stop.tokenIndex + if start is None or stop is None or start<0 or stop<0: + return "" + if stop >= len(self.tokens): + stop = len(self.tokens)-1 + with StringIO() as buf: + for i in range(start, stop+1): + t = self.tokens[i] + if t.type==Token.EOF: + break + buf.write(t.text) + return buf.getvalue() + + + # Get all tokens from lexer until EOF#/ + def fill(self): + self.lazyInit() + while self.fetch(1000)==1000: + pass diff --git a/src/antlr4/CommonTokenFactory.py b/src/antlr4/CommonTokenFactory.py new file mode 100644 index 00000000..17296fab --- /dev/null +++ b/src/antlr4/CommonTokenFactory.py @@ -0,0 +1,59 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# This default implementation of {@link TokenFactory} creates +# {@link CommonToken} objects. +# +from antlr4.Token import CommonToken + +class TokenFactory(object): + + pass + +class CommonTokenFactory(TokenFactory): + # + # The default {@link CommonTokenFactory} instance. + # + #

      + # This token factory does not explicitly copy token text when constructing + # tokens.

      + # + DEFAULT = None + + def __init__(self, copyText:bool=False): + # Indicates whether {@link CommonToken#setText} should be called after + # constructing tokens to explicitly set the text. This is useful for cases + # where the input stream might not be able to provide arbitrary substrings + # of text from the input after the lexer creates a token (e.g. the + # implementation of {@link CharStream#getText} in + # {@link UnbufferedCharStream} throws an + # {@link UnsupportedOperationException}). Explicitly setting the token text + # allows {@link Token#getText} to be called at any time regardless of the + # input stream implementation. + # + #

      + # The default value is {@code false} to avoid the performance and memory + # overhead of copying text for every token unless explicitly requested.

      + # + self.copyText = copyText + + def create(self, source, type:int, text:str, channel:int, start:int, stop:int, line:int, column:int): + t = CommonToken(source, type, channel, start, stop) + t.line = line + t.column = column + if text is not None: + t.text = text + elif self.copyText and source[1] is not None: + t.text = source[1].getText(start,stop) + return t + + def createThin(self, type:int, text:str): + t = CommonToken(type=type) + t.text = text + return t + +CommonTokenFactory.DEFAULT = CommonTokenFactory() \ No newline at end of file diff --git a/src/antlr4/CommonTokenStream.py b/src/antlr4/CommonTokenStream.py new file mode 100644 index 00000000..f0837442 --- /dev/null +++ b/src/antlr4/CommonTokenStream.py @@ -0,0 +1,86 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# +# This class extends {@link BufferedTokenStream} with functionality to filter +# token streams to tokens on a particular channel (tokens where +# {@link Token#getChannel} returns a particular value). +# +#

      +# This token stream provides access to all tokens by index or when calling +# methods like {@link #getText}. The channel filtering is only used for code +# accessing tokens via the lookahead methods {@link #LA}, {@link #LT}, and +# {@link #LB}.

      +# +#

      +# By default, tokens are placed on the default channel +# ({@link Token#DEFAULT_CHANNEL}), but may be reassigned by using the +# {@code ->channel(HIDDEN)} lexer command, or by using an embedded action to +# call {@link Lexer#setChannel}. +#

      +# +#

      +# Note: lexer rules which use the {@code ->skip} lexer command or call +# {@link Lexer#skip} do not produce tokens at all, so input text matched by +# such a rule will not be available as part of the token stream, regardless of +# channel.

      +#/ + +from antlr4.BufferedTokenStream import BufferedTokenStream +from antlr4.Lexer import Lexer +from antlr4.Token import Token + + +class CommonTokenStream(BufferedTokenStream): + + def __init__(self, lexer:Lexer, channel:int=Token.DEFAULT_CHANNEL): + super().__init__(lexer) + self.channel = channel + + def adjustSeekIndex(self, i:int): + return self.nextTokenOnChannel(i, self.channel) + + def LB(self, k:int): + if k==0 or (self.index-k)<0: + return None + i = self.index + n = 1 + # find k good tokens looking backwards + while n <= k: + # skip off-channel tokens + i = self.previousTokenOnChannel(i - 1, self.channel) + n += 1 + if i < 0: + return None + return self.tokens[i] + + def LT(self, k:int): + self.lazyInit() + if k == 0: + return None + if k < 0: + return self.LB(-k) + i = self.index + n = 1 # we know tokens[pos] is a good one + # find k good tokens + while n < k: + # skip off-channel tokens, but make sure to not look past EOF + if self.sync(i + 1): + i = self.nextTokenOnChannel(i + 1, self.channel) + n += 1 + return self.tokens[i] + + # Count EOF just once.#/ + def getNumberOfOnChannelTokens(self): + n = 0 + self.fill() + for i in range(0, len(self.tokens)): + t = self.tokens[i] + if t.channel==self.channel: + n += 1 + if t.type==Token.EOF: + break + return n diff --git a/src/antlr4/FileStream.py b/src/antlr4/FileStream.py new file mode 100644 index 00000000..d7977361 --- /dev/null +++ b/src/antlr4/FileStream.py @@ -0,0 +1,34 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# This is an InputStream that is loaded from a file all at once +# when you construct the object. +# + +import codecs +import unittest +from antlr4.InputStream import InputStream + + +class FileStream(InputStream): + + def __init__(self, fileName:str, encoding:str='ascii', errors:str='strict'): + super().__init__(self.readDataFrom(fileName, encoding, errors)) + self.fileName = fileName + + def readDataFrom(self, fileName:str, encoding:str, errors:str='strict'): + # read binary to avoid line ending conversion + with open(fileName, 'rb') as file: + bytes = file.read() + return codecs.decode(bytes, encoding, errors) + + +class TestFileStream(unittest.TestCase): + + def testStream(self): + stream = FileStream(__file__) + self.assertTrue(stream.size>0) diff --git a/src/antlr4/InputStream.py b/src/antlr4/InputStream.py new file mode 100644 index 00000000..87e66af7 --- /dev/null +++ b/src/antlr4/InputStream.py @@ -0,0 +1,104 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# +import unittest + + +# +# Vacuum all input from a string and then treat it like a buffer. +# +from antlr4.Token import Token + + +class InputStream (object): + + def __init__(self, data: str): + self.name = "" + self.strdata = data + self._loadString() + + def _loadString(self): + self._index = 0 + self.data = [ord(c) for c in self.strdata] + self._size = len(self.data) + + @property + def index(self): + return self._index + + @property + def size(self): + return self._size + + # Reset the stream so that it's in the same state it was + # when the object was created *except* the data array is not + # touched. + # + def reset(self): + self._index = 0 + + def consume(self): + if self._index >= self._size: + assert self.LA(1) == Token.EOF + raise Exception("cannot consume EOF") + self._index += 1 + + def LA(self, offset: int): + if offset==0: + return 0 # undefined + if offset<0: + offset += 1 # e.g., translate LA(-1) to use offset=0 + pos = self._index + offset - 1 + if pos < 0 or pos >= self._size: # invalid + return Token.EOF + return self.data[pos] + + def LT(self, offset: int): + return self.LA(offset) + + # mark/release do nothing; we have entire buffer + def mark(self): + return -1 + + def release(self, marker: int): + pass + + # consume() ahead until p==_index; can't just set p=_index as we must + # update line and column. If we seek backwards, just set p + # + def seek(self, _index: int): + if _index<=self._index: + self._index = _index # just jump; don't update stream state (line, ...) + return + # seek forward + self._index = min(_index, self._size) + + def getText(self, start :int, stop: int): + if stop >= self._size: + stop = self._size-1 + if start >= self._size: + return "" + else: + return self.strdata[start:stop+1] + + def __str__(self): + return self.strdata + + +class TestInputStream(unittest.TestCase): + + def testStream(self): + stream = InputStream("abcde") + self.assertEqual(0, stream.index) + self.assertEqual(5, stream.size) + self.assertEqual(ord("a"), stream.LA(1)) + stream.consume() + self.assertEqual(1, stream.index) + stream.seek(5) + self.assertEqual(Token.EOF, stream.LA(1)) + self.assertEqual("bcd", stream.getText(1, 3)) + stream.reset() + self.assertEqual(0, stream.index) + diff --git a/src/antlr4/IntervalSet.py b/src/antlr4/IntervalSet.py new file mode 100644 index 00000000..54320994 --- /dev/null +++ b/src/antlr4/IntervalSet.py @@ -0,0 +1,282 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +from io import StringIO +import unittest +from antlr4.Token import Token + +# need forward declarations +IntervalSet = None + +class IntervalSet(object): + + def __init__(self): + self.intervals = None + self.readOnly = False + + def __iter__(self): + if self.intervals is not None: + for i in self.intervals: + for c in i: + yield c + + def __getitem__(self, item): + i = 0 + for k in self: + if i==item: + return k + else: + i += 1 + return Token.INVALID_TYPE + + def addOne(self, v:int): + self.addRange(range(v, v+1)) + + def addRange(self, v:range): + if self.intervals is None: + self.intervals = list() + self.intervals.append(v) + else: + # find insert pos + k = 0 + for i in self.intervals: + # distinct range -> insert + if v.stop adjust + elif v.stop==i.start: + self.intervals[k] = range(v.start, i.stop) + return + # overlapping range -> adjust and reduce + elif v.start<=i.stop: + self.intervals[k] = range(min(i.start,v.start), max(i.stop,v.stop)) + self.reduce(k) + return + k += 1 + # greater than any existing + self.intervals.append(v) + + def addSet(self, other:IntervalSet): + if other.intervals is not None: + for i in other.intervals: + self.addRange(i) + return self + + def reduce(self, k:int): + # only need to reduce if k is not the last + if k= r.stop: + self.intervals.pop(k+1) + self.reduce(k) + elif l.stop >= r.start: + self.intervals[k] = range(l.start, r.stop) + self.intervals.pop(k+1) + + def complement(self, start, stop): + result = IntervalSet() + result.addRange(range(start,stop+1)) + for i in self.intervals: + result.removeRange(i) + return result + + def __contains__(self, item): + if self.intervals is None: + return False + else: + return any(item in i for i in self.intervals) + + def __len__(self): + return sum(len(i) for i in self.intervals) + + def removeRange(self, v): + if v.start==v.stop-1: + self.removeOne(v.start) + elif self.intervals is not None: + k = 0 + for i in self.intervals: + # intervals are ordered + if v.stop<=i.start: + return + # check for including range, split it + elif v.start>i.start and v.stop=i.stop: + self.intervals.pop(k) + k -= 1 # need another pass + # check for lower boundary + elif v.start1: + buf.write("{") + first = True + for i in self.intervals: + for j in i: + if not first: + buf.write(", ") + buf.write(self.elementName(literalNames, symbolicNames, j)) + first = False + if len(self)>1: + buf.write("}") + return buf.getvalue() + + def elementName(self, literalNames:list, symbolicNames:list, a:int): + if a==Token.EOF: + return "" + elif a==Token.EPSILON: + return "" + else: + if a" + + +class TestIntervalSet(unittest.TestCase): + + def testEmpty(self): + s = IntervalSet() + self.assertIsNone(s.intervals) + self.assertFalse(30 in s) + + def testOne(self): + s = IntervalSet() + s.addOne(30) + self.assertTrue(30 in s) + self.assertFalse(29 in s) + self.assertFalse(31 in s) + + def testTwo(self): + s = IntervalSet() + s.addOne(30) + s.addOne(40) + self.assertTrue(30 in s) + self.assertTrue(40 in s) + self.assertFalse(35 in s) + + def testRange(self): + s = IntervalSet() + s.addRange(range(30,41)) + self.assertTrue(30 in s) + self.assertTrue(40 in s) + self.assertTrue(35 in s) + + def testDistinct1(self): + s = IntervalSet() + s.addRange(range(30,32)) + s.addRange(range(40,42)) + self.assertEquals(2,len(s.intervals)) + self.assertTrue(30 in s) + self.assertTrue(40 in s) + self.assertFalse(35 in s) + + def testDistinct2(self): + s = IntervalSet() + s.addRange(range(40,42)) + s.addRange(range(30,32)) + self.assertEquals(2,len(s.intervals)) + self.assertTrue(30 in s) + self.assertTrue(40 in s) + self.assertFalse(35 in s) + + def testContiguous1(self): + s = IntervalSet() + s.addRange(range(30,36)) + s.addRange(range(36,41)) + self.assertEquals(1,len(s.intervals)) + self.assertTrue(30 in s) + self.assertTrue(40 in s) + self.assertTrue(35 in s) + + def testContiguous2(self): + s = IntervalSet() + s.addRange(range(36,41)) + s.addRange(range(30,36)) + self.assertEquals(1,len(s.intervals)) + self.assertTrue(30 in s) + self.assertTrue(40 in s) + + def testOverlapping1(self): + s = IntervalSet() + s.addRange(range(30,40)) + s.addRange(range(35,45)) + self.assertEquals(1,len(s.intervals)) + self.assertTrue(30 in s) + self.assertTrue(44 in s) + + def testOverlapping2(self): + s = IntervalSet() + s.addRange(range(35,45)) + s.addRange(range(30,40)) + self.assertEquals(1,len(s.intervals)) + self.assertTrue(30 in s) + self.assertTrue(44 in s) + + def testOverlapping3(self): + s = IntervalSet() + s.addRange(range(30,32)) + s.addRange(range(40,42)) + s.addRange(range(50,52)) + s.addRange(range(20,61)) + self.assertEquals(1,len(s.intervals)) + self.assertTrue(20 in s) + self.assertTrue(60 in s) + + def testComplement(self): + s = IntervalSet() + s.addRange(range(10,21)) + c = s.complement(1,100) + self.assertTrue(1 in c) + self.assertTrue(100 in c) + self.assertTrue(10 not in c) + self.assertTrue(20 not in c) + + diff --git a/src/antlr4/LL1Analyzer.py b/src/antlr4/LL1Analyzer.py new file mode 100644 index 00000000..6b398fcd --- /dev/null +++ b/src/antlr4/LL1Analyzer.py @@ -0,0 +1,172 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ +from antlr4.IntervalSet import IntervalSet +from antlr4.Token import Token +from antlr4.PredictionContext import PredictionContext, SingletonPredictionContext, PredictionContextFromRuleContext +from antlr4.RuleContext import RuleContext +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNConfig import ATNConfig +from antlr4.atn.ATNState import ATNState, RuleStopState +from antlr4.atn.Transition import WildcardTransition, NotSetTransition, AbstractPredicateTransition, RuleTransition + + +class LL1Analyzer (object): + + #* Special value added to the lookahead sets to indicate that we hit + # a predicate during analysis if {@code seeThruPreds==false}. + #/ + HIT_PRED = Token.INVALID_TYPE + + def __init__(self, atn:ATN): + self.atn = atn + + #* + # Calculates the SLL(1) expected lookahead set for each outgoing transition + # of an {@link ATNState}. The returned array has one element for each + # outgoing transition in {@code s}. If the closure from transition + # i leads to a semantic predicate before matching a symbol, the + # element at index i of the result will be {@code null}. + # + # @param s the ATN state + # @return the expected symbols for each outgoing transition of {@code s}. + #/ + def getDecisionLookahead(self, s:ATNState): + if s is None: + return None + + count = len(s.transitions) + look = [] * count + for alt in range(0, count): + look[alt] = set() + lookBusy = set() + seeThruPreds = False # fail to get lookahead upon pred + self._LOOK(s.transition(alt).target, None, PredictionContext.EMPTY, + look[alt], lookBusy, set(), seeThruPreds, False) + # Wipe out lookahead for this alternative if we found nothing + # or we had a predicate when we !seeThruPreds + if len(look[alt])==0 or self.HIT_PRED in look[alt]: + look[alt] = None + return look + + #* + # Compute set of tokens that can follow {@code s} in the ATN in the + # specified {@code ctx}. + # + #

      If {@code ctx} is {@code null} and the end of the rule containing + # {@code s} is reached, {@link Token#EPSILON} is added to the result set. + # If {@code ctx} is not {@code null} and the end of the outermost rule is + # reached, {@link Token#EOF} is added to the result set.

      + # + # @param s the ATN state + # @param stopState the ATN state to stop at. This can be a + # {@link BlockEndState} to detect epsilon paths through a closure. + # @param ctx the complete parser context, or {@code null} if the context + # should be ignored + # + # @return The set of tokens that can follow {@code s} in the ATN in the + # specified {@code ctx}. + #/ + def LOOK(self, s:ATNState, stopState:ATNState=None, ctx:RuleContext=None): + r = IntervalSet() + seeThruPreds = True # ignore preds; get all lookahead + lookContext = PredictionContextFromRuleContext(s.atn, ctx) if ctx is not None else None + self._LOOK(s, stopState, lookContext, r, set(), set(), seeThruPreds, True) + return r + + #* + # Compute set of tokens that can follow {@code s} in the ATN in the + # specified {@code ctx}. + # + #

      If {@code ctx} is {@code null} and {@code stopState} or the end of the + # rule containing {@code s} is reached, {@link Token#EPSILON} is added to + # the result set. If {@code ctx} is not {@code null} and {@code addEOF} is + # {@code true} and {@code stopState} or the end of the outermost rule is + # reached, {@link Token#EOF} is added to the result set.

      + # + # @param s the ATN state. + # @param stopState the ATN state to stop at. This can be a + # {@link BlockEndState} to detect epsilon paths through a closure. + # @param ctx The outer context, or {@code null} if the outer context should + # not be used. + # @param look The result lookahead set. + # @param lookBusy A set used for preventing epsilon closures in the ATN + # from causing a stack overflow. Outside code should pass + # {@code new HashSet} for this argument. + # @param calledRuleStack A set used for preventing left recursion in the + # ATN from causing a stack overflow. Outside code should pass + # {@code new BitSet()} for this argument. + # @param seeThruPreds {@code true} to true semantic predicates as + # implicitly {@code true} and "see through them", otherwise {@code false} + # to treat semantic predicates as opaque and add {@link #HIT_PRED} to the + # result if one is encountered. + # @param addEOF Add {@link Token#EOF} to the result if the end of the + # outermost context is reached. This parameter has no effect if {@code ctx} + # is {@code null}. + #/ + def _LOOK(self, s:ATNState, stopState:ATNState , ctx:PredictionContext, look:IntervalSet, lookBusy:set, + calledRuleStack:set, seeThruPreds:bool, addEOF:bool): + c = ATNConfig(s, 0, ctx) + + if c in lookBusy: + return + lookBusy.add(c) + + if s == stopState: + if ctx is None: + look.addOne(Token.EPSILON) + return + elif ctx.isEmpty() and addEOF: + look.addOne(Token.EOF) + return + + if isinstance(s, RuleStopState ): + if ctx is None: + look.addOne(Token.EPSILON) + return + elif ctx.isEmpty() and addEOF: + look.addOne(Token.EOF) + return + + if ctx != PredictionContext.EMPTY: + # run thru all possible stack tops in ctx + for i in range(0, len(ctx)): + returnState = self.atn.states[ctx.getReturnState(i)] + removed = returnState.ruleIndex in calledRuleStack + try: + calledRuleStack.discard(returnState.ruleIndex) + self._LOOK(returnState, stopState, ctx.getParent(i), look, lookBusy, calledRuleStack, seeThruPreds, addEOF) + finally: + if removed: + calledRuleStack.add(returnState.ruleIndex) + return + + for t in s.transitions: + if type(t) == RuleTransition: + if t.target.ruleIndex in calledRuleStack: + continue + + newContext = SingletonPredictionContext.create(ctx, t.followState.stateNumber) + + try: + calledRuleStack.add(t.target.ruleIndex) + self._LOOK(t.target, stopState, newContext, look, lookBusy, calledRuleStack, seeThruPreds, addEOF) + finally: + calledRuleStack.remove(t.target.ruleIndex) + elif isinstance(t, AbstractPredicateTransition ): + if seeThruPreds: + self._LOOK(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF) + else: + look.addOne(self.HIT_PRED) + elif t.isEpsilon: + self._LOOK(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF) + elif type(t) == WildcardTransition: + look.addRange( range(Token.MIN_USER_TOKEN_TYPE, self.atn.maxTokenType + 1) ) + else: + set_ = t.label + if set_ is not None: + if isinstance(t, NotSetTransition): + set_ = set_.complement(Token.MIN_USER_TOKEN_TYPE, self.atn.maxTokenType) + look.addSet(set_) diff --git a/src/antlr4/Lexer.py b/src/antlr4/Lexer.py new file mode 100644 index 00000000..a60b5bcc --- /dev/null +++ b/src/antlr4/Lexer.py @@ -0,0 +1,321 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# A lexer is recognizer that draws input symbols from a character stream. +# lexer grammars result in a subclass of self object. A Lexer object +# uses simplified match() and error recovery mechanisms in the interest +# of speed. +#/ +from io import StringIO +from typing.io import TextIO +import sys +from antlr4.CommonTokenFactory import CommonTokenFactory +from antlr4.atn.LexerATNSimulator import LexerATNSimulator +from antlr4.InputStream import InputStream +from antlr4.Recognizer import Recognizer +from antlr4.Token import Token +from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException + +class TokenSource(object): + + pass + + +class Lexer(Recognizer, TokenSource): + + DEFAULT_MODE = 0 + MORE = -2 + SKIP = -3 + + DEFAULT_TOKEN_CHANNEL = Token.DEFAULT_CHANNEL + HIDDEN = Token.HIDDEN_CHANNEL + MIN_CHAR_VALUE = 0x0000 + MAX_CHAR_VALUE = 0x10FFFF + + def __init__(self, input:InputStream, output:TextIO = sys.stdout): + super().__init__() + self._input = input + self._output = output + self._factory = CommonTokenFactory.DEFAULT + self._tokenFactorySourcePair = (self, input) + + self._interp = None # child classes must populate this + + # The goal of all lexer rules/methods is to create a token object. + # self is an instance variable as multiple rules may collaborate to + # create a single token. nextToken will return self object after + # matching lexer rule(s). If you subclass to allow multiple token + # emissions, then set self to the last token to be matched or + # something nonnull so that the auto token emit mechanism will not + # emit another token. + self._token = None + + # What character index in the stream did the current token start at? + # Needed, for example, to get the text for current token. Set at + # the start of nextToken. + self._tokenStartCharIndex = -1 + + # The line on which the first character of the token resides#/ + self._tokenStartLine = -1 + + # The character position of first character within the line#/ + self._tokenStartColumn = -1 + + # Once we see EOF on char stream, next token will be EOF. + # If you have DONE : EOF ; then you see DONE EOF. + self._hitEOF = False + + # The channel number for the current token#/ + self._channel = Token.DEFAULT_CHANNEL + + # The token type for the current token#/ + self._type = Token.INVALID_TYPE + + self._modeStack = [] + self._mode = self.DEFAULT_MODE + + # You can set the text for the current token to override what is in + # the input char buffer. Use setText() or can set self instance var. + #/ + self._text = None + + + def reset(self): + # wack Lexer state variables + if self._input is not None: + self._input.seek(0) # rewind the input + self._token = None + self._type = Token.INVALID_TYPE + self._channel = Token.DEFAULT_CHANNEL + self._tokenStartCharIndex = -1 + self._tokenStartColumn = -1 + self._tokenStartLine = -1 + self._text = None + + self._hitEOF = False + self._mode = Lexer.DEFAULT_MODE + self._modeStack = [] + + self._interp.reset() + + # Return a token from self source; i.e., match a token on the char + # stream. + def nextToken(self): + if self._input is None: + raise IllegalStateException("nextToken requires a non-null input stream.") + + # Mark start location in char stream so unbuffered streams are + # guaranteed at least have text of current token + tokenStartMarker = self._input.mark() + try: + while True: + if self._hitEOF: + self.emitEOF() + return self._token + self._token = None + self._channel = Token.DEFAULT_CHANNEL + self._tokenStartCharIndex = self._input.index + self._tokenStartColumn = self._interp.column + self._tokenStartLine = self._interp.line + self._text = None + continueOuter = False + while True: + self._type = Token.INVALID_TYPE + ttype = self.SKIP + try: + ttype = self._interp.match(self._input, self._mode) + except LexerNoViableAltException as e: + self.notifyListeners(e) # report error + self.recover(e) + if self._input.LA(1)==Token.EOF: + self._hitEOF = True + if self._type == Token.INVALID_TYPE: + self._type = ttype + if self._type == self.SKIP: + continueOuter = True + break + if self._type!=self.MORE: + break + if continueOuter: + continue + if self._token is None: + self.emit() + return self._token + finally: + # make sure we release marker after match or + # unbuffered char stream will keep buffering + self._input.release(tokenStartMarker) + + # Instruct the lexer to skip creating a token for current lexer rule + # and look for another token. nextToken() knows to keep looking when + # a lexer rule finishes with token set to SKIP_TOKEN. Recall that + # if token==null at end of any token rule, it creates one for you + # and emits it. + #/ + def skip(self): + self._type = self.SKIP + + def more(self): + self._type = self.MORE + + def mode(self, m:int): + self._mode = m + + def pushMode(self, m:int): + if self._interp.debug: + print("pushMode " + str(m), file=self._output) + self._modeStack.append(self._mode) + self.mode(m) + + def popMode(self): + if len(self._modeStack)==0: + raise Exception("Empty Stack") + if self._interp.debug: + print("popMode back to "+ self._modeStack[:-1], file=self._output) + self.mode( self._modeStack.pop() ) + return self._mode + + # Set the char stream and reset the lexer#/ + @property + def inputStream(self): + return self._input + + @inputStream.setter + def inputStream(self, input:InputStream): + self._input = None + self._tokenFactorySourcePair = (self, self._input) + self.reset() + self._input = input + self._tokenFactorySourcePair = (self, self._input) + + @property + def sourceName(self): + return self._input.sourceName + + # By default does not support multiple emits per nextToken invocation + # for efficiency reasons. Subclass and override self method, nextToken, + # and getToken (to push tokens into a list and pull from that list + # rather than a single variable as self implementation does). + #/ + def emitToken(self, token:Token): + self._token = token + + # The standard method called to automatically emit a token at the + # outermost lexical rule. The token object should point into the + # char buffer start..stop. If there is a text override in 'text', + # use that to set the token's text. Override self method to emit + # custom Token objects or provide a new factory. + #/ + def emit(self): + t = self._factory.create(self._tokenFactorySourcePair, self._type, self._text, self._channel, self._tokenStartCharIndex, + self.getCharIndex()-1, self._tokenStartLine, self._tokenStartColumn) + self.emitToken(t) + return t + + def emitEOF(self): + cpos = self.column + lpos = self.line + eof = self._factory.create(self._tokenFactorySourcePair, Token.EOF, None, Token.DEFAULT_CHANNEL, self._input.index, + self._input.index-1, lpos, cpos) + self.emitToken(eof) + return eof + + @property + def type(self): + return self._type + + @type.setter + def type(self, type:int): + self._type = type + + @property + def line(self): + return self._interp.line + + @line.setter + def line(self, line:int): + self._interp.line = line + + @property + def column(self): + return self._interp.column + + @column.setter + def column(self, column:int): + self._interp.column = column + + # What is the index of the current character of lookahead?#/ + def getCharIndex(self): + return self._input.index + + # Return the text matched so far for the current token or any + # text override. + @property + def text(self): + if self._text is not None: + return self._text + else: + return self._interp.getText(self._input) + + # Set the complete text of self token; it wipes any previous + # changes to the text. + @text.setter + def text(self, txt:str): + self._text = txt + + # Return a list of all Token objects in input char stream. + # Forces load of all tokens. Does not include EOF token. + #/ + def getAllTokens(self): + tokens = [] + t = self.nextToken() + while t.type!=Token.EOF: + tokens.append(t) + t = self.nextToken() + return tokens + + def notifyListeners(self, e:LexerNoViableAltException): + start = self._tokenStartCharIndex + stop = self._input.index + text = self._input.getText(start, stop) + msg = "token recognition error at: '" + self.getErrorDisplay(text) + "'" + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, None, self._tokenStartLine, self._tokenStartColumn, msg, e) + + def getErrorDisplay(self, s:str): + with StringIO() as buf: + for c in s: + buf.write(self.getErrorDisplayForChar(c)) + return buf.getvalue() + + def getErrorDisplayForChar(self, c:str): + if ord(c[0])==Token.EOF: + return "" + elif c=='\n': + return "\\n" + elif c=='\t': + return "\\t" + elif c=='\r': + return "\\r" + else: + return c + + def getCharErrorDisplay(self, c:str): + return "'" + self.getErrorDisplayForChar(c) + "'" + + # Lexers can normally match any char in it's vocabulary after matching + # a token, so do the easy thing and just kill a character and hope + # it all works out. You can instead use the rule invocation stack + # to do sophisticated error recovery if you are in a fragment rule. + #/ + def recover(self, re:RecognitionException): + if self._input.LA(1) != Token.EOF: + if isinstance(re, LexerNoViableAltException): + # skip a char and try again + self._interp.consume(self._input) + else: + # TODO: Do we lose character or line position information? + self._input.consume() + diff --git a/src/antlr4/ListTokenSource.py b/src/antlr4/ListTokenSource.py new file mode 100644 index 00000000..eebc7564 --- /dev/null +++ b/src/antlr4/ListTokenSource.py @@ -0,0 +1,143 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# Provides an implementation of {@link TokenSource} as a wrapper around a list +# of {@link Token} objects. +# +#

      If the final token in the list is an {@link Token#EOF} token, it will be used +# as the EOF token for every call to {@link #nextToken} after the end of the +# list is reached. Otherwise, an EOF token will be created.

      +# +from antlr4.CommonTokenFactory import CommonTokenFactory +from antlr4.Lexer import TokenSource +from antlr4.Token import Token + + +class ListTokenSource(TokenSource): + + # Constructs a new {@link ListTokenSource} instance from the specified + # collection of {@link Token} objects and source name. + # + # @param tokens The collection of {@link Token} objects to provide as a + # {@link TokenSource}. + # @param sourceName The name of the {@link TokenSource}. If this value is + # {@code null}, {@link #getSourceName} will attempt to infer the name from + # the next {@link Token} (or the previous token if the end of the input has + # been reached). + # + # @exception NullPointerException if {@code tokens} is {@code null} + # + def __init__(self, tokens:list, sourceName:str=None): + if tokens is None: + raise ReferenceError("tokens cannot be null") + self.tokens = tokens + self.sourceName = sourceName + # The index into {@link #tokens} of token to return by the next call to + # {@link #nextToken}. The end of the input is indicated by this value + # being greater than or equal to the number of items in {@link #tokens}. + self.pos = 0 + # This field caches the EOF token for the token source. + self.eofToken = None + # This is the backing field for {@link #getTokenFactory} and + self._factory = CommonTokenFactory.DEFAULT + + + # + # {@inheritDoc} + # + @property + def column(self): + if self.pos < len(self.tokens): + return self.tokens[self.pos].column + elif self.eofToken is not None: + return self.eofToken.column + elif len(self.tokens) > 0: + # have to calculate the result from the line/column of the previous + # token, along with the text of the token. + lastToken = self.tokens[len(self.tokens) - 1] + tokenText = lastToken.text + if tokenText is not None: + lastNewLine = tokenText.rfind('\n') + if lastNewLine >= 0: + return len(tokenText) - lastNewLine - 1 + return lastToken.column + lastToken.stop - lastToken.start + 1 + + # only reach this if tokens is empty, meaning EOF occurs at the first + # position in the input + return 0 + + # + # {@inheritDoc} + # + def nextToken(self): + if self.pos >= len(self.tokens): + if self.eofToken is None: + start = -1 + if len(self.tokens) > 0: + previousStop = self.tokens[len(self.tokens) - 1].stop + if previousStop != -1: + start = previousStop + 1 + stop = max(-1, start - 1) + self.eofToken = self._factory.create((self, self.getInputStream()), + Token.EOF, "EOF", Token.DEFAULT_CHANNEL, start, stop, self.line, self.column) + return self.eofToken + t = self.tokens[self.pos] + if self.pos == len(self.tokens) - 1 and t.type == Token.EOF: + self.eofToken = t + self.pos += 1 + return t + + # + # {@inheritDoc} + # + @property + def line(self): + if self.pos < len(self.tokens): + return self.tokens[self.pos].line + elif self.eofToken is not None: + return self.eofToken.line + elif len(self.tokens) > 0: + # have to calculate the result from the line/column of the previous + # token, along with the text of the token. + lastToken = self.tokens[len(self.tokens) - 1] + line = lastToken.line + tokenText = lastToken.text + if tokenText is not None: + line += tokenText.count('\n') + + # if no text is available, assume the token did not contain any newline characters. + return line + + # only reach this if tokens is empty, meaning EOF occurs at the first + # position in the input + return 1 + + # + # {@inheritDoc} + # + def getInputStream(self): + if self.pos < len(self.tokens): + return self.tokens[self.pos].getInputStream() + elif self.eofToken is not None: + return self.eofToken.getInputStream() + elif len(self.tokens) > 0: + return self.tokens[len(self.tokens) - 1].getInputStream() + else: + # no input stream information is available + return None + + # + # {@inheritDoc} + # + def getSourceName(self): + if self.sourceName is not None: + return self.sourceName + inputStream = self.getInputStream() + if inputStream is not None: + return inputStream.getSourceName() + else: + return "List" \ No newline at end of file diff --git a/src/antlr4/Parser.py b/src/antlr4/Parser.py new file mode 100644 index 00000000..c461bbdc --- /dev/null +++ b/src/antlr4/Parser.py @@ -0,0 +1,572 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +import sys +from typing.io import TextIO +from antlr4.BufferedTokenStream import TokenStream +from antlr4.CommonTokenFactory import TokenFactory +from antlr4.error.ErrorStrategy import DefaultErrorStrategy +from antlr4.InputStream import InputStream +from antlr4.Recognizer import Recognizer +from antlr4.RuleContext import RuleContext +from antlr4.ParserRuleContext import ParserRuleContext +from antlr4.Token import Token +from antlr4.Lexer import Lexer +from antlr4.atn.ATNDeserializer import ATNDeserializer +from antlr4.atn.ATNDeserializationOptions import ATNDeserializationOptions +from antlr4.error.Errors import UnsupportedOperationException, RecognitionException +from antlr4.tree.ParseTreePatternMatcher import ParseTreePatternMatcher +from antlr4.tree.Tree import ParseTreeListener, TerminalNode, ErrorNode + +class TraceListener(ParseTreeListener): + + def __init__(self, parser): + self._parser = parser + + def enterEveryRule(self, ctx): + print("enter " + self._parser.ruleNames[ctx.getRuleIndex()] + ", LT(1)=" + self._parser._input.LT(1).text, file=self._parser._output) + + def visitTerminal(self, node): + + print("consume " + str(node.symbol) + " rule " + self._parser.ruleNames[self._parser._ctx.getRuleIndex()], file=self._parser._output) + + def visitErrorNode(self, node): + pass + + + def exitEveryRule(self, ctx): + print("exit " + self._parser.ruleNames[ctx.getRuleIndex()] + ", LT(1)=" + self._parser._input.LT(1).text, file=self._parser._output) + + +# self is all the parsing support code essentially; most of it is error recovery stuff.# +class Parser (Recognizer): + + # self field maps from the serialized ATN string to the deserialized {@link ATN} with + # bypass alternatives. + # + # @see ATNDeserializationOptions#isGenerateRuleBypassTransitions() + # + bypassAltsAtnCache = dict() + + def __init__(self, input:TokenStream, output:TextIO = sys.stdout): + super().__init__() + # The input stream. + self._input = None + self._output = output + # The error handling strategy for the parser. The default value is a new + # instance of {@link DefaultErrorStrategy}. + self._errHandler = DefaultErrorStrategy() + self._precedenceStack = list() + self._precedenceStack.append(0) + # The {@link ParserRuleContext} object for the currently executing rule. + # self is always non-null during the parsing process. + self._ctx = None + # Specifies whether or not the parser should construct a parse tree during + # the parsing process. The default value is {@code true}. + self.buildParseTrees = True + # When {@link #setTrace}{@code (true)} is called, a reference to the + # {@link TraceListener} is stored here so it can be easily removed in a + # later call to {@link #setTrace}{@code (false)}. The listener itself is + # implemented as a parser listener so self field is not directly used by + # other parser methods. + self._tracer = None + # The list of {@link ParseTreeListener} listeners registered to receive + # events during the parse. + self._parseListeners = None + # The number of syntax errors reported during parsing. self value is + # incremented each time {@link #notifyErrorListeners} is called. + self._syntaxErrors = 0 + self.setInputStream(input) + + # reset the parser's state# + def reset(self): + if self._input is not None: + self._input.seek(0) + self._errHandler.reset(self) + self._ctx = None + self._syntaxErrors = 0 + self.setTrace(False) + self._precedenceStack = list() + self._precedenceStack.append(0) + if self._interp is not None: + self._interp.reset() + + # Match current input symbol against {@code ttype}. If the symbol type + # matches, {@link ANTLRErrorStrategy#reportMatch} and {@link #consume} are + # called to complete the match process. + # + #

      If the symbol type does not match, + # {@link ANTLRErrorStrategy#recoverInline} is called on the current error + # strategy to attempt recovery. If {@link #getBuildParseTree} is + # {@code true} and the token index of the symbol returned by + # {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to + # the parse tree by calling {@link ParserRuleContext#addErrorNode}.

      + # + # @param ttype the token type to match + # @return the matched symbol + # @throws RecognitionException if the current input symbol did not match + # {@code ttype} and the error strategy could not recover from the + # mismatched symbol + + def match(self, ttype:int): + t = self.getCurrentToken() + if t.type==ttype: + self._errHandler.reportMatch(self) + self.consume() + else: + t = self._errHandler.recoverInline(self) + if self.buildParseTrees and t.tokenIndex==-1: + # we must have conjured up a new token during single token insertion + # if it's not the current symbol + self._ctx.addErrorNode(t) + return t + + # Match current input symbol as a wildcard. If the symbol type matches + # (i.e. has a value greater than 0), {@link ANTLRErrorStrategy#reportMatch} + # and {@link #consume} are called to complete the match process. + # + #

      If the symbol type does not match, + # {@link ANTLRErrorStrategy#recoverInline} is called on the current error + # strategy to attempt recovery. If {@link #getBuildParseTree} is + # {@code true} and the token index of the symbol returned by + # {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to + # the parse tree by calling {@link ParserRuleContext#addErrorNode}.

      + # + # @return the matched symbol + # @throws RecognitionException if the current input symbol did not match + # a wildcard and the error strategy could not recover from the mismatched + # symbol + + def matchWildcard(self): + t = self.getCurrentToken() + if t.type > 0: + self._errHandler.reportMatch(self) + self.consume() + else: + t = self._errHandler.recoverInline(self) + if self.buildParseTrees and t.tokenIndex == -1: + # we must have conjured up a new token during single token insertion + # if it's not the current symbol + self._ctx.addErrorNode(t) + + return t + + def getParseListeners(self): + return list() if self._parseListeners is None else self._parseListeners + + # Registers {@code listener} to receive events during the parsing process. + # + #

      To support output-preserving grammar transformations (including but not + # limited to left-recursion removal, automated left-factoring, and + # optimized code generation), calls to listener methods during the parse + # may differ substantially from calls made by + # {@link ParseTreeWalker#DEFAULT} used after the parse is complete. In + # particular, rule entry and exit events may occur in a different order + # during the parse than after the parser. In addition, calls to certain + # rule entry methods may be omitted.

      + # + #

      With the following specific exceptions, calls to listener events are + # deterministic, i.e. for identical input the calls to listener + # methods will be the same.

      + # + #
        + #
      • Alterations to the grammar used to generate code may change the + # behavior of the listener calls.
      • + #
      • Alterations to the command line options passed to ANTLR 4 when + # generating the parser may change the behavior of the listener calls.
      • + #
      • Changing the version of the ANTLR Tool used to generate the parser + # may change the behavior of the listener calls.
      • + #
      + # + # @param listener the listener to add + # + # @throws NullPointerException if {@code} listener is {@code null} + # + def addParseListener(self, listener:ParseTreeListener): + if listener is None: + raise ReferenceError("listener") + if self._parseListeners is None: + self._parseListeners = [] + self._parseListeners.append(listener) + + # + # Remove {@code listener} from the list of parse listeners. + # + #

      If {@code listener} is {@code null} or has not been added as a parse + # listener, self method does nothing.

      + # @param listener the listener to remove + # + def removeParseListener(self, listener:ParseTreeListener): + if self._parseListeners is not None: + self._parseListeners.remove(listener) + if len(self._parseListeners)==0: + self._parseListeners = None + + # Remove all parse listeners. + def removeParseListeners(self): + self._parseListeners = None + + # Notify any parse listeners of an enter rule event. + def triggerEnterRuleEvent(self): + if self._parseListeners is not None: + for listener in self._parseListeners: + listener.enterEveryRule(self._ctx) + self._ctx.enterRule(listener) + + # + # Notify any parse listeners of an exit rule event. + # + # @see #addParseListener + # + def triggerExitRuleEvent(self): + if self._parseListeners is not None: + # reverse order walk of listeners + for listener in reversed(self._parseListeners): + self._ctx.exitRule(listener) + listener.exitEveryRule(self._ctx) + + + # Gets the number of syntax errors reported during parsing. This value is + # incremented each time {@link #notifyErrorListeners} is called. + # + # @see #notifyErrorListeners + # + def getNumberOfSyntaxErrors(self): + return self._syntaxErrors + + def getTokenFactory(self): + return self._input.tokenSource._factory + + # Tell our token source and error strategy about a new way to create tokens.# + def setTokenFactory(self, factory:TokenFactory): + self._input.tokenSource._factory = factory + + # The ATN with bypass alternatives is expensive to create so we create it + # lazily. + # + # @throws UnsupportedOperationException if the current parser does not + # implement the {@link #getSerializedATN()} method. + # + def getATNWithBypassAlts(self): + serializedAtn = self.getSerializedATN() + if serializedAtn is None: + raise UnsupportedOperationException("The current parser does not support an ATN with bypass alternatives.") + result = self.bypassAltsAtnCache.get(serializedAtn, None) + if result is None: + deserializationOptions = ATNDeserializationOptions() + deserializationOptions.generateRuleBypassTransitions = True + result = ATNDeserializer(deserializationOptions).deserialize(serializedAtn) + self.bypassAltsAtnCache[serializedAtn] = result + return result + + # The preferred method of getting a tree pattern. For example, here's a + # sample use: + # + #
      +    # ParseTree t = parser.expr();
      +    # ParseTreePattern p = parser.compileParseTreePattern("<ID>+0", MyParser.RULE_expr);
      +    # ParseTreeMatch m = p.match(t);
      +    # String id = m.get("ID");
      +    # 
      + # + def compileParseTreePattern(self, pattern:str, patternRuleIndex:int, lexer:Lexer = None): + if lexer is None: + if self.getTokenStream() is not None: + tokenSource = self.getTokenStream().tokenSource + if isinstance( tokenSource, Lexer ): + lexer = tokenSource + if lexer is None: + raise UnsupportedOperationException("Parser can't discover a lexer to use") + + m = ParseTreePatternMatcher(lexer, self) + return m.compile(pattern, patternRuleIndex) + + + def getInputStream(self): + return self.getTokenStream() + + def setInputStream(self, input:InputStream): + self.setTokenStream(input) + + def getTokenStream(self): + return self._input + + # Set the token stream and reset the parser.# + def setTokenStream(self, input:TokenStream): + self._input = None + self.reset() + self._input = input + + # Match needs to return the current input symbol, which gets put + # into the label for the associated token ref; e.g., x=ID. + # + def getCurrentToken(self): + return self._input.LT(1) + + def notifyErrorListeners(self, msg:str, offendingToken:Token = None, e:RecognitionException = None): + if offendingToken is None: + offendingToken = self.getCurrentToken() + self._syntaxErrors += 1 + line = offendingToken.line + column = offendingToken.column + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, offendingToken, line, column, msg, e) + + # + # Consume and return the {@linkplain #getCurrentToken current symbol}. + # + #

      E.g., given the following input with {@code A} being the current + # lookahead symbol, self function moves the cursor to {@code B} and returns + # {@code A}.

      + # + #
      +    #  A B
      +    #  ^
      +    # 
      + # + # If the parser is not in error recovery mode, the consumed symbol is added + # to the parse tree using {@link ParserRuleContext#addChild(Token)}, and + # {@link ParseTreeListener#visitTerminal} is called on any parse listeners. + # If the parser is in error recovery mode, the consumed symbol is + # added to the parse tree using + # {@link ParserRuleContext#addErrorNode(Token)}, and + # {@link ParseTreeListener#visitErrorNode} is called on any parse + # listeners. + # + def consume(self): + o = self.getCurrentToken() + if o.type != Token.EOF: + self.getInputStream().consume() + hasListener = self._parseListeners is not None and len(self._parseListeners)>0 + if self.buildParseTrees or hasListener: + if self._errHandler.inErrorRecoveryMode(self): + node = self._ctx.addErrorNode(o) + else: + node = self._ctx.addTokenNode(o) + if hasListener: + for listener in self._parseListeners: + if isinstance(node, ErrorNode): + listener.visitErrorNode(node) + elif isinstance(node, TerminalNode): + listener.visitTerminal(node) + return o + + def addContextToParseTree(self): + # add current context to parent if we have a parent + if self._ctx.parentCtx is not None: + self._ctx.parentCtx.addChild(self._ctx) + + # Always called by generated parsers upon entry to a rule. Access field + # {@link #_ctx} get the current context. + # + def enterRule(self, localctx:ParserRuleContext , state:int , ruleIndex:int): + self.state = state + self._ctx = localctx + self._ctx.start = self._input.LT(1) + if self.buildParseTrees: + self.addContextToParseTree() + if self._parseListeners is not None: + self.triggerEnterRuleEvent() + + def exitRule(self): + self._ctx.stop = self._input.LT(-1) + # trigger event on _ctx, before it reverts to parent + if self._parseListeners is not None: + self.triggerExitRuleEvent() + self.state = self._ctx.invokingState + self._ctx = self._ctx.parentCtx + + def enterOuterAlt(self, localctx:ParserRuleContext, altNum:int): + localctx.setAltNumber(altNum) + # if we have new localctx, make sure we replace existing ctx + # that is previous child of parse tree + if self.buildParseTrees and self._ctx != localctx: + if self._ctx.parentCtx is not None: + self._ctx.parentCtx.removeLastChild() + self._ctx.parentCtx.addChild(localctx) + self._ctx = localctx + + # Get the precedence level for the top-most precedence rule. + # + # @return The precedence level for the top-most precedence rule, or -1 if + # the parser context is not nested within a precedence rule. + # + def getPrecedence(self): + if len(self._precedenceStack)==0: + return -1 + else: + return self._precedenceStack[-1] + + def enterRecursionRule(self, localctx:ParserRuleContext, state:int, ruleIndex:int, precedence:int): + self.state = state + self._precedenceStack.append(precedence) + self._ctx = localctx + self._ctx.start = self._input.LT(1) + if self._parseListeners is not None: + self.triggerEnterRuleEvent() # simulates rule entry for left-recursive rules + + # + # Like {@link #enterRule} but for recursive rules. + # + def pushNewRecursionContext(self, localctx:ParserRuleContext, state:int, ruleIndex:int): + previous = self._ctx + previous.parentCtx = localctx + previous.invokingState = state + previous.stop = self._input.LT(-1) + + self._ctx = localctx + self._ctx.start = previous.start + if self.buildParseTrees: + self._ctx.addChild(previous) + + if self._parseListeners is not None: + self.triggerEnterRuleEvent() # simulates rule entry for left-recursive rules + + def unrollRecursionContexts(self, parentCtx:ParserRuleContext): + self._precedenceStack.pop() + self._ctx.stop = self._input.LT(-1) + retCtx = self._ctx # save current ctx (return value) + # unroll so _ctx is as it was before call to recursive method + if self._parseListeners is not None: + while self._ctx is not parentCtx: + self.triggerExitRuleEvent() + self._ctx = self._ctx.parentCtx + else: + self._ctx = parentCtx + + # hook into tree + retCtx.parentCtx = parentCtx + + if self.buildParseTrees and parentCtx is not None: + # add return ctx into invoking rule's tree + parentCtx.addChild(retCtx) + + def getInvokingContext(self, ruleIndex:int): + ctx = self._ctx + while ctx is not None: + if ctx.ruleIndex == ruleIndex: + return ctx + ctx = ctx.parentCtx + return None + + + def precpred(self, localctx:RuleContext , precedence:int): + return precedence >= self._precedenceStack[-1] + + def inContext(self, context:str): + # TODO: useful in parser? + return False + + # + # Checks whether or not {@code symbol} can follow the current state in the + # ATN. The behavior of self method is equivalent to the following, but is + # implemented such that the complete context-sensitive follow set does not + # need to be explicitly constructed. + # + #
      +    # return getExpectedTokens().contains(symbol);
      +    # 
      + # + # @param symbol the symbol type to check + # @return {@code true} if {@code symbol} can follow the current state in + # the ATN, otherwise {@code false}. + # + def isExpectedToken(self, symbol:int): + atn = self._interp.atn + ctx = self._ctx + s = atn.states[self.state] + following = atn.nextTokens(s) + if symbol in following: + return True + if not Token.EPSILON in following: + return False + + while ctx is not None and ctx.invokingState>=0 and Token.EPSILON in following: + invokingState = atn.states[ctx.invokingState] + rt = invokingState.transitions[0] + following = atn.nextTokens(rt.followState) + if symbol in following: + return True + ctx = ctx.parentCtx + + if Token.EPSILON in following and symbol == Token.EOF: + return True + else: + return False + + # Computes the set of input symbols which could follow the current parser + # state and context, as given by {@link #getState} and {@link #getContext}, + # respectively. + # + # @see ATN#getExpectedTokens(int, RuleContext) + # + def getExpectedTokens(self): + return self._interp.atn.getExpectedTokens(self.state, self._ctx) + + def getExpectedTokensWithinCurrentRule(self): + atn = self._interp.atn + s = atn.states[self.state] + return atn.nextTokens(s) + + # Get a rule's index (i.e., {@code RULE_ruleName} field) or -1 if not found.# + def getRuleIndex(self, ruleName:str): + ruleIndex = self.getRuleIndexMap().get(ruleName, None) + if ruleIndex is not None: + return ruleIndex + else: + return -1 + + # Return List<String> of the rule names in your parser instance + # leading up to a call to the current rule. You could override if + # you want more details such as the file/line info of where + # in the ATN a rule is invoked. + # + # this is very useful for error messages. + # + def getRuleInvocationStack(self, p:RuleContext=None): + if p is None: + p = self._ctx + stack = list() + while p is not None: + # compute what follows who invoked us + ruleIndex = p.getRuleIndex() + if ruleIndex<0: + stack.append("n/a") + else: + stack.append(self.ruleNames[ruleIndex]) + p = p.parentCtx + return stack + + # For debugging and other purposes.# + def getDFAStrings(self): + return [ str(dfa) for dfa in self._interp.decisionToDFA] + + # For debugging and other purposes.# + def dumpDFA(self): + seenOne = False + for i in range(0, len(self._interp.decisionToDFA)): + dfa = self._interp.decisionToDFA[i] + if len(dfa.states)>0: + if seenOne: + print(file=self._output) + print("Decision " + str(dfa.decision) + ":", file=self._output) + print(dfa.toString(self.literalNames, self.symbolicNames), end='', file=self._output) + seenOne = True + + + def getSourceName(self): + return self._input.sourceName + + # During a parse is sometimes useful to listen in on the rule entry and exit + # events as well as token matches. self is for quick and dirty debugging. + # + def setTrace(self, trace:bool): + if not trace: + self.removeParseListener(self._tracer) + self._tracer = None + else: + if self._tracer is not None: + self.removeParseListener(self._tracer) + self._tracer = TraceListener(self) + self.addParseListener(self._tracer) diff --git a/src/antlr4/ParserInterpreter.py b/src/antlr4/ParserInterpreter.py new file mode 100644 index 00000000..117f67ba --- /dev/null +++ b/src/antlr4/ParserInterpreter.py @@ -0,0 +1,165 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# A parser simulator that mimics what ANTLR's generated +# parser code does. A ParserATNSimulator is used to make +# predictions via adaptivePredict but this class moves a pointer through the +# ATN to simulate parsing. ParserATNSimulator just +# makes us efficient rather than having to backtrack, for example. +# +# This properly creates parse trees even for left recursive rules. +# +# We rely on the left recursive rule invocation and special predicate +# transitions to make left recursive rules work. +# +# See TestParserInterpreter for examples. +# +from antlr4.dfa.DFA import DFA +from antlr4.BufferedTokenStream import TokenStream +from antlr4.Lexer import Lexer +from antlr4.Parser import Parser +from antlr4.ParserRuleContext import InterpreterRuleContext, ParserRuleContext +from antlr4.Token import Token +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNState import StarLoopEntryState, ATNState, LoopEndState +from antlr4.atn.ParserATNSimulator import ParserATNSimulator +from antlr4.PredictionContext import PredictionContextCache +from antlr4.atn.Transition import Transition +from antlr4.error.Errors import RecognitionException, UnsupportedOperationException, FailedPredicateException + + +class ParserInterpreter(Parser): + + def __init__(self, grammarFileName:str, tokenNames:list, ruleNames:list, atn:ATN, input:TokenStream): + super().__init__(input) + self.grammarFileName = grammarFileName + self.atn = atn + self.tokenNames = tokenNames + self.ruleNames = ruleNames + self.decisionToDFA = [ DFA(state) for state in atn.decisionToState ] + self.sharedContextCache = PredictionContextCache() + self._parentContextStack = list() + # identify the ATN states where pushNewRecursionContext must be called + self.pushRecursionContextStates = set() + for state in atn.states: + if not isinstance(state, StarLoopEntryState): + continue + if state.isPrecedenceDecision: + self.pushRecursionContextStates.add(state.stateNumber) + # get atn simulator that knows how to do predictions + self._interp = ParserATNSimulator(self, atn, self.decisionToDFA, self.sharedContextCache) + + # Begin parsing at startRuleIndex# + def parse(self, startRuleIndex:int): + startRuleStartState = self.atn.ruleToStartState[startRuleIndex] + rootContext = InterpreterRuleContext(None, ATNState.INVALID_STATE_NUMBER, startRuleIndex) + if startRuleStartState.isPrecedenceRule: + self.enterRecursionRule(rootContext, startRuleStartState.stateNumber, startRuleIndex, 0) + else: + self.enterRule(rootContext, startRuleStartState.stateNumber, startRuleIndex) + while True: + p = self.getATNState() + if p.stateType==ATNState.RULE_STOP : + # pop; return from rule + if len(self._ctx)==0: + if startRuleStartState.isPrecedenceRule: + result = self._ctx + parentContext = self._parentContextStack.pop() + self.unrollRecursionContexts(parentContext.a) + return result + else: + self.exitRule() + return rootContext + self.visitRuleStopState(p) + + else: + try: + self.visitState(p) + except RecognitionException as e: + self.state = self.atn.ruleToStopState[p.ruleIndex].stateNumber + self._ctx.exception = e + self._errHandler.reportError(self, e) + self._errHandler.recover(self, e) + + def enterRecursionRule(self, localctx:ParserRuleContext, state:int, ruleIndex:int, precedence:int): + self._parentContextStack.append((self._ctx, localctx.invokingState)) + super().enterRecursionRule(localctx, state, ruleIndex, precedence) + + def getATNState(self): + return self.atn.states[self.state] + + def visitState(self, p:ATNState): + edge = 0 + if len(p.transitions) > 1: + self._errHandler.sync(self) + edge = self._interp.adaptivePredict(self._input, p.decision, self._ctx) + else: + edge = 1 + + transition = p.transitions[edge - 1] + tt = transition.serializationType + if tt==Transition.EPSILON: + + if self.pushRecursionContextStates[p.stateNumber] and not isinstance(transition.target, LoopEndState): + t = self._parentContextStack[-1] + ctx = InterpreterRuleContext(t[0], t[1], self._ctx.ruleIndex) + self.pushNewRecursionContext(ctx, self.atn.ruleToStartState[p.ruleIndex].stateNumber, self._ctx.ruleIndex) + + elif tt==Transition.ATOM: + + self.match(transition.label) + + elif tt in [ Transition.RANGE, Transition.SET, Transition.NOT_SET]: + + if not transition.matches(self._input.LA(1), Token.MIN_USER_TOKEN_TYPE, Lexer.MAX_CHAR_VALUE): + self._errHandler.recoverInline(self) + self.matchWildcard() + + elif tt==Transition.WILDCARD: + + self.matchWildcard() + + elif tt==Transition.RULE: + + ruleStartState = transition.target + ruleIndex = ruleStartState.ruleIndex + ctx = InterpreterRuleContext(self._ctx, p.stateNumber, ruleIndex) + if ruleStartState.isPrecedenceRule: + self.enterRecursionRule(ctx, ruleStartState.stateNumber, ruleIndex, transition.precedence) + else: + self.enterRule(ctx, transition.target.stateNumber, ruleIndex) + + elif tt==Transition.PREDICATE: + + if not self.sempred(self._ctx, transition.ruleIndex, transition.predIndex): + raise FailedPredicateException(self) + + elif tt==Transition.ACTION: + + self.action(self._ctx, transition.ruleIndex, transition.actionIndex) + + elif tt==Transition.PRECEDENCE: + + if not self.precpred(self._ctx, transition.precedence): + msg = "precpred(_ctx, " + str(transition.precedence) + ")" + raise FailedPredicateException(self, msg) + + else: + raise UnsupportedOperationException("Unrecognized ATN transition type.") + + self.state = transition.target.stateNumber + + def visitRuleStopState(self, p:ATNState): + ruleStartState = self.atn.ruleToStartState[p.ruleIndex] + if ruleStartState.isPrecedenceRule: + parentContext = self._parentContextStack.pop() + self.unrollRecursionContexts(parentContext.a) + self.state = parentContext[1] + else: + self.exitRule() + + ruleTransition = self.atn.states[self.state].transitions[0] + self.state = ruleTransition.followState.stateNumber diff --git a/src/antlr4/ParserRuleContext.py b/src/antlr4/ParserRuleContext.py new file mode 100644 index 00000000..c5049eb7 --- /dev/null +++ b/src/antlr4/ParserRuleContext.py @@ -0,0 +1,186 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. + +#* A rule invocation record for parsing. +# +# Contains all of the information about the current rule not stored in the +# RuleContext. It handles parse tree children list, Any ATN state +# tracing, and the default values available for rule indications: +# start, stop, rule index, current alt number, current +# ATN state. +# +# Subclasses made for each rule and grammar track the parameters, +# return values, locals, and labels specific to that rule. These +# are the objects that are returned from rules. +# +# Note text is not an actual field of a rule return value; it is computed +# from start and stop using the input stream's toString() method. I +# could add a ctor to this so that we can pass in and store the input +# stream, but I'm not sure we want to do that. It would seem to be undefined +# to get the .text property anyway if the rule matches tokens from multiple +# input streams. +# +# I do not use getters for fields of objects that are used simply to +# group values such as this aggregate. The getters/setters are there to +# satisfy the superclass interface. + +from antlr4.RuleContext import RuleContext +from antlr4.Token import Token +from antlr4.tree.Tree import ParseTreeListener, ParseTree, TerminalNodeImpl, ErrorNodeImpl, TerminalNode, \ + INVALID_INTERVAL + +# need forward declaration +ParserRuleContext = None + +class ParserRuleContext(RuleContext): + + def __init__(self, parent:ParserRuleContext = None, invokingStateNumber:int = None ): + super().__init__(parent, invokingStateNumber) + #* If we are debugging or building a parse tree for a visitor, + # we need to track all of the tokens and rule invocations associated + # with this rule's context. This is empty for parsing w/o tree constr. + # operation because we don't the need to track the details about + # how we parse this rule. + #/ + self.children = None + self.start = None + self.stop = None + # The exception that forced this rule to return. If the rule successfully + # completed, this is {@code null}. + self.exception = None + + #* COPY a ctx (I'm deliberately not using copy constructor)#/ + # + # This is used in the generated parser code to flip a generic XContext + # node for rule X to a YContext for alt label Y. In that sense, it is + # not really a generic copy function. + # + # If we do an error sync() at start of a rule, we might add error nodes + # to the generic XContext so this function must copy those nodes to + # the YContext as well else they are lost! + #/ + def copyFrom(self, ctx:ParserRuleContext): + # from RuleContext + self.parentCtx = ctx.parentCtx + self.invokingState = ctx.invokingState + self.children = None + self.start = ctx.start + self.stop = ctx.stop + + # copy any error nodes to alt label node + if ctx.children is not None: + self.children = [] + # reset parent pointer for any error nodes + for child in ctx.children: + if isinstance(child, ErrorNodeImpl): + self.children.append(child) + child.parentCtx = self + + # Double dispatch methods for listeners + def enterRule(self, listener:ParseTreeListener): + pass + + def exitRule(self, listener:ParseTreeListener): + pass + + #* Does not set parent link; other add methods do that#/ + def addChild(self, child:ParseTree): + if self.children is None: + self.children = [] + self.children.append(child) + return child + + #* Used by enterOuterAlt to toss out a RuleContext previously added as + # we entered a rule. If we have # label, we will need to remove + # generic ruleContext object. + #/ + def removeLastChild(self): + if self.children is not None: + del self.children[len(self.children)-1] + + def addTokenNode(self, token:Token): + node = TerminalNodeImpl(token) + self.addChild(node) + node.parentCtx = self + return node + + def addErrorNode(self, badToken:Token): + node = ErrorNodeImpl(badToken) + self.addChild(node) + node.parentCtx = self + return node + + def getChild(self, i:int, ttype:type = None): + if ttype is None: + return self.children[i] if len(self.children)>=i else None + else: + for child in self.getChildren(): + if not isinstance(child, ttype): + continue + if i==0: + return child + i -= 1 + return None + + def getChildren(self, predicate = None): + if self.children is not None: + for child in self.children: + if predicate is not None and not predicate(child): + continue + yield child + + def getToken(self, ttype:int, i:int): + for child in self.getChildren(): + if not isinstance(child, TerminalNode): + continue + if child.symbol.type != ttype: + continue + if i==0: + return child + i -= 1 + return None + + def getTokens(self, ttype:int ): + if self.getChildren() is None: + return [] + tokens = [] + for child in self.getChildren(): + if not isinstance(child, TerminalNode): + continue + if child.symbol.type != ttype: + continue + tokens.append(child) + return tokens + + def getTypedRuleContext(self, ctxType:type, i:int): + return self.getChild(i, ctxType) + + def getTypedRuleContexts(self, ctxType:type): + children = self.getChildren() + if children is None: + return [] + contexts = [] + for child in children: + if not isinstance(child, ctxType): + continue + contexts.append(child) + return contexts + + def getChildCount(self): + return len(self.children) if self.children else 0 + + def getSourceInterval(self): + if self.start is None or self.stop is None: + return INVALID_INTERVAL + else: + return (self.start.tokenIndex, self.stop.tokenIndex) + + +RuleContext.EMPTY = ParserRuleContext() + +class InterpreterRuleContext(ParserRuleContext): + + def __init__(self, parent:ParserRuleContext, invokingStateNumber:int, ruleIndex:int): + super().__init__(parent, invokingStateNumber) + self.ruleIndex = ruleIndex diff --git a/src/antlr4/PredictionContext.py b/src/antlr4/PredictionContext.py new file mode 100644 index 00000000..e3736ad2 --- /dev/null +++ b/src/antlr4/PredictionContext.py @@ -0,0 +1,623 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ +from io import StringIO + +from antlr4.error.Errors import IllegalStateException + +from antlr4.RuleContext import RuleContext +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNState import ATNState + + +class PredictionContext(object): + + # Represents {@code $} in local context prediction, which means wildcard. + # {@code#+x =#}. + #/ + EMPTY = None + + # Represents {@code $} in an array in full context mode, when {@code $} + # doesn't mean wildcard: {@code $ + x = [$,x]}. Here, + # {@code $} = {@link #EMPTY_RETURN_STATE}. + #/ + EMPTY_RETURN_STATE = 0x7FFFFFFF + + globalNodeCount = 1 + id = globalNodeCount + + # Stores the computed hash code of this {@link PredictionContext}. The hash + # code is computed in parts to match the following reference algorithm. + # + #
      +    #  private int referenceHashCode() {
      +    #      int hash = {@link MurmurHash#initialize MurmurHash.initialize}({@link #INITIAL_HASH});
      +    #
      +    #      for (int i = 0; i < {@link #size()}; i++) {
      +    #          hash = {@link MurmurHash#update MurmurHash.update}(hash, {@link #getParent getParent}(i));
      +    #      }
      +    #
      +    #      for (int i = 0; i < {@link #size()}; i++) {
      +    #          hash = {@link MurmurHash#update MurmurHash.update}(hash, {@link #getReturnState getReturnState}(i));
      +    #      }
      +    #
      +    #      hash = {@link MurmurHash#finish MurmurHash.finish}(hash, 2# {@link #size()});
      +    #      return hash;
      +    #  }
      +    # 
      + #/ + + def __init__(self, cachedHashCode:int): + self.cachedHashCode = cachedHashCode + + def __len__(self): + return 0 + + # This means only the {@link #EMPTY} context is in set. + def isEmpty(self): + return self is self.EMPTY + + def hasEmptyPath(self): + return self.getReturnState(len(self) - 1) == self.EMPTY_RETURN_STATE + + def getReturnState(self, index:int): + raise IllegalStateException("illegal!") + + def __hash__(self): + return self.cachedHashCode + +def calculateHashCode(parent:PredictionContext, returnState:int): + return hash("") if parent is None else hash((hash(parent), returnState)) + +def calculateListsHashCode(parents:[], returnStates:[] ): + h = 0 + for parent, returnState in zip(parents, returnStates): + h = hash((h, calculateHashCode(parent, returnState))) + return h + +# Used to cache {@link PredictionContext} objects. Its used for the shared +# context cash associated with contexts in DFA states. This cache +# can be used for both lexers and parsers. + +class PredictionContextCache(object): + + def __init__(self): + self.cache = dict() + + # Add a context to the cache and return it. If the context already exists, + # return that one instead and do not add a new context to the cache. + # Protect shared cache from unsafe thread access. + # + def add(self, ctx:PredictionContext): + if ctx==PredictionContext.EMPTY: + return PredictionContext.EMPTY + existing = self.cache.get(ctx, None) + if existing is not None: + return existing + self.cache[ctx] = ctx + return ctx + + def get(self, ctx:PredictionContext): + return self.cache.get(ctx, None) + + def __len__(self): + return len(self.cache) + + +class SingletonPredictionContext(PredictionContext): + + @staticmethod + def create(parent:PredictionContext , returnState:int ): + if returnState == PredictionContext.EMPTY_RETURN_STATE and parent is None: + # someone can pass in the bits of an array ctx that mean $ + return SingletonPredictionContext.EMPTY + else: + return SingletonPredictionContext(parent, returnState) + + def __init__(self, parent:PredictionContext, returnState:int): + hashCode = calculateHashCode(parent, returnState) + super().__init__(hashCode) + self.parentCtx = parent + self.returnState = returnState + + def __len__(self): + return 1 + + def getParent(self, index:int): + return self.parentCtx + + def getReturnState(self, index:int): + return self.returnState + + def __eq__(self, other): + if self is other: + return True + elif other is None: + return False + elif not isinstance(other, SingletonPredictionContext): + return False + else: + return self.returnState == other.returnState and self.parentCtx == other.parentCtx + + def __hash__(self): + return self.cachedHashCode + + def __str__(self): + up = "" if self.parentCtx is None else str(self.parentCtx) + if len(up)==0: + if self.returnState == self.EMPTY_RETURN_STATE: + return "$" + else: + return str(self.returnState) + else: + return str(self.returnState) + " " + up + + +class EmptyPredictionContext(SingletonPredictionContext): + + def __init__(self): + super().__init__(None, self.EMPTY_RETURN_STATE) + + def isEmpty(self): + return True + + def __eq__(self, other): + return self is other + + def __hash__(self): + return self.cachedHashCode + + def __str__(self): + return "$" + + +PredictionContext.EMPTY = EmptyPredictionContext() + +class ArrayPredictionContext(PredictionContext): + # Parent can be null only if full ctx mode and we make an array + # from {@link #EMPTY} and non-empty. We merge {@link #EMPTY} by using null parent and + # returnState == {@link #EMPTY_RETURN_STATE}. + + def __init__(self, parents:list, returnStates:list): + super().__init__(calculateListsHashCode(parents, returnStates)) + self.parents = parents + self.returnStates = returnStates + + def isEmpty(self): + # since EMPTY_RETURN_STATE can only appear in the last position, we + # don't need to verify that size==1 + return self.returnStates[0]==PredictionContext.EMPTY_RETURN_STATE + + def __len__(self): + return len(self.returnStates) + + def getParent(self, index:int): + return self.parents[index] + + def getReturnState(self, index:int): + return self.returnStates[index] + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, ArrayPredictionContext): + return False + elif hash(self) != hash(other): + return False # can't be same if hash is different + else: + return self.returnStates==other.returnStates and self.parents==other.parents + + def __str__(self): + if self.isEmpty(): + return "[]" + with StringIO() as buf: + buf.write("[") + for i in range(0,len(self.returnStates)): + if i>0: + buf.write(", ") + if self.returnStates[i]==PredictionContext.EMPTY_RETURN_STATE: + buf.write("$") + continue + buf.write(str(self.returnStates[i])) + if self.parents[i] is not None: + buf.write(' ') + buf.write(str(self.parents[i])) + else: + buf.write("null") + buf.write("]") + return buf.getvalue() + + def __hash__(self): + return self.cachedHashCode + + + +# Convert a {@link RuleContext} tree to a {@link PredictionContext} graph. +# Return {@link #EMPTY} if {@code outerContext} is empty or null. +#/ +def PredictionContextFromRuleContext(atn:ATN, outerContext:RuleContext=None): + if outerContext is None: + outerContext = RuleContext.EMPTY + + # if we are in RuleContext of start rule, s, then PredictionContext + # is EMPTY. Nobody called us. (if we are empty, return empty) + if outerContext.parentCtx is None or outerContext is RuleContext.EMPTY: + return PredictionContext.EMPTY + + # If we have a parent, convert it to a PredictionContext graph + parent = PredictionContextFromRuleContext(atn, outerContext.parentCtx) + state = atn.states[outerContext.invokingState] + transition = state.transitions[0] + return SingletonPredictionContext.create(parent, transition.followState.stateNumber) + + +def merge(a:PredictionContext, b:PredictionContext, rootIsWildcard:bool, mergeCache:dict): + + # share same graph if both same + if a==b: + return a + + if isinstance(a, SingletonPredictionContext) and isinstance(b, SingletonPredictionContext): + return mergeSingletons(a, b, rootIsWildcard, mergeCache) + + # At least one of a or b is array + # If one is $ and rootIsWildcard, return $ as# wildcard + if rootIsWildcard: + if isinstance( a, EmptyPredictionContext ): + return a + if isinstance( b, EmptyPredictionContext ): + return b + + # convert singleton so both are arrays to normalize + if isinstance( a, SingletonPredictionContext ): + a = ArrayPredictionContext([a.parentCtx], [a.returnState]) + if isinstance( b, SingletonPredictionContext): + b = ArrayPredictionContext([b.parentCtx], [b.returnState]) + return mergeArrays(a, b, rootIsWildcard, mergeCache) + + +# +# Merge two {@link SingletonPredictionContext} instances. +# +#

      Stack tops equal, parents merge is same; return left graph.
      +#

      +# +#

      Same stack top, parents differ; merge parents giving array node, then +# remainders of those graphs. A new root node is created to point to the +# merged parents.
      +#

      +# +#

      Different stack tops pointing to same parent. Make array node for the +# root where both element in the root point to the same (original) +# parent.
      +#

      +# +#

      Different stack tops pointing to different parents. Make array node for +# the root where each element points to the corresponding original +# parent.
      +#

      +# +# @param a the first {@link SingletonPredictionContext} +# @param b the second {@link SingletonPredictionContext} +# @param rootIsWildcard {@code true} if this is a local-context merge, +# otherwise false to indicate a full-context merge +# @param mergeCache +#/ +def mergeSingletons(a:SingletonPredictionContext, b:SingletonPredictionContext, rootIsWildcard:bool, mergeCache:dict): + if mergeCache is not None: + previous = mergeCache.get((a,b), None) + if previous is not None: + return previous + previous = mergeCache.get((b,a), None) + if previous is not None: + return previous + + merged = mergeRoot(a, b, rootIsWildcard) + if merged is not None: + if mergeCache is not None: + mergeCache[(a, b)] = merged + return merged + + if a.returnState==b.returnState: + parent = merge(a.parentCtx, b.parentCtx, rootIsWildcard, mergeCache) + # if parent is same as existing a or b parent or reduced to a parent, return it + if parent == a.parentCtx: + return a # ax + bx = ax, if a=b + if parent == b.parentCtx: + return b # ax + bx = bx, if a=b + # else: ax + ay = a'[x,y] + # merge parents x and y, giving array node with x,y then remainders + # of those graphs. dup a, a' points at merged array + # new joined parent so create new singleton pointing to it, a' + merged = SingletonPredictionContext.create(parent, a.returnState) + if mergeCache is not None: + mergeCache[(a, b)] = merged + return merged + else: # a != b payloads differ + # see if we can collapse parents due to $+x parents if local ctx + singleParent = None + if a is b or (a.parentCtx is not None and a.parentCtx==b.parentCtx): # ax + bx = [a,b]x + singleParent = a.parentCtx + if singleParent is not None: # parents are same + # sort payloads and use same parent + payloads = [ a.returnState, b.returnState ] + if a.returnState > b.returnState: + payloads = [ b.returnState, a.returnState ] + parents = [singleParent, singleParent] + merged = ArrayPredictionContext(parents, payloads) + if mergeCache is not None: + mergeCache[(a, b)] = merged + return merged + # parents differ and can't merge them. Just pack together + # into array; can't merge. + # ax + by = [ax,by] + payloads = [ a.returnState, b.returnState ] + parents = [ a.parentCtx, b.parentCtx ] + if a.returnState > b.returnState: # sort by payload + payloads = [ b.returnState, a.returnState ] + parents = [ b.parentCtx, a.parentCtx ] + merged = ArrayPredictionContext(parents, payloads) + if mergeCache is not None: + mergeCache[(a, b)] = merged + return merged + + +# +# Handle case where at least one of {@code a} or {@code b} is +# {@link #EMPTY}. In the following diagrams, the symbol {@code $} is used +# to represent {@link #EMPTY}. +# +#

      Local-Context Merges

      +# +#

      These local-context merge operations are used when {@code rootIsWildcard} +# is true.

      +# +#

      {@link #EMPTY} is superset of any graph; return {@link #EMPTY}.
      +#

      +# +#

      {@link #EMPTY} and anything is {@code #EMPTY}, so merged parent is +# {@code #EMPTY}; return left graph.
      +#

      +# +#

      Special case of last merge if local context.
      +#

      +# +#

      Full-Context Merges

      +# +#

      These full-context merge operations are used when {@code rootIsWildcard} +# is false.

      +# +#

      +# +#

      Must keep all contexts; {@link #EMPTY} in array is a special value (and +# null parent).
      +#

      +# +#

      +# +# @param a the first {@link SingletonPredictionContext} +# @param b the second {@link SingletonPredictionContext} +# @param rootIsWildcard {@code true} if this is a local-context merge, +# otherwise false to indicate a full-context merge +#/ +def mergeRoot(a:SingletonPredictionContext, b:SingletonPredictionContext, rootIsWildcard:bool): + if rootIsWildcard: + if a == PredictionContext.EMPTY: + return PredictionContext.EMPTY ## + b =# + if b == PredictionContext.EMPTY: + return PredictionContext.EMPTY # a +# =# + else: + if a == PredictionContext.EMPTY and b == PredictionContext.EMPTY: + return PredictionContext.EMPTY # $ + $ = $ + elif a == PredictionContext.EMPTY: # $ + x = [$,x] + payloads = [ b.returnState, PredictionContext.EMPTY_RETURN_STATE ] + parents = [ b.parentCtx, None ] + return ArrayPredictionContext(parents, payloads) + elif b == PredictionContext.EMPTY: # x + $ = [$,x] ($ is always first if present) + payloads = [ a.returnState, PredictionContext.EMPTY_RETURN_STATE ] + parents = [ a.parentCtx, None ] + return ArrayPredictionContext(parents, payloads) + return None + + +# +# Merge two {@link ArrayPredictionContext} instances. +# +#

      Different tops, different parents.
      +#

      +# +#

      Shared top, same parents.
      +#

      +# +#

      Shared top, different parents.
      +#

      +# +#

      Shared top, all shared parents.
      +#

      +# +#

      Equal tops, merge parents and reduce top to +# {@link SingletonPredictionContext}.
      +#

      +#/ +def mergeArrays(a:ArrayPredictionContext, b:ArrayPredictionContext, rootIsWildcard:bool, mergeCache:dict): + if mergeCache is not None: + previous = mergeCache.get((a,b), None) + if previous is not None: + return previous + previous = mergeCache.get((b,a), None) + if previous is not None: + return previous + + # merge sorted payloads a + b => M + i = 0 # walks a + j = 0 # walks b + k = 0 # walks target M array + + mergedReturnStates = [None] * (len(a.returnStates) + len( b.returnStates)) + mergedParents = [None] * len(mergedReturnStates) + # walk and merge to yield mergedParents, mergedReturnStates + while i ax + if bothDollars or ax_ax: + mergedParents[k] = a_parent # choose left + mergedReturnStates[k] = payload + else: # ax+ay -> a'[x,y] + mergedParent = merge(a_parent, b_parent, rootIsWildcard, mergeCache) + mergedParents[k] = mergedParent + mergedReturnStates[k] = payload + i += 1 # hop over left one as usual + j += 1 # but also skip one in right side since we merge + elif a.returnStates[i] a, copy b[j] to M + mergedParents[k] = b_parent + mergedReturnStates[k] = b.returnStates[j] + j += 1 + k += 1 + + # copy over any payloads remaining in either array + if i < len(a.returnStates): + for p in range(i, len(a.returnStates)): + mergedParents[k] = a.parents[p] + mergedReturnStates[k] = a.returnStates[p] + k += 1 + else: + for p in range(j, len(b.returnStates)): + mergedParents[k] = b.parents[p] + mergedReturnStates[k] = b.returnStates[p] + k += 1 + + # trim merged if we combined a few that had same stack tops + if k < len(mergedParents): # write index < last position; trim + if k == 1: # for just one merged element, return singleton top + merged = SingletonPredictionContext.create(mergedParents[0], mergedReturnStates[0]) + if mergeCache is not None: + mergeCache[(a,b)] = merged + return merged + mergedParents = mergedParents[0:k] + mergedReturnStates = mergedReturnStates[0:k] + + merged = ArrayPredictionContext(mergedParents, mergedReturnStates) + + # if we created same array as a or b, return that instead + # TODO: track whether this is possible above during merge sort for speed + if merged==a: + if mergeCache is not None: + mergeCache[(a,b)] = a + return a + if merged==b: + if mergeCache is not None: + mergeCache[(a,b)] = b + return b + combineCommonParents(mergedParents) + + if mergeCache is not None: + mergeCache[(a,b)] = merged + return merged + + +# +# Make pass over all M {@code parents}; merge any {@code equals()} +# ones. +#/ +def combineCommonParents(parents:list): + uniqueParents = dict() + + for p in range(0, len(parents)): + parent = parents[p] + if uniqueParents.get(parent, None) is None: + uniqueParents[parent] = parent + + for p in range(0, len(parents)): + parents[p] = uniqueParents[parents[p]] + +def getCachedPredictionContext(context:PredictionContext, contextCache:PredictionContextCache, visited:dict): + if context.isEmpty(): + return context + existing = visited.get(context) + if existing is not None: + return existing + existing = contextCache.get(context) + if existing is not None: + visited[context] = existing + return existing + changed = False + parents = [None] * len(context) + for i in range(0, len(parents)): + parent = getCachedPredictionContext(context.getParent(i), contextCache, visited) + if changed or parent is not context.getParent(i): + if not changed: + parents = [context.getParent(j) for j in range(len(context))] + changed = True + parents[i] = parent + if not changed: + contextCache.add(context) + visited[context] = context + return context + + updated = None + if len(parents) == 0: + updated = PredictionContext.EMPTY + elif len(parents) == 1: + updated = SingletonPredictionContext.create(parents[0], context.getReturnState(0)) + else: + updated = ArrayPredictionContext(parents, context.returnStates) + + contextCache.add(updated) + visited[updated] = updated + visited[context] = updated + + return updated + + +# # extra structures, but cut/paste/morphed works, so leave it. +# # seems to do a breadth-first walk +# public static List getAllNodes(PredictionContext context) { +# Map visited = +# new IdentityHashMap(); +# Deque workList = new ArrayDeque(); +# workList.add(context); +# visited.put(context, context); +# List nodes = new ArrayList(); +# while (!workList.isEmpty()) { +# PredictionContext current = workList.pop(); +# nodes.add(current); +# for (int i = 0; i < current.size(); i++) { +# PredictionContext parent = current.getParent(i); +# if ( parent!=null && visited.put(parent, parent) == null) { +# workList.push(parent); +# } +# } +# } +# return nodes; +# } + +# ter's recursive version of Sam's getAllNodes() +def getAllContextNodes(context:PredictionContext, nodes:list=None, visited:dict=None): + if nodes is None: + nodes = list() + return getAllContextNodes(context, nodes, visited) + elif visited is None: + visited = dict() + return getAllContextNodes(context, nodes, visited) + else: + if context is None or visited.get(context, None) is not None: + return nodes + visited.put(context, context) + nodes.add(context) + for i in range(0, len(context)): + getAllContextNodes(context.getParent(i), nodes, visited) + return nodes + diff --git a/src/antlr4/Recognizer.py b/src/antlr4/Recognizer.py new file mode 100644 index 00000000..01017351 --- /dev/null +++ b/src/antlr4/Recognizer.py @@ -0,0 +1,160 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# +from antlr4.RuleContext import RuleContext +from antlr4.Token import Token +from antlr4.error.ErrorListener import ProxyErrorListener, ConsoleErrorListener + +# need forward delcaration +RecognitionException = None + +class Recognizer(object): + + tokenTypeMapCache = dict() + ruleIndexMapCache = dict() + + def __init__(self): + self._listeners = [ ConsoleErrorListener.INSTANCE ] + self._interp = None + self._stateNumber = -1 + + def extractVersion(self, version): + pos = version.find(".") + major = version[0:pos] + version = version[pos+1:] + pos = version.find(".") + if pos==-1: + pos = version.find("-") + if pos==-1: + pos = len(version) + minor = version[0:pos] + return major, minor + + def checkVersion(self, toolVersion): + runtimeVersion = "4.7.2" + rvmajor, rvminor = self.extractVersion(runtimeVersion) + tvmajor, tvminor = self.extractVersion(toolVersion) + if rvmajor!=tvmajor or rvminor!=tvminor: + print("ANTLR runtime and generated code versions disagree: "+runtimeVersion+"!="+toolVersion) + + def addErrorListener(self, listener): + self._listeners.append(listener) + + def removeErrorListener(self, listener): + self._listeners.remove(listener) + + def removeErrorListeners(self): + self._listeners = [] + + def getTokenTypeMap(self): + tokenNames = self.getTokenNames() + if tokenNames is None: + from antlr4.error.Errors import UnsupportedOperationException + raise UnsupportedOperationException("The current recognizer does not provide a list of token names.") + result = self.tokenTypeMapCache.get(tokenNames, None) + if result is None: + result = zip( tokenNames, range(0, len(tokenNames))) + result["EOF"] = Token.EOF + self.tokenTypeMapCache[tokenNames] = result + return result + + # Get a map from rule names to rule indexes. + # + #

      Used for XPath and tree pattern compilation.

      + # + def getRuleIndexMap(self): + ruleNames = self.getRuleNames() + if ruleNames is None: + from antlr4.error.Errors import UnsupportedOperationException + raise UnsupportedOperationException("The current recognizer does not provide a list of rule names.") + result = self.ruleIndexMapCache.get(ruleNames, None) + if result is None: + result = zip( ruleNames, range(0, len(ruleNames))) + self.ruleIndexMapCache[ruleNames] = result + return result + + def getTokenType(self, tokenName:str): + ttype = self.getTokenTypeMap().get(tokenName, None) + if ttype is not None: + return ttype + else: + return Token.INVALID_TYPE + + + # What is the error header, normally line/character position information?# + def getErrorHeader(self, e:RecognitionException): + line = e.getOffendingToken().line + column = e.getOffendingToken().column + return "line "+line+":"+column + + + # How should a token be displayed in an error message? The default + # is to display just the text, but during development you might + # want to have a lot of information spit out. Override in that case + # to use t.toString() (which, for CommonToken, dumps everything about + # the token). This is better than forcing you to override a method in + # your token objects because you don't have to go modify your lexer + # so that it creates a new Java type. + # + # @deprecated This method is not called by the ANTLR 4 Runtime. Specific + # implementations of {@link ANTLRErrorStrategy} may provide a similar + # feature when necessary. For example, see + # {@link DefaultErrorStrategy#getTokenErrorDisplay}. + # + def getTokenErrorDisplay(self, t:Token): + if t is None: + return "" + s = t.text + if s is None: + if t.type==Token.EOF: + s = "" + else: + s = "<" + str(t.type) + ">" + s = s.replace("\n","\\n") + s = s.replace("\r","\\r") + s = s.replace("\t","\\t") + return "'" + s + "'" + + def getErrorListenerDispatch(self): + return ProxyErrorListener(self._listeners) + + # subclass needs to override these if there are sempreds or actions + # that the ATN interp needs to execute + def sempred(self, localctx:RuleContext, ruleIndex:int, actionIndex:int): + return True + + def precpred(self, localctx:RuleContext , precedence:int): + return True + + @property + def state(self): + return self._stateNumber + + # Indicate that the recognizer has changed internal state that is + # consistent with the ATN state passed in. This way we always know + # where we are in the ATN as the parser goes along. The rule + # context objects form a stack that lets us see the stack of + # invoking rules. Combine this and we have complete ATN + # configuration information. + + @state.setter + def state(self, atnState:int): + self._stateNumber = atnState + +del RecognitionException + +import unittest +class Test(unittest.TestCase): + + def testVersion(self): + major, minor = Recognizer().extractVersion("1.2") + self.assertEqual("1", major) + self.assertEqual("2", minor) + major, minor = Recognizer().extractVersion("1.2.3") + self.assertEqual("1", major) + self.assertEqual("2", minor) + major, minor = Recognizer().extractVersion("1.2-snapshot") + self.assertEqual("1", major) + self.assertEqual("2", minor) diff --git a/src/antlr4/RuleContext.py b/src/antlr4/RuleContext.py new file mode 100644 index 00000000..7f6dd914 --- /dev/null +++ b/src/antlr4/RuleContext.py @@ -0,0 +1,228 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + + +# A rule context is a record of a single rule invocation. It knows +# which context invoked it, if any. If there is no parent context, then +# naturally the invoking state is not valid. The parent link +# provides a chain upwards from the current rule invocation to the root +# of the invocation tree, forming a stack. We actually carry no +# information about the rule associated with this context (except +# when parsing). We keep only the state number of the invoking state from +# the ATN submachine that invoked this. Contrast this with the s +# pointer inside ParserRuleContext that tracks the current state +# being "executed" for the current rule. +# +# The parent contexts are useful for computing lookahead sets and +# getting error information. +# +# These objects are used during parsing and prediction. +# For the special case of parsers, we use the subclass +# ParserRuleContext. +# +# @see ParserRuleContext +#/ +from io import StringIO +from antlr4.tree.Tree import RuleNode, INVALID_INTERVAL, ParseTreeVisitor +from antlr4.tree.Trees import Trees + +# need forward declarations +RuleContext = None +Parser = None + +class RuleContext(RuleNode): + + EMPTY = None + + def __init__(self, parent:RuleContext=None, invokingState:int=-1): + super().__init__() + # What context invoked this rule? + self.parentCtx = parent + # What state invoked the rule associated with this context? + # The "return address" is the followState of invokingState + # If parent is null, this should be -1. + self.invokingState = invokingState + + + def depth(self): + n = 0 + p = self + while p is not None: + p = p.parentCtx + n += 1 + return n + + # A context is empty if there is no invoking state; meaning nobody call + # current context. + def isEmpty(self): + return self.invokingState == -1 + + # satisfy the ParseTree / SyntaxTree interface + + def getSourceInterval(self): + return INVALID_INTERVAL + + def getRuleContext(self): + return self + + def getPayload(self): + return self + + # Return the combined text of all child nodes. This method only considers + # tokens which have been added to the parse tree. + #

      + # Since tokens on hidden channels (e.g. whitespace or comments) are not + # added to the parse trees, they will not appear in the output of this + # method. + #/ + def getText(self): + if self.getChildCount() == 0: + return "" + with StringIO() as builder: + for child in self.getChildren(): + builder.write(child.getText()) + return builder.getvalue() + + def getRuleIndex(self): + return -1 + + # For rule associated with this parse tree internal node, return + # the outer alternative number used to match the input. Default + # implementation does not compute nor store this alt num. Create + # a subclass of ParserRuleContext with backing field and set + # option contextSuperClass. + # to set it. + def getAltNumber(self): + return 0 # should use ATN.INVALID_ALT_NUMBER but won't compile + + # Set the outer alternative number for this context node. Default + # implementation does nothing to avoid backing field overhead for + # trees that don't need it. Create + # a subclass of ParserRuleContext with backing field and set + # option contextSuperClass. + def setAltNumber(self, altNumber:int): + pass + + def getChild(self, i:int): + return None + + def getChildCount(self): + return 0 + + def getChildren(self): + for c in []: + yield c + + def accept(self, visitor:ParseTreeVisitor): + return visitor.visitChildren(self) + + # # Call this method to view a parse tree in a dialog box visually.#/ + # public Future inspect(@Nullable Parser parser) { + # List ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null; + # return inspect(ruleNames); + # } + # + # public Future inspect(@Nullable List ruleNames) { + # TreeViewer viewer = new TreeViewer(ruleNames, this); + # return viewer.open(); + # } + # + # # Save this tree in a postscript file#/ + # public void save(@Nullable Parser parser, String fileName) + # throws IOException, PrintException + # { + # List ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null; + # save(ruleNames, fileName); + # } + # + # # Save this tree in a postscript file using a particular font name and size#/ + # public void save(@Nullable Parser parser, String fileName, + # String fontName, int fontSize) + # throws IOException + # { + # List ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null; + # save(ruleNames, fileName, fontName, fontSize); + # } + # + # # Save this tree in a postscript file#/ + # public void save(@Nullable List ruleNames, String fileName) + # throws IOException, PrintException + # { + # Trees.writePS(this, ruleNames, fileName); + # } + # + # # Save this tree in a postscript file using a particular font name and size#/ + # public void save(@Nullable List ruleNames, String fileName, + # String fontName, int fontSize) + # throws IOException + # { + # Trees.writePS(this, ruleNames, fileName, fontName, fontSize); + # } + # + # # Print out a whole tree, not just a node, in LISP format + # # (root child1 .. childN). Print just a node if this is a leaf. + # # We have to know the recognizer so we can get rule names. + # #/ + # @Override + # public String toStringTree(@Nullable Parser recog) { + # return Trees.toStringTree(this, recog); + # } + # + # Print out a whole tree, not just a node, in LISP format + # (root child1 .. childN). Print just a node if this is a leaf. + # + def toStringTree(self, ruleNames:list=None, recog:Parser=None): + return Trees.toStringTree(self, ruleNames=ruleNames, recog=recog) + # } + # + # @Override + # public String toStringTree() { + # return toStringTree((List)null); + # } + # + def __str__(self): + return self.toString(None, None) + + # @Override + # public String toString() { + # return toString((List)null, (RuleContext)null); + # } + # + # public final String toString(@Nullable Recognizer recog) { + # return toString(recog, ParserRuleContext.EMPTY); + # } + # + # public final String toString(@Nullable List ruleNames) { + # return toString(ruleNames, null); + # } + # + # // recog null unless ParserRuleContext, in which case we use subclass toString(...) + # public String toString(@Nullable Recognizer recog, @Nullable RuleContext stop) { + # String[] ruleNames = recog != null ? recog.getRuleNames() : null; + # List ruleNamesList = ruleNames != null ? Arrays.asList(ruleNames) : null; + # return toString(ruleNamesList, stop); + # } + + def toString(self, ruleNames:list, stop:RuleContext)->str: + with StringIO() as buf: + p = self + buf.write("[") + while p is not None and p is not stop: + if ruleNames is None: + if not p.isEmpty(): + buf.write(str(p.invokingState)) + else: + ri = p.getRuleIndex() + ruleName = ruleNames[ri] if ri >= 0 and ri < len(ruleNames) else str(ri) + buf.write(ruleName) + + if p.parentCtx is not None and (ruleNames is not None or not p.parentCtx.isEmpty()): + buf.write(" ") + + p = p.parentCtx + + buf.write("]") + return buf.getvalue() + diff --git a/src/antlr4/StdinStream.py b/src/antlr4/StdinStream.py new file mode 100644 index 00000000..f044fc4d --- /dev/null +++ b/src/antlr4/StdinStream.py @@ -0,0 +1,11 @@ +import codecs +import sys + +from antlr4.InputStream import InputStream + + +class StdinStream(InputStream): + def __init__(self, encoding:str='ascii', errors:str='strict') -> None: + bytes = sys.stdin.buffer.read() + data = codecs.decode(bytes, encoding, errors) + super().__init__(data) diff --git a/src/antlr4/Token.py b/src/antlr4/Token.py new file mode 100644 index 00000000..6f4d5e26 --- /dev/null +++ b/src/antlr4/Token.py @@ -0,0 +1,155 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# A token has properties: text, type, line, character position in the line +# (so we can ignore tabs), token channel, index, and source from which +# we obtained this token. +from io import StringIO + + +class Token (object): + + INVALID_TYPE = 0 + + # During lookahead operations, this "token" signifies we hit rule end ATN state + # and did not follow it despite needing to. + EPSILON = -2 + + MIN_USER_TOKEN_TYPE = 1 + + EOF = -1 + + # All tokens go to the parser (unless skip() is called in that rule) + # on a particular "channel". The parser tunes to a particular channel + # so that whitespace etc... can go to the parser on a "hidden" channel. + + DEFAULT_CHANNEL = 0 + + # Anything on different channel than DEFAULT_CHANNEL is not parsed + # by parser. + + HIDDEN_CHANNEL = 1 + + def __init__(self): + self.source = None + self.type = None # token type of the token + self.channel = None # The parser ignores everything not on DEFAULT_CHANNEL + self.start = None # optional; return -1 if not implemented. + self.stop = None # optional; return -1 if not implemented. + self.tokenIndex = None # from 0..n-1 of the token object in the input stream + self.line = None # line=1..n of the 1st character + self.column = None # beginning of the line at which it occurs, 0..n-1 + self._text = None # text of the token. + + @property + def text(self): + return self._text + + # Explicitly set the text for this token. If {code text} is not + # {@code null}, then {@link #getText} will return this value rather than + # extracting the text from the input. + # + # @param text The explicit text of the token, or {@code null} if the text + # should be obtained from the input along with the start and stop indexes + # of the token. + + @text.setter + def text(self, text:str): + self._text = text + + + def getTokenSource(self): + return self.source[0] + + def getInputStream(self): + return self.source[1] + +class CommonToken(Token): + + + # An empty {@link Pair} which is used as the default value of + # {@link #source} for tokens that do not have a source. + EMPTY_SOURCE = (None, None) + + def __init__(self, source:tuple = EMPTY_SOURCE, type:int = None, channel:int=Token.DEFAULT_CHANNEL, start:int=-1, stop:int=-1): + super().__init__() + self.source = source + self.type = type + self.channel = channel + self.start = start + self.stop = stop + self.tokenIndex = -1 + if source[0] is not None: + self.line = source[0].line + self.column = source[0].column + else: + self.column = -1 + + # Constructs a new {@link CommonToken} as a copy of another {@link Token}. + # + #

      + # If {@code oldToken} is also a {@link CommonToken} instance, the newly + # constructed token will share a reference to the {@link #text} field and + # the {@link Pair} stored in {@link #source}. Otherwise, {@link #text} will + # be assigned the result of calling {@link #getText}, and {@link #source} + # will be constructed from the result of {@link Token#getTokenSource} and + # {@link Token#getInputStream}.

      + # + # @param oldToken The token to copy. + # + def clone(self): + t = CommonToken(self.source, self.type, self.channel, self.start, self.stop) + t.tokenIndex = self.tokenIndex + t.line = self.line + t.column = self.column + t.text = self.text + return t + + @property + def text(self): + if self._text is not None: + return self._text + input = self.getInputStream() + if input is None: + return None + n = input.size + if self.start < n and self.stop < n: + return input.getText(self.start, self.stop) + else: + return "" + + @text.setter + def text(self, text:str): + self._text = text + + def __str__(self): + with StringIO() as buf: + buf.write("[@") + buf.write(str(self.tokenIndex)) + buf.write(",") + buf.write(str(self.start)) + buf.write(":") + buf.write(str(self.stop)) + buf.write("='") + txt = self.text + if txt is not None: + txt = txt.replace("\n","\\n") + txt = txt.replace("\r","\\r") + txt = txt.replace("\t","\\t") + else: + txt = "" + buf.write(txt) + buf.write("',<") + buf.write(str(self.type)) + buf.write(">") + if self.channel > 0: + buf.write(",channel=") + buf.write(str(self.channel)) + buf.write(",") + buf.write(str(self.line)) + buf.write(":") + buf.write(str(self.column)) + buf.write("]") + return buf.getvalue() diff --git a/src/antlr4/TokenStreamRewriter.py b/src/antlr4/TokenStreamRewriter.py new file mode 100644 index 00000000..617fe620 --- /dev/null +++ b/src/antlr4/TokenStreamRewriter.py @@ -0,0 +1,237 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +from io import StringIO +from antlr4.Token import Token + +from antlr4.CommonTokenStream import CommonTokenStream + + +class TokenStreamRewriter(object): + DEFAULT_PROGRAM_NAME = "default" + PROGRAM_INIT_SIZE = 100 + MIN_TOKEN_INDEX = 0 + + def __init__(self, tokens): + """ + :type tokens: antlr4.BufferedTokenStream.BufferedTokenStream + :param tokens: + :return: + """ + super(TokenStreamRewriter, self).__init__() + self.tokens = tokens + self.programs = {self.DEFAULT_PROGRAM_NAME: []} + self.lastRewriteTokenIndexes = {} + + def getTokenStream(self): + return self.tokens + + def rollback(self, instruction_index, program_name): + ins = self.programs.get(program_name, None) + if ins: + self.programs[program_name] = ins[self.MIN_TOKEN_INDEX: instruction_index] + + def deleteProgram(self, program_name=DEFAULT_PROGRAM_NAME): + self.rollback(self.MIN_TOKEN_INDEX, program_name) + + def insertAfterToken(self, token, text, program_name=DEFAULT_PROGRAM_NAME): + self.insertAfter(token.tokenIndex, text, program_name) + + def insertAfter(self, index, text, program_name=DEFAULT_PROGRAM_NAME): + self.insertBefore(program_name, index + 1, text) + + def insertBeforeIndex(self, index, text): + self.insertBefore(self.DEFAULT_PROGRAM_NAME, index, text) + + def insertBeforeToken(self, token, text, program_name=DEFAULT_PROGRAM_NAME): + self.insertBefore(program_name, token.tokenIndex, text) + + def insertBefore(self, program_name, index, text): + op = self.InsertBeforeOp(self.tokens, index, text) + rewrites = self.getProgram(program_name) + op.instructionIndex = len(rewrites) + rewrites.append(op) + + def replaceIndex(self, index, text): + self.replace(self.DEFAULT_PROGRAM_NAME, index, index, text) + + def replaceRange(self, from_idx, to_idx, text): + self.replace(self.DEFAULT_PROGRAM_NAME, from_idx, to_idx, text) + + def replaceSingleToken(self, token, text): + self.replace(self.DEFAULT_PROGRAM_NAME, token.tokenIndex, token.tokenIndex, text) + + def replaceRangeTokens(self, from_token, to_token, text, program_name=DEFAULT_PROGRAM_NAME): + self.replace(program_name, from_token.tokenIndex, to_token.tokenIndex, text) + + def replace(self, program_name, from_idx, to_idx, text): + if any((from_idx > to_idx, from_idx < 0, to_idx < 0, to_idx >= len(self.tokens.tokens))): + raise ValueError( + 'replace: range invalid: {}..{}(size={})'.format(from_idx, to_idx, len(self.tokens.tokens))) + op = self.ReplaceOp(from_idx, to_idx, self.tokens, text) + rewrites = self.getProgram(program_name) + op.instructionIndex = len(rewrites) + rewrites.append(op) + + def deleteToken(self, token): + self.delete(self.DEFAULT_PROGRAM_NAME, token, token) + + def deleteIndex(self, index): + self.delete(self.DEFAULT_PROGRAM_NAME, index, index) + + def delete(self, program_name, from_idx, to_idx): + if isinstance(from_idx, Token): + self.replace(program_name, from_idx.tokenIndex, to_idx.tokenIndex, None) + self.replace(program_name, from_idx, to_idx, None) + + def lastRewriteTokenIndex(self, program_name=DEFAULT_PROGRAM_NAME): + return self.lastRewriteTokenIndexes.get(program_name, -1) + + def setLastRewriteTokenIndex(self, program_name, i): + self.lastRewriteTokenIndexes[program_name] = i + + def getProgram(self, program_name): + return self.programs.setdefault(program_name, []) + + def getText(self, program_name, interval): + """ + :type interval: Interval.Interval + :param program_name: + :param interval: + :return: + """ + rewrites = self.programs.get(program_name) + start = interval.start + stop = interval.stop + + # ensure start/end are in range + if stop > len(self.tokens.tokens) - 1: stop = len(self.tokens.tokens) - 1 + if start < 0: start = 0 + + # if no instructions to execute + if not rewrites: return self.tokens.getText(interval) + buf = StringIO() + indexToOp = self._reduceToSingleOperationPerIndex(rewrites) + i = start + while all((i <= stop, i < len(self.tokens.tokens))): + op = indexToOp.get(i) + token = self.tokens.get(i) + if op is None: + if token.type != Token.EOF: buf.write(token.text) + i += 1 + else: + i = op.execute(buf) + + if stop == len(self.tokens.tokens)-1: + for op in indexToOp.values(): + if op.index >= len(self.tokens.tokens)-1: buf.write(op.text) + + return buf.getvalue() + + def _reduceToSingleOperationPerIndex(self, rewrites): + # Walk replaces + for i, rop in enumerate(rewrites): + if any((rop is None, not isinstance(rop, TokenStreamRewriter.ReplaceOp))): + continue + # Wipe prior inserts within range + inserts = [op for op in rewrites[:i] if isinstance(rop, TokenStreamRewriter.InsertBeforeOp)] + for iop in inserts: + if iop.index == rop.index: + rewrites[iop.instructionIndex] = None + rop.text = '{}{}'.format(iop.text, rop.text) + elif all((iop.index > rop.index, iop.index <= rop.last_index)): + rewrites[iop.instructionIndex] = None + + # Drop any prior replaces contained within + prevReplaces = [op for op in rewrites[:i] if isinstance(op, TokenStreamRewriter.ReplaceOp)] + for prevRop in prevReplaces: + if all((prevRop.index >= rop.index, prevRop.last_index <= rop.last_index)): + rewrites[prevRop.instructioIndex] = None + continue + isDisjoint = any((prevRop.last_indexrop)) + isSame = all((prevRop.index == rop.index, prevRop.last_index == rop.last_index)) + if all((prevRop.text is None, rop.text is None, not isDisjoint)): + rewrites[prevRop.instructioIndex] = None + rop.index = min(prevRop.index, rop.index) + rop.last_index = min(prevRop.last_index, rop.last_index) + print('New rop {}'.format(rop)) + elif not all((isDisjoint, isSame)): + raise ValueError("replace op boundaries of {} overlap with previous {}".format(rop, prevRop)) + + # Walk inserts + for i, iop in enumerate(rewrites): + if any((iop is None, not isinstance(iop, TokenStreamRewriter.InsertBeforeOp))): + continue + prevInserts = [op for op in rewrites[:i] if isinstance(iop, TokenStreamRewriter.InsertBeforeOp)] + for prevIop in prevInserts: + if prevIop.index == iop.index: + iop.text += prevIop.text + rewrites[i] = None + # look for replaces where iop.index is in range; error + prevReplaces = [op for op in rewrites[:i] if isinstance(op, TokenStreamRewriter.ReplaceOp)] + for rop in prevReplaces: + if iop.index == rop.index: + rop.text = iop.text + rop.text + rewrites[i] = None + continue + if all((iop.index >= rop.index, iop.index <= rop.index)): + raise ValueError("insert op {} within boundaries of previous {}".format(iop, rop)) + + reduced = {} + for i, op in enumerate(rewrites): + if op is None: continue + if reduced.get(op.index): raise ValueError('should be only one op per index') + reduced[op.index] = op + + return reduced + + class RewriteOperation(object): + + def __init__(self, tokens, index, text=""): + """ + :type tokens: CommonTokenStream + :param tokens: + :param index: + :param text: + :return: + """ + self.tokens = tokens + self.index = index + self.text = text + self.instructionIndex = 0 + + def execute(self, buf): + """ + :type buf: StringIO.StringIO + :param buf: + :return: + """ + return self.index + + def __str__(self): + pass + + class InsertBeforeOp(RewriteOperation): + + def __init__(self, tokens, index, text=""): + super(TokenStreamRewriter.InsertBeforeOp, self).__init__(tokens, index, text) + + def execute(self, buf): + buf.write(self.text) + if self.tokens.get(self.index).type != Token.EOF: + buf.write(self.tokens.get(self.index).text) + return self.index + 1 + + class ReplaceOp(RewriteOperation): + + def __init__(self, from_idx, to_idx, tokens, text): + super(TokenStreamRewriter.ReplaceOp, self).__init__(tokens, from_idx, text) + self.last_index = to_idx + + def execute(self, buf): + if self.text: + buf.write(self.text) + return self.last_index + 1 \ No newline at end of file diff --git a/src/antlr4/Utils.py b/src/antlr4/Utils.py new file mode 100644 index 00000000..88c870da --- /dev/null +++ b/src/antlr4/Utils.py @@ -0,0 +1,33 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +from io import StringIO + +def str_list(val): + with StringIO() as buf: + buf.write('[') + first = True + for item in val: + if not first: + buf.write(', ') + buf.write(str(item)) + first = False + buf.write(']') + return buf.getvalue() + +def escapeWhitespace(s:str, escapeSpaces:bool): + with StringIO() as buf: + for c in s: + if c==' ' and escapeSpaces: + buf.write('\u00B7') + elif c=='\t': + buf.write("\\t") + elif c=='\n': + buf.write("\\n") + elif c=='\r': + buf.write("\\r") + else: + buf.write(c) + return buf.getvalue() diff --git a/src/antlr4/__init__.py b/src/antlr4/__init__.py new file mode 100644 index 00000000..42027289 --- /dev/null +++ b/src/antlr4/__init__.py @@ -0,0 +1,21 @@ +from antlr4.Token import Token +from antlr4.InputStream import InputStream +from antlr4.FileStream import FileStream +from antlr4.StdinStream import StdinStream +from antlr4.BufferedTokenStream import TokenStream +from antlr4.CommonTokenStream import CommonTokenStream +from antlr4.Lexer import Lexer +from antlr4.Parser import Parser +from antlr4.dfa.DFA import DFA +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNDeserializer import ATNDeserializer +from antlr4.atn.LexerATNSimulator import LexerATNSimulator +from antlr4.atn.ParserATNSimulator import ParserATNSimulator +from antlr4.atn.PredictionMode import PredictionMode +from antlr4.PredictionContext import PredictionContextCache +from antlr4.ParserRuleContext import RuleContext, ParserRuleContext +from antlr4.tree.Tree import ParseTreeListener, ParseTreeVisitor, ParseTreeWalker, TerminalNode, ErrorNode, RuleNode +from antlr4.error.Errors import RecognitionException, IllegalStateException, NoViableAltException +from antlr4.error.ErrorStrategy import BailErrorStrategy +from antlr4.error.DiagnosticErrorListener import DiagnosticErrorListener +from antlr4.Utils import str_list diff --git a/src/antlr4/atn/ATN.py b/src/antlr4/atn/ATN.py new file mode 100644 index 00000000..4ef5640b --- /dev/null +++ b/src/antlr4/atn/ATN.py @@ -0,0 +1,127 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ +from antlr4.IntervalSet import IntervalSet + +from antlr4.RuleContext import RuleContext + +from antlr4.Token import Token +from antlr4.atn.ATNType import ATNType +from antlr4.atn.ATNState import ATNState, DecisionState + + +class ATN(object): + + INVALID_ALT_NUMBER = 0 + + # Used for runtime deserialization of ATNs from strings#/ + def __init__(self, grammarType:ATNType , maxTokenType:int ): + # The type of the ATN. + self.grammarType = grammarType + # The maximum value for any symbol recognized by a transition in the ATN. + self.maxTokenType = maxTokenType + self.states = [] + # Each subrule/rule is a decision point and we must track them so we + # can go back later and build DFA predictors for them. This includes + # all the rules, subrules, optional blocks, ()+, ()* etc... + self.decisionToState = [] + # Maps from rule index to starting state number. + self.ruleToStartState = [] + # Maps from rule index to stop state number. + self.ruleToStopState = None + self.modeNameToStartState = dict() + # For lexer ATNs, this maps the rule index to the resulting token type. + # For parser ATNs, this maps the rule index to the generated bypass token + # type if the + # {@link ATNDeserializationOptions#isGenerateRuleBypassTransitions} + # deserialization option was specified; otherwise, this is {@code null}. + self.ruleToTokenType = None + # For lexer ATNs, this is an array of {@link LexerAction} objects which may + # be referenced by action transitions in the ATN. + self.lexerActions = None + self.modeToStartState = [] + + # Compute the set of valid tokens that can occur starting in state {@code s}. + # If {@code ctx} is null, the set of tokens will not include what can follow + # the rule surrounding {@code s}. In other words, the set will be + # restricted to tokens reachable staying within {@code s}'s rule. + def nextTokensInContext(self, s:ATNState, ctx:RuleContext): + from antlr4.LL1Analyzer import LL1Analyzer + anal = LL1Analyzer(self) + return anal.LOOK(s, ctx=ctx) + + # Compute the set of valid tokens that can occur starting in {@code s} and + # staying in same rule. {@link Token#EPSILON} is in set if we reach end of + # rule. + def nextTokensNoContext(self, s:ATNState): + if s.nextTokenWithinRule is not None: + return s.nextTokenWithinRule + s.nextTokenWithinRule = self.nextTokensInContext(s, None) + s.nextTokenWithinRule.readonly = True + return s.nextTokenWithinRule + + def nextTokens(self, s:ATNState, ctx:RuleContext = None): + if ctx==None: + return self.nextTokensNoContext(s) + else: + return self.nextTokensInContext(s, ctx) + + def addState(self, state:ATNState): + if state is not None: + state.atn = self + state.stateNumber = len(self.states) + self.states.append(state) + + def removeState(self, state:ATNState): + self.states[state.stateNumber] = None # just free mem, don't shift states in list + + def defineDecisionState(self, s:DecisionState): + self.decisionToState.append(s) + s.decision = len(self.decisionToState)-1 + return s.decision + + def getDecisionState(self, decision:int): + if len(self.decisionToState)==0: + return None + else: + return self.decisionToState[decision] + + # Computes the set of input symbols which could follow ATN state number + # {@code stateNumber} in the specified full {@code context}. This method + # considers the complete parser context, but does not evaluate semantic + # predicates (i.e. all predicates encountered during the calculation are + # assumed true). If a path in the ATN exists from the starting state to the + # {@link RuleStopState} of the outermost context without matching any + # symbols, {@link Token#EOF} is added to the returned set. + # + #

      If {@code context} is {@code null}, it is treated as + # {@link ParserRuleContext#EMPTY}.

      + # + # @param stateNumber the ATN state number + # @param context the full parse context + # @return The set of potentially valid input symbols which could follow the + # specified state in the specified context. + # @throws IllegalArgumentException if the ATN does not contain a state with + # number {@code stateNumber} + #/ + def getExpectedTokens(self, stateNumber:int, ctx:RuleContext ): + if stateNumber < 0 or stateNumber >= len(self.states): + raise Exception("Invalid state number.") + s = self.states[stateNumber] + following = self.nextTokens(s) + if Token.EPSILON not in following: + return following + expected = IntervalSet() + expected.addSet(following) + expected.removeOne(Token.EPSILON) + while (ctx != None and ctx.invokingState >= 0 and Token.EPSILON in following): + invokingState = self.states[ctx.invokingState] + rt = invokingState.transitions[0] + following = self.nextTokens(rt.followState) + expected.addSet(following) + expected.removeOne(Token.EPSILON) + ctx = ctx.parentCtx + if Token.EPSILON in following: + expected.addOne(Token.EOF) + return expected \ No newline at end of file diff --git a/src/antlr4/atn/ATNConfig.py b/src/antlr4/atn/ATNConfig.py new file mode 100644 index 00000000..e2d8b99c --- /dev/null +++ b/src/antlr4/atn/ATNConfig.py @@ -0,0 +1,154 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# A tuple: (ATN state, predicted alt, syntactic, semantic context). +# The syntactic context is a graph-structured stack node whose +# path(s) to the root is the rule invocation(s) +# chain used to arrive at the state. The semantic context is +# the tree of semantic predicates encountered before reaching +# an ATN state. +#/ +from io import StringIO +from antlr4.PredictionContext import PredictionContext +from antlr4.atn.ATNState import ATNState, DecisionState +from antlr4.atn.LexerActionExecutor import LexerActionExecutor +from antlr4.atn.SemanticContext import SemanticContext + +# need a forward declaration +ATNConfig = None + +class ATNConfig(object): + + def __init__(self, state:ATNState=None, alt:int=None, context:PredictionContext=None, semantic:SemanticContext=None, config:ATNConfig=None): + if config is not None: + if state is None: + state = config.state + if alt is None: + alt = config.alt + if context is None: + context = config.context + if semantic is None: + semantic = config.semanticContext + if semantic is None: + semantic = SemanticContext.NONE + # The ATN state associated with this configuration#/ + self.state = state + # What alt (or lexer rule) is predicted by this configuration#/ + self.alt = alt + # The stack of invoking states leading to the rule/states associated + # with this config. We track only those contexts pushed during + # execution of the ATN simulator. + self.context = context + self.semanticContext = semantic + # We cannot execute predicates dependent upon local context unless + # we know for sure we are in the correct context. Because there is + # no way to do this efficiently, we simply cannot evaluate + # dependent predicates unless we are in the rule that initially + # invokes the ATN simulator. + # + # closure() tracks the depth of how far we dip into the + # outer context: depth > 0. Note that it may not be totally + # accurate depth since I don't ever decrement. TODO: make it a boolean then + self.reachesIntoOuterContext = 0 if config is None else config.reachesIntoOuterContext + self.precedenceFilterSuppressed = False if config is None else config.precedenceFilterSuppressed + + # An ATN configuration is equal to another if both have + # the same state, they predict the same alternative, and + # syntactic/semantic contexts are the same. + #/ + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, ATNConfig): + return False + else: + return self.state.stateNumber==other.state.stateNumber \ + and self.alt==other.alt \ + and ((self.context is other.context) or (self.context==other.context)) \ + and self.semanticContext==other.semanticContext \ + and self.precedenceFilterSuppressed==other.precedenceFilterSuppressed + + def __hash__(self): + return hash((self.state.stateNumber, self.alt, self.context, self.semanticContext)) + + def hashCodeForConfigSet(self): + return hash((self.state.stateNumber, self.alt, hash(self.semanticContext))) + + def equalsForConfigSet(self, other): + if self is other: + return True + elif not isinstance(other, ATNConfig): + return False + else: + return self.state.stateNumber==other.state.stateNumber \ + and self.alt==other.alt \ + and self.semanticContext==other.semanticContext + + def __str__(self): + with StringIO() as buf: + buf.write('(') + buf.write(str(self.state)) + buf.write(",") + buf.write(str(self.alt)) + if self.context is not None: + buf.write(",[") + buf.write(str(self.context)) + buf.write("]") + if self.semanticContext is not None and self.semanticContext is not SemanticContext.NONE: + buf.write(",") + buf.write(str(self.semanticContext)) + if self.reachesIntoOuterContext>0: + buf.write(",up=") + buf.write(str(self.reachesIntoOuterContext)) + buf.write(')') + return buf.getvalue() + +# need a forward declaration +LexerATNConfig = None + +class LexerATNConfig(ATNConfig): + + def __init__(self, state:ATNState, alt:int=None, context:PredictionContext=None, semantic:SemanticContext=SemanticContext.NONE, + lexerActionExecutor:LexerActionExecutor=None, config:LexerATNConfig=None): + super().__init__(state=state, alt=alt, context=context, semantic=semantic, config=config) + if config is not None: + if lexerActionExecutor is None: + lexerActionExecutor = config.lexerActionExecutor + # This is the backing field for {@link #getLexerActionExecutor}. + self.lexerActionExecutor = lexerActionExecutor + self.passedThroughNonGreedyDecision = False if config is None else self.checkNonGreedyDecision(config, state) + + def __hash__(self): + return hash((self.state.stateNumber, self.alt, self.context, + self.semanticContext, self.passedThroughNonGreedyDecision, + self.lexerActionExecutor)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerATNConfig): + return False + if self.passedThroughNonGreedyDecision != other.passedThroughNonGreedyDecision: + return False + if not(self.lexerActionExecutor == other.lexerActionExecutor): + return False + return super().__eq__(other) + + + + def hashCodeForConfigSet(self): + return hash(self) + + + + def equalsForConfigSet(self, other): + return self==other + + + + def checkNonGreedyDecision(self, source:LexerATNConfig, target:ATNState): + return source.passedThroughNonGreedyDecision \ + or isinstance(target, DecisionState) and target.nonGreedy diff --git a/src/antlr4/atn/ATNConfigSet.py b/src/antlr4/atn/ATNConfigSet.py new file mode 100644 index 00000000..b240c25d --- /dev/null +++ b/src/antlr4/atn/ATNConfigSet.py @@ -0,0 +1,209 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. + +# +# Specialized {@link Set}{@code <}{@link ATNConfig}{@code >} that can track +# info about the set, with support for combining similar configurations using a +# graph-structured stack. +#/ +from io import StringIO +from functools import reduce +from antlr4.PredictionContext import PredictionContext, merge +from antlr4.Utils import str_list +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNConfig import ATNConfig +from antlr4.atn.SemanticContext import SemanticContext +from antlr4.error.Errors import UnsupportedOperationException, IllegalStateException + +ATNSimulator = None + +class ATNConfigSet(object): + # + # The reason that we need this is because we don't want the hash map to use + # the standard hash code and equals. We need all configurations with the same + # {@code (s,i,_,semctx)} to be equal. Unfortunately, this key effectively doubles + # the number of objects associated with ATNConfigs. The other solution is to + # use a hash table that lets us specify the equals/hashcode operation. + + def __init__(self, fullCtx:bool=True): + # All configs but hashed by (s, i, _, pi) not including context. Wiped out + # when we go readonly as this set becomes a DFA state. + self.configLookup = dict() + # Indicates that this configuration set is part of a full context + # LL prediction. It will be used to determine how to merge $. With SLL + # it's a wildcard whereas it is not for LL context merge. + self.fullCtx = fullCtx + # Indicates that the set of configurations is read-only. Do not + # allow any code to manipulate the set; DFA states will point at + # the sets and they must not change. This does not protect the other + # fields; in particular, conflictingAlts is set after + # we've made this readonly. + self.readonly = False + # Track the elements as they are added to the set; supports get(i)#/ + self.configs = [] + + # TODO: these fields make me pretty uncomfortable but nice to pack up info together, saves recomputation + # TODO: can we track conflicts as they are added to save scanning configs later? + self.uniqueAlt = 0 + self.conflictingAlts = None + + # Used in parser and lexer. In lexer, it indicates we hit a pred + # while computing a closure operation. Don't make a DFA state from this. + self.hasSemanticContext = False + self.dipsIntoOuterContext = False + + self.cachedHashCode = -1 + + def __iter__(self): + return self.configs.__iter__() + + # Adding a new config means merging contexts with existing configs for + # {@code (s, i, pi, _)}, where {@code s} is the + # {@link ATNConfig#state}, {@code i} is the {@link ATNConfig#alt}, and + # {@code pi} is the {@link ATNConfig#semanticContext}. We use + # {@code (s,i,pi)} as key. + # + #

      This method updates {@link #dipsIntoOuterContext} and + # {@link #hasSemanticContext} when necessary.

      + #/ + def add(self, config:ATNConfig, mergeCache=None): + if self.readonly: + raise Exception("This set is readonly") + if config.semanticContext is not SemanticContext.NONE: + self.hasSemanticContext = True + if config.reachesIntoOuterContext > 0: + self.dipsIntoOuterContext = True + existing = self.getOrAdd(config) + if existing is config: + self.cachedHashCode = -1 + self.configs.append(config) # track order here + return True + # a previous (s,i,pi,_), merge with it and save result + rootIsWildcard = not self.fullCtx + merged = merge(existing.context, config.context, rootIsWildcard, mergeCache) + # no need to check for existing.context, config.context in cache + # since only way to create new graphs is "call rule" and here. + # We cache at both places. + existing.reachesIntoOuterContext = max(existing.reachesIntoOuterContext, config.reachesIntoOuterContext) + # make sure to preserve the precedence filter suppression during the merge + if config.precedenceFilterSuppressed: + existing.precedenceFilterSuppressed = True + existing.context = merged # replace context; no need to alt mapping + return True + + def getOrAdd(self, config:ATNConfig): + h = config.hashCodeForConfigSet() + l = self.configLookup.get(h, None) + if l is not None: + r = next((cfg for cfg in l if config.equalsForConfigSet(cfg)), None) + if r is not None: + return r + if l is None: + l = [config] + self.configLookup[h] = l + else: + l.append(config) + return config + + def getStates(self): + return set(c.state for c in self.configs) + + def getPredicates(self): + return list(cfg.semanticContext for cfg in self.configs if cfg.semanticContext!=SemanticContext.NONE) + + def get(self, i:int): + return self.configs[i] + + def optimizeConfigs(self, interpreter:ATNSimulator): + if self.readonly: + raise IllegalStateException("This set is readonly") + if len(self.configs)==0: + return + for config in self.configs: + config.context = interpreter.getCachedContext(config.context) + + def addAll(self, coll:list): + for c in coll: + self.add(c) + return False + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, ATNConfigSet): + return False + + same = self.configs is not None and \ + self.configs==other.configs and \ + self.fullCtx == other.fullCtx and \ + self.uniqueAlt == other.uniqueAlt and \ + self.conflictingAlts == other.conflictingAlts and \ + self.hasSemanticContext == other.hasSemanticContext and \ + self.dipsIntoOuterContext == other.dipsIntoOuterContext + + return same + + def __hash__(self): + if self.readonly: + if self.cachedHashCode == -1: + self.cachedHashCode = self.hashConfigs() + return self.cachedHashCode + return self.hashConfigs() + + def hashConfigs(self): + return reduce(lambda h, cfg: hash((h, cfg)), self.configs, 0) + + def __len__(self): + return len(self.configs) + + def isEmpty(self): + return len(self.configs)==0 + + def __contains__(self, config): + if self.configLookup is None: + raise UnsupportedOperationException("This method is not implemented for readonly sets.") + h = config.hashCodeForConfigSet() + l = self.configLookup.get(h, None) + if l is not None: + for c in l: + if config.equalsForConfigSet(c): + return True + return False + + def clear(self): + if self.readonly: + raise IllegalStateException("This set is readonly") + self.configs.clear() + self.cachedHashCode = -1 + self.configLookup.clear() + + def setReadonly(self, readonly:bool): + self.readonly = readonly + self.configLookup = None # can't mod, no need for lookup cache + + def __str__(self): + with StringIO() as buf: + buf.write(str_list(self.configs)) + if self.hasSemanticContext: + buf.write(",hasSemanticContext=") + buf.write(str(self.hasSemanticContext)) + if self.uniqueAlt!=ATN.INVALID_ALT_NUMBER: + buf.write(",uniqueAlt=") + buf.write(str(self.uniqueAlt)) + if self.conflictingAlts is not None: + buf.write(",conflictingAlts=") + buf.write(str(self.conflictingAlts)) + if self.dipsIntoOuterContext: + buf.write(",dipsIntoOuterContext") + return buf.getvalue() + + +class OrderedATNConfigSet(ATNConfigSet): + + def __init__(self): + super().__init__() + + + diff --git a/src/antlr4/atn/ATNDeserializationOptions.py b/src/antlr4/atn/ATNDeserializationOptions.py new file mode 100644 index 00000000..9c4e23de --- /dev/null +++ b/src/antlr4/atn/ATNDeserializationOptions.py @@ -0,0 +1,24 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. + +# need a forward declaration +ATNDeserializationOptions = None + +class ATNDeserializationOptions(object): + + defaultOptions = None + + def __init__(self, copyFrom:ATNDeserializationOptions = None): + self.readOnly = False + self.verifyATN = True if copyFrom is None else copyFrom.verifyATN + self.generateRuleBypassTransitions = False if copyFrom is None else copyFrom.generateRuleBypassTransitions + + def __setattr__(self, key, value): + if key!="readOnly" and self.readOnly: + raise Exception("The object is read only.") + super(type(self), self).__setattr__(key,value) + +ATNDeserializationOptions.defaultOptions = ATNDeserializationOptions() +ATNDeserializationOptions.defaultOptions.readOnly = True + diff --git a/src/antlr4/atn/ATNDeserializer.py b/src/antlr4/atn/ATNDeserializer.py new file mode 100644 index 00000000..cd0bb661 --- /dev/null +++ b/src/antlr4/atn/ATNDeserializer.py @@ -0,0 +1,528 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ +from uuid import UUID +from io import StringIO +from typing import Callable +from antlr4.Token import Token +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNType import ATNType +from antlr4.atn.ATNState import * +from antlr4.atn.Transition import * +from antlr4.atn.LexerAction import * +from antlr4.atn.ATNDeserializationOptions import ATNDeserializationOptions + +# This is the earliest supported serialized UUID. +BASE_SERIALIZED_UUID = UUID("AADB8D7E-AEEF-4415-AD2B-8204D6CF042E") + +# This UUID indicates the serialized ATN contains two sets of +# IntervalSets, where the second set's values are encoded as +# 32-bit integers to support the full Unicode SMP range up to U+10FFFF. +ADDED_UNICODE_SMP = UUID("59627784-3BE5-417A-B9EB-8131A7286089") + +# This list contains all of the currently supported UUIDs, ordered by when +# the feature first appeared in this branch. +SUPPORTED_UUIDS = [ BASE_SERIALIZED_UUID, ADDED_UNICODE_SMP ] + +SERIALIZED_VERSION = 3 + +# This is the current serialized UUID. +SERIALIZED_UUID = ADDED_UNICODE_SMP + +class ATNDeserializer (object): + + def __init__(self, options : ATNDeserializationOptions = None): + if options is None: + options = ATNDeserializationOptions.defaultOptions + self.deserializationOptions = options + + # Determines if a particular serialized representation of an ATN supports + # a particular feature, identified by the {@link UUID} used for serializing + # the ATN at the time the feature was first introduced. + # + # @param feature The {@link UUID} marking the first time the feature was + # supported in the serialized ATN. + # @param actualUuid The {@link UUID} of the actual serialized ATN which is + # currently being deserialized. + # @return {@code true} if the {@code actualUuid} value represents a + # serialized ATN at or after the feature identified by {@code feature} was + # introduced; otherwise, {@code false}. + + def isFeatureSupported(self, feature : UUID , actualUuid : UUID ): + idx1 = SUPPORTED_UUIDS.index(feature) + if idx1<0: + return False + idx2 = SUPPORTED_UUIDS.index(actualUuid) + return idx2 >= idx1 + + def deserialize(self, data : str): + self.reset(data) + self.checkVersion() + self.checkUUID() + atn = self.readATN() + self.readStates(atn) + self.readRules(atn) + self.readModes(atn) + sets = [] + # First, read all sets with 16-bit Unicode code points <= U+FFFF. + self.readSets(atn, sets, self.readInt) + # Next, if the ATN was serialized with the Unicode SMP feature, + # deserialize sets with 32-bit arguments <= U+10FFFF. + if self.isFeatureSupported(ADDED_UNICODE_SMP, self.uuid): + self.readSets(atn, sets, self.readInt32) + self.readEdges(atn, sets) + self.readDecisions(atn) + self.readLexerActions(atn) + self.markPrecedenceDecisions(atn) + self.verifyATN(atn) + if self.deserializationOptions.generateRuleBypassTransitions \ + and atn.grammarType == ATNType.PARSER: + self.generateRuleBypassTransitions(atn) + # re-verify after modification + self.verifyATN(atn) + return atn + + def reset(self, data:str): + def adjust(c): + v = ord(c) + return v-2 if v>1 else v + 65533 + temp = [ adjust(c) for c in data ] + # don't adjust the first value since that's the version number + temp[0] = ord(data[0]) + self.data = temp + self.pos = 0 + + def checkVersion(self): + version = self.readInt() + if version != SERIALIZED_VERSION: + raise Exception("Could not deserialize ATN with version " + str(version) + " (expected " + str(SERIALIZED_VERSION) + ").") + + def checkUUID(self): + uuid = self.readUUID() + if not uuid in SUPPORTED_UUIDS: + raise Exception("Could not deserialize ATN with UUID: " + str(uuid) + \ + " (expected " + str(SERIALIZED_UUID) + " or a legacy UUID).", uuid, SERIALIZED_UUID) + self.uuid = uuid + + def readATN(self): + idx = self.readInt() + grammarType = ATNType.fromOrdinal(idx) + maxTokenType = self.readInt() + return ATN(grammarType, maxTokenType) + + def readStates(self, atn:ATN): + loopBackStateNumbers = [] + endStateNumbers = [] + nstates = self.readInt() + for i in range(0, nstates): + stype = self.readInt() + # ignore bad type of states + if stype==ATNState.INVALID_TYPE: + atn.addState(None) + continue + ruleIndex = self.readInt() + if ruleIndex == 0xFFFF: + ruleIndex = -1 + + s = self.stateFactory(stype, ruleIndex) + if stype == ATNState.LOOP_END: # special case + loopBackStateNumber = self.readInt() + loopBackStateNumbers.append((s, loopBackStateNumber)) + elif isinstance(s, BlockStartState): + endStateNumber = self.readInt() + endStateNumbers.append((s, endStateNumber)) + + atn.addState(s) + + # delay the assignment of loop back and end states until we know all the state instances have been initialized + for pair in loopBackStateNumbers: + pair[0].loopBackState = atn.states[pair[1]] + + for pair in endStateNumbers: + pair[0].endState = atn.states[pair[1]] + + numNonGreedyStates = self.readInt() + for i in range(0, numNonGreedyStates): + stateNumber = self.readInt() + atn.states[stateNumber].nonGreedy = True + + numPrecedenceStates = self.readInt() + for i in range(0, numPrecedenceStates): + stateNumber = self.readInt() + atn.states[stateNumber].isPrecedenceRule = True + + def readRules(self, atn:ATN): + nrules = self.readInt() + if atn.grammarType == ATNType.LEXER: + atn.ruleToTokenType = [0] * nrules + + atn.ruleToStartState = [0] * nrules + for i in range(0, nrules): + s = self.readInt() + startState = atn.states[s] + atn.ruleToStartState[i] = startState + if atn.grammarType == ATNType.LEXER: + tokenType = self.readInt() + if tokenType == 0xFFFF: + tokenType = Token.EOF + + atn.ruleToTokenType[i] = tokenType + + atn.ruleToStopState = [0] * nrules + for state in atn.states: + if not isinstance(state, RuleStopState): + continue + atn.ruleToStopState[state.ruleIndex] = state + atn.ruleToStartState[state.ruleIndex].stopState = state + + def readModes(self, atn:ATN): + nmodes = self.readInt() + for i in range(0, nmodes): + s = self.readInt() + atn.modeToStartState.append(atn.states[s]) + + def readSets(self, atn:ATN, sets:list, readUnicode:Callable[[], int]): + m = self.readInt() + for i in range(0, m): + iset = IntervalSet() + sets.append(iset) + n = self.readInt() + containsEof = self.readInt() + if containsEof!=0: + iset.addOne(-1) + for j in range(0, n): + i1 = readUnicode() + i2 = readUnicode() + iset.addRange(range(i1, i2 + 1)) # range upper limit is exclusive + + def readEdges(self, atn:ATN, sets:list): + nedges = self.readInt() + for i in range(0, nedges): + src = self.readInt() + trg = self.readInt() + ttype = self.readInt() + arg1 = self.readInt() + arg2 = self.readInt() + arg3 = self.readInt() + trans = self.edgeFactory(atn, ttype, src, trg, arg1, arg2, arg3, sets) + srcState = atn.states[src] + srcState.addTransition(trans) + + # edges for rule stop states can be derived, so they aren't serialized + for state in atn.states: + for i in range(0, len(state.transitions)): + t = state.transitions[i] + if not isinstance(t, RuleTransition): + continue + outermostPrecedenceReturn = -1 + if atn.ruleToStartState[t.target.ruleIndex].isPrecedenceRule: + if t.precedence == 0: + outermostPrecedenceReturn = t.target.ruleIndex + trans = EpsilonTransition(t.followState, outermostPrecedenceReturn) + atn.ruleToStopState[t.target.ruleIndex].addTransition(trans) + + for state in atn.states: + if isinstance(state, BlockStartState): + # we need to know the end state to set its start state + if state.endState is None: + raise Exception("IllegalState") + # block end states can only be associated to a single block start state + if state.endState.startState is not None: + raise Exception("IllegalState") + state.endState.startState = state + + if isinstance(state, PlusLoopbackState): + for i in range(0, len(state.transitions)): + target = state.transitions[i].target + if isinstance(target, PlusBlockStartState): + target.loopBackState = state + elif isinstance(state, StarLoopbackState): + for i in range(0, len(state.transitions)): + target = state.transitions[i].target + if isinstance(target, StarLoopEntryState): + target.loopBackState = state + + def readDecisions(self, atn:ATN): + ndecisions = self.readInt() + for i in range(0, ndecisions): + s = self.readInt() + decState = atn.states[s] + atn.decisionToState.append(decState) + decState.decision = i + + def readLexerActions(self, atn:ATN): + if atn.grammarType == ATNType.LEXER: + count = self.readInt() + atn.lexerActions = [ None ] * count + for i in range(0, count): + actionType = self.readInt() + data1 = self.readInt() + if data1 == 0xFFFF: + data1 = -1 + data2 = self.readInt() + if data2 == 0xFFFF: + data2 = -1 + lexerAction = self.lexerActionFactory(actionType, data1, data2) + atn.lexerActions[i] = lexerAction + + def generateRuleBypassTransitions(self, atn:ATN): + + count = len(atn.ruleToStartState) + atn.ruleToTokenType = [ 0 ] * count + for i in range(0, count): + atn.ruleToTokenType[i] = atn.maxTokenType + i + 1 + + for i in range(0, count): + self.generateRuleBypassTransition(atn, i) + + def generateRuleBypassTransition(self, atn:ATN, idx:int): + + bypassStart = BasicBlockStartState() + bypassStart.ruleIndex = idx + atn.addState(bypassStart) + + bypassStop = BlockEndState() + bypassStop.ruleIndex = idx + atn.addState(bypassStop) + + bypassStart.endState = bypassStop + atn.defineDecisionState(bypassStart) + + bypassStop.startState = bypassStart + + excludeTransition = None + + if atn.ruleToStartState[idx].isPrecedenceRule: + # wrap from the beginning of the rule to the StarLoopEntryState + endState = None + for state in atn.states: + if self.stateIsEndStateFor(state, idx): + endState = state + excludeTransition = state.loopBackState.transitions[0] + break + + if excludeTransition is None: + raise Exception("Couldn't identify final state of the precedence rule prefix section.") + + else: + + endState = atn.ruleToStopState[idx] + + # all non-excluded transitions that currently target end state need to target blockEnd instead + for state in atn.states: + for transition in state.transitions: + if transition == excludeTransition: + continue + if transition.target == endState: + transition.target = bypassStop + + # all transitions leaving the rule start state need to leave blockStart instead + ruleToStartState = atn.ruleToStartState[idx] + count = len(ruleToStartState.transitions) + while count > 0: + bypassStart.addTransition(ruleToStartState.transitions[count-1]) + del ruleToStartState.transitions[-1] + + # link the new states + atn.ruleToStartState[idx].addTransition(EpsilonTransition(bypassStart)) + bypassStop.addTransition(EpsilonTransition(endState)) + + matchState = BasicState() + atn.addState(matchState) + matchState.addTransition(AtomTransition(bypassStop, atn.ruleToTokenType[idx])) + bypassStart.addTransition(EpsilonTransition(matchState)) + + + def stateIsEndStateFor(self, state:ATNState, idx:int): + if state.ruleIndex != idx: + return None + if not isinstance(state, StarLoopEntryState): + return None + + maybeLoopEndState = state.transitions[len(state.transitions) - 1].target + if not isinstance(maybeLoopEndState, LoopEndState): + return None + + if maybeLoopEndState.epsilonOnlyTransitions and \ + isinstance(maybeLoopEndState.transitions[0].target, RuleStopState): + return state + else: + return None + + + # + # Analyze the {@link StarLoopEntryState} states in the specified ATN to set + # the {@link StarLoopEntryState#isPrecedenceDecision} field to the + # correct value. + # + # @param atn The ATN. + # + def markPrecedenceDecisions(self, atn:ATN): + for state in atn.states: + if not isinstance(state, StarLoopEntryState): + continue + + # We analyze the ATN to determine if this ATN decision state is the + # decision for the closure block that determines whether a + # precedence rule should continue or complete. + # + if atn.ruleToStartState[state.ruleIndex].isPrecedenceRule: + maybeLoopEndState = state.transitions[len(state.transitions) - 1].target + if isinstance(maybeLoopEndState, LoopEndState): + if maybeLoopEndState.epsilonOnlyTransitions and \ + isinstance(maybeLoopEndState.transitions[0].target, RuleStopState): + state.isPrecedenceDecision = True + + def verifyATN(self, atn:ATN): + if not self.deserializationOptions.verifyATN: + return + # verify assumptions + for state in atn.states: + if state is None: + continue + + self.checkCondition(state.epsilonOnlyTransitions or len(state.transitions) <= 1) + + if isinstance(state, PlusBlockStartState): + self.checkCondition(state.loopBackState is not None) + + if isinstance(state, StarLoopEntryState): + self.checkCondition(state.loopBackState is not None) + self.checkCondition(len(state.transitions) == 2) + + if isinstance(state.transitions[0].target, StarBlockStartState): + self.checkCondition(isinstance(state.transitions[1].target, LoopEndState)) + self.checkCondition(not state.nonGreedy) + elif isinstance(state.transitions[0].target, LoopEndState): + self.checkCondition(isinstance(state.transitions[1].target, StarBlockStartState)) + self.checkCondition(state.nonGreedy) + else: + raise Exception("IllegalState") + + if isinstance(state, StarLoopbackState): + self.checkCondition(len(state.transitions) == 1) + self.checkCondition(isinstance(state.transitions[0].target, StarLoopEntryState)) + + if isinstance(state, LoopEndState): + self.checkCondition(state.loopBackState is not None) + + if isinstance(state, RuleStartState): + self.checkCondition(state.stopState is not None) + + if isinstance(state, BlockStartState): + self.checkCondition(state.endState is not None) + + if isinstance(state, BlockEndState): + self.checkCondition(state.startState is not None) + + if isinstance(state, DecisionState): + self.checkCondition(len(state.transitions) <= 1 or state.decision >= 0) + else: + self.checkCondition(len(state.transitions) <= 1 or isinstance(state, RuleStopState)) + + def checkCondition(self, condition:bool, message=None): + if not condition: + if message is None: + message = "IllegalState" + raise Exception(message) + + def readInt(self): + i = self.data[self.pos] + self.pos += 1 + return i + + def readInt32(self): + low = self.readInt() + high = self.readInt() + return low | (high << 16) + + def readLong(self): + low = self.readInt32() + high = self.readInt32() + return (low & 0x00000000FFFFFFFF) | (high << 32) + + def readUUID(self): + low = self.readLong() + high = self.readLong() + allBits = (low & 0xFFFFFFFFFFFFFFFF) | (high << 64) + return UUID(int=allBits) + + edgeFactories = [ lambda args : None, + lambda atn, src, trg, arg1, arg2, arg3, sets, target : EpsilonTransition(target), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + RangeTransition(target, Token.EOF, arg2) if arg3 != 0 else RangeTransition(target, arg1, arg2), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + RuleTransition(atn.states[arg1], arg2, arg3, target), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + PredicateTransition(target, arg1, arg2, arg3 != 0), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + AtomTransition(target, Token.EOF) if arg3 != 0 else AtomTransition(target, arg1), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + ActionTransition(target, arg1, arg2, arg3 != 0), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + SetTransition(target, sets[arg1]), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + NotSetTransition(target, sets[arg1]), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + WildcardTransition(target), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + PrecedencePredicateTransition(target, arg1) + ] + + def edgeFactory(self, atn:ATN, type:int, src:int, trg:int, arg1:int, arg2:int, arg3:int, sets:list): + target = atn.states[trg] + if type > len(self.edgeFactories) or self.edgeFactories[type] is None: + raise Exception("The specified transition type: " + str(type) + " is not valid.") + else: + return self.edgeFactories[type](atn, src, trg, arg1, arg2, arg3, sets, target) + + stateFactories = [ lambda : None, + lambda : BasicState(), + lambda : RuleStartState(), + lambda : BasicBlockStartState(), + lambda : PlusBlockStartState(), + lambda : StarBlockStartState(), + lambda : TokensStartState(), + lambda : RuleStopState(), + lambda : BlockEndState(), + lambda : StarLoopbackState(), + lambda : StarLoopEntryState(), + lambda : PlusLoopbackState(), + lambda : LoopEndState() + ] + + def stateFactory(self, type:int, ruleIndex:int): + if type> len(self.stateFactories) or self.stateFactories[type] is None: + raise Exception("The specified state type " + str(type) + " is not valid.") + else: + s = self.stateFactories[type]() + if s is not None: + s.ruleIndex = ruleIndex + return s + + CHANNEL = 0 #The type of a {@link LexerChannelAction} action. + CUSTOM = 1 #The type of a {@link LexerCustomAction} action. + MODE = 2 #The type of a {@link LexerModeAction} action. + MORE = 3 #The type of a {@link LexerMoreAction} action. + POP_MODE = 4 #The type of a {@link LexerPopModeAction} action. + PUSH_MODE = 5 #The type of a {@link LexerPushModeAction} action. + SKIP = 6 #The type of a {@link LexerSkipAction} action. + TYPE = 7 #The type of a {@link LexerTypeAction} action. + + actionFactories = [ lambda data1, data2: LexerChannelAction(data1), + lambda data1, data2: LexerCustomAction(data1, data2), + lambda data1, data2: LexerModeAction(data1), + lambda data1, data2: LexerMoreAction.INSTANCE, + lambda data1, data2: LexerPopModeAction.INSTANCE, + lambda data1, data2: LexerPushModeAction(data1), + lambda data1, data2: LexerSkipAction.INSTANCE, + lambda data1, data2: LexerTypeAction(data1) + ] + + def lexerActionFactory(self, type:int, data1:int, data2:int): + + if type > len(self.actionFactories) or self.actionFactories[type] is None: + raise Exception("The specified lexer action type " + str(type) + " is not valid.") + else: + return self.actionFactories[type](data1, data2) diff --git a/src/antlr4/atn/ATNSimulator.py b/src/antlr4/atn/ATNSimulator.py new file mode 100644 index 00000000..26c0b94a --- /dev/null +++ b/src/antlr4/atn/ATNSimulator.py @@ -0,0 +1,47 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ +from antlr4.PredictionContext import PredictionContextCache, PredictionContext, getCachedPredictionContext +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNConfigSet import ATNConfigSet +from antlr4.dfa.DFAState import DFAState + + +class ATNSimulator(object): + + # Must distinguish between missing edge and edge we know leads nowhere#/ + ERROR = DFAState(configs=ATNConfigSet()) + ERROR.stateNumber = 0x7FFFFFFF + + # The context cache maps all PredictionContext objects that are == + # to a single cached copy. This cache is shared across all contexts + # in all ATNConfigs in all DFA states. We rebuild each ATNConfigSet + # to use only cached nodes/graphs in addDFAState(). We don't want to + # fill this during closure() since there are lots of contexts that + # pop up but are not used ever again. It also greatly slows down closure(). + # + #

      This cache makes a huge difference in memory and a little bit in speed. + # For the Java grammar on java.*, it dropped the memory requirements + # at the end from 25M to 16M. We don't store any of the full context + # graphs in the DFA because they are limited to local context only, + # but apparently there's a lot of repetition there as well. We optimize + # the config contexts before storing the config set in the DFA states + # by literally rebuilding them with cached subgraphs only.

      + # + #

      I tried a cache for use during closure operations, that was + # whacked after each adaptivePredict(). It cost a little bit + # more time I think and doesn't save on the overall footprint + # so it's not worth the complexity.

      + #/ + def __init__(self, atn:ATN, sharedContextCache:PredictionContextCache): + self.atn = atn + self.sharedContextCache = sharedContextCache + + def getCachedContext(self, context:PredictionContext): + if self.sharedContextCache is None: + return context + visited = dict() + return getCachedPredictionContext(context, self.sharedContextCache, visited) + diff --git a/src/antlr4/atn/ATNState.py b/src/antlr4/atn/ATNState.py new file mode 100644 index 00000000..97ade955 --- /dev/null +++ b/src/antlr4/atn/ATNState.py @@ -0,0 +1,254 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# The following images show the relation of states and +# {@link ATNState#transitions} for various grammar constructs. +# +#
        +# +#
      • Solid edges marked with an ε indicate a required +# {@link EpsilonTransition}.
      • +# +#
      • Dashed edges indicate locations where any transition derived from +# {@link Transition} might appear.
      • +# +#
      • Dashed nodes are place holders for either a sequence of linked +# {@link BasicState} states or the inclusion of a block representing a nested +# construct in one of the forms below.
      • +# +#
      • Nodes showing multiple outgoing alternatives with a {@code ...} support +# any number of alternatives (one or more). Nodes without the {@code ...} only +# support the exact number of alternatives shown in the diagram.
      • +# +#
      +# +#

      Basic Blocks

      +# +#

      Rule

      +# +# +# +#

      Block of 1 or more alternatives

      +# +# +# +#

      Greedy Loops

      +# +#

      Greedy Closure: {@code (...)*}

      +# +# +# +#

      Greedy Positive Closure: {@code (...)+}

      +# +# +# +#

      Greedy Optional: {@code (...)?}

      +# +# +# +#

      Non-Greedy Loops

      +# +#

      Non-Greedy Closure: {@code (...)*?}

      +# +# +# +#

      Non-Greedy Positive Closure: {@code (...)+?}

      +# +# +# +#

      Non-Greedy Optional: {@code (...)??}

      +# +# +# + +from antlr4.atn.Transition import Transition + +INITIAL_NUM_TRANSITIONS = 4 + +class ATNState(object): + + # constants for serialization + INVALID_TYPE = 0 + BASIC = 1 + RULE_START = 2 + BLOCK_START = 3 + PLUS_BLOCK_START = 4 + STAR_BLOCK_START = 5 + TOKEN_START = 6 + RULE_STOP = 7 + BLOCK_END = 8 + STAR_LOOP_BACK = 9 + STAR_LOOP_ENTRY = 10 + PLUS_LOOP_BACK = 11 + LOOP_END = 12 + + serializationNames = [ + "INVALID", + "BASIC", + "RULE_START", + "BLOCK_START", + "PLUS_BLOCK_START", + "STAR_BLOCK_START", + "TOKEN_START", + "RULE_STOP", + "BLOCK_END", + "STAR_LOOP_BACK", + "STAR_LOOP_ENTRY", + "PLUS_LOOP_BACK", + "LOOP_END" ] + + INVALID_STATE_NUMBER = -1 + + def __init__(self): + # Which ATN are we in? + self.atn = None + self.stateNumber = ATNState.INVALID_STATE_NUMBER + self.stateType = None + self.ruleIndex = 0 # at runtime, we don't have Rule objects + self.epsilonOnlyTransitions = False + # Track the transitions emanating from this ATN state. + self.transitions = [] + # Used to cache lookahead during parsing, not used during construction + self.nextTokenWithinRule = None + + def __hash__(self): + return self.stateNumber + + def __eq__(self, other): + return isinstance(other, ATNState) and self.stateNumber==other.stateNumber + + def onlyHasEpsilonTransitions(self): + return self.epsilonOnlyTransitions + + def isNonGreedyExitState(self): + return False + + def __str__(self): + return str(self.stateNumber) + + def addTransition(self, trans:Transition, index:int=-1): + if len(self.transitions)==0: + self.epsilonOnlyTransitions = trans.isEpsilon + elif self.epsilonOnlyTransitions != trans.isEpsilon: + self.epsilonOnlyTransitions = False + # TODO System.err.format(Locale.getDefault(), "ATN state %d has both epsilon and non-epsilon transitions.\n", stateNumber); + if index==-1: + self.transitions.append(trans) + else: + self.transitions.insert(index, trans) + +class BasicState(ATNState): + + def __init__(self): + super().__init__() + self.stateType = self.BASIC + + +class DecisionState(ATNState): + + def __init__(self): + super().__init__() + self.decision = -1 + self.nonGreedy = False + +# The start of a regular {@code (...)} block. +class BlockStartState(DecisionState): + + def __init__(self): + super().__init__() + self.endState = None + +class BasicBlockStartState(BlockStartState): + + def __init__(self): + super().__init__() + self.stateType = self.BLOCK_START + +# Terminal node of a simple {@code (a|b|c)} block. +class BlockEndState(ATNState): + + def __init__(self): + super().__init__() + self.stateType = self.BLOCK_END + self.startState = None + +# The last node in the ATN for a rule, unless that rule is the start symbol. +# In that case, there is one transition to EOF. Later, we might encode +# references to all calls to this rule to compute FOLLOW sets for +# error handling. +# +class RuleStopState(ATNState): + + def __init__(self): + super().__init__() + self.stateType = self.RULE_STOP + +class RuleStartState(ATNState): + + def __init__(self): + super().__init__() + self.stateType = self.RULE_START + self.stopState = None + self.isPrecedenceRule = False + +# Decision state for {@code A+} and {@code (A|B)+}. It has two transitions: +# one to the loop back to start of the block and one to exit. +# +class PlusLoopbackState(DecisionState): + + def __init__(self): + super().__init__() + self.stateType = self.PLUS_LOOP_BACK + +# Start of {@code (A|B|...)+} loop. Technically a decision state, but +# we don't use for code generation; somebody might need it, so I'm defining +# it for completeness. In reality, the {@link PlusLoopbackState} node is the +# real decision-making note for {@code A+}. +# +class PlusBlockStartState(BlockStartState): + + def __init__(self): + super().__init__() + self.stateType = self.PLUS_BLOCK_START + self.loopBackState = None + +# The block that begins a closure loop. +class StarBlockStartState(BlockStartState): + + def __init__(self): + super().__init__() + self.stateType = self.STAR_BLOCK_START + +class StarLoopbackState(ATNState): + + def __init__(self): + super().__init__() + self.stateType = self.STAR_LOOP_BACK + + +class StarLoopEntryState(DecisionState): + + def __init__(self): + super().__init__() + self.stateType = self.STAR_LOOP_ENTRY + self.loopBackState = None + # Indicates whether this state can benefit from a precedence DFA during SLL decision making. + self.isPrecedenceDecision = None + +# Mark the end of a * or + loop. +class LoopEndState(ATNState): + + def __init__(self): + super().__init__() + self.stateType = self.LOOP_END + self.loopBackState = None + +# The Tokens rule start state linking to each lexer rule start state */ +class TokensStartState(DecisionState): + + def __init__(self): + super().__init__() + self.stateType = self.TOKEN_START diff --git a/src/antlr4/atn/ATNType.py b/src/antlr4/atn/ATNType.py new file mode 100644 index 00000000..cc0d4d92 --- /dev/null +++ b/src/antlr4/atn/ATNType.py @@ -0,0 +1,17 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +from enum import IntEnum + +# Represents the type of recognizer an ATN applies to. + +class ATNType(IntEnum): + + LEXER = 0 + PARSER = 1 + + @classmethod + def fromOrdinal(cls, i:int): + return cls._value2member_map_[i] diff --git a/src/antlr4/atn/LexerATNSimulator.py b/src/antlr4/atn/LexerATNSimulator.py new file mode 100644 index 00000000..cc638c82 --- /dev/null +++ b/src/antlr4/atn/LexerATNSimulator.py @@ -0,0 +1,568 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# When we hit an accept state in either the DFA or the ATN, we +# have to notify the character stream to start buffering characters +# via {@link IntStream#mark} and record the current state. The current sim state +# includes the current index into the input, the current line, +# and current character position in that line. Note that the Lexer is +# tracking the starting line and characterization of the token. These +# variables track the "state" of the simulator when it hits an accept state. +# +#

      We track these variables separately for the DFA and ATN simulation +# because the DFA simulation often has to fail over to the ATN +# simulation. If the ATN simulation fails, we need the DFA to fall +# back to its previously accepted state, if any. If the ATN succeeds, +# then the ATN does the accept and the DFA simulator that invoked it +# can simply return the predicted token type.

      +#/ + +from antlr4.PredictionContext import PredictionContextCache, SingletonPredictionContext, PredictionContext +from antlr4.InputStream import InputStream +from antlr4.Token import Token +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNConfig import LexerATNConfig +from antlr4.atn.ATNSimulator import ATNSimulator +from antlr4.atn.ATNConfigSet import ATNConfigSet, OrderedATNConfigSet +from antlr4.atn.ATNState import RuleStopState, ATNState +from antlr4.atn.LexerActionExecutor import LexerActionExecutor +from antlr4.atn.Transition import Transition +from antlr4.dfa.DFAState import DFAState +from antlr4.error.Errors import LexerNoViableAltException, UnsupportedOperationException + +class SimState(object): + + def __init__(self): + self.reset() + + def reset(self): + self.index = -1 + self.line = 0 + self.column = -1 + self.dfaState = None + +# need forward declaration +Lexer = None +LexerATNSimulator = None + +class LexerATNSimulator(ATNSimulator): + + debug = False + dfa_debug = False + + MIN_DFA_EDGE = 0 + MAX_DFA_EDGE = 127 # forces unicode to stay in ATN + + ERROR = None + + match_calls = 0 + + def __init__(self, recog:Lexer, atn:ATN, decisionToDFA:list, sharedContextCache:PredictionContextCache): + super().__init__(atn, sharedContextCache) + self.decisionToDFA = decisionToDFA + self.recog = recog + # The current token's starting index into the character stream. + # Shared across DFA to ATN simulation in case the ATN fails and the + # DFA did not have a previous accept state. In this case, we use the + # ATN-generated exception object. + self.startIndex = -1 + # line number 1..n within the input#/ + self.line = 1 + # The index of the character relative to the beginning of the line 0..n-1#/ + self.column = 0 + from antlr4.Lexer import Lexer + self.mode = Lexer.DEFAULT_MODE + # Used during DFA/ATN exec to record the most recent accept configuration info + self.prevAccept = SimState() + + + def copyState(self, simulator:LexerATNSimulator ): + self.column = simulator.column + self.line = simulator.line + self.mode = simulator.mode + self.startIndex = simulator.startIndex + + def match(self, input:InputStream , mode:int): + self.match_calls += 1 + self.mode = mode + mark = input.mark() + try: + self.startIndex = input.index + self.prevAccept.reset() + dfa = self.decisionToDFA[mode] + if dfa.s0 is None: + return self.matchATN(input) + else: + return self.execATN(input, dfa.s0) + finally: + input.release(mark) + + def reset(self): + self.prevAccept.reset() + self.startIndex = -1 + self.line = 1 + self.column = 0 + from antlr4.Lexer import Lexer + self.mode = Lexer.DEFAULT_MODE + + def matchATN(self, input:InputStream): + startState = self.atn.modeToStartState[self.mode] + + if LexerATNSimulator.debug: + print("matchATN mode " + str(self.mode) + " start: " + str(startState)) + + old_mode = self.mode + s0_closure = self.computeStartState(input, startState) + suppressEdge = s0_closure.hasSemanticContext + s0_closure.hasSemanticContext = False + + next = self.addDFAState(s0_closure) + if not suppressEdge: + self.decisionToDFA[self.mode].s0 = next + + predict = self.execATN(input, next) + + if LexerATNSimulator.debug: + print("DFA after matchATN: " + str(self.decisionToDFA[old_mode].toLexerString())) + + return predict + + def execATN(self, input:InputStream, ds0:DFAState): + if LexerATNSimulator.debug: + print("start state closure=" + str(ds0.configs)) + + if ds0.isAcceptState: + # allow zero-length tokens + self.captureSimState(self.prevAccept, input, ds0) + + t = input.LA(1) + s = ds0 # s is current/from DFA state + + while True: # while more work + if LexerATNSimulator.debug: + print("execATN loop starting closure:", str(s.configs)) + + # As we move src->trg, src->trg, we keep track of the previous trg to + # avoid looking up the DFA state again, which is expensive. + # If the previous target was already part of the DFA, we might + # be able to avoid doing a reach operation upon t. If s!=null, + # it means that semantic predicates didn't prevent us from + # creating a DFA state. Once we know s!=null, we check to see if + # the DFA state has an edge already for t. If so, we can just reuse + # it's configuration set; there's no point in re-computing it. + # This is kind of like doing DFA simulation within the ATN + # simulation because DFA simulation is really just a way to avoid + # computing reach/closure sets. Technically, once we know that + # we have a previously added DFA state, we could jump over to + # the DFA simulator. But, that would mean popping back and forth + # a lot and making things more complicated algorithmically. + # This optimization makes a lot of sense for loops within DFA. + # A character will take us back to an existing DFA state + # that already has lots of edges out of it. e.g., .* in comments. + # print("Target for:" + str(s) + " and:" + str(t)) + target = self.getExistingTargetState(s, t) + # print("Existing:" + str(target)) + if target is None: + target = self.computeTargetState(input, s, t) + # print("Computed:" + str(target)) + + if target == self.ERROR: + break + + # If this is a consumable input element, make sure to consume before + # capturing the accept state so the input index, line, and char + # position accurately reflect the state of the interpreter at the + # end of the token. + if t != Token.EOF: + self.consume(input) + + if target.isAcceptState: + self.captureSimState(self.prevAccept, input, target) + if t == Token.EOF: + break + + t = input.LA(1) + + s = target # flip; current DFA target becomes new src/from state + + return self.failOrAccept(self.prevAccept, input, s.configs, t) + + # Get an existing target state for an edge in the DFA. If the target state + # for the edge has not yet been computed or is otherwise not available, + # this method returns {@code null}. + # + # @param s The current DFA state + # @param t The next input symbol + # @return The existing target DFA state for the given input symbol + # {@code t}, or {@code null} if the target state for this edge is not + # already cached + def getExistingTargetState(self, s:DFAState, t:int): + if s.edges is None or t < self.MIN_DFA_EDGE or t > self.MAX_DFA_EDGE: + return None + + target = s.edges[t - self.MIN_DFA_EDGE] + if LexerATNSimulator.debug and target is not None: + print("reuse state", str(s.stateNumber), "edge to", str(target.stateNumber)) + + return target + + # Compute a target state for an edge in the DFA, and attempt to add the + # computed state and corresponding edge to the DFA. + # + # @param input The input stream + # @param s The current DFA state + # @param t The next input symbol + # + # @return The computed target DFA state for the given input symbol + # {@code t}. If {@code t} does not lead to a valid DFA state, this method + # returns {@link #ERROR}. + def computeTargetState(self, input:InputStream, s:DFAState, t:int): + reach = OrderedATNConfigSet() + + # if we don't find an existing DFA state + # Fill reach starting from closure, following t transitions + self.getReachableConfigSet(input, s.configs, reach, t) + + if len(reach)==0: # we got nowhere on t from s + if not reach.hasSemanticContext: + # we got nowhere on t, don't throw out this knowledge; it'd + # cause a failover from DFA later. + self. addDFAEdge(s, t, self.ERROR) + + # stop when we can't match any more char + return self.ERROR + + # Add an edge from s to target DFA found/created for reach + return self.addDFAEdge(s, t, cfgs=reach) + + def failOrAccept(self, prevAccept:SimState , input:InputStream, reach:ATNConfigSet, t:int): + if self.prevAccept.dfaState is not None: + lexerActionExecutor = prevAccept.dfaState.lexerActionExecutor + self.accept(input, lexerActionExecutor, self.startIndex, prevAccept.index, prevAccept.line, prevAccept.column) + return prevAccept.dfaState.prediction + else: + # if no accept and EOF is first char, return EOF + if t==Token.EOF and input.index==self.startIndex: + return Token.EOF + raise LexerNoViableAltException(self.recog, input, self.startIndex, reach) + + # Given a starting configuration set, figure out all ATN configurations + # we can reach upon input {@code t}. Parameter {@code reach} is a return + # parameter. + def getReachableConfigSet(self, input:InputStream, closure:ATNConfigSet, reach:ATNConfigSet, t:int): + # this is used to skip processing for configs which have a lower priority + # than a config that already reached an accept state for the same rule + skipAlt = ATN.INVALID_ALT_NUMBER + for cfg in closure: + currentAltReachedAcceptState = ( cfg.alt == skipAlt ) + if currentAltReachedAcceptState and cfg.passedThroughNonGreedyDecision: + continue + + if LexerATNSimulator.debug: + print("testing", self.getTokenName(t), "at", str(cfg)) + + for trans in cfg.state.transitions: # for each transition + target = self.getReachableTarget(trans, t) + if target is not None: + lexerActionExecutor = cfg.lexerActionExecutor + if lexerActionExecutor is not None: + lexerActionExecutor = lexerActionExecutor.fixOffsetBeforeMatch(input.index - self.startIndex) + + treatEofAsEpsilon = (t == Token.EOF) + config = LexerATNConfig(state=target, lexerActionExecutor=lexerActionExecutor, config=cfg) + if self.closure(input, config, reach, currentAltReachedAcceptState, True, treatEofAsEpsilon): + # any remaining configs for this alt have a lower priority than + # the one that just reached an accept state. + skipAlt = cfg.alt + + def accept(self, input:InputStream, lexerActionExecutor:LexerActionExecutor, startIndex:int, index:int, line:int, charPos:int): + if LexerATNSimulator.debug: + print("ACTION", lexerActionExecutor) + + # seek to after last char in token + input.seek(index) + self.line = line + self.column = charPos + + if lexerActionExecutor is not None and self.recog is not None: + lexerActionExecutor.execute(self.recog, input, startIndex) + + def getReachableTarget(self, trans:Transition, t:int): + from antlr4.Lexer import Lexer + if trans.matches(t, 0, Lexer.MAX_CHAR_VALUE): + return trans.target + else: + return None + + def computeStartState(self, input:InputStream, p:ATNState): + initialContext = PredictionContext.EMPTY + configs = OrderedATNConfigSet() + for i in range(0,len(p.transitions)): + target = p.transitions[i].target + c = LexerATNConfig(state=target, alt=i+1, context=initialContext) + self.closure(input, c, configs, False, False, False) + return configs + + # Since the alternatives within any lexer decision are ordered by + # preference, this method stops pursuing the closure as soon as an accept + # state is reached. After the first accept state is reached by depth-first + # search from {@code config}, all other (potentially reachable) states for + # this rule would have a lower priority. + # + # @return {@code true} if an accept state is reached, otherwise + # {@code false}. + def closure(self, input:InputStream, config:LexerATNConfig, configs:ATNConfigSet, currentAltReachedAcceptState:bool, + speculative:bool, treatEofAsEpsilon:bool): + if LexerATNSimulator.debug: + print("closure(" + str(config) + ")") + + if isinstance( config.state, RuleStopState ): + if LexerATNSimulator.debug: + if self.recog is not None: + print("closure at", self.recog.symbolicNames[config.state.ruleIndex], "rule stop", str(config)) + else: + print("closure at rule stop", str(config)) + + if config.context is None or config.context.hasEmptyPath(): + if config.context is None or config.context.isEmpty(): + configs.add(config) + return True + else: + configs.add(LexerATNConfig(state=config.state, config=config, context=PredictionContext.EMPTY)) + currentAltReachedAcceptState = True + + if config.context is not None and not config.context.isEmpty(): + for i in range(0,len(config.context)): + if config.context.getReturnState(i) != PredictionContext.EMPTY_RETURN_STATE: + newContext = config.context.getParent(i) # "pop" return state + returnState = self.atn.states[config.context.getReturnState(i)] + c = LexerATNConfig(state=returnState, config=config, context=newContext) + currentAltReachedAcceptState = self.closure(input, c, configs, + currentAltReachedAcceptState, speculative, treatEofAsEpsilon) + + return currentAltReachedAcceptState + + # optimization + if not config.state.epsilonOnlyTransitions: + if not currentAltReachedAcceptState or not config.passedThroughNonGreedyDecision: + configs.add(config) + + for t in config.state.transitions: + c = self.getEpsilonTarget(input, config, t, configs, speculative, treatEofAsEpsilon) + if c is not None: + currentAltReachedAcceptState = self.closure(input, c, configs, currentAltReachedAcceptState, speculative, treatEofAsEpsilon) + + return currentAltReachedAcceptState + + # side-effect: can alter configs.hasSemanticContext + def getEpsilonTarget(self, input:InputStream, config:LexerATNConfig, t:Transition, configs:ATNConfigSet, + speculative:bool, treatEofAsEpsilon:bool): + c = None + if t.serializationType==Transition.RULE: + newContext = SingletonPredictionContext.create(config.context, t.followState.stateNumber) + c = LexerATNConfig(state=t.target, config=config, context=newContext) + + elif t.serializationType==Transition.PRECEDENCE: + raise UnsupportedOperationException("Precedence predicates are not supported in lexers.") + + elif t.serializationType==Transition.PREDICATE: + # Track traversing semantic predicates. If we traverse, + # we cannot add a DFA state for this "reach" computation + # because the DFA would not test the predicate again in the + # future. Rather than creating collections of semantic predicates + # like v3 and testing them on prediction, v4 will test them on the + # fly all the time using the ATN not the DFA. This is slower but + # semantically it's not used that often. One of the key elements to + # this predicate mechanism is not adding DFA states that see + # predicates immediately afterwards in the ATN. For example, + + # a : ID {p1}? | ID {p2}? ; + + # should create the start state for rule 'a' (to save start state + # competition), but should not create target of ID state. The + # collection of ATN states the following ID references includes + # states reached by traversing predicates. Since this is when we + # test them, we cannot cash the DFA state target of ID. + + if LexerATNSimulator.debug: + print("EVAL rule "+ str(t.ruleIndex) + ":" + str(t.predIndex)) + configs.hasSemanticContext = True + if self.evaluatePredicate(input, t.ruleIndex, t.predIndex, speculative): + c = LexerATNConfig(state=t.target, config=config) + + elif t.serializationType==Transition.ACTION: + if config.context is None or config.context.hasEmptyPath(): + # execute actions anywhere in the start rule for a token. + # + # TODO: if the entry rule is invoked recursively, some + # actions may be executed during the recursive call. The + # problem can appear when hasEmptyPath() is true but + # isEmpty() is false. In this case, the config needs to be + # split into two contexts - one with just the empty path + # and another with everything but the empty path. + # Unfortunately, the current algorithm does not allow + # getEpsilonTarget to return two configurations, so + # additional modifications are needed before we can support + # the split operation. + lexerActionExecutor = LexerActionExecutor.append(config.lexerActionExecutor, + self.atn.lexerActions[t.actionIndex]) + c = LexerATNConfig(state=t.target, config=config, lexerActionExecutor=lexerActionExecutor) + + else: + # ignore actions in referenced rules + c = LexerATNConfig(state=t.target, config=config) + + elif t.serializationType==Transition.EPSILON: + c = LexerATNConfig(state=t.target, config=config) + + elif t.serializationType in [ Transition.ATOM, Transition.RANGE, Transition.SET ]: + if treatEofAsEpsilon: + from antlr4.Lexer import Lexer + if t.matches(Token.EOF, 0, Lexer.MAX_CHAR_VALUE): + c = LexerATNConfig(state=t.target, config=config) + + return c + + # Evaluate a predicate specified in the lexer. + # + #

      If {@code speculative} is {@code true}, this method was called before + # {@link #consume} for the matched character. This method should call + # {@link #consume} before evaluating the predicate to ensure position + # sensitive values, including {@link Lexer#getText}, {@link Lexer#getLine}, + # and {@link Lexer#getcolumn}, properly reflect the current + # lexer state. This method should restore {@code input} and the simulator + # to the original state before returning (i.e. undo the actions made by the + # call to {@link #consume}.

      + # + # @param input The input stream. + # @param ruleIndex The rule containing the predicate. + # @param predIndex The index of the predicate within the rule. + # @param speculative {@code true} if the current index in {@code input} is + # one character before the predicate's location. + # + # @return {@code true} if the specified predicate evaluates to + # {@code true}. + #/ + def evaluatePredicate(self, input:InputStream, ruleIndex:int, predIndex:int, speculative:bool): + # assume true if no recognizer was provided + if self.recog is None: + return True + + if not speculative: + return self.recog.sempred(None, ruleIndex, predIndex) + + savedcolumn = self.column + savedLine = self.line + index = input.index + marker = input.mark() + try: + self.consume(input) + return self.recog.sempred(None, ruleIndex, predIndex) + finally: + self.column = savedcolumn + self.line = savedLine + input.seek(index) + input.release(marker) + + def captureSimState(self, settings:SimState, input:InputStream, dfaState:DFAState): + settings.index = input.index + settings.line = self.line + settings.column = self.column + settings.dfaState = dfaState + + def addDFAEdge(self, from_:DFAState, tk:int, to:DFAState=None, cfgs:ATNConfigSet=None) -> DFAState: + + if to is None and cfgs is not None: + # leading to this call, ATNConfigSet.hasSemanticContext is used as a + # marker indicating dynamic predicate evaluation makes this edge + # dependent on the specific input sequence, so the static edge in the + # DFA should be omitted. The target DFAState is still created since + # execATN has the ability to resynchronize with the DFA state cache + # following the predicate evaluation step. + # + # TJP notes: next time through the DFA, we see a pred again and eval. + # If that gets us to a previously created (but dangling) DFA + # state, we can continue in pure DFA mode from there. + #/ + suppressEdge = cfgs.hasSemanticContext + cfgs.hasSemanticContext = False + + to = self.addDFAState(cfgs) + + if suppressEdge: + return to + + # add the edge + if tk < self.MIN_DFA_EDGE or tk > self.MAX_DFA_EDGE: + # Only track edges within the DFA bounds + return to + + if LexerATNSimulator.debug: + print("EDGE " + str(from_) + " -> " + str(to) + " upon "+ chr(tk)) + + if from_.edges is None: + # make room for tokens 1..n and -1 masquerading as index 0 + from_.edges = [ None ] * (self.MAX_DFA_EDGE - self.MIN_DFA_EDGE + 1) + + from_.edges[tk - self.MIN_DFA_EDGE] = to # connect + + return to + + + # Add a new DFA state if there isn't one with this set of + # configurations already. This method also detects the first + # configuration containing an ATN rule stop state. Later, when + # traversing the DFA, we will know which rule to accept. + def addDFAState(self, configs:ATNConfigSet) -> DFAState: + + proposed = DFAState(configs=configs) + firstConfigWithRuleStopState = next((cfg for cfg in configs if isinstance(cfg.state, RuleStopState)), None) + + if firstConfigWithRuleStopState is not None: + proposed.isAcceptState = True + proposed.lexerActionExecutor = firstConfigWithRuleStopState.lexerActionExecutor + proposed.prediction = self.atn.ruleToTokenType[firstConfigWithRuleStopState.state.ruleIndex] + + dfa = self.decisionToDFA[self.mode] + existing = dfa.states.get(proposed, None) + if existing is not None: + return existing + + newState = proposed + + newState.stateNumber = len(dfa.states) + configs.setReadonly(True) + newState.configs = configs + dfa.states[newState] = newState + return newState + + def getDFA(self, mode:int): + return self.decisionToDFA[mode] + + # Get the text matched so far for the current token. + def getText(self, input:InputStream): + # index is first lookahead char, don't include. + return input.getText(self.startIndex, input.index-1) + + def consume(self, input:InputStream): + curChar = input.LA(1) + if curChar==ord('\n'): + self.line += 1 + self.column = 0 + else: + self.column += 1 + input.consume() + + def getTokenName(self, t:int): + if t==-1: + return "EOF" + else: + return "'" + chr(t) + "'" + + +LexerATNSimulator.ERROR = DFAState(0x7FFFFFFF, ATNConfigSet()) + +del Lexer \ No newline at end of file diff --git a/src/antlr4/atn/LexerAction.py b/src/antlr4/atn/LexerAction.py new file mode 100644 index 00000000..5d11f21a --- /dev/null +++ b/src/antlr4/atn/LexerAction.py @@ -0,0 +1,291 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. + # + +from enum import IntEnum + +# need forward declaration +Lexer = None + + +class LexerActionType(IntEnum): + + CHANNEL = 0 #The type of a {@link LexerChannelAction} action. + CUSTOM = 1 #The type of a {@link LexerCustomAction} action. + MODE = 2 #The type of a {@link LexerModeAction} action. + MORE = 3 #The type of a {@link LexerMoreAction} action. + POP_MODE = 4 #The type of a {@link LexerPopModeAction} action. + PUSH_MODE = 5 #The type of a {@link LexerPushModeAction} action. + SKIP = 6 #The type of a {@link LexerSkipAction} action. + TYPE = 7 #The type of a {@link LexerTypeAction} action. + +class LexerAction(object): + + def __init__(self, action:LexerActionType): + self.actionType = action + self.isPositionDependent = False + + def __hash__(self): + return hash(self.actionType) + + def __eq__(self, other): + return self is other + + +# +# Implements the {@code skip} lexer action by calling {@link Lexer#skip}. +# +#

      The {@code skip} command does not have any parameters, so this action is +# implemented as a singleton instance exposed by {@link #INSTANCE}.

      +class LexerSkipAction(LexerAction ): + + # Provides a singleton instance of this parameterless lexer action. + INSTANCE = None + + def __init__(self): + super().__init__(LexerActionType.SKIP) + + def execute(self, lexer:Lexer): + lexer.skip() + + def __str__(self): + return "skip" + +LexerSkipAction.INSTANCE = LexerSkipAction() + +# Implements the {@code type} lexer action by calling {@link Lexer#setType} +# with the assigned type. +class LexerTypeAction(LexerAction): + + def __init__(self, type:int): + super().__init__(LexerActionType.TYPE) + self.type = type + + def execute(self, lexer:Lexer): + lexer.type = self.type + + def __hash__(self): + return hash((self.actionType, self.type)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerTypeAction): + return False + else: + return self.type == other.type + + def __str__(self): + return "type(" + str(self.type) + ")" + + +# Implements the {@code pushMode} lexer action by calling +# {@link Lexer#pushMode} with the assigned mode. +class LexerPushModeAction(LexerAction): + + def __init__(self, mode:int): + super().__init__(LexerActionType.PUSH_MODE) + self.mode = mode + + #

      This action is implemented by calling {@link Lexer#pushMode} with the + # value provided by {@link #getMode}.

      + def execute(self, lexer:Lexer): + lexer.pushMode(self.mode) + + def __hash__(self): + return hash((self.actionType, self.mode)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerPushModeAction): + return False + else: + return self.mode == other.mode + + def __str__(self): + return "pushMode(" + str(self.mode) + ")" + + +# Implements the {@code popMode} lexer action by calling {@link Lexer#popMode}. +# +#

      The {@code popMode} command does not have any parameters, so this action is +# implemented as a singleton instance exposed by {@link #INSTANCE}.

      +class LexerPopModeAction(LexerAction): + + INSTANCE = None + + def __init__(self): + super().__init__(LexerActionType.POP_MODE) + + #

      This action is implemented by calling {@link Lexer#popMode}.

      + def execute(self, lexer:Lexer): + lexer.popMode() + + def __str__(self): + return "popMode" + +LexerPopModeAction.INSTANCE = LexerPopModeAction() + +# Implements the {@code more} lexer action by calling {@link Lexer#more}. +# +#

      The {@code more} command does not have any parameters, so this action is +# implemented as a singleton instance exposed by {@link #INSTANCE}.

      +class LexerMoreAction(LexerAction): + + INSTANCE = None + + def __init__(self): + super().__init__(LexerActionType.MORE) + + #

      This action is implemented by calling {@link Lexer#popMode}.

      + def execute(self, lexer:Lexer): + lexer.more() + + def __str__(self): + return "more" + +LexerMoreAction.INSTANCE = LexerMoreAction() + +# Implements the {@code mode} lexer action by calling {@link Lexer#mode} with +# the assigned mode. +class LexerModeAction(LexerAction): + + def __init__(self, mode:int): + super().__init__(LexerActionType.MODE) + self.mode = mode + + #

      This action is implemented by calling {@link Lexer#mode} with the + # value provided by {@link #getMode}.

      + def execute(self, lexer:Lexer): + lexer.mode(self.mode) + + def __hash__(self): + return hash((self.actionType, self.mode)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerModeAction): + return False + else: + return self.mode == other.mode + + def __str__(self): + return "mode(" + str(self.mode) + ")" + +# Executes a custom lexer action by calling {@link Recognizer#action} with the +# rule and action indexes assigned to the custom action. The implementation of +# a custom action is added to the generated code for the lexer in an override +# of {@link Recognizer#action} when the grammar is compiled. +# +#

      This class may represent embedded actions created with the {...} +# syntax in ANTLR 4, as well as actions created for lexer commands where the +# command argument could not be evaluated when the grammar was compiled.

      + +class LexerCustomAction(LexerAction): + + # Constructs a custom lexer action with the specified rule and action + # indexes. + # + # @param ruleIndex The rule index to use for calls to + # {@link Recognizer#action}. + # @param actionIndex The action index to use for calls to + # {@link Recognizer#action}. + #/ + def __init__(self, ruleIndex:int, actionIndex:int): + super().__init__(LexerActionType.CUSTOM) + self.ruleIndex = ruleIndex + self.actionIndex = actionIndex + self.isPositionDependent = True + + #

      Custom actions are implemented by calling {@link Lexer#action} with the + # appropriate rule and action indexes.

      + def execute(self, lexer:Lexer): + lexer.action(None, self.ruleIndex, self.actionIndex) + + def __hash__(self): + return hash((self.actionType, self.ruleIndex, self.actionIndex)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerCustomAction): + return False + else: + return self.ruleIndex == other.ruleIndex and self.actionIndex == other.actionIndex + +# Implements the {@code channel} lexer action by calling +# {@link Lexer#setChannel} with the assigned channel. +class LexerChannelAction(LexerAction): + + # Constructs a new {@code channel} action with the specified channel value. + # @param channel The channel value to pass to {@link Lexer#setChannel}. + def __init__(self, channel:int): + super().__init__(LexerActionType.CHANNEL) + self.channel = channel + + #

      This action is implemented by calling {@link Lexer#setChannel} with the + # value provided by {@link #getChannel}.

      + def execute(self, lexer:Lexer): + lexer._channel = self.channel + + def __hash__(self): + return hash((self.actionType, self.channel)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerChannelAction): + return False + else: + return self.channel == other.channel + + def __str__(self): + return "channel(" + str(self.channel) + ")" + +# This implementation of {@link LexerAction} is used for tracking input offsets +# for position-dependent actions within a {@link LexerActionExecutor}. +# +#

      This action is not serialized as part of the ATN, and is only required for +# position-dependent lexer actions which appear at a location other than the +# end of a rule. For more information about DFA optimizations employed for +# lexer actions, see {@link LexerActionExecutor#append} and +# {@link LexerActionExecutor#fixOffsetBeforeMatch}.

      +class LexerIndexedCustomAction(LexerAction): + + # Constructs a new indexed custom action by associating a character offset + # with a {@link LexerAction}. + # + #

      Note: This class is only required for lexer actions for which + # {@link LexerAction#isPositionDependent} returns {@code true}.

      + # + # @param offset The offset into the input {@link CharStream}, relative to + # the token start index, at which the specified lexer action should be + # executed. + # @param action The lexer action to execute at a particular offset in the + # input {@link CharStream}. + def __init__(self, offset:int, action:LexerAction): + super().__init__(action.actionType) + self.offset = offset + self.action = action + self.isPositionDependent = True + + #

      This method calls {@link #execute} on the result of {@link #getAction} + # using the provided {@code lexer}.

      + def execute(self, lexer:Lexer): + # assume the input stream position was properly set by the calling code + self.action.execute(lexer) + + def __hash__(self): + return hash((self.actionType, self.offset, self.action)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerIndexedCustomAction): + return False + else: + return self.offset == other.offset and self.action == other.action diff --git a/src/antlr4/atn/LexerActionExecutor.py b/src/antlr4/atn/LexerActionExecutor.py new file mode 100644 index 00000000..df125169 --- /dev/null +++ b/src/antlr4/atn/LexerActionExecutor.py @@ -0,0 +1,142 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# Represents an executor for a sequence of lexer actions which traversed during +# the matching operation of a lexer rule (token). +# +#

      The executor tracks position information for position-dependent lexer actions +# efficiently, ensuring that actions appearing only at the end of the rule do +# not cause bloating of the {@link DFA} created for the lexer.

      + + +from antlr4.InputStream import InputStream +from antlr4.atn.LexerAction import LexerAction, LexerIndexedCustomAction + +# need a forward declaration +Lexer = None +LexerActionExecutor = None + +class LexerActionExecutor(object): + + def __init__(self, lexerActions:list=list()): + self.lexerActions = lexerActions + # Caches the result of {@link #hashCode} since the hash code is an element + # of the performance-critical {@link LexerATNConfig#hashCode} operation. + self.hashCode = hash("".join([str(la) for la in lexerActions])) + + + # Creates a {@link LexerActionExecutor} which executes the actions for + # the input {@code lexerActionExecutor} followed by a specified + # {@code lexerAction}. + # + # @param lexerActionExecutor The executor for actions already traversed by + # the lexer while matching a token within a particular + # {@link LexerATNConfig}. If this is {@code null}, the method behaves as + # though it were an empty executor. + # @param lexerAction The lexer action to execute after the actions + # specified in {@code lexerActionExecutor}. + # + # @return A {@link LexerActionExecutor} for executing the combine actions + # of {@code lexerActionExecutor} and {@code lexerAction}. + @staticmethod + def append(lexerActionExecutor:LexerActionExecutor , lexerAction:LexerAction ): + if lexerActionExecutor is None: + return LexerActionExecutor([ lexerAction ]) + + lexerActions = lexerActionExecutor.lexerActions + [ lexerAction ] + return LexerActionExecutor(lexerActions) + + # Creates a {@link LexerActionExecutor} which encodes the current offset + # for position-dependent lexer actions. + # + #

      Normally, when the executor encounters lexer actions where + # {@link LexerAction#isPositionDependent} returns {@code true}, it calls + # {@link IntStream#seek} on the input {@link CharStream} to set the input + # position to the end of the current token. This behavior provides + # for efficient DFA representation of lexer actions which appear at the end + # of a lexer rule, even when the lexer rule matches a variable number of + # characters.

      + # + #

      Prior to traversing a match transition in the ATN, the current offset + # from the token start index is assigned to all position-dependent lexer + # actions which have not already been assigned a fixed offset. By storing + # the offsets relative to the token start index, the DFA representation of + # lexer actions which appear in the middle of tokens remains efficient due + # to sharing among tokens of the same length, regardless of their absolute + # position in the input stream.

      + # + #

      If the current executor already has offsets assigned to all + # position-dependent lexer actions, the method returns {@code this}.

      + # + # @param offset The current offset to assign to all position-dependent + # lexer actions which do not already have offsets assigned. + # + # @return A {@link LexerActionExecutor} which stores input stream offsets + # for all position-dependent lexer actions. + #/ + def fixOffsetBeforeMatch(self, offset:int): + updatedLexerActions = None + for i in range(0, len(self.lexerActions)): + if self.lexerActions[i].isPositionDependent and not isinstance(self.lexerActions[i], LexerIndexedCustomAction): + if updatedLexerActions is None: + updatedLexerActions = [ la for la in self.lexerActions ] + updatedLexerActions[i] = LexerIndexedCustomAction(offset, self.lexerActions[i]) + + if updatedLexerActions is None: + return self + else: + return LexerActionExecutor(updatedLexerActions) + + + # Execute the actions encapsulated by this executor within the context of a + # particular {@link Lexer}. + # + #

      This method calls {@link IntStream#seek} to set the position of the + # {@code input} {@link CharStream} prior to calling + # {@link LexerAction#execute} on a position-dependent action. Before the + # method returns, the input position will be restored to the same position + # it was in when the method was invoked.

      + # + # @param lexer The lexer instance. + # @param input The input stream which is the source for the current token. + # When this method is called, the current {@link IntStream#index} for + # {@code input} should be the start of the following token, i.e. 1 + # character past the end of the current token. + # @param startIndex The token start index. This value may be passed to + # {@link IntStream#seek} to set the {@code input} position to the beginning + # of the token. + #/ + def execute(self, lexer:Lexer, input:InputStream, startIndex:int): + requiresSeek = False + stopIndex = input.index + try: + for lexerAction in self.lexerActions: + if isinstance(lexerAction, LexerIndexedCustomAction): + offset = lexerAction.offset + input.seek(startIndex + offset) + lexerAction = lexerAction.action + requiresSeek = (startIndex + offset) != stopIndex + elif lexerAction.isPositionDependent: + input.seek(stopIndex) + requiresSeek = False + lexerAction.execute(lexer) + finally: + if requiresSeek: + input.seek(stopIndex) + + def __hash__(self): + return self.hashCode + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerActionExecutor): + return False + else: + return self.hashCode == other.hashCode \ + and self.lexerActions == other.lexerActions + +del Lexer \ No newline at end of file diff --git a/src/antlr4/atn/ParserATNSimulator.py b/src/antlr4/atn/ParserATNSimulator.py new file mode 100644 index 00000000..5f932dbe --- /dev/null +++ b/src/antlr4/atn/ParserATNSimulator.py @@ -0,0 +1,1649 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# The embodiment of the adaptive LL(*), ALL(*), parsing strategy. +# +#

      +# The basic complexity of the adaptive strategy makes it harder to understand. +# We begin with ATN simulation to build paths in a DFA. Subsequent prediction +# requests go through the DFA first. If they reach a state without an edge for +# the current symbol, the algorithm fails over to the ATN simulation to +# complete the DFA path for the current input (until it finds a conflict state +# or uniquely predicting state).

      +# +#

      +# All of that is done without using the outer context because we want to create +# a DFA that is not dependent upon the rule invocation stack when we do a +# prediction. One DFA works in all contexts. We avoid using context not +# necessarily because it's slower, although it can be, but because of the DFA +# caching problem. The closure routine only considers the rule invocation stack +# created during prediction beginning in the decision rule. For example, if +# prediction occurs without invoking another rule's ATN, there are no context +# stacks in the configurations. When lack of context leads to a conflict, we +# don't know if it's an ambiguity or a weakness in the strong LL(*) parsing +# strategy (versus full LL(*)).

      +# +#

      +# When SLL yields a configuration set with conflict, we rewind the input and +# retry the ATN simulation, this time using full outer context without adding +# to the DFA. Configuration context stacks will be the full invocation stacks +# from the start rule. If we get a conflict using full context, then we can +# definitively say we have a true ambiguity for that input sequence. If we +# don't get a conflict, it implies that the decision is sensitive to the outer +# context. (It is not context-sensitive in the sense of context-sensitive +# grammars.)

      +# +#

      +# The next time we reach this DFA state with an SLL conflict, through DFA +# simulation, we will again retry the ATN simulation using full context mode. +# This is slow because we can't save the results and have to "interpret" the +# ATN each time we get that input.

      +# +#

      +# CACHING FULL CONTEXT PREDICTIONS

      +# +#

      +# We could cache results from full context to predicted alternative easily and +# that saves a lot of time but doesn't work in presence of predicates. The set +# of visible predicates from the ATN start state changes depending on the +# context, because closure can fall off the end of a rule. I tried to cache +# tuples (stack context, semantic context, predicted alt) but it was slower +# than interpreting and much more complicated. Also required a huge amount of +# memory. The goal is not to create the world's fastest parser anyway. I'd like +# to keep this algorithm simple. By launching multiple threads, we can improve +# the speed of parsing across a large number of files.

      +# +#

      +# There is no strict ordering between the amount of input used by SLL vs LL, +# which makes it really hard to build a cache for full context. Let's say that +# we have input A B C that leads to an SLL conflict with full context X. That +# implies that using X we might only use A B but we could also use A B C D to +# resolve conflict. Input A B C D could predict alternative 1 in one position +# in the input and A B C E could predict alternative 2 in another position in +# input. The conflicting SLL configurations could still be non-unique in the +# full context prediction, which would lead us to requiring more input than the +# original A B C. To make a prediction cache work, we have to track the exact +# input used during the previous prediction. That amounts to a cache that maps +# X to a specific DFA for that context.

      +# +#

      +# Something should be done for left-recursive expression predictions. They are +# likely LL(1) + pred eval. Easier to do the whole SLL unless error and retry +# with full LL thing Sam does.

      +# +#

      +# AVOIDING FULL CONTEXT PREDICTION

      +# +#

      +# We avoid doing full context retry when the outer context is empty, we did not +# dip into the outer context by falling off the end of the decision state rule, +# or when we force SLL mode.

      +# +#

      +# As an example of the not dip into outer context case, consider as super +# constructor calls versus function calls. One grammar might look like +# this:

      +# +#
      +# ctorBody
      +#   : '{' superCall? stat* '}'
      +#   ;
      +# 
      +# +#

      +# Or, you might see something like

      +# +#
      +# stat
      +#   : superCall ';'
      +#   | expression ';'
      +#   | ...
      +#   ;
      +# 
      +# +#

      +# In both cases I believe that no closure operations will dip into the outer +# context. In the first case ctorBody in the worst case will stop at the '}'. +# In the 2nd case it should stop at the ';'. Both cases should stay within the +# entry rule and not dip into the outer context.

      +# +#

      +# PREDICATES

      +# +#

      +# Predicates are always evaluated if present in either SLL or LL both. SLL and +# LL simulation deals with predicates differently. SLL collects predicates as +# it performs closure operations like ANTLR v3 did. It delays predicate +# evaluation until it reaches and accept state. This allows us to cache the SLL +# ATN simulation whereas, if we had evaluated predicates on-the-fly during +# closure, the DFA state configuration sets would be different and we couldn't +# build up a suitable DFA.

      +# +#

      +# When building a DFA accept state during ATN simulation, we evaluate any +# predicates and return the sole semantically valid alternative. If there is +# more than 1 alternative, we report an ambiguity. If there are 0 alternatives, +# we throw an exception. Alternatives without predicates act like they have +# true predicates. The simple way to think about it is to strip away all +# alternatives with false predicates and choose the minimum alternative that +# remains.

      +# +#

      +# When we start in the DFA and reach an accept state that's predicated, we test +# those and return the minimum semantically viable alternative. If no +# alternatives are viable, we throw an exception.

      +# +#

      +# During full LL ATN simulation, closure always evaluates predicates and +# on-the-fly. This is crucial to reducing the configuration set size during +# closure. It hits a landmine when parsing with the Java grammar, for example, +# without this on-the-fly evaluation.

      +# +#

      +# SHARING DFA

      +# +#

      +# All instances of the same parser share the same decision DFAs through a +# static field. Each instance gets its own ATN simulator but they share the +# same {@link #decisionToDFA} field. They also share a +# {@link PredictionContextCache} object that makes sure that all +# {@link PredictionContext} objects are shared among the DFA states. This makes +# a big size difference.

      +# +#

      +# THREAD SAFETY

      +# +#

      +# The {@link ParserATNSimulator} locks on the {@link #decisionToDFA} field when +# it adds a new DFA object to that array. {@link #addDFAEdge} +# locks on the DFA for the current decision when setting the +# {@link DFAState#edges} field. {@link #addDFAState} locks on +# the DFA for the current decision when looking up a DFA state to see if it +# already exists. We must make sure that all requests to add DFA states that +# are equivalent result in the same shared DFA object. This is because lots of +# threads will be trying to update the DFA at once. The +# {@link #addDFAState} method also locks inside the DFA lock +# but this time on the shared context cache when it rebuilds the +# configurations' {@link PredictionContext} objects using cached +# subgraphs/nodes. No other locking occurs, even during DFA simulation. This is +# safe as long as we can guarantee that all threads referencing +# {@code s.edge[t]} get the same physical target {@link DFAState}, or +# {@code null}. Once into the DFA, the DFA simulation does not reference the +# {@link DFA#states} map. It follows the {@link DFAState#edges} field to new +# targets. The DFA simulator will either find {@link DFAState#edges} to be +# {@code null}, to be non-{@code null} and {@code dfa.edges[t]} null, or +# {@code dfa.edges[t]} to be non-null. The +# {@link #addDFAEdge} method could be racing to set the field +# but in either case the DFA simulator works; if {@code null}, and requests ATN +# simulation. It could also race trying to get {@code dfa.edges[t]}, but either +# way it will work because it's not doing a test and set operation.

      +# +#

      +# Starting with SLL then failing to combined SLL/LL (Two-Stage +# Parsing)

      +# +#

      +# Sam pointed out that if SLL does not give a syntax error, then there is no +# point in doing full LL, which is slower. We only have to try LL if we get a +# syntax error. For maximum speed, Sam starts the parser set to pure SLL +# mode with the {@link BailErrorStrategy}:

      +# +#
      +# parser.{@link Parser#getInterpreter() getInterpreter()}.{@link #setPredictionMode setPredictionMode}{@code (}{@link PredictionMode#SLL}{@code )};
      +# parser.{@link Parser#setErrorHandler setErrorHandler}(new {@link BailErrorStrategy}());
      +# 
      +# +#

      +# If it does not get a syntax error, then we're done. If it does get a syntax +# error, we need to retry with the combined SLL/LL strategy.

      +# +#

      +# The reason this works is as follows. If there are no SLL conflicts, then the +# grammar is SLL (at least for that input set). If there is an SLL conflict, +# the full LL analysis must yield a set of viable alternatives which is a +# subset of the alternatives reported by SLL. If the LL set is a singleton, +# then the grammar is LL but not SLL. If the LL set is the same size as the SLL +# set, the decision is SLL. If the LL set has size > 1, then that decision +# is truly ambiguous on the current input. If the LL set is smaller, then the +# SLL conflict resolution might choose an alternative that the full LL would +# rule out as a possibility based upon better context information. If that's +# the case, then the SLL parse will definitely get an error because the full LL +# analysis says it's not viable. If SLL conflict resolution chooses an +# alternative within the LL set, them both SLL and LL would choose the same +# alternative because they both choose the minimum of multiple conflicting +# alternatives.

      +# +#

      +# Let's say we have a set of SLL conflicting alternatives {@code {1, 2, 3}} and +# a smaller LL set called s. If s is {@code {2, 3}}, then SLL +# parsing will get an error because SLL will pursue alternative 1. If +# s is {@code {1, 2}} or {@code {1, 3}} then both SLL and LL will +# choose the same alternative because alternative one is the minimum of either +# set. If s is {@code {2}} or {@code {3}} then SLL will get a syntax +# error. If s is {@code {1}} then SLL will succeed.

      +# +#

      +# Of course, if the input is invalid, then we will get an error for sure in +# both SLL and LL parsing. Erroneous input will therefore require 2 passes over +# the input.

      +# +import sys +from antlr4 import DFA +from antlr4.PredictionContext import PredictionContextCache, PredictionContext, SingletonPredictionContext, \ + PredictionContextFromRuleContext +from antlr4.BufferedTokenStream import TokenStream +from antlr4.Parser import Parser +from antlr4.ParserRuleContext import ParserRuleContext +from antlr4.RuleContext import RuleContext +from antlr4.Token import Token +from antlr4.Utils import str_list +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNConfig import ATNConfig +from antlr4.atn.ATNConfigSet import ATNConfigSet +from antlr4.atn.ATNSimulator import ATNSimulator +from antlr4.atn.ATNState import StarLoopEntryState, DecisionState, RuleStopState, ATNState +from antlr4.atn.PredictionMode import PredictionMode +from antlr4.atn.SemanticContext import SemanticContext, AND, andContext, orContext +from antlr4.atn.Transition import Transition, RuleTransition, ActionTransition, PrecedencePredicateTransition, \ + PredicateTransition, AtomTransition, SetTransition, NotSetTransition +from antlr4.dfa.DFAState import DFAState, PredPrediction +from antlr4.error.Errors import NoViableAltException + + +class ParserATNSimulator(ATNSimulator): + + debug = False + debug_list_atn_decisions = False + dfa_debug = False + retry_debug = False + + + def __init__(self, parser:Parser, atn:ATN, decisionToDFA:list, sharedContextCache:PredictionContextCache): + super().__init__(atn, sharedContextCache) + self.parser = parser + self.decisionToDFA = decisionToDFA + # SLL, LL, or LL + exact ambig detection?# + self.predictionMode = PredictionMode.LL + # LAME globals to avoid parameters!!!!! I need these down deep in predTransition + self._input = None + self._startIndex = 0 + self._outerContext = None + self._dfa = None + # Each prediction operation uses a cache for merge of prediction contexts. + # Don't keep around as it wastes huge amounts of memory. DoubleKeyMap + # isn't synchronized but we're ok since two threads shouldn't reuse same + # parser/atnsim object because it can only handle one input at a time. + # This maps graphs a and b to merged result c. (a,b)→c. We can avoid + # the merge if we ever see a and b again. Note that (b,a)→c should + # also be examined during cache lookup. + # + self.mergeCache = None + + + def reset(self): + pass + + def adaptivePredict(self, input:TokenStream, decision:int, outerContext:ParserRuleContext): + if ParserATNSimulator.debug or ParserATNSimulator.debug_list_atn_decisions: + print("adaptivePredict decision " + str(decision) + + " exec LA(1)==" + self.getLookaheadName(input) + + " line " + str(input.LT(1).line) + ":" + + str(input.LT(1).column)) + self._input = input + self._startIndex = input.index + self._outerContext = outerContext + + dfa = self.decisionToDFA[decision] + self._dfa = dfa + m = input.mark() + index = input.index + + # Now we are certain to have a specific decision's DFA + # But, do we still need an initial state? + try: + if dfa.precedenceDfa: + # the start state for a precedence DFA depends on the current + # parser precedence, and is provided by a DFA method. + s0 = dfa.getPrecedenceStartState(self.parser.getPrecedence()) + else: + # the start state for a "regular" DFA is just s0 + s0 = dfa.s0 + + if s0 is None: + if outerContext is None: + outerContext = ParserRuleContext.EMPTY + if ParserATNSimulator.debug or ParserATNSimulator.debug_list_atn_decisions: + print("predictATN decision " + str(dfa.decision) + + " exec LA(1)==" + self.getLookaheadName(input) + + ", outerContext=" + outerContext.toString(self.parser.literalNames, None)) + + fullCtx = False + s0_closure = self.computeStartState(dfa.atnStartState, ParserRuleContext.EMPTY, fullCtx) + + if dfa.precedenceDfa: + # If this is a precedence DFA, we use applyPrecedenceFilter + # to convert the computed start state to a precedence start + # state. We then use DFA.setPrecedenceStartState to set the + # appropriate start state for the precedence level rather + # than simply setting DFA.s0. + # + dfa.s0.configs = s0_closure # not used for prediction but useful to know start configs anyway + s0_closure = self.applyPrecedenceFilter(s0_closure) + s0 = self.addDFAState(dfa, DFAState(configs=s0_closure)) + dfa.setPrecedenceStartState(self.parser.getPrecedence(), s0) + else: + s0 = self.addDFAState(dfa, DFAState(configs=s0_closure)) + dfa.s0 = s0 + + alt = self.execATN(dfa, s0, input, index, outerContext) + if ParserATNSimulator.debug: + print("DFA after predictATN: " + dfa.toString(self.parser.literalNames)) + return alt + finally: + self._dfa = None + self.mergeCache = None # wack cache after each prediction + input.seek(index) + input.release(m) + + # Performs ATN simulation to compute a predicted alternative based + # upon the remaining input, but also updates the DFA cache to avoid + # having to traverse the ATN again for the same input sequence. + + # There are some key conditions we're looking for after computing a new + # set of ATN configs (proposed DFA state): + # if the set is empty, there is no viable alternative for current symbol + # does the state uniquely predict an alternative? + # does the state have a conflict that would prevent us from + # putting it on the work list? + + # We also have some key operations to do: + # add an edge from previous DFA state to potentially new DFA state, D, + # upon current symbol but only if adding to work list, which means in all + # cases except no viable alternative (and possibly non-greedy decisions?) + # collecting predicates and adding semantic context to DFA accept states + # adding rule context to context-sensitive DFA accept states + # consuming an input symbol + # reporting a conflict + # reporting an ambiguity + # reporting a context sensitivity + # reporting insufficient predicates + + # cover these cases: + # dead end + # single alt + # single alt + preds + # conflict + # conflict + preds + # + def execATN(self, dfa:DFA, s0:DFAState, input:TokenStream, startIndex:int, outerContext:ParserRuleContext ): + if ParserATNSimulator.debug or ParserATNSimulator.debug_list_atn_decisions: + print("execATN decision " + str(dfa.decision) + + " exec LA(1)==" + self.getLookaheadName(input) + + " line " + str(input.LT(1).line) + ":" + str(input.LT(1).column)) + + previousD = s0 + + if ParserATNSimulator.debug: + print("s0 = " + str(s0)) + + t = input.LA(1) + + while True: # while more work + D = self.getExistingTargetState(previousD, t) + if D is None: + D = self.computeTargetState(dfa, previousD, t) + if D is self.ERROR: + # if any configs in previous dipped into outer context, that + # means that input up to t actually finished entry rule + # at least for SLL decision. Full LL doesn't dip into outer + # so don't need special case. + # We will get an error no matter what so delay until after + # decision; better error message. Also, no reachable target + # ATN states in SLL implies LL will also get nowhere. + # If conflict in states that dip out, choose min since we + # will get error no matter what. + e = self.noViableAlt(input, outerContext, previousD.configs, startIndex) + input.seek(startIndex) + alt = self.getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule(previousD.configs, outerContext) + if alt!=ATN.INVALID_ALT_NUMBER: + return alt + raise e + + if D.requiresFullContext and self.predictionMode != PredictionMode.SLL: + # IF PREDS, MIGHT RESOLVE TO SINGLE ALT => SLL (or syntax error) + conflictingAlts = D.configs.conflictingAlts + if D.predicates is not None: + if ParserATNSimulator.debug: + print("DFA state has preds in DFA sim LL failover") + conflictIndex = input.index + if conflictIndex != startIndex: + input.seek(startIndex) + + conflictingAlts = self.evalSemanticContext(D.predicates, outerContext, True) + if len(conflictingAlts)==1: + if ParserATNSimulator.debug: + print("Full LL avoided") + return min(conflictingAlts) + + if conflictIndex != startIndex: + # restore the index so reporting the fallback to full + # context occurs with the index at the correct spot + input.seek(conflictIndex) + + if ParserATNSimulator.dfa_debug: + print("ctx sensitive state " + str(outerContext) +" in " + str(D)) + fullCtx = True + s0_closure = self.computeStartState(dfa.atnStartState, outerContext, fullCtx) + self.reportAttemptingFullContext(dfa, conflictingAlts, D.configs, startIndex, input.index) + alt = self.execATNWithFullContext(dfa, D, s0_closure, input, startIndex, outerContext) + return alt + + if D.isAcceptState: + if D.predicates is None: + return D.prediction + + stopIndex = input.index + input.seek(startIndex) + alts = self.evalSemanticContext(D.predicates, outerContext, True) + if len(alts)==0: + raise self.noViableAlt(input, outerContext, D.configs, startIndex) + elif len(alts)==1: + return min(alts) + else: + # report ambiguity after predicate evaluation to make sure the correct + # set of ambig alts is reported. + self.reportAmbiguity(dfa, D, startIndex, stopIndex, False, alts, D.configs) + return min(alts) + + previousD = D + + if t != Token.EOF: + input.consume() + t = input.LA(1) + + # + # Get an existing target state for an edge in the DFA. If the target state + # for the edge has not yet been computed or is otherwise not available, + # this method returns {@code null}. + # + # @param previousD The current DFA state + # @param t The next input symbol + # @return The existing target DFA state for the given input symbol + # {@code t}, or {@code null} if the target state for this edge is not + # already cached + # + def getExistingTargetState(self, previousD:DFAState, t:int): + edges = previousD.edges + if edges is None or t + 1 < 0 or t + 1 >= len(edges): + return None + else: + return edges[t + 1] + + # + # Compute a target state for an edge in the DFA, and attempt to add the + # computed state and corresponding edge to the DFA. + # + # @param dfa The DFA + # @param previousD The current DFA state + # @param t The next input symbol + # + # @return The computed target DFA state for the given input symbol + # {@code t}. If {@code t} does not lead to a valid DFA state, this method + # returns {@link #ERROR}. + # + def computeTargetState(self, dfa:DFA, previousD:DFAState, t:int): + reach = self.computeReachSet(previousD.configs, t, False) + if reach is None: + self.addDFAEdge(dfa, previousD, t, self.ERROR) + return self.ERROR + + # create new target state; we'll add to DFA after it's complete + D = DFAState(configs=reach) + + predictedAlt = self.getUniqueAlt(reach) + + if ParserATNSimulator.debug: + altSubSets = PredictionMode.getConflictingAltSubsets(reach) + print("SLL altSubSets=" + str(altSubSets) + ", configs=" + str(reach) + + ", predict=" + str(predictedAlt) + ", allSubsetsConflict=" + + str(PredictionMode.allSubsetsConflict(altSubSets)) + ", conflictingAlts=" + + str(self.getConflictingAlts(reach))) + + if predictedAlt!=ATN.INVALID_ALT_NUMBER: + # NO CONFLICT, UNIQUELY PREDICTED ALT + D.isAcceptState = True + D.configs.uniqueAlt = predictedAlt + D.prediction = predictedAlt + elif PredictionMode.hasSLLConflictTerminatingPrediction(self.predictionMode, reach): + # MORE THAN ONE VIABLE ALTERNATIVE + D.configs.conflictingAlts = self.getConflictingAlts(reach) + D.requiresFullContext = True + # in SLL-only mode, we will stop at this state and return the minimum alt + D.isAcceptState = True + D.prediction = min(D.configs.conflictingAlts) + + if D.isAcceptState and D.configs.hasSemanticContext: + self.predicateDFAState(D, self.atn.getDecisionState(dfa.decision)) + if D.predicates is not None: + D.prediction = ATN.INVALID_ALT_NUMBER + + # all adds to dfa are done after we've created full D state + D = self.addDFAEdge(dfa, previousD, t, D) + return D + + def predicateDFAState(self, dfaState:DFAState, decisionState:DecisionState): + # We need to test all predicates, even in DFA states that + # uniquely predict alternative. + nalts = len(decisionState.transitions) + # Update DFA so reach becomes accept state with (predicate,alt) + # pairs if preds found for conflicting alts + altsToCollectPredsFrom = self.getConflictingAltsOrUniqueAlt(dfaState.configs) + altToPred = self.getPredsForAmbigAlts(altsToCollectPredsFrom, dfaState.configs, nalts) + if altToPred is not None: + dfaState.predicates = self.getPredicatePredictions(altsToCollectPredsFrom, altToPred) + dfaState.prediction = ATN.INVALID_ALT_NUMBER # make sure we use preds + else: + # There are preds in configs but they might go away + # when OR'd together like {p}? || NONE == NONE. If neither + # alt has preds, resolve to min alt + dfaState.prediction = min(altsToCollectPredsFrom) + + # comes back with reach.uniqueAlt set to a valid alt + def execATNWithFullContext(self, dfa:DFA, D:DFAState, # how far we got before failing over + s0:ATNConfigSet, + input:TokenStream, + startIndex:int, + outerContext:ParserRuleContext): + if ParserATNSimulator.debug or ParserATNSimulator.debug_list_atn_decisions: + print("execATNWithFullContext", str(s0)) + fullCtx = True + foundExactAmbig = False + reach = None + previous = s0 + input.seek(startIndex) + t = input.LA(1) + predictedAlt = -1 + while (True): # while more work + reach = self.computeReachSet(previous, t, fullCtx) + if reach is None: + # if any configs in previous dipped into outer context, that + # means that input up to t actually finished entry rule + # at least for LL decision. Full LL doesn't dip into outer + # so don't need special case. + # We will get an error no matter what so delay until after + # decision; better error message. Also, no reachable target + # ATN states in SLL implies LL will also get nowhere. + # If conflict in states that dip out, choose min since we + # will get error no matter what. + e = self.noViableAlt(input, outerContext, previous, startIndex) + input.seek(startIndex) + alt = self.getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule(previous, outerContext) + if alt!=ATN.INVALID_ALT_NUMBER: + return alt + else: + raise e + + altSubSets = PredictionMode.getConflictingAltSubsets(reach) + if ParserATNSimulator.debug: + print("LL altSubSets=" + str(altSubSets) + ", predict=" + + str(PredictionMode.getUniqueAlt(altSubSets)) + ", resolvesToJustOneViableAlt=" + + str(PredictionMode.resolvesToJustOneViableAlt(altSubSets))) + + reach.uniqueAlt = self.getUniqueAlt(reach) + # unique prediction? + if reach.uniqueAlt!=ATN.INVALID_ALT_NUMBER: + predictedAlt = reach.uniqueAlt + break + elif self.predictionMode is not PredictionMode.LL_EXACT_AMBIG_DETECTION: + predictedAlt = PredictionMode.resolvesToJustOneViableAlt(altSubSets) + if predictedAlt != ATN.INVALID_ALT_NUMBER: + break + else: + # In exact ambiguity mode, we never try to terminate early. + # Just keeps scarfing until we know what the conflict is + if PredictionMode.allSubsetsConflict(altSubSets) and PredictionMode.allSubsetsEqual(altSubSets): + foundExactAmbig = True + predictedAlt = PredictionMode.getSingleViableAlt(altSubSets) + break + # else there are multiple non-conflicting subsets or + # we're not sure what the ambiguity is yet. + # So, keep going. + + previous = reach + if t != Token.EOF: + input.consume() + t = input.LA(1) + + # If the configuration set uniquely predicts an alternative, + # without conflict, then we know that it's a full LL decision + # not SLL. + if reach.uniqueAlt != ATN.INVALID_ALT_NUMBER : + self.reportContextSensitivity(dfa, predictedAlt, reach, startIndex, input.index) + return predictedAlt + + # We do not check predicates here because we have checked them + # on-the-fly when doing full context prediction. + + # + # In non-exact ambiguity detection mode, we might actually be able to + # detect an exact ambiguity, but I'm not going to spend the cycles + # needed to check. We only emit ambiguity warnings in exact ambiguity + # mode. + # + # For example, we might know that we have conflicting configurations. + # But, that does not mean that there is no way forward without a + # conflict. It's possible to have nonconflicting alt subsets as in: + + # altSubSets=[{1, 2}, {1, 2}, {1}, {1, 2}] + + # from + # + # [(17,1,[5 $]), (13,1,[5 10 $]), (21,1,[5 10 $]), (11,1,[$]), + # (13,2,[5 10 $]), (21,2,[5 10 $]), (11,2,[$])] + # + # In this case, (17,1,[5 $]) indicates there is some next sequence that + # would resolve this without conflict to alternative 1. Any other viable + # next sequence, however, is associated with a conflict. We stop + # looking for input because no amount of further lookahead will alter + # the fact that we should predict alternative 1. We just can't say for + # sure that there is an ambiguity without looking further. + + self.reportAmbiguity(dfa, D, startIndex, input.index, foundExactAmbig, None, reach) + + return predictedAlt + + def computeReachSet(self, closure:ATNConfigSet, t:int, fullCtx:bool): + if ParserATNSimulator.debug: + print("in computeReachSet, starting closure: " + str(closure)) + + if self.mergeCache is None: + self.mergeCache = dict() + + intermediate = ATNConfigSet(fullCtx) + + # Configurations already in a rule stop state indicate reaching the end + # of the decision rule (local context) or end of the start rule (full + # context). Once reached, these configurations are never updated by a + # closure operation, so they are handled separately for the performance + # advantage of having a smaller intermediate set when calling closure. + # + # For full-context reach operations, separate handling is required to + # ensure that the alternative matching the longest overall sequence is + # chosen when multiple such configurations can match the input. + + skippedStopStates = None + + # First figure out where we can reach on input t + for c in closure: + if ParserATNSimulator.debug: + print("testing " + self.getTokenName(t) + " at " + str(c)) + + if isinstance(c.state, RuleStopState): + if fullCtx or t == Token.EOF: + if skippedStopStates is None: + skippedStopStates = list() + skippedStopStates.append(c) + continue + + for trans in c.state.transitions: + target = self.getReachableTarget(trans, t) + if target is not None: + intermediate.add(ATNConfig(state=target, config=c), self.mergeCache) + + # Now figure out where the reach operation can take us... + + reach = None + + # This block optimizes the reach operation for intermediate sets which + # trivially indicate a termination state for the overall + # adaptivePredict operation. + # + # The conditions assume that intermediate + # contains all configurations relevant to the reach set, but this + # condition is not true when one or more configurations have been + # withheld in skippedStopStates, or when the current symbol is EOF. + # + if skippedStopStates is None and t!=Token.EOF: + if len(intermediate)==1: + # Don't pursue the closure if there is just one state. + # It can only have one alternative; just add to result + # Also don't pursue the closure if there is unique alternative + # among the configurations. + reach = intermediate + elif self.getUniqueAlt(intermediate)!=ATN.INVALID_ALT_NUMBER: + # Also don't pursue the closure if there is unique alternative + # among the configurations. + reach = intermediate + + # If the reach set could not be trivially determined, perform a closure + # operation on the intermediate set to compute its initial value. + # + if reach is None: + reach = ATNConfigSet(fullCtx) + closureBusy = set() + treatEofAsEpsilon = t == Token.EOF + for c in intermediate: + self.closure(c, reach, closureBusy, False, fullCtx, treatEofAsEpsilon) + + if t == Token.EOF: + # After consuming EOF no additional input is possible, so we are + # only interested in configurations which reached the end of the + # decision rule (local context) or end of the start rule (full + # context). Update reach to contain only these configurations. This + # handles both explicit EOF transitions in the grammar and implicit + # EOF transitions following the end of the decision or start rule. + # + # When reach==intermediate, no closure operation was performed. In + # this case, removeAllConfigsNotInRuleStopState needs to check for + # reachable rule stop states as well as configurations already in + # a rule stop state. + # + # This is handled before the configurations in skippedStopStates, + # because any configurations potentially added from that list are + # already guaranteed to meet this condition whether or not it's + # required. + # + reach = self.removeAllConfigsNotInRuleStopState(reach, reach is intermediate) + + # If skippedStopStates is not null, then it contains at least one + # configuration. For full-context reach operations, these + # configurations reached the end of the start rule, in which case we + # only add them back to reach if no configuration during the current + # closure operation reached such a state. This ensures adaptivePredict + # chooses an alternative matching the longest overall sequence when + # multiple alternatives are viable. + # + if skippedStopStates is not None and ( (not fullCtx) or (not PredictionMode.hasConfigInRuleStopState(reach))): + for c in skippedStopStates: + reach.add(c, self.mergeCache) + if len(reach)==0: + return None + else: + return reach + + # + # Return a configuration set containing only the configurations from + # {@code configs} which are in a {@link RuleStopState}. If all + # configurations in {@code configs} are already in a rule stop state, this + # method simply returns {@code configs}. + # + #

      When {@code lookToEndOfRule} is true, this method uses + # {@link ATN#nextTokens} for each configuration in {@code configs} which is + # not already in a rule stop state to see if a rule stop state is reachable + # from the configuration via epsilon-only transitions.

      + # + # @param configs the configuration set to update + # @param lookToEndOfRule when true, this method checks for rule stop states + # reachable by epsilon-only transitions from each configuration in + # {@code configs}. + # + # @return {@code configs} if all configurations in {@code configs} are in a + # rule stop state, otherwise return a new configuration set containing only + # the configurations from {@code configs} which are in a rule stop state + # + def removeAllConfigsNotInRuleStopState(self, configs:ATNConfigSet, lookToEndOfRule:bool): + if PredictionMode.allConfigsInRuleStopStates(configs): + return configs + result = ATNConfigSet(configs.fullCtx) + for config in configs: + if isinstance(config.state, RuleStopState): + result.add(config, self.mergeCache) + continue + if lookToEndOfRule and config.state.epsilonOnlyTransitions: + nextTokens = self.atn.nextTokens(config.state) + if Token.EPSILON in nextTokens: + endOfRuleState = self.atn.ruleToStopState[config.state.ruleIndex] + result.add(ATNConfig(state=endOfRuleState, config=config), self.mergeCache) + return result + + def computeStartState(self, p:ATNState, ctx:RuleContext, fullCtx:bool): + # always at least the implicit call to start rule + initialContext = PredictionContextFromRuleContext(self.atn, ctx) + configs = ATNConfigSet(fullCtx) + + for i in range(0, len(p.transitions)): + target = p.transitions[i].target + c = ATNConfig(target, i+1, initialContext) + closureBusy = set() + self.closure(c, configs, closureBusy, True, fullCtx, False) + return configs + + # + # This method transforms the start state computed by + # {@link #computeStartState} to the special start state used by a + # precedence DFA for a particular precedence value. The transformation + # process applies the following changes to the start state's configuration + # set. + # + #
        + #
      1. Evaluate the precedence predicates for each configuration using + # {@link SemanticContext#evalPrecedence}.
      2. + #
      3. Remove all configurations which predict an alternative greater than + # 1, for which another configuration that predicts alternative 1 is in the + # same ATN state with the same prediction context. This transformation is + # valid for the following reasons: + #
          + #
        • The closure block cannot contain any epsilon transitions which bypass + # the body of the closure, so all states reachable via alternative 1 are + # part of the precedence alternatives of the transformed left-recursive + # rule.
        • + #
        • The "primary" portion of a left recursive rule cannot contain an + # epsilon transition, so the only way an alternative other than 1 can exist + # in a state that is also reachable via alternative 1 is by nesting calls + # to the left-recursive rule, with the outer calls not being at the + # preferred precedence level.
        • + #
        + #
      4. + #
      + # + #

      + # The prediction context must be considered by this filter to address + # situations like the following. + #

      + # + #
      +    # grammar TA;
      +    # prog: statement* EOF;
      +    # statement: letterA | statement letterA 'b' ;
      +    # letterA: 'a';
      +    # 
      + #
      + #

      + # If the above grammar, the ATN state immediately before the token + # reference {@code 'a'} in {@code letterA} is reachable from the left edge + # of both the primary and closure blocks of the left-recursive rule + # {@code statement}. The prediction context associated with each of these + # configurations distinguishes between them, and prevents the alternative + # which stepped out to {@code prog} (and then back in to {@code statement} + # from being eliminated by the filter. + #

      + # + # @param configs The configuration set computed by + # {@link #computeStartState} as the start state for the DFA. + # @return The transformed configuration set representing the start state + # for a precedence DFA at a particular precedence level (determined by + # calling {@link Parser#getPrecedence}). + # + def applyPrecedenceFilter(self, configs:ATNConfigSet): + statesFromAlt1 = dict() + configSet = ATNConfigSet(configs.fullCtx) + for config in configs: + # handle alt 1 first + if config.alt != 1: + continue + updatedContext = config.semanticContext.evalPrecedence(self.parser, self._outerContext) + if updatedContext is None: + # the configuration was eliminated + continue + + statesFromAlt1[config.state.stateNumber] = config.context + if updatedContext is not config.semanticContext: + configSet.add(ATNConfig(config=config, semantic=updatedContext), self.mergeCache) + else: + configSet.add(config, self.mergeCache) + + for config in configs: + if config.alt == 1: + # already handled + continue + + # In the future, this elimination step could be updated to also + # filter the prediction context for alternatives predicting alt>1 + # (basically a graph subtraction algorithm). + # + if not config.precedenceFilterSuppressed: + context = statesFromAlt1.get(config.state.stateNumber, None) + if context==config.context: + # eliminated + continue + + configSet.add(config, self.mergeCache) + + return configSet + + def getReachableTarget(self, trans:Transition, ttype:int): + if trans.matches(ttype, 0, self.atn.maxTokenType): + return trans.target + else: + return None + + def getPredsForAmbigAlts(self, ambigAlts:set, configs:ATNConfigSet, nalts:int): + # REACH=[1|1|[]|0:0, 1|2|[]|0:1] + # altToPred starts as an array of all null contexts. The entry at index i + # corresponds to alternative i. altToPred[i] may have one of three values: + # 1. null: no ATNConfig c is found such that c.alt==i + # 2. SemanticContext.NONE: At least one ATNConfig c exists such that + # c.alt==i and c.semanticContext==SemanticContext.NONE. In other words, + # alt i has at least one unpredicated config. + # 3. Non-NONE Semantic Context: There exists at least one, and for all + # ATNConfig c such that c.alt==i, c.semanticContext!=SemanticContext.NONE. + # + # From this, it is clear that NONE||anything==NONE. + # + altToPred = [None] * (nalts + 1) + for c in configs: + if c.alt in ambigAlts: + altToPred[c.alt] = orContext(altToPred[c.alt], c.semanticContext) + + nPredAlts = 0 + for i in range(1, nalts+1): + if altToPred[i] is None: + altToPred[i] = SemanticContext.NONE + elif altToPred[i] is not SemanticContext.NONE: + nPredAlts += 1 + + # nonambig alts are null in altToPred + if nPredAlts==0: + altToPred = None + if ParserATNSimulator.debug: + print("getPredsForAmbigAlts result " + str_list(altToPred)) + return altToPred + + def getPredicatePredictions(self, ambigAlts:set, altToPred:list): + pairs = [] + containsPredicate = False + for i in range(1, len(altToPred)): + pred = altToPred[i] + # unpredicated is indicated by SemanticContext.NONE + if ambigAlts is not None and i in ambigAlts: + pairs.append(PredPrediction(pred, i)) + if pred is not SemanticContext.NONE: + containsPredicate = True + + if not containsPredicate: + return None + + return pairs + + # + # This method is used to improve the localization of error messages by + # choosing an alternative rather than throwing a + # {@link NoViableAltException} in particular prediction scenarios where the + # {@link #ERROR} state was reached during ATN simulation. + # + #

      + # The default implementation of this method uses the following + # algorithm to identify an ATN configuration which successfully parsed the + # decision entry rule. Choosing such an alternative ensures that the + # {@link ParserRuleContext} returned by the calling rule will be complete + # and valid, and the syntax error will be reported later at a more + # localized location.

      + # + #
        + #
      • If a syntactically valid path or paths reach the end of the decision rule and + # they are semantically valid if predicated, return the min associated alt.
      • + #
      • Else, if a semantically invalid but syntactically valid path exist + # or paths exist, return the minimum associated alt. + #
      • + #
      • Otherwise, return {@link ATN#INVALID_ALT_NUMBER}.
      • + #
      + # + #

      + # In some scenarios, the algorithm described above could predict an + # alternative which will result in a {@link FailedPredicateException} in + # the parser. Specifically, this could occur if the only configuration + # capable of successfully parsing to the end of the decision rule is + # blocked by a semantic predicate. By choosing this alternative within + # {@link #adaptivePredict} instead of throwing a + # {@link NoViableAltException}, the resulting + # {@link FailedPredicateException} in the parser will identify the specific + # predicate which is preventing the parser from successfully parsing the + # decision rule, which helps developers identify and correct logic errors + # in semantic predicates. + #

      + # + # @param configs The ATN configurations which were valid immediately before + # the {@link #ERROR} state was reached + # @param outerContext The is the \gamma_0 initial parser context from the paper + # or the parser stack at the instant before prediction commences. + # + # @return The value to return from {@link #adaptivePredict}, or + # {@link ATN#INVALID_ALT_NUMBER} if a suitable alternative was not + # identified and {@link #adaptivePredict} should report an error instead. + # + def getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule(self, configs:ATNConfigSet, outerContext:ParserRuleContext): + semValidConfigs, semInvalidConfigs = self.splitAccordingToSemanticValidity(configs, outerContext) + alt = self.getAltThatFinishedDecisionEntryRule(semValidConfigs) + if alt!=ATN.INVALID_ALT_NUMBER: # semantically/syntactically viable path exists + return alt + # Is there a syntactically valid path with a failed pred? + if len(semInvalidConfigs)>0: + alt = self.getAltThatFinishedDecisionEntryRule(semInvalidConfigs) + if alt!=ATN.INVALID_ALT_NUMBER: # syntactically viable path exists + return alt + return ATN.INVALID_ALT_NUMBER + + def getAltThatFinishedDecisionEntryRule(self, configs:ATNConfigSet): + alts = set() + for c in configs: + if c.reachesIntoOuterContext>0 or (isinstance(c.state, RuleStopState) and c.context.hasEmptyPath() ): + alts.add(c.alt) + if len(alts)==0: + return ATN.INVALID_ALT_NUMBER + else: + return min(alts) + + # Walk the list of configurations and split them according to + # those that have preds evaluating to true/false. If no pred, assume + # true pred and include in succeeded set. Returns Pair of sets. + # + # Create a new set so as not to alter the incoming parameter. + # + # Assumption: the input stream has been restored to the starting point + # prediction, which is where predicates need to evaluate. + # + def splitAccordingToSemanticValidity(self, configs:ATNConfigSet, outerContext:ParserRuleContext): + succeeded = ATNConfigSet(configs.fullCtx) + failed = ATNConfigSet(configs.fullCtx) + for c in configs: + if c.semanticContext is not SemanticContext.NONE: + predicateEvaluationResult = c.semanticContext.eval(self.parser, outerContext) + if predicateEvaluationResult: + succeeded.add(c) + else: + failed.add(c) + else: + succeeded.add(c) + return (succeeded,failed) + + # Look through a list of predicate/alt pairs, returning alts for the + # pairs that win. A {@code NONE} predicate indicates an alt containing an + # unpredicated config which behaves as "always true." If !complete + # then we stop at the first predicate that evaluates to true. This + # includes pairs with null predicates. + # + def evalSemanticContext(self, predPredictions:list, outerContext:ParserRuleContext, complete:bool): + predictions = set() + for pair in predPredictions: + if pair.pred is SemanticContext.NONE: + predictions.add(pair.alt) + if not complete: + break + continue + predicateEvaluationResult = pair.pred.eval(self.parser, outerContext) + if ParserATNSimulator.debug or ParserATNSimulator.dfa_debug: + print("eval pred " + str(pair) + "=" + str(predicateEvaluationResult)) + + if predicateEvaluationResult: + if ParserATNSimulator.debug or ParserATNSimulator.dfa_debug: + print("PREDICT " + str(pair.alt)) + predictions.add(pair.alt) + if not complete: + break + return predictions + + + # TODO: If we are doing predicates, there is no point in pursuing + # closure operations if we reach a DFA state that uniquely predicts + # alternative. We will not be caching that DFA state and it is a + # waste to pursue the closure. Might have to advance when we do + # ambig detection thought :( + # + + def closure(self, config:ATNConfig, configs:ATNConfigSet, closureBusy:set, collectPredicates:bool, fullCtx:bool, treatEofAsEpsilon:bool): + initialDepth = 0 + self.closureCheckingStopState(config, configs, closureBusy, collectPredicates, + fullCtx, initialDepth, treatEofAsEpsilon) + + + def closureCheckingStopState(self, config:ATNConfig, configs:ATNConfigSet, closureBusy:set, collectPredicates:bool, fullCtx:bool, depth:int, treatEofAsEpsilon:bool): + if ParserATNSimulator.debug: + print("closure(" + str(config) + ")") + + if isinstance(config.state, RuleStopState): + # We hit rule end. If we have context info, use it + # run thru all possible stack tops in ctx + if not config.context.isEmpty(): + for i in range(0, len(config.context)): + state = config.context.getReturnState(i) + if state is PredictionContext.EMPTY_RETURN_STATE: + if fullCtx: + configs.add(ATNConfig(state=config.state, context=PredictionContext.EMPTY, config=config), self.mergeCache) + continue + else: + # we have no context info, just chase follow links (if greedy) + if ParserATNSimulator.debug: + print("FALLING off rule " + self.getRuleName(config.state.ruleIndex)) + self.closure_(config, configs, closureBusy, collectPredicates, + fullCtx, depth, treatEofAsEpsilon) + continue + returnState = self.atn.states[state] + newContext = config.context.getParent(i) # "pop" return state + c = ATNConfig(state=returnState, alt=config.alt, context=newContext, semantic=config.semanticContext) + # While we have context to pop back from, we may have + # gotten that context AFTER having falling off a rule. + # Make sure we track that we are now out of context. + c.reachesIntoOuterContext = config.reachesIntoOuterContext + self.closureCheckingStopState(c, configs, closureBusy, collectPredicates, fullCtx, depth - 1, treatEofAsEpsilon) + return + elif fullCtx: + # reached end of start rule + configs.add(config, self.mergeCache) + return + else: + # else if we have no context info, just chase follow links (if greedy) + if ParserATNSimulator.debug: + print("FALLING off rule " + self.getRuleName(config.state.ruleIndex)) + + self.closure_(config, configs, closureBusy, collectPredicates, fullCtx, depth, treatEofAsEpsilon) + + # Do the actual work of walking epsilon edges# + def closure_(self, config:ATNConfig, configs:ATNConfigSet, closureBusy:set, collectPredicates:bool, fullCtx:bool, depth:int, treatEofAsEpsilon:bool): + p = config.state + # optimization + if not p.epsilonOnlyTransitions: + configs.add(config, self.mergeCache) + # make sure to not return here, because EOF transitions can act as + # both epsilon transitions and non-epsilon transitions. + + first = True + for t in p.transitions: + if first: + first = False + if self.canDropLoopEntryEdgeInLeftRecursiveRule(config): + continue + + continueCollecting = collectPredicates and not isinstance(t, ActionTransition) + c = self.getEpsilonTarget(config, t, continueCollecting, depth == 0, fullCtx, treatEofAsEpsilon) + if c is not None: + newDepth = depth + if isinstance( config.state, RuleStopState): + # target fell off end of rule; mark resulting c as having dipped into outer context + # We can't get here if incoming config was rule stop and we had context + # track how far we dip into outer context. Might + # come in handy and we avoid evaluating context dependent + # preds if this is > 0. + if self._dfa is not None and self._dfa.precedenceDfa: + if t.outermostPrecedenceReturn == self._dfa.atnStartState.ruleIndex: + c.precedenceFilterSuppressed = True + c.reachesIntoOuterContext += 1 + if c in closureBusy: + # avoid infinite recursion for right-recursive rules + continue + closureBusy.add(c) + configs.dipsIntoOuterContext = True # TODO: can remove? only care when we add to set per middle of this method + newDepth -= 1 + if ParserATNSimulator.debug: + print("dips into outer ctx: " + str(c)) + else: + if not t.isEpsilon: + if c in closureBusy: + # avoid infinite recursion for EOF* and EOF+ + continue + closureBusy.add(c) + if isinstance(t, RuleTransition): + # latch when newDepth goes negative - once we step out of the entry context we can't return + if newDepth >= 0: + newDepth += 1 + + self.closureCheckingStopState(c, configs, closureBusy, continueCollecting, fullCtx, newDepth, treatEofAsEpsilon) + + + + # Implements first-edge (loop entry) elimination as an optimization + # during closure operations. See antlr/antlr4#1398. + # + # The optimization is to avoid adding the loop entry config when + # the exit path can only lead back to the same + # StarLoopEntryState after popping context at the rule end state + # (traversing only epsilon edges, so we're still in closure, in + # this same rule). + # + # We need to detect any state that can reach loop entry on + # epsilon w/o exiting rule. We don't have to look at FOLLOW + # links, just ensure that all stack tops for config refer to key + # states in LR rule. + # + # To verify we are in the right situation we must first check + # closure is at a StarLoopEntryState generated during LR removal. + # Then we check that each stack top of context is a return state + # from one of these cases: + # + # 1. 'not' expr, '(' type ')' expr. The return state points at loop entry state + # 2. expr op expr. The return state is the block end of internal block of (...)* + # 3. 'between' expr 'and' expr. The return state of 2nd expr reference. + # That state points at block end of internal block of (...)*. + # 4. expr '?' expr ':' expr. The return state points at block end, + # which points at loop entry state. + # + # If any is true for each stack top, then closure does not add a + # config to the current config set for edge[0], the loop entry branch. + # + # Conditions fail if any context for the current config is: + # + # a. empty (we'd fall out of expr to do a global FOLLOW which could + # even be to some weird spot in expr) or, + # b. lies outside of expr or, + # c. lies within expr but at a state not the BlockEndState + # generated during LR removal + # + # Do we need to evaluate predicates ever in closure for this case? + # + # No. Predicates, including precedence predicates, are only + # evaluated when computing a DFA start state. I.e., only before + # the lookahead (but not parser) consumes a token. + # + # There are no epsilon edges allowed in LR rule alt blocks or in + # the "primary" part (ID here). If closure is in + # StarLoopEntryState any lookahead operation will have consumed a + # token as there are no epsilon-paths that lead to + # StarLoopEntryState. We do not have to evaluate predicates + # therefore if we are in the generated StarLoopEntryState of a LR + # rule. Note that when making a prediction starting at that + # decision point, decision d=2, compute-start-state performs + # closure starting at edges[0], edges[1] emanating from + # StarLoopEntryState. That means it is not performing closure on + # StarLoopEntryState during compute-start-state. + # + # How do we know this always gives same prediction answer? + # + # Without predicates, loop entry and exit paths are ambiguous + # upon remaining input +b (in, say, a+b). Either paths lead to + # valid parses. Closure can lead to consuming + immediately or by + # falling out of this call to expr back into expr and loop back + # again to StarLoopEntryState to match +b. In this special case, + # we choose the more efficient path, which is to take the bypass + # path. + # + # The lookahead language has not changed because closure chooses + # one path over the other. Both paths lead to consuming the same + # remaining input during a lookahead operation. If the next token + # is an operator, lookahead will enter the choice block with + # operators. If it is not, lookahead will exit expr. Same as if + # closure had chosen to enter the choice block immediately. + # + # Closure is examining one config (some loopentrystate, some alt, + # context) which means it is considering exactly one alt. Closure + # always copies the same alt to any derived configs. + # + # How do we know this optimization doesn't mess up precedence in + # our parse trees? + # + # Looking through expr from left edge of stat only has to confirm + # that an input, say, a+b+c; begins with any valid interpretation + # of an expression. The precedence actually doesn't matter when + # making a decision in stat seeing through expr. It is only when + # parsing rule expr that we must use the precedence to get the + # right interpretation and, hence, parse tree. + # + # @since 4.6 + # + def canDropLoopEntryEdgeInLeftRecursiveRule(self, config): + # return False + p = config.state + # First check to see if we are in StarLoopEntryState generated during + # left-recursion elimination. For efficiency, also check if + # the context has an empty stack case. If so, it would mean + # global FOLLOW so we can't perform optimization + # Are we the special loop entry/exit state? or SLL wildcard + if p.stateType != ATNState.STAR_LOOP_ENTRY \ + or not p.isPrecedenceDecision \ + or config.context.isEmpty() \ + or config.context.hasEmptyPath(): + return False + + # Require all return states to return back to the same rule + # that p is in. + numCtxs = len(config.context) + for i in range(0, numCtxs): # for each stack context + returnState = self.atn.states[config.context.getReturnState(i)] + if returnState.ruleIndex != p.ruleIndex: + return False + + decisionStartState = p.transitions[0].target + blockEndStateNum = decisionStartState.endState.stateNumber + blockEndState = self.atn.states[blockEndStateNum] + + # Verify that the top of each stack context leads to loop entry/exit + # state through epsilon edges and w/o leaving rule. + for i in range(0, numCtxs): # for each stack context + returnStateNumber = config.context.getReturnState(i) + returnState = self.atn.states[returnStateNumber] + # all states must have single outgoing epsilon edge + if len(returnState.transitions) != 1 or not returnState.transitions[0].isEpsilon: + return False + + # Look for prefix op case like 'not expr', (' type ')' expr + returnStateTarget = returnState.transitions[0].target + if returnState.stateType == ATNState.BLOCK_END and returnStateTarget is p: + continue + + # Look for 'expr op expr' or case where expr's return state is block end + # of (...)* internal block; the block end points to loop back + # which points to p but we don't need to check that + if returnState is blockEndState: + continue + + # Look for ternary expr ? expr : expr. The return state points at block end, + # which points at loop entry state + if returnStateTarget is blockEndState: + continue + + # Look for complex prefix 'between expr and expr' case where 2nd expr's + # return state points at block end state of (...)* internal block + if returnStateTarget.stateType == ATNState.BLOCK_END \ + and len(returnStateTarget.transitions) == 1 \ + and returnStateTarget.transitions[0].isEpsilon \ + and returnStateTarget.transitions[0].target is p: + continue + + # anything else ain't conforming + return False + + return True + + + def getRuleName(self, index:int): + if self.parser is not None and index>=0: + return self.parser.ruleNames[index] + else: + return "" + + epsilonTargetMethods = dict() + epsilonTargetMethods[Transition.RULE] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + sim.ruleTransition(config, t) + epsilonTargetMethods[Transition.PRECEDENCE] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + sim.precedenceTransition(config, t, collectPredicates, inContext, fullCtx) + epsilonTargetMethods[Transition.PREDICATE] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + sim.predTransition(config, t, collectPredicates, inContext, fullCtx) + epsilonTargetMethods[Transition.ACTION] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + sim.actionTransition(config, t) + epsilonTargetMethods[Transition.EPSILON] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + ATNConfig(state=t.target, config=config) + epsilonTargetMethods[Transition.ATOM] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + ATNConfig(state=t.target, config=config) if treatEofAsEpsilon and t.matches(Token.EOF, 0, 1) else None + epsilonTargetMethods[Transition.RANGE] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + ATNConfig(state=t.target, config=config) if treatEofAsEpsilon and t.matches(Token.EOF, 0, 1) else None + epsilonTargetMethods[Transition.SET] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + ATNConfig(state=t.target, config=config) if treatEofAsEpsilon and t.matches(Token.EOF, 0, 1) else None + + def getEpsilonTarget(self, config:ATNConfig, t:Transition, collectPredicates:bool, inContext:bool, fullCtx:bool, treatEofAsEpsilon:bool): + m = self.epsilonTargetMethods.get(t.serializationType, None) + if m is None: + return None + else: + return m(self, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon) + + def actionTransition(self, config:ATNConfig, t:ActionTransition): + if ParserATNSimulator.debug: + print("ACTION edge " + str(t.ruleIndex) + ":" + str(t.actionIndex)) + return ATNConfig(state=t.target, config=config) + + def precedenceTransition(self, config:ATNConfig, pt:PrecedencePredicateTransition, collectPredicates:bool, inContext:bool, fullCtx:bool): + if ParserATNSimulator.debug: + print("PRED (collectPredicates=" + str(collectPredicates) + ") " + + str(pt.precedence) + ">=_p, ctx dependent=true") + if self.parser is not None: + print("context surrounding pred is " + str(self.parser.getRuleInvocationStack())) + + c = None + if collectPredicates and inContext: + if fullCtx: + # In full context mode, we can evaluate predicates on-the-fly + # during closure, which dramatically reduces the size of + # the config sets. It also obviates the need to test predicates + # later during conflict resolution. + currentPosition = self._input.index + self._input.seek(self._startIndex) + predSucceeds = pt.getPredicate().eval(self.parser, self._outerContext) + self._input.seek(currentPosition) + if predSucceeds: + c = ATNConfig(state=pt.target, config=config) # no pred context + else: + newSemCtx = andContext(config.semanticContext, pt.getPredicate()) + c = ATNConfig(state=pt.target, semantic=newSemCtx, config=config) + else: + c = ATNConfig(state=pt.target, config=config) + + if ParserATNSimulator.debug: + print("config from pred transition=" + str(c)) + return c + + def predTransition(self, config:ATNConfig, pt:PredicateTransition, collectPredicates:bool, inContext:bool, fullCtx:bool): + if ParserATNSimulator.debug: + print("PRED (collectPredicates=" + str(collectPredicates) + ") " + str(pt.ruleIndex) + + ":" + str(pt.predIndex) + ", ctx dependent=" + str(pt.isCtxDependent)) + if self.parser is not None: + print("context surrounding pred is " + str(self.parser.getRuleInvocationStack())) + + c = None + if collectPredicates and (not pt.isCtxDependent or (pt.isCtxDependent and inContext)): + if fullCtx: + # In full context mode, we can evaluate predicates on-the-fly + # during closure, which dramatically reduces the size of + # the config sets. It also obviates the need to test predicates + # later during conflict resolution. + currentPosition = self._input.index + self._input.seek(self._startIndex) + predSucceeds = pt.getPredicate().eval(self.parser, self._outerContext) + self._input.seek(currentPosition) + if predSucceeds: + c = ATNConfig(state=pt.target, config=config) # no pred context + else: + newSemCtx = andContext(config.semanticContext, pt.getPredicate()) + c = ATNConfig(state=pt.target, semantic=newSemCtx, config=config) + else: + c = ATNConfig(state=pt.target, config=config) + + if ParserATNSimulator.debug: + print("config from pred transition=" + str(c)) + return c + + def ruleTransition(self, config:ATNConfig, t:RuleTransition): + if ParserATNSimulator.debug: + print("CALL rule " + self.getRuleName(t.target.ruleIndex) + ", ctx=" + str(config.context)) + returnState = t.followState + newContext = SingletonPredictionContext.create(config.context, returnState.stateNumber) + return ATNConfig(state=t.target, context=newContext, config=config ) + + def getConflictingAlts(self, configs:ATNConfigSet): + altsets = PredictionMode.getConflictingAltSubsets(configs) + return PredictionMode.getAlts(altsets) + + # Sam pointed out a problem with the previous definition, v3, of + # ambiguous states. If we have another state associated with conflicting + # alternatives, we should keep going. For example, the following grammar + # + # s : (ID | ID ID?) ';' ; + # + # When the ATN simulation reaches the state before ';', it has a DFA + # state that looks like: [12|1|[], 6|2|[], 12|2|[]]. Naturally + # 12|1|[] and 12|2|[] conflict, but we cannot stop processing this node + # because alternative to has another way to continue, via [6|2|[]]. + # The key is that we have a single state that has config's only associated + # with a single alternative, 2, and crucially the state transitions + # among the configurations are all non-epsilon transitions. That means + # we don't consider any conflicts that include alternative 2. So, we + # ignore the conflict between alts 1 and 2. We ignore a set of + # conflicting alts when there is an intersection with an alternative + # associated with a single alt state in the state→config-list map. + # + # It's also the case that we might have two conflicting configurations but + # also a 3rd nonconflicting configuration for a different alternative: + # [1|1|[], 1|2|[], 8|3|[]]. This can come about from grammar: + # + # a : A | A | A B ; + # + # After matching input A, we reach the stop state for rule A, state 1. + # State 8 is the state right before B. Clearly alternatives 1 and 2 + # conflict and no amount of further lookahead will separate the two. + # However, alternative 3 will be able to continue and so we do not + # stop working on this state. In the previous example, we're concerned + # with states associated with the conflicting alternatives. Here alt + # 3 is not associated with the conflicting configs, but since we can continue + # looking for input reasonably, I don't declare the state done. We + # ignore a set of conflicting alts when we have an alternative + # that we still need to pursue. + # + + def getConflictingAltsOrUniqueAlt(self, configs:ATNConfigSet): + conflictingAlts = None + if configs.uniqueAlt!= ATN.INVALID_ALT_NUMBER: + conflictingAlts = set() + conflictingAlts.add(configs.uniqueAlt) + else: + conflictingAlts = configs.conflictingAlts + return conflictingAlts + + def getTokenName(self, t:int): + if t==Token.EOF: + return "EOF" + if self.parser is not None and \ + self.parser.literalNames is not None and \ + t < len(self.parser.literalNames): + return self.parser.literalNames[t] + "<" + str(t) + ">" + else: + return str(t) + + def getLookaheadName(self, input:TokenStream): + return self.getTokenName(input.LA(1)) + + # Used for debugging in adaptivePredict around execATN but I cut + # it out for clarity now that alg. works well. We can leave this + # "dead" code for a bit. + # + def dumpDeadEndConfigs(self, nvae:NoViableAltException): + print("dead end configs: ") + for c in nvae.getDeadEndConfigs(): + trans = "no edges" + if len(c.state.transitions)>0: + t = c.state.transitions[0] + if isinstance(t, AtomTransition): + trans = "Atom "+ self.getTokenName(t.label) + elif isinstance(t, SetTransition): + neg = isinstance(t, NotSetTransition) + trans = ("~" if neg else "")+"Set "+ str(t.set) + print(c.toString(self.parser, True) + ":" + trans, file=sys.stderr) + + def noViableAlt(self, input:TokenStream, outerContext:ParserRuleContext, configs:ATNConfigSet, startIndex:int): + return NoViableAltException(self.parser, input, input.get(startIndex), input.LT(1), configs, outerContext) + + def getUniqueAlt(self, configs:ATNConfigSet): + alt = ATN.INVALID_ALT_NUMBER + for c in configs: + if alt == ATN.INVALID_ALT_NUMBER: + alt = c.alt # found first alt + elif c.alt!=alt: + return ATN.INVALID_ALT_NUMBER + return alt + + # + # Add an edge to the DFA, if possible. This method calls + # {@link #addDFAState} to ensure the {@code to} state is present in the + # DFA. If {@code from} is {@code null}, or if {@code t} is outside the + # range of edges that can be represented in the DFA tables, this method + # returns without adding the edge to the DFA. + # + #

      If {@code to} is {@code null}, this method returns {@code null}. + # Otherwise, this method returns the {@link DFAState} returned by calling + # {@link #addDFAState} for the {@code to} state.

      + # + # @param dfa The DFA + # @param from The source state for the edge + # @param t The input symbol + # @param to The target state for the edge + # + # @return If {@code to} is {@code null}, this method returns {@code null}; + # otherwise this method returns the result of calling {@link #addDFAState} + # on {@code to} + # + def addDFAEdge(self, dfa:DFA, from_:DFAState, t:int, to:DFAState): + if ParserATNSimulator.debug: + print("EDGE " + str(from_) + " -> " + str(to) + " upon " + self.getTokenName(t)) + + if to is None: + return None + + to = self.addDFAState(dfa, to) # used existing if possible not incoming + if from_ is None or t < -1 or t > self.atn.maxTokenType: + return to + + if from_.edges is None: + from_.edges = [None] * (self.atn.maxTokenType + 2) + from_.edges[t+1] = to # connect + + if ParserATNSimulator.debug: + names = None if self.parser is None else self.parser.literalNames + print("DFA=\n" + dfa.toString(names)) + + return to + + # + # Add state {@code D} to the DFA if it is not already present, and return + # the actual instance stored in the DFA. If a state equivalent to {@code D} + # is already in the DFA, the existing state is returned. Otherwise this + # method returns {@code D} after adding it to the DFA. + # + #

      If {@code D} is {@link #ERROR}, this method returns {@link #ERROR} and + # does not change the DFA.

      + # + # @param dfa The dfa + # @param D The DFA state to add + # @return The state stored in the DFA. This will be either the existing + # state if {@code D} is already in the DFA, or {@code D} itself if the + # state was not already present. + # + def addDFAState(self, dfa:DFA, D:DFAState): + if D is self.ERROR: + return D + + + existing = dfa.states.get(D, None) + if existing is not None: + return existing + + D.stateNumber = len(dfa.states) + if not D.configs.readonly: + D.configs.optimizeConfigs(self) + D.configs.setReadonly(True) + dfa.states[D] = D + if ParserATNSimulator.debug: + print("adding new DFA state: " + str(D)) + return D + + def reportAttemptingFullContext(self, dfa:DFA, conflictingAlts:set, configs:ATNConfigSet, startIndex:int, stopIndex:int): + if ParserATNSimulator.debug or ParserATNSimulator.retry_debug: + interval = (startIndex, stopIndex + 1) + print("reportAttemptingFullContext decision=" + str(dfa.decision) + ":" + str(configs) + + ", input=" + self.parser.getTokenStream().getText(interval)) + if self.parser is not None: + self.parser.getErrorListenerDispatch().reportAttemptingFullContext(self.parser, dfa, startIndex, stopIndex, conflictingAlts, configs) + + def reportContextSensitivity(self, dfa:DFA, prediction:int, configs:ATNConfigSet, startIndex:int, stopIndex:int): + if ParserATNSimulator.debug or ParserATNSimulator.retry_debug: + interval = (startIndex, stopIndex + 1) + print("reportContextSensitivity decision=" + str(dfa.decision) + ":" + str(configs) + + ", input=" + self.parser.getTokenStream().getText(interval)) + if self.parser is not None: + self.parser.getErrorListenerDispatch().reportContextSensitivity(self.parser, dfa, startIndex, stopIndex, prediction, configs) + + # If context sensitive parsing, we know it's ambiguity not conflict# + def reportAmbiguity(self, dfa:DFA, D:DFAState, startIndex:int, stopIndex:int, + exact:bool, ambigAlts:set, configs:ATNConfigSet ): + if ParserATNSimulator.debug or ParserATNSimulator.retry_debug: +# ParserATNPathFinder finder = new ParserATNPathFinder(parser, atn); +# int i = 1; +# for (Transition t : dfa.atnStartState.transitions) { +# print("ALT "+i+"="); +# print(startIndex+".."+stopIndex+", len(input)="+parser.getInputStream().size()); +# TraceTree path = finder.trace(t.target, parser.getContext(), (TokenStream)parser.getInputStream(), +# startIndex, stopIndex); +# if ( path!=null ) { +# print("path = "+path.toStringTree()); +# for (TraceTree leaf : path.leaves) { +# List states = path.getPathToNode(leaf); +# print("states="+states); +# } +# } +# i++; +# } + interval = (startIndex, stopIndex + 1) + print("reportAmbiguity " + str(ambigAlts) + ":" + str(configs) + + ", input=" + self.parser.getTokenStream().getText(interval)) + if self.parser is not None: + self.parser.getErrorListenerDispatch().reportAmbiguity(self.parser, dfa, startIndex, stopIndex, exact, ambigAlts, configs) + diff --git a/src/antlr4/atn/PredictionMode.py b/src/antlr4/atn/PredictionMode.py new file mode 100644 index 00000000..8e5c73bb --- /dev/null +++ b/src/antlr4/atn/PredictionMode.py @@ -0,0 +1,499 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# +# +# This enumeration defines the prediction modes available in ANTLR 4 along with +# utility methods for analyzing configuration sets for conflicts and/or +# ambiguities. + + +from enum import Enum +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNConfig import ATNConfig +from antlr4.atn.ATNConfigSet import ATNConfigSet +from antlr4.atn.ATNState import RuleStopState +from antlr4.atn.SemanticContext import SemanticContext + +PredictionMode = None + +class PredictionMode(Enum): + # + # The SLL(*) prediction mode. This prediction mode ignores the current + # parser context when making predictions. This is the fastest prediction + # mode, and provides correct results for many grammars. This prediction + # mode is more powerful than the prediction mode provided by ANTLR 3, but + # may result in syntax errors for grammar and input combinations which are + # not SLL. + # + #

      + # When using this prediction mode, the parser will either return a correct + # parse tree (i.e. the same parse tree that would be returned with the + # {@link #LL} prediction mode), or it will report a syntax error. If a + # syntax error is encountered when using the {@link #SLL} prediction mode, + # it may be due to either an actual syntax error in the input or indicate + # that the particular combination of grammar and input requires the more + # powerful {@link #LL} prediction abilities to complete successfully.

      + # + #

      + # This prediction mode does not provide any guarantees for prediction + # behavior for syntactically-incorrect inputs.

      + # + SLL = 0 + # + # The LL(*) prediction mode. This prediction mode allows the current parser + # context to be used for resolving SLL conflicts that occur during + # prediction. This is the fastest prediction mode that guarantees correct + # parse results for all combinations of grammars with syntactically correct + # inputs. + # + #

      + # When using this prediction mode, the parser will make correct decisions + # for all syntactically-correct grammar and input combinations. However, in + # cases where the grammar is truly ambiguous this prediction mode might not + # report a precise answer for exactly which alternatives are + # ambiguous.

      + # + #

      + # This prediction mode does not provide any guarantees for prediction + # behavior for syntactically-incorrect inputs.

      + # + LL = 1 + # + # The LL(*) prediction mode with exact ambiguity detection. In addition to + # the correctness guarantees provided by the {@link #LL} prediction mode, + # this prediction mode instructs the prediction algorithm to determine the + # complete and exact set of ambiguous alternatives for every ambiguous + # decision encountered while parsing. + # + #

      + # This prediction mode may be used for diagnosing ambiguities during + # grammar development. Due to the performance overhead of calculating sets + # of ambiguous alternatives, this prediction mode should be avoided when + # the exact results are not necessary.

      + # + #

      + # This prediction mode does not provide any guarantees for prediction + # behavior for syntactically-incorrect inputs.

      + # + LL_EXACT_AMBIG_DETECTION = 2 + + + # + # Computes the SLL prediction termination condition. + # + #

      + # This method computes the SLL prediction termination condition for both of + # the following cases.

      + # + #
        + #
      • The usual SLL+LL fallback upon SLL conflict
      • + #
      • Pure SLL without LL fallback
      • + #
      + # + #

      COMBINED SLL+LL PARSING

      + # + #

      When LL-fallback is enabled upon SLL conflict, correct predictions are + # ensured regardless of how the termination condition is computed by this + # method. Due to the substantially higher cost of LL prediction, the + # prediction should only fall back to LL when the additional lookahead + # cannot lead to a unique SLL prediction.

      + # + #

      Assuming combined SLL+LL parsing, an SLL configuration set with only + # conflicting subsets should fall back to full LL, even if the + # configuration sets don't resolve to the same alternative (e.g. + # {@code {1,2}} and {@code {3,4}}. If there is at least one non-conflicting + # configuration, SLL could continue with the hopes that more lookahead will + # resolve via one of those non-conflicting configurations.

      + # + #

      Here's the prediction termination rule them: SLL (for SLL+LL parsing) + # stops when it sees only conflicting configuration subsets. In contrast, + # full LL keeps going when there is uncertainty.

      + # + #

      HEURISTIC

      + # + #

      As a heuristic, we stop prediction when we see any conflicting subset + # unless we see a state that only has one alternative associated with it. + # The single-alt-state thing lets prediction continue upon rules like + # (otherwise, it would admit defeat too soon):

      + # + #

      {@code [12|1|[], 6|2|[], 12|2|[]]. s : (ID | ID ID?) ';' ;}

      + # + #

      When the ATN simulation reaches the state before {@code ';'}, it has a + # DFA state that looks like: {@code [12|1|[], 6|2|[], 12|2|[]]}. Naturally + # {@code 12|1|[]} and {@code 12|2|[]} conflict, but we cannot stop + # processing this node because alternative to has another way to continue, + # via {@code [6|2|[]]}.

      + # + #

      It also let's us continue for this rule:

      + # + #

      {@code [1|1|[], 1|2|[], 8|3|[]] a : A | A | A B ;}

      + # + #

      After matching input A, we reach the stop state for rule A, state 1. + # State 8 is the state right before B. Clearly alternatives 1 and 2 + # conflict and no amount of further lookahead will separate the two. + # However, alternative 3 will be able to continue and so we do not stop + # working on this state. In the previous example, we're concerned with + # states associated with the conflicting alternatives. Here alt 3 is not + # associated with the conflicting configs, but since we can continue + # looking for input reasonably, don't declare the state done.

      + # + #

      PURE SLL PARSING

      + # + #

      To handle pure SLL parsing, all we have to do is make sure that we + # combine stack contexts for configurations that differ only by semantic + # predicate. From there, we can do the usual SLL termination heuristic.

      + # + #

      PREDICATES IN SLL+LL PARSING

      + # + #

      SLL decisions don't evaluate predicates until after they reach DFA stop + # states because they need to create the DFA cache that works in all + # semantic situations. In contrast, full LL evaluates predicates collected + # during start state computation so it can ignore predicates thereafter. + # This means that SLL termination detection can totally ignore semantic + # predicates.

      + # + #

      Implementation-wise, {@link ATNConfigSet} combines stack contexts but not + # semantic predicate contexts so we might see two configurations like the + # following.

      + # + #

      {@code (s, 1, x, {}), (s, 1, x', {p})}

      + # + #

      Before testing these configurations against others, we have to merge + # {@code x} and {@code x'} (without modifying the existing configurations). + # For example, we test {@code (x+x')==x''} when looking for conflicts in + # the following configurations.

      + # + #

      {@code (s, 1, x, {}), (s, 1, x', {p}), (s, 2, x'', {})}

      + # + #

      If the configuration set has predicates (as indicated by + # {@link ATNConfigSet#hasSemanticContext}), this algorithm makes a copy of + # the configurations to strip out all of the predicates so that a standard + # {@link ATNConfigSet} will merge everything ignoring predicates.

      + # + @classmethod + def hasSLLConflictTerminatingPrediction(cls, mode:PredictionMode, configs:ATNConfigSet): + # Configs in rule stop states indicate reaching the end of the decision + # rule (local context) or end of start rule (full context). If all + # configs meet this condition, then none of the configurations is able + # to match additional input so we terminate prediction. + # + if cls.allConfigsInRuleStopStates(configs): + return True + + # pure SLL mode parsing + if mode == PredictionMode.SLL: + # Don't bother with combining configs from different semantic + # contexts if we can fail over to full LL; costs more time + # since we'll often fail over anyway. + if configs.hasSemanticContext: + # dup configs, tossing out semantic predicates + dup = ATNConfigSet() + for c in configs: + c = ATNConfig(config=c, semantic=SemanticContext.NONE) + dup.add(c) + configs = dup + # now we have combined contexts for configs with dissimilar preds + + # pure SLL or combined SLL+LL mode parsing + altsets = cls.getConflictingAltSubsets(configs) + return cls.hasConflictingAltSet(altsets) and not cls.hasStateAssociatedWithOneAlt(configs) + + # Checks if any configuration in {@code configs} is in a + # {@link RuleStopState}. Configurations meeting this condition have reached + # the end of the decision rule (local context) or end of start rule (full + # context). + # + # @param configs the configuration set to test + # @return {@code true} if any configuration in {@code configs} is in a + # {@link RuleStopState}, otherwise {@code false} + @classmethod + def hasConfigInRuleStopState(cls, configs:ATNConfigSet): + return any(isinstance(cfg.state, RuleStopState) for cfg in configs) + + # Checks if all configurations in {@code configs} are in a + # {@link RuleStopState}. Configurations meeting this condition have reached + # the end of the decision rule (local context) or end of start rule (full + # context). + # + # @param configs the configuration set to test + # @return {@code true} if all configurations in {@code configs} are in a + # {@link RuleStopState}, otherwise {@code false} + @classmethod + def allConfigsInRuleStopStates(cls, configs:ATNConfigSet): + return all(isinstance(cfg.state, RuleStopState) for cfg in configs) + + # + # Full LL prediction termination. + # + #

      Can we stop looking ahead during ATN simulation or is there some + # uncertainty as to which alternative we will ultimately pick, after + # consuming more input? Even if there are partial conflicts, we might know + # that everything is going to resolve to the same minimum alternative. That + # means we can stop since no more lookahead will change that fact. On the + # other hand, there might be multiple conflicts that resolve to different + # minimums. That means we need more look ahead to decide which of those + # alternatives we should predict.

      + # + #

      The basic idea is to split the set of configurations {@code C}, into + # conflicting subsets {@code (s, _, ctx, _)} and singleton subsets with + # non-conflicting configurations. Two configurations conflict if they have + # identical {@link ATNConfig#state} and {@link ATNConfig#context} values + # but different {@link ATNConfig#alt} value, e.g. {@code (s, i, ctx, _)} + # and {@code (s, j, ctx, _)} for {@code i!=j}.

      + # + #

      Reduce these configuration subsets to the set of possible alternatives. + # You can compute the alternative subsets in one pass as follows:

      + # + #

      {@code A_s,ctx = {i | (s, i, ctx, _)}} for each configuration in + # {@code C} holding {@code s} and {@code ctx} fixed.

      + # + #

      Or in pseudo-code, for each configuration {@code c} in {@code C}:

      + # + #
      +    # map[c] U= c.{@link ATNConfig#alt alt} # map hash/equals uses s and x, not
      +    # alt and not pred
      +    # 
      + # + #

      The values in {@code map} are the set of {@code A_s,ctx} sets.

      + # + #

      If {@code |A_s,ctx|=1} then there is no conflict associated with + # {@code s} and {@code ctx}.

      + # + #

      Reduce the subsets to singletons by choosing a minimum of each subset. If + # the union of these alternative subsets is a singleton, then no amount of + # more lookahead will help us. We will always pick that alternative. If, + # however, there is more than one alternative, then we are uncertain which + # alternative to predict and must continue looking for resolution. We may + # or may not discover an ambiguity in the future, even if there are no + # conflicting subsets this round.

      + # + #

      The biggest sin is to terminate early because it means we've made a + # decision but were uncertain as to the eventual outcome. We haven't used + # enough lookahead. On the other hand, announcing a conflict too late is no + # big deal; you will still have the conflict. It's just inefficient. It + # might even look until the end of file.

      + # + #

      No special consideration for semantic predicates is required because + # predicates are evaluated on-the-fly for full LL prediction, ensuring that + # no configuration contains a semantic context during the termination + # check.

      + # + #

      CONFLICTING CONFIGS

      + # + #

      Two configurations {@code (s, i, x)} and {@code (s, j, x')}, conflict + # when {@code i!=j} but {@code x=x'}. Because we merge all + # {@code (s, i, _)} configurations together, that means that there are at + # most {@code n} configurations associated with state {@code s} for + # {@code n} possible alternatives in the decision. The merged stacks + # complicate the comparison of configuration contexts {@code x} and + # {@code x'}. Sam checks to see if one is a subset of the other by calling + # merge and checking to see if the merged result is either {@code x} or + # {@code x'}. If the {@code x} associated with lowest alternative {@code i} + # is the superset, then {@code i} is the only possible prediction since the + # others resolve to {@code min(i)} as well. However, if {@code x} is + # associated with {@code j>i} then at least one stack configuration for + # {@code j} is not in conflict with alternative {@code i}. The algorithm + # should keep going, looking for more lookahead due to the uncertainty.

      + # + #

      For simplicity, I'm doing a equality check between {@code x} and + # {@code x'} that lets the algorithm continue to consume lookahead longer + # than necessary. The reason I like the equality is of course the + # simplicity but also because that is the test you need to detect the + # alternatives that are actually in conflict.

      + # + #

      CONTINUE/STOP RULE

      + # + #

      Continue if union of resolved alternative sets from non-conflicting and + # conflicting alternative subsets has more than one alternative. We are + # uncertain about which alternative to predict.

      + # + #

      The complete set of alternatives, {@code [i for (_,i,_)]}, tells us which + # alternatives are still in the running for the amount of input we've + # consumed at this point. The conflicting sets let us to strip away + # configurations that won't lead to more states because we resolve + # conflicts to the configuration with a minimum alternate for the + # conflicting set.

      + # + #

      CASES

      + # + #
        + # + #
      • no conflicts and more than 1 alternative in set => continue
      • + # + #
      • {@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s, 3, z)}, + # {@code (s', 1, y)}, {@code (s', 2, y)} yields non-conflicting set + # {@code {3}} U conflicting sets {@code min({1,2})} U {@code min({1,2})} = + # {@code {1,3}} => continue + #
      • + # + #
      • {@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s', 1, y)}, + # {@code (s', 2, y)}, {@code (s'', 1, z)} yields non-conflicting set + # {@code {1}} U conflicting sets {@code min({1,2})} U {@code min({1,2})} = + # {@code {1}} => stop and predict 1
      • + # + #
      • {@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s', 1, y)}, + # {@code (s', 2, y)} yields conflicting, reduced sets {@code {1}} U + # {@code {1}} = {@code {1}} => stop and predict 1, can announce + # ambiguity {@code {1,2}}
      • + # + #
      • {@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s', 2, y)}, + # {@code (s', 3, y)} yields conflicting, reduced sets {@code {1}} U + # {@code {2}} = {@code {1,2}} => continue
      • + # + #
      • {@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s', 3, y)}, + # {@code (s', 4, y)} yields conflicting, reduced sets {@code {1}} U + # {@code {3}} = {@code {1,3}} => continue
      • + # + #
      + # + #

      EXACT AMBIGUITY DETECTION

      + # + #

      If all states report the same conflicting set of alternatives, then we + # know we have the exact ambiguity set.

      + # + #

      |A_i|>1 and + # A_i = A_j for all i, j.

      + # + #

      In other words, we continue examining lookahead until all {@code A_i} + # have more than one alternative and all {@code A_i} are the same. If + # {@code A={{1,2}, {1,3}}}, then regular LL prediction would terminate + # because the resolved set is {@code {1}}. To determine what the real + # ambiguity is, we have to know whether the ambiguity is between one and + # two or one and three so we keep going. We can only stop prediction when + # we need exact ambiguity detection when the sets look like + # {@code A={{1,2}}} or {@code {{1,2},{1,2}}}, etc...

      + # + @classmethod + def resolvesToJustOneViableAlt(cls, altsets:list): + return cls.getSingleViableAlt(altsets) + + # + # Determines if every alternative subset in {@code altsets} contains more + # than one alternative. + # + # @param altsets a collection of alternative subsets + # @return {@code true} if every {@link BitSet} in {@code altsets} has + # {@link BitSet#cardinality cardinality} > 1, otherwise {@code false} + # + @classmethod + def allSubsetsConflict(cls, altsets:list): + return not cls.hasNonConflictingAltSet(altsets) + + # + # Determines if any single alternative subset in {@code altsets} contains + # exactly one alternative. + # + # @param altsets a collection of alternative subsets + # @return {@code true} if {@code altsets} contains a {@link BitSet} with + # {@link BitSet#cardinality cardinality} 1, otherwise {@code false} + # + @classmethod + def hasNonConflictingAltSet(cls, altsets:list): + return any(len(alts) == 1 for alts in altsets) + + # + # Determines if any single alternative subset in {@code altsets} contains + # more than one alternative. + # + # @param altsets a collection of alternative subsets + # @return {@code true} if {@code altsets} contains a {@link BitSet} with + # {@link BitSet#cardinality cardinality} > 1, otherwise {@code false} + # + @classmethod + def hasConflictingAltSet(cls, altsets:list): + return any(len(alts) > 1 for alts in altsets) + + # + # Determines if every alternative subset in {@code altsets} is equivalent. + # + # @param altsets a collection of alternative subsets + # @return {@code true} if every member of {@code altsets} is equal to the + # others, otherwise {@code false} + # + @classmethod + def allSubsetsEqual(cls, altsets:list): + if not altsets: + return True + first = next(iter(altsets)) + return all(alts == first for alts in iter(altsets)) + + # + # Returns the unique alternative predicted by all alternative subsets in + # {@code altsets}. If no such alternative exists, this method returns + # {@link ATN#INVALID_ALT_NUMBER}. + # + # @param altsets a collection of alternative subsets + # + @classmethod + def getUniqueAlt(cls, altsets:list): + all = cls.getAlts(altsets) + if len(all)==1: + return next(iter(all)) + return ATN.INVALID_ALT_NUMBER + + # Gets the complete set of represented alternatives for a collection of + # alternative subsets. This method returns the union of each {@link BitSet} + # in {@code altsets}. + # + # @param altsets a collection of alternative subsets + # @return the set of represented alternatives in {@code altsets} + # + @classmethod + def getAlts(cls, altsets:list): + return set.union(*altsets) + + # + # This function gets the conflicting alt subsets from a configuration set. + # For each configuration {@code c} in {@code configs}: + # + #
      +    # map[c] U= c.{@link ATNConfig#alt alt} # map hash/equals uses s and x, not
      +    # alt and not pred
      +    # 
      + # + @classmethod + def getConflictingAltSubsets(cls, configs:ATNConfigSet): + configToAlts = dict() + for c in configs: + h = hash((c.state.stateNumber, c.context)) + alts = configToAlts.get(h, None) + if alts is None: + alts = set() + configToAlts[h] = alts + alts.add(c.alt) + return configToAlts.values() + + # + # Get a map from state to alt subset from a configuration set. For each + # configuration {@code c} in {@code configs}: + # + #
      +    # map[c.{@link ATNConfig#state state}] U= c.{@link ATNConfig#alt alt}
      +    # 
      + # + @classmethod + def getStateToAltMap(cls, configs:ATNConfigSet): + m = dict() + for c in configs: + alts = m.get(c.state, None) + if alts is None: + alts = set() + m[c.state] = alts + alts.add(c.alt) + return m + + @classmethod + def hasStateAssociatedWithOneAlt(cls, configs:ATNConfigSet): + return any(len(alts) == 1 for alts in cls.getStateToAltMap(configs).values()) + + @classmethod + def getSingleViableAlt(cls, altsets:list): + viableAlts = set() + for alts in altsets: + minAlt = min(alts) + viableAlts.add(minAlt) + if len(viableAlts)>1 : # more than 1 viable alt + return ATN.INVALID_ALT_NUMBER + return min(viableAlts) diff --git a/src/antlr4/atn/SemanticContext.py b/src/antlr4/atn/SemanticContext.py new file mode 100644 index 00000000..d4593195 --- /dev/null +++ b/src/antlr4/atn/SemanticContext.py @@ -0,0 +1,320 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# A tree structure used to record the semantic context in which +# an ATN configuration is valid. It's either a single predicate, +# a conjunction {@code p1&&p2}, or a sum of products {@code p1||p2}. +# +#

      I have scoped the {@link AND}, {@link OR}, and {@link Predicate} subclasses of +# {@link SemanticContext} within the scope of this outer class.

      +# +from antlr4.Recognizer import Recognizer +from antlr4.RuleContext import RuleContext +from io import StringIO + + +class SemanticContext(object): + # + # The default {@link SemanticContext}, which is semantically equivalent to + # a predicate of the form {@code {true}?}. + # + NONE = None + + # + # For context independent predicates, we evaluate them without a local + # context (i.e., null context). That way, we can evaluate them without + # having to create proper rule-specific context during prediction (as + # opposed to the parser, which creates them naturally). In a practical + # sense, this avoids a cast exception from RuleContext to myruleContext. + # + #

      For context dependent predicates, we must pass in a local context so that + # references such as $arg evaluate properly as _localctx.arg. We only + # capture context dependent predicates in the context in which we begin + # prediction, so we passed in the outer context here in case of context + # dependent predicate evaluation.

      + # + def eval(self, parser:Recognizer , outerContext:RuleContext ): + pass + + # + # Evaluate the precedence predicates for the context and reduce the result. + # + # @param parser The parser instance. + # @param outerContext The current parser context object. + # @return The simplified semantic context after precedence predicates are + # evaluated, which will be one of the following values. + #
        + #
      • {@link #NONE}: if the predicate simplifies to {@code true} after + # precedence predicates are evaluated.
      • + #
      • {@code null}: if the predicate simplifies to {@code false} after + # precedence predicates are evaluated.
      • + #
      • {@code this}: if the semantic context is not changed as a result of + # precedence predicate evaluation.
      • + #
      • A non-{@code null} {@link SemanticContext}: the new simplified + # semantic context after precedence predicates are evaluated.
      • + #
      + # + def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext): + return self + +# need forward declaration +AND = None + +def andContext(a:SemanticContext, b:SemanticContext): + if a is None or a is SemanticContext.NONE: + return b + if b is None or b is SemanticContext.NONE: + return a + result = AND(a, b) + if len(result.opnds) == 1: + return result.opnds[0] + else: + return result + +# need forward declaration +OR = None + +def orContext(a:SemanticContext, b:SemanticContext): + if a is None: + return b + if b is None: + return a + if a is SemanticContext.NONE or b is SemanticContext.NONE: + return SemanticContext.NONE + result = OR(a, b) + if len(result.opnds) == 1: + return result.opnds[0] + else: + return result + +def filterPrecedencePredicates(collection:set): + return [context for context in collection if isinstance(context, PrecedencePredicate)] + + +class Predicate(SemanticContext): + + def __init__(self, ruleIndex:int=-1, predIndex:int=-1, isCtxDependent:bool=False): + self.ruleIndex = ruleIndex + self.predIndex = predIndex + self.isCtxDependent = isCtxDependent # e.g., $i ref in pred + + def eval(self, parser:Recognizer , outerContext:RuleContext ): + localctx = outerContext if self.isCtxDependent else None + return parser.sempred(localctx, self.ruleIndex, self.predIndex) + + def __hash__(self): + return hash((self.ruleIndex, self.predIndex, self.isCtxDependent)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, Predicate): + return False + return self.ruleIndex == other.ruleIndex and \ + self.predIndex == other.predIndex and \ + self.isCtxDependent == other.isCtxDependent + + def __str__(self): + return "{" + str(self.ruleIndex) + ":" + str(self.predIndex) + "}?" + + +class PrecedencePredicate(SemanticContext): + + def __init__(self, precedence:int=0): + self.precedence = precedence + + def eval(self, parser:Recognizer , outerContext:RuleContext ): + return parser.precpred(outerContext, self.precedence) + + def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext): + if parser.precpred(outerContext, self.precedence): + return SemanticContext.NONE + else: + return None + + def __lt__(self, other): + return self.precedence < other.precedence + + def __hash__(self): + return 31 + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, PrecedencePredicate): + return False + else: + return self.precedence == other.precedence + +# A semantic context which is true whenever none of the contained contexts +# is false. +del AND +class AND(SemanticContext): + + def __init__(self, a:SemanticContext, b:SemanticContext): + operands = set() + if isinstance( a, AND ): + operands.update(a.opnds) + else: + operands.add(a) + if isinstance( b, AND ): + operands.update(b.opnds) + else: + operands.add(b) + + precedencePredicates = filterPrecedencePredicates(operands) + if len(precedencePredicates)>0: + # interested in the transition with the lowest precedence + reduced = min(precedencePredicates) + operands.add(reduced) + + self.opnds = list(operands) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, AND): + return False + else: + return self.opnds == other.opnds + + def __hash__(self): + h = 0 + for o in self.opnds: + h = hash((h, o)) + return hash((h, "AND")) + + # + # {@inheritDoc} + # + #

      + # The evaluation of predicates by this context is short-circuiting, but + # unordered.

      + # + def eval(self, parser:Recognizer, outerContext:RuleContext): + return all(opnd.eval(parser, outerContext) for opnd in self.opnds) + + def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext): + differs = False + operands = [] + for context in self.opnds: + evaluated = context.evalPrecedence(parser, outerContext) + differs |= evaluated is not context + if evaluated is None: + # The AND context is false if any element is false + return None + elif evaluated is not SemanticContext.NONE: + # Reduce the result by skipping true elements + operands.append(evaluated) + + if not differs: + return self + + if len(operands)==0: + # all elements were true, so the AND context is true + return SemanticContext.NONE + + result = None + for o in operands: + result = o if result is None else andContext(result, o) + + return result + + def __str__(self): + with StringIO() as buf: + first = True + for o in self.opnds: + if not first: + buf.write("&&") + buf.write(str(o)) + first = False + return buf.getvalue() + +# +# A semantic context which is true whenever at least one of the contained +# contexts is true. +del OR +class OR (SemanticContext): + + def __init__(self, a:SemanticContext, b:SemanticContext): + operands = set() + if isinstance( a, OR ): + operands.update(a.opnds) + else: + operands.add(a) + if isinstance( b, OR ): + operands.update(b.opnds) + else: + operands.add(b) + + precedencePredicates = filterPrecedencePredicates(operands) + if len(precedencePredicates)>0: + # interested in the transition with the highest precedence + s = sorted(precedencePredicates) + reduced = s[-1] + operands.add(reduced) + + self.opnds = list(operands) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, OR): + return False + else: + return self.opnds == other.opnds + + def __hash__(self): + h = 0 + for o in self.opnds: + h = hash((h, o)) + return hash((h, "OR")) + + #

      + # The evaluation of predicates by this context is short-circuiting, but + # unordered.

      + # + def eval(self, parser:Recognizer, outerContext:RuleContext): + return any(opnd.eval(parser, outerContext) for opnd in self.opnds) + + def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext): + differs = False + operands = [] + for context in self.opnds: + evaluated = context.evalPrecedence(parser, outerContext) + differs |= evaluated is not context + if evaluated is SemanticContext.NONE: + # The OR context is true if any element is true + return SemanticContext.NONE + elif evaluated is not None: + # Reduce the result by skipping false elements + operands.append(evaluated) + + if not differs: + return self + + if len(operands)==0: + # all elements were false, so the OR context is false + return None + + result = None + for o in operands: + result = o if result is None else orContext(result, o) + + return result + + def __str__(self): + with StringIO() as buf: + first = True + for o in self.opnds: + if not first: + buf.write("||") + buf.write(str(o)) + first = False + return buf.getvalue() + + +SemanticContext.NONE = Predicate() \ No newline at end of file diff --git a/src/antlr4/atn/Transition.py b/src/antlr4/atn/Transition.py new file mode 100644 index 00000000..0ed042cd --- /dev/null +++ b/src/antlr4/atn/Transition.py @@ -0,0 +1,257 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# An ATN transition between any two ATN states. Subclasses define +# atom, set, epsilon, action, predicate, rule transitions. +# +#

      This is a one way link. It emanates from a state (usually via a list of +# transitions) and has a target state.

      +# +#

      Since we never have to change the ATN transitions once we construct it, +# we can fix these transitions as specific classes. The DFA transitions +# on the other hand need to update the labels as it adds transitions to +# the states. We'll use the term Edge for the DFA to distinguish them from +# ATN transitions.

      +# +from antlr4.IntervalSet import IntervalSet +from antlr4.Token import Token + +# need forward declarations +from antlr4.atn.SemanticContext import Predicate, PrecedencePredicate + +ATNState = None +RuleStartState = None + +class Transition (object): + # constants for serialization + EPSILON = 1 + RANGE = 2 + RULE = 3 + PREDICATE = 4 # e.g., {isType(input.LT(1))}? + ATOM = 5 + ACTION = 6 + SET = 7 # ~(A|B) or ~atom, wildcard, which convert to next 2 + NOT_SET = 8 + WILDCARD = 9 + PRECEDENCE = 10 + + serializationNames = [ + "INVALID", + "EPSILON", + "RANGE", + "RULE", + "PREDICATE", + "ATOM", + "ACTION", + "SET", + "NOT_SET", + "WILDCARD", + "PRECEDENCE" + ] + + serializationTypes = dict() + + def __init__(self, target:ATNState): + # The target of this transition. + if target is None: + raise Exception("target cannot be null.") + self.target = target + # Are we epsilon, action, sempred? + self.isEpsilon = False + self.label = None + + +# TODO: make all transitions sets? no, should remove set edges +class AtomTransition(Transition): + + def __init__(self, target:ATNState, label:int): + super().__init__(target) + self.label_ = label # The token type or character value; or, signifies special label. + self.label = self.makeLabel() + self.serializationType = self.ATOM + + def makeLabel(self): + s = IntervalSet() + s.addOne(self.label_) + return s + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return self.label_ == symbol + + def __str__(self): + return str(self.label_) + +class RuleTransition(Transition): + + def __init__(self, ruleStart:RuleStartState, ruleIndex:int, precedence:int, followState:ATNState): + super().__init__(ruleStart) + self.ruleIndex = ruleIndex # ptr to the rule definition object for this rule ref + self.precedence = precedence + self.followState = followState # what node to begin computations following ref to rule + self.serializationType = self.RULE + self.isEpsilon = True + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return False + + +class EpsilonTransition(Transition): + + def __init__(self, target, outermostPrecedenceReturn=-1): + super(EpsilonTransition, self).__init__(target) + self.serializationType = self.EPSILON + self.isEpsilon = True + self.outermostPrecedenceReturn = outermostPrecedenceReturn + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return False + + def __str__(self): + return "epsilon" + +class RangeTransition(Transition): + + def __init__(self, target:ATNState, start:int, stop:int): + super().__init__(target) + self.serializationType = self.RANGE + self.start = start + self.stop = stop + self.label = self.makeLabel() + + def makeLabel(self): + s = IntervalSet() + s.addRange(range(self.start, self.stop + 1)) + return s + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return symbol >= self.start and symbol <= self.stop + + def __str__(self): + return "'" + chr(self.start) + "'..'" + chr(self.stop) + "'" + +class AbstractPredicateTransition(Transition): + + def __init__(self, target:ATNState): + super().__init__(target) + + +class PredicateTransition(AbstractPredicateTransition): + + def __init__(self, target:ATNState, ruleIndex:int, predIndex:int, isCtxDependent:bool): + super().__init__(target) + self.serializationType = self.PREDICATE + self.ruleIndex = ruleIndex + self.predIndex = predIndex + self.isCtxDependent = isCtxDependent # e.g., $i ref in pred + self.isEpsilon = True + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return False + + def getPredicate(self): + return Predicate(self.ruleIndex, self.predIndex, self.isCtxDependent) + + def __str__(self): + return "pred_" + str(self.ruleIndex) + ":" + str(self.predIndex) + +class ActionTransition(Transition): + + def __init__(self, target:ATNState, ruleIndex:int, actionIndex:int=-1, isCtxDependent:bool=False): + super().__init__(target) + self.serializationType = self.ACTION + self.ruleIndex = ruleIndex + self.actionIndex = actionIndex + self.isCtxDependent = isCtxDependent # e.g., $i ref in pred + self.isEpsilon = True + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return False + + def __str__(self): + return "action_"+self.ruleIndex+":"+self.actionIndex + +# A transition containing a set of values. +class SetTransition(Transition): + + def __init__(self, target:ATNState, set:IntervalSet): + super().__init__(target) + self.serializationType = self.SET + if set is not None: + self.label = set + else: + self.label = IntervalSet() + self.label.addRange(range(Token.INVALID_TYPE, Token.INVALID_TYPE + 1)) + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return symbol in self.label + + def __str__(self): + return str(self.label) + +class NotSetTransition(SetTransition): + + def __init__(self, target:ATNState, set:IntervalSet): + super().__init__(target, set) + self.serializationType = self.NOT_SET + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return symbol >= minVocabSymbol \ + and symbol <= maxVocabSymbol \ + and not super(type(self), self).matches(symbol, minVocabSymbol, maxVocabSymbol) + + def __str__(self): + return '~' + super(type(self), self).__str__() + + +class WildcardTransition(Transition): + + def __init__(self, target:ATNState): + super().__init__(target) + self.serializationType = self.WILDCARD + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return symbol >= minVocabSymbol and symbol <= maxVocabSymbol + + def __str__(self): + return "." + + +class PrecedencePredicateTransition(AbstractPredicateTransition): + + def __init__(self, target:ATNState, precedence:int): + super().__init__(target) + self.serializationType = self.PRECEDENCE + self.precedence = precedence + self.isEpsilon = True + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return False + + + def getPredicate(self): + return PrecedencePredicate(self.precedence) + + def __str__(self): + return self.precedence + " >= _p" + + +Transition.serializationTypes = { + EpsilonTransition: Transition.EPSILON, + RangeTransition: Transition.RANGE, + RuleTransition: Transition.RULE, + PredicateTransition: Transition.PREDICATE, + AtomTransition: Transition.ATOM, + ActionTransition: Transition.ACTION, + SetTransition: Transition.SET, + NotSetTransition: Transition.NOT_SET, + WildcardTransition: Transition.WILDCARD, + PrecedencePredicateTransition: Transition.PRECEDENCE + } + +del ATNState +del RuleStartState + +from antlr4.atn.ATNState import * \ No newline at end of file diff --git a/src/antlr4/atn/__init__.py b/src/antlr4/atn/__init__.py new file mode 100644 index 00000000..216c000d --- /dev/null +++ b/src/antlr4/atn/__init__.py @@ -0,0 +1 @@ +__author__ = 'ericvergnaud' diff --git a/src/antlr4/dfa/DFA.py b/src/antlr4/dfa/DFA.py new file mode 100644 index 00000000..af6839ca --- /dev/null +++ b/src/antlr4/dfa/DFA.py @@ -0,0 +1,133 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +from antlr4.atn.ATNState import StarLoopEntryState + +from antlr4.atn.ATNConfigSet import ATNConfigSet +from antlr4.atn.ATNState import DecisionState +from antlr4.dfa.DFAState import DFAState +from antlr4.error.Errors import IllegalStateException + + +class DFA(object): + + def __init__(self, atnStartState:DecisionState, decision:int=0): + # From which ATN state did we create this DFA? + self.atnStartState = atnStartState + self.decision = decision + # A set of all DFA states. Use {@link Map} so we can get old state back + # ({@link Set} only allows you to see if it's there). + self._states = dict() + self.s0 = None + # {@code true} if this DFA is for a precedence decision; otherwise, + # {@code false}. This is the backing field for {@link #isPrecedenceDfa}, + # {@link #setPrecedenceDfa}. + self.precedenceDfa = False + + if isinstance(atnStartState, StarLoopEntryState): + if atnStartState.isPrecedenceDecision: + self.precedenceDfa = True + precedenceState = DFAState(configs=ATNConfigSet()) + precedenceState.edges = [] + precedenceState.isAcceptState = False + precedenceState.requiresFullContext = False + self.s0 = precedenceState + + + # Get the start state for a specific precedence value. + # + # @param precedence The current precedence. + # @return The start state corresponding to the specified precedence, or + # {@code null} if no start state exists for the specified precedence. + # + # @throws IllegalStateException if this is not a precedence DFA. + # @see #isPrecedenceDfa() + + def getPrecedenceStartState(self, precedence:int): + if not self.precedenceDfa: + raise IllegalStateException("Only precedence DFAs may contain a precedence start state.") + + # s0.edges is never null for a precedence DFA + if precedence < 0 or precedence >= len(self.s0.edges): + return None + return self.s0.edges[precedence] + + # Set the start state for a specific precedence value. + # + # @param precedence The current precedence. + # @param startState The start state corresponding to the specified + # precedence. + # + # @throws IllegalStateException if this is not a precedence DFA. + # @see #isPrecedenceDfa() + # + def setPrecedenceStartState(self, precedence:int, startState:DFAState): + if not self.precedenceDfa: + raise IllegalStateException("Only precedence DFAs may contain a precedence start state.") + + if precedence < 0: + return + + # synchronization on s0 here is ok. when the DFA is turned into a + # precedence DFA, s0 will be initialized once and not updated again + # s0.edges is never null for a precedence DFA + if precedence >= len(self.s0.edges): + ext = [None] * (precedence + 1 - len(self.s0.edges)) + self.s0.edges.extend(ext) + self.s0.edges[precedence] = startState + # + # Sets whether this is a precedence DFA. If the specified value differs + # from the current DFA configuration, the following actions are taken; + # otherwise no changes are made to the current DFA. + # + #
        + #
      • The {@link #states} map is cleared
      • + #
      • If {@code precedenceDfa} is {@code false}, the initial state + # {@link #s0} is set to {@code null}; otherwise, it is initialized to a new + # {@link DFAState} with an empty outgoing {@link DFAState#edges} array to + # store the start states for individual precedence values.
      • + #
      • The {@link #precedenceDfa} field is updated
      • + #
      + # + # @param precedenceDfa {@code true} if this is a precedence DFA; otherwise, + # {@code false} + + def setPrecedenceDfa(self, precedenceDfa:bool): + if self.precedenceDfa != precedenceDfa: + self._states = dict() + if precedenceDfa: + precedenceState = DFAState(configs=ATNConfigSet()) + precedenceState.edges = [] + precedenceState.isAcceptState = False + precedenceState.requiresFullContext = False + self.s0 = precedenceState + else: + self.s0 = None + self.precedenceDfa = precedenceDfa + + @property + def states(self): + return self._states + + # Return a list of all states in this DFA, ordered by state number. + def sortedStates(self): + return sorted(self._states.keys(), key=lambda state: state.stateNumber) + + def __str__(self): + return self.toString(None) + + def toString(self, literalNames:list=None, symbolicNames:list=None): + if self.s0 is None: + return "" + from antlr4.dfa.DFASerializer import DFASerializer + serializer = DFASerializer(self,literalNames,symbolicNames) + return str(serializer) + + def toLexerString(self): + if self.s0 is None: + return "" + from antlr4.dfa.DFASerializer import LexerDFASerializer + serializer = LexerDFASerializer(self) + return str(serializer) + diff --git a/src/antlr4/dfa/DFASerializer.py b/src/antlr4/dfa/DFASerializer.py new file mode 100644 index 00000000..eeb6e366 --- /dev/null +++ b/src/antlr4/dfa/DFASerializer.py @@ -0,0 +1,72 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# A DFA walker that knows how to dump them to serialized strings.#/ +from io import StringIO +from antlr4 import DFA +from antlr4.Utils import str_list +from antlr4.dfa.DFAState import DFAState + + +class DFASerializer(object): + + def __init__(self, dfa:DFA, literalNames:list=None, symbolicNames:list=None): + self.dfa = dfa + self.literalNames = literalNames + self.symbolicNames = symbolicNames + + def __str__(self): + if self.dfa.s0 is None: + return None + with StringIO() as buf: + for s in self.dfa.sortedStates(): + n = 0 + if s.edges is not None: + n = len(s.edges) + for i in range(0, n): + t = s.edges[i] + if t is not None and t.stateNumber != 0x7FFFFFFF: + buf.write(self.getStateString(s)) + label = self.getEdgeLabel(i) + buf.write("-") + buf.write(label) + buf.write("->") + buf.write(self.getStateString(t)) + buf.write('\n') + output = buf.getvalue() + if len(output)==0: + return None + else: + return output + + def getEdgeLabel(self, i:int): + if i==0: + return "EOF" + if self.literalNames is not None and i<=len(self.literalNames): + return self.literalNames[i-1] + elif self.symbolicNames is not None and i<=len(self.symbolicNames): + return self.symbolicNames[i-1] + else: + return str(i-1) + + def getStateString(self, s:DFAState): + n = s.stateNumber + baseStateStr = ( ":" if s.isAcceptState else "") + "s" + str(n) + ( "^" if s.requiresFullContext else "") + if s.isAcceptState: + if s.predicates is not None: + return baseStateStr + "=>" + str_list(s.predicates) + else: + return baseStateStr + "=>" + str(s.prediction) + else: + return baseStateStr + +class LexerDFASerializer(DFASerializer): + + def __init__(self, dfa:DFA): + super().__init__(dfa, None) + + def getEdgeLabel(self, i:int): + return "'" + chr(i) + "'" diff --git a/src/antlr4/dfa/DFAState.py b/src/antlr4/dfa/DFAState.py new file mode 100644 index 00000000..d7af5a17 --- /dev/null +++ b/src/antlr4/dfa/DFAState.py @@ -0,0 +1,120 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# Map a predicate to a predicted alternative.#/ +from io import StringIO +from antlr4.atn.ATNConfigSet import ATNConfigSet +from antlr4.atn.SemanticContext import SemanticContext + + +class PredPrediction(object): + def __init__(self, pred:SemanticContext, alt:int): + self.alt = alt + self.pred = pred + + def __str__(self): + return "(" + str(self.pred) + ", " + str(self.alt) + ")" + +# A DFA state represents a set of possible ATN configurations. +# As Aho, Sethi, Ullman p. 117 says "The DFA uses its state +# to keep track of all possible states the ATN can be in after +# reading each input symbol. That is to say, after reading +# input a1a2..an, the DFA is in a state that represents the +# subset T of the states of the ATN that are reachable from the +# ATN's start state along some path labeled a1a2..an." +# In conventional NFA→DFA conversion, therefore, the subset T +# would be a bitset representing the set of states the +# ATN could be in. We need to track the alt predicted by each +# state as well, however. More importantly, we need to maintain +# a stack of states, tracking the closure operations as they +# jump from rule to rule, emulating rule invocations (method calls). +# I have to add a stack to simulate the proper lookahead sequences for +# the underlying LL grammar from which the ATN was derived. +# +#

      I use a set of ATNConfig objects not simple states. An ATNConfig +# is both a state (ala normal conversion) and a RuleContext describing +# the chain of rules (if any) followed to arrive at that state.

      +# +#

      A DFA state may have multiple references to a particular state, +# but with different ATN contexts (with same or different alts) +# meaning that state was reached via a different set of rule invocations.

      +#/ +class DFAState(object): + + def __init__(self, stateNumber:int=-1, configs:ATNConfigSet=ATNConfigSet()): + self.stateNumber = stateNumber + self.configs = configs + # {@code edges[symbol]} points to target of symbol. Shift up by 1 so (-1) + # {@link Token#EOF} maps to {@code edges[0]}. + self.edges = None + self.isAcceptState = False + # if accept state, what ttype do we match or alt do we predict? + # This is set to {@link ATN#INVALID_ALT_NUMBER} when {@link #predicates}{@code !=null} or + # {@link #requiresFullContext}. + self.prediction = 0 + self.lexerActionExecutor = None + # Indicates that this state was created during SLL prediction that + # discovered a conflict between the configurations in the state. Future + # {@link ParserATNSimulator#execATN} invocations immediately jumped doing + # full context prediction if this field is true. + self.requiresFullContext = False + # During SLL parsing, this is a list of predicates associated with the + # ATN configurations of the DFA state. When we have predicates, + # {@link #requiresFullContext} is {@code false} since full context prediction evaluates predicates + # on-the-fly. If this is not null, then {@link #prediction} is + # {@link ATN#INVALID_ALT_NUMBER}. + # + #

      We only use these for non-{@link #requiresFullContext} but conflicting states. That + # means we know from the context (it's $ or we don't dip into outer + # context) that it's an ambiguity not a conflict.

      + # + #

      This list is computed by {@link ParserATNSimulator#predicateDFAState}.

      + self.predicates = None + + + + # Get the set of all alts mentioned by all ATN configurations in this + # DFA state. + def getAltSet(self): + if self.configs is not None: + return set(cfg.alt for cfg in self.configs) or None + return None + + def __hash__(self): + return hash(self.configs) + + # Two {@link DFAState} instances are equal if their ATN configuration sets + # are the same. This method is used to see if a state already exists. + # + #

      Because the number of alternatives and number of ATN configurations are + # finite, there is a finite number of DFA states that can be processed. + # This is necessary to show that the algorithm terminates.

      + # + #

      Cannot test the DFA state numbers here because in + # {@link ParserATNSimulator#addDFAState} we need to know if any other state + # exists that has this exact set of ATN configurations. The + # {@link #stateNumber} is irrelevant.

      + def __eq__(self, other): + # compare set of ATN configurations in this set with other + if self is other: + return True + elif not isinstance(other, DFAState): + return False + else: + return self.configs==other.configs + + def __str__(self): + with StringIO() as buf: + buf.write(str(self.stateNumber)) + buf.write(":") + buf.write(str(self.configs)) + if self.isAcceptState: + buf.write("=>") + if self.predicates is not None: + buf.write(str(self.predicates)) + else: + buf.write(str(self.prediction)) + return buf.getvalue() diff --git a/src/antlr4/dfa/__init__.py b/src/antlr4/dfa/__init__.py new file mode 100644 index 00000000..216c000d --- /dev/null +++ b/src/antlr4/dfa/__init__.py @@ -0,0 +1 @@ +__author__ = 'ericvergnaud' diff --git a/src/antlr4/error/DiagnosticErrorListener.py b/src/antlr4/error/DiagnosticErrorListener.py new file mode 100644 index 00000000..7f983deb --- /dev/null +++ b/src/antlr4/error/DiagnosticErrorListener.py @@ -0,0 +1,107 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + + +# +# This implementation of {@link ANTLRErrorListener} can be used to identify +# certain potential correctness and performance problems in grammars. "Reports" +# are made by calling {@link Parser#notifyErrorListeners} with the appropriate +# message. +# +#
        +#
      • Ambiguities: These are cases where more than one path through the +# grammar can match the input.
      • +#
      • Weak context sensitivity: These are cases where full-context +# prediction resolved an SLL conflict to a unique alternative which equaled the +# minimum alternative of the SLL conflict.
      • +#
      • Strong (forced) context sensitivity: These are cases where the +# full-context prediction resolved an SLL conflict to a unique alternative, +# and the minimum alternative of the SLL conflict was found to not be +# a truly viable alternative. Two-stage parsing cannot be used for inputs where +# this situation occurs.
      • +#
      + +from io import StringIO +from antlr4 import Parser, DFA +from antlr4.atn.ATNConfigSet import ATNConfigSet +from antlr4.error.ErrorListener import ErrorListener + +class DiagnosticErrorListener(ErrorListener): + + def __init__(self, exactOnly:bool=True): + # whether all ambiguities or only exact ambiguities are reported. + self.exactOnly = exactOnly + + def reportAmbiguity(self, recognizer:Parser, dfa:DFA, startIndex:int, + stopIndex:int, exact:bool, ambigAlts:set, configs:ATNConfigSet): + if self.exactOnly and not exact: + return + + with StringIO() as buf: + buf.write("reportAmbiguity d=") + buf.write(self.getDecisionDescription(recognizer, dfa)) + buf.write(": ambigAlts=") + buf.write(str(self.getConflictingAlts(ambigAlts, configs))) + buf.write(", input='") + buf.write(recognizer.getTokenStream().getText((startIndex, stopIndex))) + buf.write("'") + recognizer.notifyErrorListeners(buf.getvalue()) + + + def reportAttemptingFullContext(self, recognizer:Parser, dfa:DFA, startIndex:int, + stopIndex:int, conflictingAlts:set, configs:ATNConfigSet): + with StringIO() as buf: + buf.write("reportAttemptingFullContext d=") + buf.write(self.getDecisionDescription(recognizer, dfa)) + buf.write(", input='") + buf.write(recognizer.getTokenStream().getText((startIndex, stopIndex))) + buf.write("'") + recognizer.notifyErrorListeners(buf.getvalue()) + + def reportContextSensitivity(self, recognizer:Parser, dfa:DFA, startIndex:int, + stopIndex:int, prediction:int, configs:ATNConfigSet): + with StringIO() as buf: + buf.write("reportContextSensitivity d=") + buf.write(self.getDecisionDescription(recognizer, dfa)) + buf.write(", input='") + buf.write(recognizer.getTokenStream().getText((startIndex, stopIndex))) + buf.write("'") + recognizer.notifyErrorListeners(buf.getvalue()) + + def getDecisionDescription(self, recognizer:Parser, dfa:DFA): + decision = dfa.decision + ruleIndex = dfa.atnStartState.ruleIndex + + ruleNames = recognizer.ruleNames + if ruleIndex < 0 or ruleIndex >= len(ruleNames): + return str(decision) + + ruleName = ruleNames[ruleIndex] + if ruleName is None or len(ruleName)==0: + return str(decision) + + return str(decision) + " (" + ruleName + ")" + + # + # Computes the set of conflicting or ambiguous alternatives from a + # configuration set, if that information was not already provided by the + # parser. + # + # @param reportedAlts The set of conflicting or ambiguous alternatives, as + # reported by the parser. + # @param configs The conflicting or ambiguous configuration set. + # @return Returns {@code reportedAlts} if it is not {@code null}, otherwise + # returns the set of alternatives represented in {@code configs}. + # + def getConflictingAlts(self, reportedAlts:set, configs:ATNConfigSet): + if reportedAlts is not None: + return reportedAlts + + result = set() + for config in configs: + result.add(config.alt) + + return result diff --git a/src/antlr4/error/ErrorListener.py b/src/antlr4/error/ErrorListener.py new file mode 100644 index 00000000..c8614beb --- /dev/null +++ b/src/antlr4/error/ErrorListener.py @@ -0,0 +1,73 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. + +# Provides an empty default implementation of {@link ANTLRErrorListener}. The +# default implementation of each method does nothing, but can be overridden as +# necessary. + + +import sys + +class ErrorListener(object): + + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): + pass + + def reportAmbiguity(self, recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs): + pass + + def reportAttemptingFullContext(self, recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs): + pass + + def reportContextSensitivity(self, recognizer, dfa, startIndex, stopIndex, prediction, configs): + pass + +class ConsoleErrorListener(ErrorListener): + # + # Provides a default instance of {@link ConsoleErrorListener}. + # + INSTANCE = None + + # + # {@inheritDoc} + # + #

      + # This implementation prints messages to {@link System#err} containing the + # values of {@code line}, {@code charPositionInLine}, and {@code msg} using + # the following format.

      + # + #
      +    # line line:charPositionInLine msg
      +    # 
      + # + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): + #file=sys.stderr + print("(" + str(line) + ", " + str(column) + ")"+ " - " + msg + ":", file=sys.stderr) + +ConsoleErrorListener.INSTANCE = ConsoleErrorListener() + +class ProxyErrorListener(ErrorListener): + + def __init__(self, delegates): + super().__init__() + if delegates is None: + raise ReferenceError("delegates") + self.delegates = delegates + + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): + for delegate in self.delegates: + delegate.syntaxError(recognizer, offendingSymbol, line, column, msg, e) + + def reportAmbiguity(self, recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs): + for delegate in self.delegates: + delegate.reportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs) + + def reportAttemptingFullContext(self, recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs): + for delegate in self.delegates: + delegate.reportAttemptingFullContext(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs) + + def reportContextSensitivity(self, recognizer, dfa, startIndex, stopIndex, prediction, configs): + for delegate in self.delegates: + delegate.reportContextSensitivity(recognizer, dfa, startIndex, stopIndex, prediction, configs) diff --git a/src/antlr4/error/ErrorStrategy.py b/src/antlr4/error/ErrorStrategy.py new file mode 100644 index 00000000..4c6d89d7 --- /dev/null +++ b/src/antlr4/error/ErrorStrategy.py @@ -0,0 +1,698 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# +import sys +from antlr4.IntervalSet import IntervalSet + +from antlr4.Token import Token +from antlr4.atn.ATNState import ATNState +from antlr4.error.Errors import RecognitionException, NoViableAltException, InputMismatchException, \ + FailedPredicateException, ParseCancellationException + +# need forward declaration +Parser = None + +class ErrorStrategy(object): + + def reset(self, recognizer:Parser): + pass + + def recoverInline(self, recognizer:Parser): + pass + + def recover(self, recognizer:Parser, e:RecognitionException): + pass + + def sync(self, recognizer:Parser): + pass + + def inErrorRecoveryMode(self, recognizer:Parser): + pass + + def reportError(self, recognizer:Parser, e:RecognitionException): + pass + + +# This is the default implementation of {@link ANTLRErrorStrategy} used for +# error reporting and recovery in ANTLR parsers. +# +class DefaultErrorStrategy(ErrorStrategy): + + def __init__(self): + super().__init__() + # Indicates whether the error strategy is currently "recovering from an + # error". This is used to suppress reporting multiple error messages while + # attempting to recover from a detected syntax error. + # + # @see #inErrorRecoveryMode + # + self.errorRecoveryMode = False + + # The index into the input stream where the last error occurred. + # This is used to prevent infinite loops where an error is found + # but no token is consumed during recovery...another error is found, + # ad nauseum. This is a failsafe mechanism to guarantee that at least + # one token/tree node is consumed for two errors. + # + self.lastErrorIndex = -1 + self.lastErrorStates = None + + #

      The default implementation simply calls {@link #endErrorCondition} to + # ensure that the handler is not in error recovery mode.

      + def reset(self, recognizer:Parser): + self.endErrorCondition(recognizer) + + # + # This method is called to enter error recovery mode when a recognition + # exception is reported. + # + # @param recognizer the parser instance + # + def beginErrorCondition(self, recognizer:Parser): + self.errorRecoveryMode = True + + def inErrorRecoveryMode(self, recognizer:Parser): + return self.errorRecoveryMode + + # + # This method is called to leave error recovery mode after recovering from + # a recognition exception. + # + # @param recognizer + # + def endErrorCondition(self, recognizer:Parser): + self.errorRecoveryMode = False + self.lastErrorStates = None + self.lastErrorIndex = -1 + + # + # {@inheritDoc} + # + #

      The default implementation simply calls {@link #endErrorCondition}.

      + # + def reportMatch(self, recognizer:Parser): + self.endErrorCondition(recognizer) + + # + # {@inheritDoc} + # + #

      The default implementation returns immediately if the handler is already + # in error recovery mode. Otherwise, it calls {@link #beginErrorCondition} + # and dispatches the reporting task based on the runtime type of {@code e} + # according to the following table.

      + # + #
        + #
      • {@link NoViableAltException}: Dispatches the call to + # {@link #reportNoViableAlternative}
      • + #
      • {@link InputMismatchException}: Dispatches the call to + # {@link #reportInputMismatch}
      • + #
      • {@link FailedPredicateException}: Dispatches the call to + # {@link #reportFailedPredicate}
      • + #
      • All other types: calls {@link Parser#notifyErrorListeners} to report + # the exception
      • + #
      + # + def reportError(self, recognizer:Parser, e:RecognitionException): + # if we've already reported an error and have not matched a token + # yet successfully, don't report any errors. + if self.inErrorRecoveryMode(recognizer): + return # don't report spurious errors + self.beginErrorCondition(recognizer) + if isinstance( e, NoViableAltException ): + self.reportNoViableAlternative(recognizer, e) + elif isinstance( e, InputMismatchException ): + self.reportInputMismatch(recognizer, e) + elif isinstance( e, FailedPredicateException ): + self.reportFailedPredicate(recognizer, e) + else: + print("unknown recognition error type: " + type(e).__name__) + recognizer.notifyErrorListeners(e.message, e.offendingToken, e) + + # + # {@inheritDoc} + # + #

      The default implementation resynchronizes the parser by consuming tokens + # until we find one in the resynchronization set--loosely the set of tokens + # that can follow the current rule.

      + # + def recover(self, recognizer:Parser, e:RecognitionException): + if self.lastErrorIndex==recognizer.getInputStream().index \ + and self.lastErrorStates is not None \ + and recognizer.state in self.lastErrorStates: + # uh oh, another error at same token index and previously-visited + # state in ATN; must be a case where LT(1) is in the recovery + # token set so nothing got consumed. Consume a single token + # at least to prevent an infinite loop; this is a failsafe. + recognizer.consume() + + self.lastErrorIndex = recognizer._input.index + if self.lastErrorStates is None: + self.lastErrorStates = [] + self.lastErrorStates.append(recognizer.state) + followSet = self.getErrorRecoverySet(recognizer) + self.consumeUntil(recognizer, followSet) + + # The default implementation of {@link ANTLRErrorStrategy#sync} makes sure + # that the current lookahead symbol is consistent with what were expecting + # at this point in the ATN. You can call this anytime but ANTLR only + # generates code to check before subrules/loops and each iteration. + # + #

      Implements Jim Idle's magic sync mechanism in closures and optional + # subrules. E.g.,

      + # + #
      +    # a : sync ( stuff sync )* ;
      +    # sync : {consume to what can follow sync} ;
      +    # 
      + # + # At the start of a sub rule upon error, {@link #sync} performs single + # token deletion, if possible. If it can't do that, it bails on the current + # rule and uses the default error recovery, which consumes until the + # resynchronization set of the current rule. + # + #

      If the sub rule is optional ({@code (...)?}, {@code (...)*}, or block + # with an empty alternative), then the expected set includes what follows + # the subrule.

      + # + #

      During loop iteration, it consumes until it sees a token that can start a + # sub rule or what follows loop. Yes, that is pretty aggressive. We opt to + # stay in the loop as long as possible.

      + # + #

      ORIGINS

      + # + #

      Previous versions of ANTLR did a poor job of their recovery within loops. + # A single mismatch token or missing token would force the parser to bail + # out of the entire rules surrounding the loop. So, for rule

      + # + #
      +    # classDef : 'class' ID '{' member* '}'
      +    # 
      + # + # input with an extra token between members would force the parser to + # consume until it found the next class definition rather than the next + # member definition of the current class. + # + #

      This functionality cost a little bit of effort because the parser has to + # compare token set at the start of the loop and at each iteration. If for + # some reason speed is suffering for you, you can turn off this + # functionality by simply overriding this method as a blank { }.

      + # + def sync(self, recognizer:Parser): + # If already recovering, don't try to sync + if self.inErrorRecoveryMode(recognizer): + return + + s = recognizer._interp.atn.states[recognizer.state] + la = recognizer.getTokenStream().LA(1) + # try cheaper subset first; might get lucky. seems to shave a wee bit off + nextTokens = recognizer.atn.nextTokens(s) + if Token.EPSILON in nextTokens or la in nextTokens: + return + + if s.stateType in [ATNState.BLOCK_START, ATNState.STAR_BLOCK_START, + ATNState.PLUS_BLOCK_START, ATNState.STAR_LOOP_ENTRY]: + # report error and recover if possible + if self.singleTokenDeletion(recognizer)is not None: + return + else: + raise InputMismatchException(recognizer) + + elif s.stateType in [ATNState.PLUS_LOOP_BACK, ATNState.STAR_LOOP_BACK]: + self.reportUnwantedToken(recognizer) + expecting = recognizer.getExpectedTokens() + whatFollowsLoopIterationOrRule = expecting.addSet(self.getErrorRecoverySet(recognizer)) + self.consumeUntil(recognizer, whatFollowsLoopIterationOrRule) + + else: + # do nothing if we can't identify the exact kind of ATN state + pass + + # This is called by {@link #reportError} when the exception is a + # {@link NoViableAltException}. + # + # @see #reportError + # + # @param recognizer the parser instance + # @param e the recognition exception + # + def reportNoViableAlternative(self, recognizer:Parser, e:NoViableAltException): + tokens = recognizer.getTokenStream() + if tokens is not None: + if e.startToken.type==Token.EOF: + input = "" + else: + input = tokens.getText((e.startToken, e.offendingToken)) + else: + input = "" + msg = "no viable alternative at input " + self.escapeWSAndQuote(input) + recognizer.notifyErrorListeners(msg, e.offendingToken, e) + + # + # This is called by {@link #reportError} when the exception is an + # {@link InputMismatchException}. + # + # @see #reportError + # + # @param recognizer the parser instance + # @param e the recognition exception + # + def reportInputMismatch(self, recognizer:Parser, e:InputMismatchException): + msg = "SyntacticError" + #self.getTokenErrorDisplay(e.offendingToken) \ + " expecting " + e.getExpectedTokens().toString(recognizer.literalNames, recognizer.symbolicNames) + recognizer.notifyErrorListeners(msg, e.offendingToken, e) + + # + # This is called by {@link #reportError} when the exception is a + # {@link FailedPredicateException}. + # + # @see #reportError + # + # @param recognizer the parser instance + # @param e the recognition exception + # + def reportFailedPredicate(self, recognizer, e): + ruleName = recognizer.ruleNames[recognizer._ctx.getRuleIndex()] + msg = "rule " + ruleName + " " + e.message + recognizer.notifyErrorListeners(msg, e.offendingToken, e) + + # This method is called to report a syntax error which requires the removal + # of a token from the input stream. At the time this method is called, the + # erroneous symbol is current {@code LT(1)} symbol and has not yet been + # removed from the input stream. When this method returns, + # {@code recognizer} is in error recovery mode. + # + #

      This method is called when {@link #singleTokenDeletion} identifies + # single-token deletion as a viable recovery strategy for a mismatched + # input error.

      + # + #

      The default implementation simply returns if the handler is already in + # error recovery mode. Otherwise, it calls {@link #beginErrorCondition} to + # enter error recovery mode, followed by calling + # {@link Parser#notifyErrorListeners}.

      + # + # @param recognizer the parser instance + # + def reportUnwantedToken(self, recognizer:Parser): + if self.inErrorRecoveryMode(recognizer): + return + + self.beginErrorCondition(recognizer) + t = recognizer.getCurrentToken() + tokenName = self.getTokenErrorDisplay(t) + expecting = self.getExpectedTokens(recognizer) + msg = "SyntacticError" + #+ tokenName + " expecting "+expecting.toString(recognizer.literalNames, recognizer.symbolicNames) + recognizer.notifyErrorListeners(msg, t, None) + + # This method is called to report a syntax error which requires the + # insertion of a missing token into the input stream. At the time this + # method is called, the missing token has not yet been inserted. When this + # method returns, {@code recognizer} is in error recovery mode. + # + #

      This method is called when {@link #singleTokenInsertion} identifies + # single-token insertion as a viable recovery strategy for a mismatched + # input error.

      + # + #

      The default implementation simply returns if the handler is already in + # error recovery mode. Otherwise, it calls {@link #beginErrorCondition} to + # enter error recovery mode, followed by calling + # {@link Parser#notifyErrorListeners}.

      + # + # @param recognizer the parser instance + # + def reportMissingToken(self, recognizer:Parser): + if self.inErrorRecoveryMode(recognizer): + return + self.beginErrorCondition(recognizer) + t = recognizer.getCurrentToken() + expecting = self.getExpectedTokens(recognizer) + msg = "missing " + expecting.toString(recognizer.literalNames, recognizer.symbolicNames) \ + + " at " + self.getTokenErrorDisplay(t) + recognizer.notifyErrorListeners(msg, t, None) + + #

      The default implementation attempts to recover from the mismatched input + # by using single token insertion and deletion as described below. If the + # recovery attempt fails, this method throws an + # {@link InputMismatchException}.

      + # + #

      EXTRA TOKEN (single token deletion)

      + # + #

      {@code LA(1)} is not what we are looking for. If {@code LA(2)} has the + # right token, however, then assume {@code LA(1)} is some extra spurious + # token and delete it. Then consume and return the next token (which was + # the {@code LA(2)} token) as the successful result of the match operation.

      + # + #

      This recovery strategy is implemented by {@link #singleTokenDeletion}.

      + # + #

      MISSING TOKEN (single token insertion)

      + # + #

      If current token (at {@code LA(1)}) is consistent with what could come + # after the expected {@code LA(1)} token, then assume the token is missing + # and use the parser's {@link TokenFactory} to create it on the fly. The + # "insertion" is performed by returning the created token as the successful + # result of the match operation.

      + # + #

      This recovery strategy is implemented by {@link #singleTokenInsertion}.

      + # + #

      EXAMPLE

      + # + #

      For example, Input {@code i=(3;} is clearly missing the {@code ')'}. When + # the parser returns from the nested call to {@code expr}, it will have + # call chain:

      + # + #
      +    # stat → expr → atom
      +    # 
      + # + # and it will be trying to match the {@code ')'} at this point in the + # derivation: + # + #
      +    # => ID '=' '(' INT ')' ('+' atom)* ';'
      +    #                    ^
      +    # 
      + # + # The attempt to match {@code ')'} will fail when it sees {@code ';'} and + # call {@link #recoverInline}. To recover, it sees that {@code LA(1)==';'} + # is in the set of tokens that can follow the {@code ')'} token reference + # in rule {@code atom}. It can assume that you forgot the {@code ')'}. + # + def recoverInline(self, recognizer:Parser): + # SINGLE TOKEN DELETION + matchedSymbol = self.singleTokenDeletion(recognizer) + if matchedSymbol is not None: + # we have deleted the extra token. + # now, move past ttype token as if all were ok + recognizer.consume() + return matchedSymbol + + # SINGLE TOKEN INSERTION + if self.singleTokenInsertion(recognizer): + return self.getMissingSymbol(recognizer) + + # even that didn't work; must throw the exception + raise InputMismatchException(recognizer) + + # + # This method implements the single-token insertion inline error recovery + # strategy. It is called by {@link #recoverInline} if the single-token + # deletion strategy fails to recover from the mismatched input. If this + # method returns {@code true}, {@code recognizer} will be in error recovery + # mode. + # + #

      This method determines whether or not single-token insertion is viable by + # checking if the {@code LA(1)} input symbol could be successfully matched + # if it were instead the {@code LA(2)} symbol. If this method returns + # {@code true}, the caller is responsible for creating and inserting a + # token with the correct type to produce this behavior.

      + # + # @param recognizer the parser instance + # @return {@code true} if single-token insertion is a viable recovery + # strategy for the current mismatched input, otherwise {@code false} + # + def singleTokenInsertion(self, recognizer:Parser): + currentSymbolType = recognizer.getTokenStream().LA(1) + # if current token is consistent with what could come after current + # ATN state, then we know we're missing a token; error recovery + # is free to conjure up and insert the missing token + atn = recognizer._interp.atn + currentState = atn.states[recognizer.state] + next = currentState.transitions[0].target + expectingAtLL2 = atn.nextTokens(next, recognizer._ctx) + if currentSymbolType in expectingAtLL2: + self.reportMissingToken(recognizer) + return True + else: + return False + + # This method implements the single-token deletion inline error recovery + # strategy. It is called by {@link #recoverInline} to attempt to recover + # from mismatched input. If this method returns null, the parser and error + # handler state will not have changed. If this method returns non-null, + # {@code recognizer} will not be in error recovery mode since the + # returned token was a successful match. + # + #

      If the single-token deletion is successful, this method calls + # {@link #reportUnwantedToken} to report the error, followed by + # {@link Parser#consume} to actually "delete" the extraneous token. Then, + # before returning {@link #reportMatch} is called to signal a successful + # match.

      + # + # @param recognizer the parser instance + # @return the successfully matched {@link Token} instance if single-token + # deletion successfully recovers from the mismatched input, otherwise + # {@code null} + # + def singleTokenDeletion(self, recognizer:Parser): + nextTokenType = recognizer.getTokenStream().LA(2) + expecting = self.getExpectedTokens(recognizer) + if nextTokenType in expecting: + self.reportUnwantedToken(recognizer) + # print("recoverFromMismatchedToken deleting " \ + # + str(recognizer.getTokenStream().LT(1)) \ + # + " since " + str(recognizer.getTokenStream().LT(2)) \ + # + " is what we want", file=sys.stderr) + recognizer.consume() # simply delete extra token + # we want to return the token we're actually matching + matchedSymbol = recognizer.getCurrentToken() + self.reportMatch(recognizer) # we know current token is correct + return matchedSymbol + else: + return None + + # Conjure up a missing token during error recovery. + # + # The recognizer attempts to recover from single missing + # symbols. But, actions might refer to that missing symbol. + # For example, x=ID {f($x);}. The action clearly assumes + # that there has been an identifier matched previously and that + # $x points at that token. If that token is missing, but + # the next token in the stream is what we want we assume that + # this token is missing and we keep going. Because we + # have to return some token to replace the missing token, + # we have to conjure one up. This method gives the user control + # over the tokens returned for missing tokens. Mostly, + # you will want to create something special for identifier + # tokens. For literals such as '{' and ',', the default + # action in the parser or tree parser works. It simply creates + # a CommonToken of the appropriate type. The text will be the token. + # If you change what tokens must be created by the lexer, + # override this method to create the appropriate tokens. + # + def getMissingSymbol(self, recognizer:Parser): + currentSymbol = recognizer.getCurrentToken() + expecting = self.getExpectedTokens(recognizer) + expectedTokenType = expecting[0] # get any element + if expectedTokenType==Token.EOF: + tokenText = "" + else: + name = None + if expectedTokenType < len(recognizer.literalNames): + name = recognizer.literalNames[expectedTokenType] + if name is None and expectedTokenType < len(recognizer.symbolicNames): + name = recognizer.symbolicNames[expectedTokenType] + tokenText = "" + current = currentSymbol + lookback = recognizer.getTokenStream().LT(-1) + if current.type==Token.EOF and lookback is not None: + current = lookback + return recognizer.getTokenFactory().create(current.source, + expectedTokenType, tokenText, Token.DEFAULT_CHANNEL, + -1, -1, current.line, current.column) + + def getExpectedTokens(self, recognizer:Parser): + return recognizer.getExpectedTokens() + + # How should a token be displayed in an error message? The default + # is to display just the text, but during development you might + # want to have a lot of information spit out. Override in that case + # to use t.toString() (which, for CommonToken, dumps everything about + # the token). This is better than forcing you to override a method in + # your token objects because you don't have to go modify your lexer + # so that it creates a new Java type. + # + def getTokenErrorDisplay(self, t:Token): + if t is None: + return "" + s = t.text + if s is None: + if t.type==Token.EOF: + s = "" + else: + s = "<" + str(t.type) + ">" + return self.escapeWSAndQuote(s) + + def escapeWSAndQuote(self, s:str): + s = s.replace("\n","\\n") + s = s.replace("\r","\\r") + s = s.replace("\t","\\t") + return "'" + s + "'" + + # Compute the error recovery set for the current rule. During + # rule invocation, the parser pushes the set of tokens that can + # follow that rule reference on the stack; this amounts to + # computing FIRST of what follows the rule reference in the + # enclosing rule. See LinearApproximator.FIRST(). + # This local follow set only includes tokens + # from within the rule; i.e., the FIRST computation done by + # ANTLR stops at the end of a rule. + # + # EXAMPLE + # + # When you find a "no viable alt exception", the input is not + # consistent with any of the alternatives for rule r. The best + # thing to do is to consume tokens until you see something that + # can legally follow a call to r#or* any rule that called r. + # You don't want the exact set of viable next tokens because the + # input might just be missing a token--you might consume the + # rest of the input looking for one of the missing tokens. + # + # Consider grammar: + # + # a : '[' b ']' + # | '(' b ')' + # ; + # b : c '^' INT ; + # c : ID + # | INT + # ; + # + # At each rule invocation, the set of tokens that could follow + # that rule is pushed on a stack. Here are the various + # context-sensitive follow sets: + # + # FOLLOW(b1_in_a) = FIRST(']') = ']' + # FOLLOW(b2_in_a) = FIRST(')') = ')' + # FOLLOW(c_in_b) = FIRST('^') = '^' + # + # Upon erroneous input "[]", the call chain is + # + # a -> b -> c + # + # and, hence, the follow context stack is: + # + # depth follow set start of rule execution + # 0 a (from main()) + # 1 ']' b + # 2 '^' c + # + # Notice that ')' is not included, because b would have to have + # been called from a different context in rule a for ')' to be + # included. + # + # For error recovery, we cannot consider FOLLOW(c) + # (context-sensitive or otherwise). We need the combined set of + # all context-sensitive FOLLOW sets--the set of all tokens that + # could follow any reference in the call chain. We need to + # resync to one of those tokens. Note that FOLLOW(c)='^' and if + # we resync'd to that token, we'd consume until EOF. We need to + # sync to context-sensitive FOLLOWs for a, b, and c: {']','^'}. + # In this case, for input "[]", LA(1) is ']' and in the set, so we would + # not consume anything. After printing an error, rule c would + # return normally. Rule b would not find the required '^' though. + # At this point, it gets a mismatched token error and throws an + # exception (since LA(1) is not in the viable following token + # set). The rule exception handler tries to recover, but finds + # the same recovery set and doesn't consume anything. Rule b + # exits normally returning to rule a. Now it finds the ']' (and + # with the successful match exits errorRecovery mode). + # + # So, you can see that the parser walks up the call chain looking + # for the token that was a member of the recovery set. + # + # Errors are not generated in errorRecovery mode. + # + # ANTLR's error recovery mechanism is based upon original ideas: + # + # "Algorithms + Data Structures = Programs" by Niklaus Wirth + # + # and + # + # "A note on error recovery in recursive descent parsers": + # http:#portal.acm.org/citation.cfm?id=947902.947905 + # + # Later, Josef Grosch had some good ideas: + # + # "Efficient and Comfortable Error Recovery in Recursive Descent + # Parsers": + # ftp:#www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip + # + # Like Grosch I implement context-sensitive FOLLOW sets that are combined + # at run-time upon error to avoid overhead during parsing. + # + def getErrorRecoverySet(self, recognizer:Parser): + atn = recognizer._interp.atn + ctx = recognizer._ctx + recoverSet = IntervalSet() + while ctx is not None and ctx.invokingState>=0: + # compute what follows who invoked us + invokingState = atn.states[ctx.invokingState] + rt = invokingState.transitions[0] + follow = atn.nextTokens(rt.followState) + recoverSet.addSet(follow) + ctx = ctx.parentCtx + recoverSet.removeOne(Token.EPSILON) + return recoverSet + + # Consume tokens until one matches the given token set.# + def consumeUntil(self, recognizer:Parser, set_:set): + ttype = recognizer.getTokenStream().LA(1) + while ttype != Token.EOF and not ttype in set_: + recognizer.consume() + ttype = recognizer.getTokenStream().LA(1) + + +# +# This implementation of {@link ANTLRErrorStrategy} responds to syntax errors +# by immediately canceling the parse operation with a +# {@link ParseCancellationException}. The implementation ensures that the +# {@link ParserRuleContext#exception} field is set for all parse tree nodes +# that were not completed prior to encountering the error. +# +#

      +# This error strategy is useful in the following scenarios.

      +# +#
        +#
      • Two-stage parsing: This error strategy allows the first +# stage of two-stage parsing to immediately terminate if an error is +# encountered, and immediately fall back to the second stage. In addition to +# avoiding wasted work by attempting to recover from errors here, the empty +# implementation of {@link BailErrorStrategy#sync} improves the performance of +# the first stage.
      • +#
      • Silent validation: When syntax errors are not being +# reported or logged, and the parse result is simply ignored if errors occur, +# the {@link BailErrorStrategy} avoids wasting work on recovering from errors +# when the result will be ignored either way.
      • +#
      +# +#

      +# {@code myparser.setErrorHandler(new BailErrorStrategy());}

      +# +# @see Parser#setErrorHandler(ANTLRErrorStrategy) +# +class BailErrorStrategy(DefaultErrorStrategy): + # Instead of recovering from exception {@code e}, re-throw it wrapped + # in a {@link ParseCancellationException} so it is not caught by the + # rule function catches. Use {@link Exception#getCause()} to get the + # original {@link RecognitionException}. + # + def recover(self, recognizer:Parser, e:RecognitionException): + context = recognizer._ctx + while context is not None: + context.exception = e + context = context.parentCtx + raise ParseCancellationException(e) + + # Make sure we don't attempt to recover inline; if the parser + # successfully recovers, it won't throw an exception. + # + def recoverInline(self, recognizer:Parser): + self.recover(recognizer, InputMismatchException(recognizer)) + + # Make sure we don't attempt to recover from problems in subrules.# + def sync(self, recognizer:Parser): + pass + +del Parser \ No newline at end of file diff --git a/src/antlr4/error/Errors.py b/src/antlr4/error/Errors.py new file mode 100644 index 00000000..e78ac059 --- /dev/null +++ b/src/antlr4/error/Errors.py @@ -0,0 +1,172 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# need forward declaration +Token = None +Lexer = None +Parser = None +TokenStream = None +ATNConfigSet = None +ParserRulecontext = None +PredicateTransition = None +BufferedTokenStream = None + +class UnsupportedOperationException(Exception): + + def __init__(self, msg:str): + super().__init__(msg) + +class IllegalStateException(Exception): + + def __init__(self, msg:str): + super().__init__(msg) + +class CancellationException(IllegalStateException): + + def __init__(self, msg:str): + super().__init__(msg) + +# The root of the ANTLR exception hierarchy. In general, ANTLR tracks just +# 3 kinds of errors: prediction errors, failed predicate errors, and +# mismatched input errors. In each case, the parser knows where it is +# in the input, where it is in the ATN, the rule invocation stack, +# and what kind of problem occurred. + +from antlr4.InputStream import InputStream +from antlr4.ParserRuleContext import ParserRuleContext +from antlr4.Recognizer import Recognizer + +class RecognitionException(Exception): + + + def __init__(self, message:str=None, recognizer:Recognizer=None, input:InputStream=None, ctx:ParserRulecontext=None): + super().__init__(message) + self.message = message + self.recognizer = recognizer + self.input = input + self.ctx = ctx + # The current {@link Token} when an error occurred. Since not all streams + # support accessing symbols by index, we have to track the {@link Token} + # instance itself. + self.offendingToken = None + # Get the ATN state number the parser was in at the time the error + # occurred. For {@link NoViableAltException} and + # {@link LexerNoViableAltException} exceptions, this is the + # {@link DecisionState} number. For others, it is the state whose outgoing + # edge we couldn't match. + self.offendingState = -1 + if recognizer is not None: + self.offendingState = recognizer.state + + #

      If the state number is not known, this method returns -1.

      + + # + # Gets the set of input symbols which could potentially follow the + # previously matched symbol at the time this exception was thrown. + # + #

      If the set of expected tokens is not known and could not be computed, + # this method returns {@code null}.

      + # + # @return The set of token types that could potentially follow the current + # state in the ATN, or {@code null} if the information is not available. + #/ + def getExpectedTokens(self): + if self.recognizer is not None: + return self.recognizer.atn.getExpectedTokens(self.offendingState, self.ctx) + else: + return None + + +class LexerNoViableAltException(RecognitionException): + + def __init__(self, lexer:Lexer, input:InputStream, startIndex:int, deadEndConfigs:ATNConfigSet): + super().__init__(message=None, recognizer=lexer, input=input, ctx=None) + self.startIndex = startIndex + self.deadEndConfigs = deadEndConfigs + + def __str__(self): + symbol = "" + if self.startIndex >= 0 and self.startIndex < self.input.size: + symbol = self.input.getText(self.startIndex, self.startIndex) + # TODO symbol = Utils.escapeWhitespace(symbol, false); + return "LexerNoViableAltException('" + symbol + "')" + +# Indicates that the parser could not decide which of two or more paths +# to take based upon the remaining input. It tracks the starting token +# of the offending input and also knows where the parser was +# in the various paths when the error. Reported by reportNoViableAlternative() +# +class NoViableAltException(RecognitionException): + + def __init__(self, recognizer:Parser, input:TokenStream=None, startToken:Token=None, + offendingToken:Token=None, deadEndConfigs:ATNConfigSet=None, ctx:ParserRuleContext=None): + if ctx is None: + ctx = recognizer._ctx + if offendingToken is None: + offendingToken = recognizer.getCurrentToken() + if startToken is None: + startToken = recognizer.getCurrentToken() + if input is None: + input = recognizer.getInputStream() + super().__init__(recognizer=recognizer, input=input, ctx=ctx) + # Which configurations did we try at input.index() that couldn't match input.LT(1)?# + self.deadEndConfigs = deadEndConfigs + # The token object at the start index; the input stream might + # not be buffering tokens so get a reference to it. (At the + # time the error occurred, of course the stream needs to keep a + # buffer all of the tokens but later we might not have access to those.) + self.startToken = startToken + self.offendingToken = offendingToken + +# This signifies any kind of mismatched input exceptions such as +# when the current input does not match the expected token. +# +class InputMismatchException(RecognitionException): + + def __init__(self, recognizer:Parser): + super().__init__(recognizer=recognizer, input=recognizer.getInputStream(), ctx=recognizer._ctx) + self.offendingToken = recognizer.getCurrentToken() + + +# A semantic predicate failed during validation. Validation of predicates +# occurs when normally parsing the alternative just like matching a token. +# Disambiguating predicate evaluation occurs when we test a predicate during +# prediction. + +class FailedPredicateException(RecognitionException): + + def __init__(self, recognizer:Parser, predicate:str=None, message:str=None): + super().__init__(message=self.formatMessage(predicate,message), recognizer=recognizer, + input=recognizer.getInputStream(), ctx=recognizer._ctx) + s = recognizer._interp.atn.states[recognizer.state] + trans = s.transitions[0] + from antlr4.atn.Transition import PredicateTransition + if isinstance(trans, PredicateTransition): + self.ruleIndex = trans.ruleIndex + self.predicateIndex = trans.predIndex + else: + self.ruleIndex = 0 + self.predicateIndex = 0 + self.predicate = predicate + self.offendingToken = recognizer.getCurrentToken() + + def formatMessage(self, predicate:str, message:str): + if message is not None: + return message + else: + return "failed predicate: {" + predicate + "}?" + +class ParseCancellationException(CancellationException): + + pass + +del Token +del Lexer +del Parser +del TokenStream +del ATNConfigSet +del ParserRulecontext +del PredicateTransition +del BufferedTokenStream diff --git a/src/antlr4/error/__init__.py b/src/antlr4/error/__init__.py new file mode 100644 index 00000000..216c000d --- /dev/null +++ b/src/antlr4/error/__init__.py @@ -0,0 +1 @@ +__author__ = 'ericvergnaud' diff --git a/src/antlr4/tree/Chunk.py b/src/antlr4/tree/Chunk.py new file mode 100644 index 00000000..a2fd16c9 --- /dev/null +++ b/src/antlr4/tree/Chunk.py @@ -0,0 +1,29 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +class Chunk(object): + pass + +class TagChunk(Chunk): + + def __init__(self, tag:str, label:str=None): + self.tag = tag + self.label = label + + def __str__(self): + if self.label is None: + return self.tag + else: + return self.label + ":" + self.tag + +class TextChunk(Chunk): + + def __init__(self, text:str): + self.text = text + + def __str__(self): + return "'" + self.text + "'" + diff --git a/src/antlr4/tree/ParseTreeMatch.py b/src/antlr4/tree/ParseTreeMatch.py new file mode 100644 index 00000000..bbda73e8 --- /dev/null +++ b/src/antlr4/tree/ParseTreeMatch.py @@ -0,0 +1,118 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + + +# +# Represents the result of matching a {@link ParseTree} against a tree pattern. +# +from io import StringIO +from antlr4.tree.ParseTreePattern import ParseTreePattern +from antlr4.tree.Tree import ParseTree + + +class ParseTreeMatch(object): + + # + # Constructs a new instance of {@link ParseTreeMatch} from the specified + # parse tree and pattern. + # + # @param tree The parse tree to match against the pattern. + # @param pattern The parse tree pattern. + # @param labels A mapping from label names to collections of + # {@link ParseTree} objects located by the tree pattern matching process. + # @param mismatchedNode The first node which failed to match the tree + # pattern during the matching process. + # + # @exception IllegalArgumentException if {@code tree} is {@code null} + # @exception IllegalArgumentException if {@code pattern} is {@code null} + # @exception IllegalArgumentException if {@code labels} is {@code null} + # + def __init__(self, tree:ParseTree, pattern:ParseTreePattern, labels:dict, mismatchedNode:ParseTree): + if tree is None: + raise Exception("tree cannot be null") + if pattern is None: + raise Exception("pattern cannot be null") + if labels is None: + raise Exception("labels cannot be null") + self.tree = tree + self.pattern = pattern + self.labels = labels + self.mismatchedNode = mismatchedNode + + # + # Get the last node associated with a specific {@code label}. + # + #

      For example, for pattern {@code }, {@code get("id")} returns the + # node matched for that {@code ID}. If more than one node + # matched the specified label, only the last is returned. If there is + # no node associated with the label, this returns {@code null}.

      + # + #

      Pattern tags like {@code } and {@code } without labels are + # considered to be labeled with {@code ID} and {@code expr}, respectively.

      + # + # @param label The label to check. + # + # @return The last {@link ParseTree} to match a tag with the specified + # label, or {@code null} if no parse tree matched a tag with the label. + # + def get(self, label:str): + parseTrees = self.labels.get(label, None) + if parseTrees is None or len(parseTrees)==0: + return None + else: + return parseTrees[len(parseTrees)-1] + + # + # Return all nodes matching a rule or token tag with the specified label. + # + #

      If the {@code label} is the name of a parser rule or token in the + # grammar, the resulting list will contain both the parse trees matching + # rule or tags explicitly labeled with the label and the complete set of + # parse trees matching the labeled and unlabeled tags in the pattern for + # the parser rule or token. For example, if {@code label} is {@code "foo"}, + # the result will contain all of the following.

      + # + #
        + #
      • Parse tree nodes matching tags of the form {@code } and + # {@code }.
      • + #
      • Parse tree nodes matching tags of the form {@code }.
      • + #
      • Parse tree nodes matching tags of the form {@code }.
      • + #
      + # + # @param label The label. + # + # @return A collection of all {@link ParseTree} nodes matching tags with + # the specified {@code label}. If no nodes matched the label, an empty list + # is returned. + # + def getAll(self, label:str): + nodes = self.labels.get(label, None) + if nodes is None: + return list() + else: + return nodes + + + # + # Gets a value indicating whether the match operation succeeded. + # + # @return {@code true} if the match operation succeeded; otherwise, + # {@code false}. + # + def succeeded(self): + return self.mismatchedNode is None + + # + # {@inheritDoc} + # + def __str__(self): + with StringIO() as buf: + buf.write("Match ") + buf.write("succeeded" if self.succeeded() else "failed") + buf.write("; found ") + buf.write(str(len(self.labels))) + buf.write(" labels") + return buf.getvalue() diff --git a/src/antlr4/tree/ParseTreePattern.py b/src/antlr4/tree/ParseTreePattern.py new file mode 100644 index 00000000..1abb880d --- /dev/null +++ b/src/antlr4/tree/ParseTreePattern.py @@ -0,0 +1,71 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# A pattern like {@code = ;} converted to a {@link ParseTree} by +# {@link ParseTreePatternMatcher#compile(String, int)}. +# +from antlr4.tree.ParseTreePatternMatcher import ParseTreePatternMatcher +from antlr4.tree.Tree import ParseTree +from antlr4.xpath.XPath import XPath + + +class ParseTreePattern(object): + + # Construct a new instance of the {@link ParseTreePattern} class. + # + # @param matcher The {@link ParseTreePatternMatcher} which created this + # tree pattern. + # @param pattern The tree pattern in concrete syntax form. + # @param patternRuleIndex The parser rule which serves as the root of the + # tree pattern. + # @param patternTree The tree pattern in {@link ParseTree} form. + # + def __init__(self, matcher:ParseTreePatternMatcher, pattern:str, patternRuleIndex:int , patternTree:ParseTree): + self.matcher = matcher + self.patternRuleIndex = patternRuleIndex + self.pattern = pattern + self.patternTree = patternTree + + # + # Match a specific parse tree against this tree pattern. + # + # @param tree The parse tree to match against this tree pattern. + # @return A {@link ParseTreeMatch} object describing the result of the + # match operation. The {@link ParseTreeMatch#succeeded()} method can be + # used to determine whether or not the match was successful. + # + def match(self, tree:ParseTree): + return self.matcher.match(tree, self) + + # + # Determine whether or not a parse tree matches this tree pattern. + # + # @param tree The parse tree to match against this tree pattern. + # @return {@code true} if {@code tree} is a match for the current tree + # pattern; otherwise, {@code false}. + # + def matches(self, tree:ParseTree): + return self.matcher.match(tree, self).succeeded() + + # Find all nodes using XPath and then try to match those subtrees against + # this tree pattern. + # + # @param tree The {@link ParseTree} to match against this pattern. + # @param xpath An expression matching the nodes + # + # @return A collection of {@link ParseTreeMatch} objects describing the + # successful matches. Unsuccessful matches are omitted from the result, + # regardless of the reason for the failure. + # + def findAll(self, tree:ParseTree, xpath:str): + subtrees = XPath.findAll(tree, xpath, self.matcher.parser) + matches = list() + for t in subtrees: + match = self.match(t) + if match.succeeded(): + matches.append(match) + return matches diff --git a/src/antlr4/tree/ParseTreePatternMatcher.py b/src/antlr4/tree/ParseTreePatternMatcher.py new file mode 100644 index 00000000..07b96408 --- /dev/null +++ b/src/antlr4/tree/ParseTreePatternMatcher.py @@ -0,0 +1,373 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# A tree pattern matching mechanism for ANTLR {@link ParseTree}s. +# +#

      Patterns are strings of source input text with special tags representing +# token or rule references such as:

      +# +#

      {@code = ;}

      +# +#

      Given a pattern start rule such as {@code statement}, this object constructs +# a {@link ParseTree} with placeholders for the {@code ID} and {@code expr} +# subtree. Then the {@link #match} routines can compare an actual +# {@link ParseTree} from a parse with this pattern. Tag {@code } matches +# any {@code ID} token and tag {@code } references the result of the +# {@code expr} rule (generally an instance of {@code ExprContext}.

      +# +#

      Pattern {@code x = 0;} is a similar pattern that matches the same pattern +# except that it requires the identifier to be {@code x} and the expression to +# be {@code 0}.

      +# +#

      The {@link #matches} routines return {@code true} or {@code false} based +# upon a match for the tree rooted at the parameter sent in. The +# {@link #match} routines return a {@link ParseTreeMatch} object that +# contains the parse tree, the parse tree pattern, and a map from tag name to +# matched nodes (more below). A subtree that fails to match, returns with +# {@link ParseTreeMatch#mismatchedNode} set to the first tree node that did not +# match.

      +# +#

      For efficiency, you can compile a tree pattern in string form to a +# {@link ParseTreePattern} object.

      +# +#

      See {@code TestParseTreeMatcher} for lots of examples. +# {@link ParseTreePattern} has two static helper methods: +# {@link ParseTreePattern#findAll} and {@link ParseTreePattern#match} that +# are easy to use but not super efficient because they create new +# {@link ParseTreePatternMatcher} objects each time and have to compile the +# pattern in string form before using it.

      +# +#

      The lexer and parser that you pass into the {@link ParseTreePatternMatcher} +# constructor are used to parse the pattern in string form. The lexer converts +# the {@code = ;} into a sequence of four tokens (assuming lexer +# throws out whitespace or puts it on a hidden channel). Be aware that the +# input stream is reset for the lexer (but not the parser; a +# {@link ParserInterpreter} is created to parse the input.). Any user-defined +# fields you have put into the lexer might get changed when this mechanism asks +# it to scan the pattern string.

      +# +#

      Normally a parser does not accept token {@code } as a valid +# {@code expr} but, from the parser passed in, we create a special version of +# the underlying grammar representation (an {@link ATN}) that allows imaginary +# tokens representing rules ({@code }) to match entire rules. We call +# these bypass alternatives.

      +# +#

      Delimiters are {@code <} and {@code >}, with {@code \} as the escape string +# by default, but you can set them to whatever you want using +# {@link #setDelimiters}. You must escape both start and stop strings +# {@code \<} and {@code \>}.

      +# +from antlr4.CommonTokenStream import CommonTokenStream +from antlr4.InputStream import InputStream +from antlr4.ParserRuleContext import ParserRuleContext +from antlr4.Lexer import Lexer +from antlr4.ListTokenSource import ListTokenSource +from antlr4.Token import Token +from antlr4.error.ErrorStrategy import BailErrorStrategy +from antlr4.error.Errors import RecognitionException, ParseCancellationException +from antlr4.tree.Chunk import TagChunk, TextChunk +from antlr4.tree.RuleTagToken import RuleTagToken +from antlr4.tree.TokenTagToken import TokenTagToken +from antlr4.tree.Tree import ParseTree, TerminalNode, RuleNode + +# need forward declaration +Parser = None +ParseTreePattern = None + +class CannotInvokeStartRule(Exception): + + def __init__(self, e:Exception): + super().__init__(e) + +class StartRuleDoesNotConsumeFullPattern(Exception): + + pass + + +class ParseTreePatternMatcher(object): + + # Constructs a {@link ParseTreePatternMatcher} or from a {@link Lexer} and + # {@link Parser} object. The lexer input stream is altered for tokenizing + # the tree patterns. The parser is used as a convenient mechanism to get + # the grammar name, plus token, rule names. + def __init__(self, lexer:Lexer, parser:Parser): + self.lexer = lexer + self.parser = parser + self.start = "<" + self.stop = ">" + self.escape = "\\" # e.g., \< and \> must escape BOTH! + + # Set the delimiters used for marking rule and token tags within concrete + # syntax used by the tree pattern parser. + # + # @param start The start delimiter. + # @param stop The stop delimiter. + # @param escapeLeft The escape sequence to use for escaping a start or stop delimiter. + # + # @exception IllegalArgumentException if {@code start} is {@code null} or empty. + # @exception IllegalArgumentException if {@code stop} is {@code null} or empty. + # + def setDelimiters(self, start:str, stop:str, escapeLeft:str): + if start is None or len(start)==0: + raise Exception("start cannot be null or empty") + if stop is None or len(stop)==0: + raise Exception("stop cannot be null or empty") + self.start = start + self.stop = stop + self.escape = escapeLeft + + # Does {@code pattern} matched as rule {@code patternRuleIndex} match {@code tree}?# + def matchesRuleIndex(self, tree:ParseTree, pattern:str, patternRuleIndex:int): + p = self.compileTreePattern(pattern, patternRuleIndex) + return self.matches(tree, p) + + # Does {@code pattern} matched as rule patternRuleIndex match tree? Pass in a + # compiled pattern instead of a string representation of a tree pattern. + # + def matchesPattern(self, tree:ParseTree, pattern:ParseTreePattern): + mismatchedNode = self.matchImpl(tree, pattern.patternTree, dict()) + return mismatchedNode is None + + # + # Compare {@code pattern} matched as rule {@code patternRuleIndex} against + # {@code tree} and return a {@link ParseTreeMatch} object that contains the + # matched elements, or the node at which the match failed. + # + def matchRuleIndex(self, tree:ParseTree, pattern:str, patternRuleIndex:int): + p = self.compileTreePattern(pattern, patternRuleIndex) + return self.matchPattern(tree, p) + + # + # Compare {@code pattern} matched against {@code tree} and return a + # {@link ParseTreeMatch} object that contains the matched elements, or the + # node at which the match failed. Pass in a compiled pattern instead of a + # string representation of a tree pattern. + # + def matchPattern(self, tree:ParseTree, pattern:ParseTreePattern): + labels = dict() + mismatchedNode = self.matchImpl(tree, pattern.patternTree, labels) + from antlr4.tree.ParseTreeMatch import ParseTreeMatch + return ParseTreeMatch(tree, pattern, labels, mismatchedNode) + + # + # For repeated use of a tree pattern, compile it to a + # {@link ParseTreePattern} using this method. + # + def compileTreePattern(self, pattern:str, patternRuleIndex:int): + tokenList = self.tokenize(pattern) + tokenSrc = ListTokenSource(tokenList) + tokens = CommonTokenStream(tokenSrc) + from antlr4.ParserInterpreter import ParserInterpreter + parserInterp = ParserInterpreter(self.parser.grammarFileName, self.parser.tokenNames, + self.parser.ruleNames, self.parser.getATNWithBypassAlts(),tokens) + tree = None + try: + parserInterp.setErrorHandler(BailErrorStrategy()) + tree = parserInterp.parse(patternRuleIndex) + except ParseCancellationException as e: + raise e.cause + except RecognitionException as e: + raise e + except Exception as e: + raise CannotInvokeStartRule(e) + + # Make sure tree pattern compilation checks for a complete parse + if tokens.LA(1)!=Token.EOF: + raise StartRuleDoesNotConsumeFullPattern() + + from antlr4.tree.ParseTreePattern import ParseTreePattern + return ParseTreePattern(self, pattern, patternRuleIndex, tree) + + # + # Recursively walk {@code tree} against {@code patternTree}, filling + # {@code match.}{@link ParseTreeMatch#labels labels}. + # + # @return the first node encountered in {@code tree} which does not match + # a corresponding node in {@code patternTree}, or {@code null} if the match + # was successful. The specific node returned depends on the matching + # algorithm used by the implementation, and may be overridden. + # + def matchImpl(self, tree:ParseTree, patternTree:ParseTree, labels:dict): + if tree is None: + raise Exception("tree cannot be null") + if patternTree is None: + raise Exception("patternTree cannot be null") + + # x and , x and y, or x and x; or could be mismatched types + if isinstance(tree, TerminalNode) and isinstance(patternTree, TerminalNode ): + mismatchedNode = None + # both are tokens and they have same type + if tree.symbol.type == patternTree.symbol.type: + if isinstance( patternTree.symbol, TokenTagToken ): # x and + tokenTagToken = patternTree.symbol + # track label->list-of-nodes for both token name and label (if any) + self.map(labels, tokenTagToken.tokenName, tree) + if tokenTagToken.label is not None: + self.map(labels, tokenTagToken.label, tree) + elif tree.getText()==patternTree.getText(): + # x and x + pass + else: + # x and y + if mismatchedNode is None: + mismatchedNode = tree + else: + if mismatchedNode is None: + mismatchedNode = tree + + return mismatchedNode + + if isinstance(tree, ParserRuleContext) and isinstance(patternTree, ParserRuleContext): + mismatchedNode = None + # (expr ...) and + ruleTagToken = self.getRuleTagToken(patternTree) + if ruleTagToken is not None: + m = None + if tree.ruleContext.ruleIndex == patternTree.ruleContext.ruleIndex: + # track label->list-of-nodes for both rule name and label (if any) + self.map(labels, ruleTagToken.ruleName, tree) + if ruleTagToken.label is not None: + self.map(labels, ruleTagToken.label, tree) + else: + if mismatchedNode is None: + mismatchedNode = tree + + return mismatchedNode + + # (expr ...) and (expr ...) + if tree.getChildCount()!=patternTree.getChildCount(): + if mismatchedNode is None: + mismatchedNode = tree + return mismatchedNode + + n = tree.getChildCount() + for i in range(0, n): + childMatch = self.matchImpl(tree.getChild(i), patternTree.getChild(i), labels) + if childMatch is not None: + return childMatch + + return mismatchedNode + + # if nodes aren't both tokens or both rule nodes, can't match + return tree + + def map(self, labels, label, tree): + v = labels.get(label, None) + if v is None: + v = list() + labels[label] = v + v.append(tree) + + # Is {@code t} {@code (expr )} subtree?# + def getRuleTagToken(self, tree:ParseTree): + if isinstance( tree, RuleNode ): + if tree.getChildCount()==1 and isinstance(tree.getChild(0), TerminalNode ): + c = tree.getChild(0) + if isinstance( c.symbol, RuleTagToken ): + return c.symbol + return None + + def tokenize(self, pattern:str): + # split pattern into chunks: sea (raw input) and islands (, ) + chunks = self.split(pattern) + + # create token stream from text and tags + tokens = list() + for chunk in chunks: + if isinstance( chunk, TagChunk ): + # add special rule token or conjure up new token from name + if chunk.tag[0].isupper(): + ttype = self.parser.getTokenType(chunk.tag) + if ttype==Token.INVALID_TYPE: + raise Exception("Unknown token " + str(chunk.tag) + " in pattern: " + pattern) + tokens.append(TokenTagToken(chunk.tag, ttype, chunk.label)) + elif chunk.tag[0].islower(): + ruleIndex = self.parser.getRuleIndex(chunk.tag) + if ruleIndex==-1: + raise Exception("Unknown rule " + str(chunk.tag) + " in pattern: " + pattern) + ruleImaginaryTokenType = self.parser.getATNWithBypassAlts().ruleToTokenType[ruleIndex] + tokens.append(RuleTagToken(chunk.tag, ruleImaginaryTokenType, chunk.label)) + else: + raise Exception("invalid tag: " + str(chunk.tag) + " in pattern: " + pattern) + else: + self.lexer.setInputStream(InputStream(chunk.text)) + t = self.lexer.nextToken() + while t.type!=Token.EOF: + tokens.append(t) + t = self.lexer.nextToken() + return tokens + + # Split {@code = ;} into 4 chunks for tokenizing by {@link #tokenize}.# + def split(self, pattern:str): + p = 0 + n = len(pattern) + chunks = list() + # find all start and stop indexes first, then collect + starts = list() + stops = list() + while p < n : + if p == pattern.find(self.escape + self.start, p): + p += len(self.escape) + len(self.start) + elif p == pattern.find(self.escape + self.stop, p): + p += len(self.escape) + len(self.stop) + elif p == pattern.find(self.start, p): + starts.append(p) + p += len(self.start) + elif p == pattern.find(self.stop, p): + stops.append(p) + p += len(self.stop) + else: + p += 1 + + nt = len(starts) + + if nt > len(stops): + raise Exception("unterminated tag in pattern: " + pattern) + if nt < len(stops): + raise Exception("missing start tag in pattern: " + pattern) + + for i in range(0, nt): + if starts[i] >= stops[i]: + raise Exception("tag delimiters out of order in pattern: " + pattern) + + # collect into chunks now + if nt==0: + chunks.append(TextChunk(pattern)) + + if nt>0 and starts[0]>0: # copy text up to first tag into chunks + text = pattern[0:starts[0]] + chunks.add(TextChunk(text)) + + for i in range(0, nt): + # copy inside of + tag = pattern[starts[i] + len(self.start) : stops[i]] + ruleOrToken = tag + label = None + colon = tag.find(':') + if colon >= 0: + label = tag[0:colon] + ruleOrToken = tag[colon+1 : len(tag)] + chunks.append(TagChunk(label, ruleOrToken)) + if i+1 < len(starts): + # copy from end of to start of next + text = pattern[stops[i] + len(self.stop) : starts[i + 1]] + chunks.append(TextChunk(text)) + + if nt > 0 : + afterLastTag = stops[nt - 1] + len(self.stop) + if afterLastTag < n : # copy text from end of last tag to end + text = pattern[afterLastTag : n] + chunks.append(TextChunk(text)) + + # strip out the escape sequences from text chunks but not tags + for i in range(0, len(chunks)): + c = chunks[i] + if isinstance( c, TextChunk ): + unescaped = c.text.replace(self.escape, "") + if len(unescaped) < len(c.text): + chunks[i] = TextChunk(unescaped) + return chunks diff --git a/src/antlr4/tree/RuleTagToken.py b/src/antlr4/tree/RuleTagToken.py new file mode 100644 index 00000000..7b2018fe --- /dev/null +++ b/src/antlr4/tree/RuleTagToken.py @@ -0,0 +1,49 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# A {@link Token} object representing an entire subtree matched by a parser +# rule; e.g., {@code }. These tokens are created for {@link TagChunk} +# chunks where the tag corresponds to a parser rule. +# +from antlr4.Token import Token + + +class RuleTagToken(Token): + # + # Constructs a new instance of {@link RuleTagToken} with the specified rule + # name, bypass token type, and label. + # + # @param ruleName The name of the parser rule this rule tag matches. + # @param bypassTokenType The bypass token type assigned to the parser rule. + # @param label The label associated with the rule tag, or {@code null} if + # the rule tag is unlabeled. + # + # @exception IllegalArgumentException if {@code ruleName} is {@code null} + # or empty. + + def __init__(self, ruleName:str, bypassTokenType:int, label:str=None): + if ruleName is None or len(ruleName)==0: + raise Exception("ruleName cannot be null or empty.") + self.source = None + self.type = bypassTokenType # token type of the token + self.channel = Token.DEFAULT_CHANNEL # The parser ignores everything not on DEFAULT_CHANNEL + self.start = -1 # optional; return -1 if not implemented. + self.stop = -1 # optional; return -1 if not implemented. + self.tokenIndex = -1 # from 0..n-1 of the token object in the input stream + self.line = 0 # line=1..n of the 1st character + self.column = -1 # beginning of the line at which it occurs, 0..n-1 + self.label = label + self._text = self.getText() # text of the token. + + self.ruleName = ruleName + + + def getText(self): + if self.label is None: + return "<" + self.ruleName + ">" + else: + return "<" + self.label + ":" + self.ruleName + ">" diff --git a/src/antlr4/tree/TokenTagToken.py b/src/antlr4/tree/TokenTagToken.py new file mode 100644 index 00000000..d00327ae --- /dev/null +++ b/src/antlr4/tree/TokenTagToken.py @@ -0,0 +1,47 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# A {@link Token} object representing a token of a particular type; e.g., +# {@code }. These tokens are created for {@link TagChunk} chunks where the +# tag corresponds to a lexer rule or token type. +# +from antlr4.Token import CommonToken + + +class TokenTagToken(CommonToken): + + # Constructs a new instance of {@link TokenTagToken} with the specified + # token name, type, and label. + # + # @param tokenName The token name. + # @param type The token type. + # @param label The label associated with the token tag, or {@code null} if + # the token tag is unlabeled. + # + def __init__(self, tokenName:str, type:int, label:str=None): + super().__init__(type=type) + self.tokenName = tokenName + self.label = label + self._text = self.getText() + + # + # {@inheritDoc} + # + #

      The implementation for {@link TokenTagToken} returns the token tag + # formatted with {@code <} and {@code >} delimiters.

      + # + def getText(self): + if self.label is None: + return "<" + self.tokenName + ">" + else: + return "<" + self.label + ":" + self.tokenName + ">" + + #

      The implementation for {@link TokenTagToken} returns a string of the form + # {@code tokenName:type}.

      + # + def __str__(self): + return self.tokenName + ":" + str(self.type) diff --git a/src/antlr4/tree/Tree.py b/src/antlr4/tree/Tree.py new file mode 100644 index 00000000..2b9db2d1 --- /dev/null +++ b/src/antlr4/tree/Tree.py @@ -0,0 +1,170 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + + +# The basic notion of a tree has a parent, a payload, and a list of children. +# It is the most abstract interface for all the trees used by ANTLR. +#/ +from antlr4.Token import Token + +INVALID_INTERVAL = (-1, -2) + +class Tree(object): + pass + +class SyntaxTree(Tree): + pass + +class ParseTree(SyntaxTree): + pass + +class RuleNode(ParseTree): + pass + +class TerminalNode(ParseTree): + pass + +class ErrorNode(TerminalNode): + pass + +class ParseTreeVisitor(object): + def visit(self, tree): + return tree.accept(self) + + def visitChildren(self, node): + result = self.defaultResult() + n = node.getChildCount() + for i in range(n): + if not self.shouldVisitNextChild(node, result): + return result + + c = node.getChild(i) + childResult = c.accept(self) + result = self.aggregateResult(result, childResult) + + return result + + def visitTerminal(self, node): + return self.defaultResult() + + def visitErrorNode(self, node): + return self.defaultResult() + + def defaultResult(self): + return None + + def aggregateResult(self, aggregate, nextResult): + return nextResult + + def shouldVisitNextChild(self, node, currentResult): + return True + +ParserRuleContext = None + +class ParseTreeListener(object): + + def visitTerminal(self, node:TerminalNode): + pass + + def visitErrorNode(self, node:ErrorNode): + pass + + def enterEveryRule(self, ctx:ParserRuleContext): + pass + + def exitEveryRule(self, ctx:ParserRuleContext): + pass + +del ParserRuleContext + +class TerminalNodeImpl(TerminalNode): + + def __init__(self, symbol:Token): + self.parentCtx = None + self.symbol = symbol + def __setattr__(self, key, value): + super().__setattr__(key, value) + + def getChild(self, i:int): + return None + + def getSymbol(self): + return self.symbol + + def getParent(self): + return self.parentCtx + + def getPayload(self): + return self.symbol + + def getSourceInterval(self): + if self.symbol is None: + return INVALID_INTERVAL + tokenIndex = self.symbol.tokenIndex + return (tokenIndex, tokenIndex) + + def getChildCount(self): + return 0 + + def accept(self, visitor:ParseTreeVisitor): + return visitor.visitTerminal(self) + + def getText(self): + return self.symbol.text + + def __str__(self): + if self.symbol.type == Token.EOF: + return "" + else: + return self.symbol.text + +# Represents a token that was consumed during resynchronization +# rather than during a valid match operation. For example, +# we will create this kind of a node during single token insertion +# and deletion as well as during "consume until error recovery set" +# upon no viable alternative exceptions. + +class ErrorNodeImpl(TerminalNodeImpl,ErrorNode): + + def __init__(self, token:Token): + super().__init__(token) + + def accept(self, visitor:ParseTreeVisitor): + return visitor.visitErrorNode(self) + + +class ParseTreeWalker(object): + + DEFAULT = None + + def walk(self, listener:ParseTreeListener, t:ParseTree): + if isinstance(t, ErrorNode): + listener.visitErrorNode(t) + return + elif isinstance(t, TerminalNode): + listener.visitTerminal(t) + return + self.enterRule(listener, t) + for child in t.getChildren(): + self.walk(listener, child) + self.exitRule(listener, t) + + # + # The discovery of a rule node, involves sending two events: the generic + # {@link ParseTreeListener#enterEveryRule} and a + # {@link RuleContext}-specific event. First we trigger the generic and then + # the rule specific. We to them in reverse order upon finishing the node. + # + def enterRule(self, listener:ParseTreeListener, r:RuleNode): + ctx = r.getRuleContext() + listener.enterEveryRule(ctx) + ctx.enterRule(listener) + + def exitRule(self, listener:ParseTreeListener, r:RuleNode): + ctx = r.getRuleContext() + ctx.exitRule(listener) + listener.exitEveryRule(ctx) + +ParseTreeWalker.DEFAULT = ParseTreeWalker() \ No newline at end of file diff --git a/src/antlr4/tree/Trees.py b/src/antlr4/tree/Trees.py new file mode 100644 index 00000000..686b8cb2 --- /dev/null +++ b/src/antlr4/tree/Trees.py @@ -0,0 +1,111 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + + +# A set of utility routines useful for all kinds of ANTLR trees.# +from io import StringIO +from antlr4.Token import Token +from antlr4.Utils import escapeWhitespace +from antlr4.tree.Tree import RuleNode, ErrorNode, TerminalNode, Tree, ParseTree + +# need forward declaration +Parser = None + +class Trees(object): + + # Print out a whole tree in LISP form. {@link #getNodeText} is used on the + # node payloads to get the text for the nodes. Detect + # parse trees and extract data appropriately. + @classmethod + def toStringTree(cls, t:Tree, ruleNames:list=None, recog:Parser=None): + if recog is not None: + ruleNames = recog.ruleNames + s = escapeWhitespace(cls.getNodeText(t, ruleNames), False) + if t.getChildCount()==0: + return s + with StringIO() as buf: + buf.write("(") + buf.write(s) + buf.write(' ') + for i in range(0, t.getChildCount()): + if i > 0: + buf.write(' ') + buf.write(cls.toStringTree(t.getChild(i), ruleNames)) + buf.write(")") + return buf.getvalue() + + @classmethod + def getNodeText(cls, t:Tree, ruleNames:list=None, recog:Parser=None): + if recog is not None: + ruleNames = recog.ruleNames + if ruleNames is not None: + if isinstance(t, RuleNode): + if t.getAltNumber()!=0: # should use ATN.INVALID_ALT_NUMBER but won't compile + return ruleNames[t.getRuleIndex()]+":"+str(t.getAltNumber()) + return ruleNames[t.getRuleIndex()] + elif isinstance( t, ErrorNode): + return str(t) + elif isinstance(t, TerminalNode): + if t.symbol is not None: + return t.symbol.text + # no recog for rule names + payload = t.getPayload() + if isinstance(payload, Token ): + return payload.text + return str(t.getPayload()) + + + # Return ordered list of all children of this node + @classmethod + def getChildren(cls, t:Tree): + return [ t.getChild(i) for i in range(0, t.getChildCount()) ] + + # Return a list of all ancestors of this node. The first node of + # list is the root and the last is the parent of this node. + # + @classmethod + def getAncestors(cls, t:Tree): + ancestors = [] + t = t.getParent() + while t is not None: + ancestors.insert(0, t) # insert at start + t = t.getParent() + return ancestors + + @classmethod + def findAllTokenNodes(cls, t:ParseTree, ttype:int): + return cls.findAllNodes(t, ttype, True) + + @classmethod + def findAllRuleNodes(cls, t:ParseTree, ruleIndex:int): + return cls.findAllNodes(t, ruleIndex, False) + + @classmethod + def findAllNodes(cls, t:ParseTree, index:int, findTokens:bool): + nodes = [] + cls._findAllNodes(t, index, findTokens, nodes) + return nodes + + @classmethod + def _findAllNodes(cls, t:ParseTree, index:int, findTokens:bool, nodes:list): + from antlr4.ParserRuleContext import ParserRuleContext + # check this node (the root) first + if findTokens and isinstance(t, TerminalNode): + if t.symbol.type==index: + nodes.append(t) + elif not findTokens and isinstance(t, ParserRuleContext): + if t.ruleIndex == index: + nodes.append(t) + # check children + for i in range(0, t.getChildCount()): + cls._findAllNodes(t.getChild(i), index, findTokens, nodes) + + @classmethod + def descendants(cls, t:ParseTree): + nodes = [t] + for i in range(0, t.getChildCount()): + nodes.extend(cls.descendants(t.getChild(i))) + return nodes diff --git a/src/antlr4/tree/__init__.py b/src/antlr4/tree/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/antlr4/xpath/XPath.py b/src/antlr4/xpath/XPath.py new file mode 100644 index 00000000..c49e3ba9 --- /dev/null +++ b/src/antlr4/xpath/XPath.py @@ -0,0 +1,343 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# Represent a subset of XPath XML path syntax for use in identifying nodes in +# parse trees. +# +#

      +# Split path into words and separators {@code /} and {@code //} via ANTLR +# itself then walk path elements from left to right. At each separator-word +# pair, find set of nodes. Next stage uses those as work list.

      +# +#

      +# The basic interface is +# {@link XPath#findAll ParseTree.findAll}{@code (tree, pathString, parser)}. +# But that is just shorthand for:

      +# +#
      +# {@link XPath} p = new {@link XPath#XPath XPath}(parser, pathString);
      +# return p.{@link #evaluate evaluate}(tree);
      +# 
      +# +#

      +# See {@code org.antlr.v4.test.TestXPath} for descriptions. In short, this +# allows operators:

      +# +#
      +#
      /
      root
      +#
      //
      anywhere
      +#
      !
      invert; this must appear directly after root or anywhere +# operator
      +#
      +# +#

      +# and path elements:

      +# +#
      +#
      ID
      token name
      +#
      'string'
      any string literal token from the grammar
      +#
      expr
      rule name
      +#
      *
      wildcard matching any node
      +#
      +# +#

      +# Whitespace is not allowed.

      +# +from antlr4 import CommonTokenStream, DFA, PredictionContextCache, Lexer, LexerATNSimulator +from antlr4.InputStream import InputStream +from antlr4.Parser import Parser +from antlr4.RuleContext import RuleContext +from antlr4.Token import Token +from antlr4.atn.ATNDeserializer import ATNDeserializer +from antlr4.error.ErrorListener import ErrorListener +from antlr4.error.Errors import LexerNoViableAltException +from antlr4.tree.Tree import ParseTree +from antlr4.tree.Trees import Trees +from io import StringIO + + +def serializedATN(): + with StringIO() as buf: + buf.write("\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2\n") + buf.write("\64\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t") + buf.write("\7\4\b\t\b\4\t\t\t\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5") + buf.write("\3\6\3\6\7\6\37\n\6\f\6\16\6\"\13\6\3\6\3\6\3\7\3\7\5") + buf.write("\7(\n\7\3\b\3\b\3\t\3\t\7\t.\n\t\f\t\16\t\61\13\t\3\t") + buf.write("\3\t\3/\2\n\3\5\5\6\7\7\t\b\13\t\r\2\17\2\21\n\3\2\4\7") + buf.write("\2\62;aa\u00b9\u00b9\u0302\u0371\u2041\u2042\17\2C\\c") + buf.write("|\u00c2\u00d8\u00da\u00f8\u00fa\u0301\u0372\u037f\u0381") + buf.write("\u2001\u200e\u200f\u2072\u2191\u2c02\u2ff1\u3003\ud801") + buf.write("\uf902\ufdd1\ufdf2\uffff\64\2\3\3\2\2\2\2\5\3\2\2\2\2") + buf.write("\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\21\3\2\2\2\3\23") + buf.write("\3\2\2\2\5\26\3\2\2\2\7\30\3\2\2\2\t\32\3\2\2\2\13\34") + buf.write("\3\2\2\2\r\'\3\2\2\2\17)\3\2\2\2\21+\3\2\2\2\23\24\7\61") + buf.write("\2\2\24\25\7\61\2\2\25\4\3\2\2\2\26\27\7\61\2\2\27\6\3") + buf.write("\2\2\2\30\31\7,\2\2\31\b\3\2\2\2\32\33\7#\2\2\33\n\3\2") + buf.write("\2\2\34 \5\17\b\2\35\37\5\r\7\2\36\35\3\2\2\2\37\"\3\2") + buf.write("\2\2 \36\3\2\2\2 !\3\2\2\2!#\3\2\2\2\" \3\2\2\2#$\b\6") + buf.write("\2\2$\f\3\2\2\2%(\5\17\b\2&(\t\2\2\2\'%\3\2\2\2\'&\3\2") + buf.write("\2\2(\16\3\2\2\2)*\t\3\2\2*\20\3\2\2\2+/\7)\2\2,.\13\2") + buf.write("\2\2-,\3\2\2\2.\61\3\2\2\2/\60\3\2\2\2/-\3\2\2\2\60\62") + buf.write("\3\2\2\2\61/\3\2\2\2\62\63\7)\2\2\63\22\3\2\2\2\6\2 \'") + buf.write("/\3\3\6\2") + return buf.getvalue() + + +class XPathLexer(Lexer): + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] + + + TOKEN_REF = 1 + RULE_REF = 2 + ANYWHERE = 3 + ROOT = 4 + WILDCARD = 5 + BANG = 6 + ID = 7 + STRING = 8 + + modeNames = [ "DEFAULT_MODE" ] + + literalNames = [ "", + "'//'", "'/'", "'*'", "'!'" ] + + symbolicNames = [ "", + "TOKEN_REF", "RULE_REF", "ANYWHERE", "ROOT", "WILDCARD", "BANG", + "ID", "STRING" ] + + ruleNames = [ "ANYWHERE", "ROOT", "WILDCARD", "BANG", "ID", "NameChar", + "NameStartChar", "STRING" ] + + grammarFileName = "XPathLexer.g4" + + def __init__(self, input=None): + super().__init__(input) + self.checkVersion("4.7.2") + self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) + self._actions = None + self._predicates = None + + + def action(self, localctx:RuleContext, ruleIndex:int, actionIndex:int): + if self._actions is None: + actions = dict() + actions[4] = self.ID_action + self._actions = actions + _action = self._actions.get(ruleIndex, None) + if _action is not None: + _action(localctx, actionIndex) + else: + raise Exception("No registered action for:" + str(ruleIndex)) + + def ID_action(self, localctx:RuleContext , actionIndex:int): + if actionIndex == 0: + char = self.text[0] + if char.isupper(): + self.type = XPathLexer.TOKEN_REF + else: + self.type = XPathLexer.RULE_REF + +class XPath(object): + + WILDCARD = "*" # word not operator/separator + NOT = "!" # word for invert operator + + def __init__(self, parser:Parser, path:str): + self.parser = parser + self.path = path + self.elements = self.split(path) + + def split(self, path:str): + input = InputStream(path) + lexer = XPathLexer(input) + def recover(self, e): + raise e + lexer.recover = recover + lexer.removeErrorListeners() + lexer.addErrorListener(ErrorListener()) # XPathErrorListener does no more + tokenStream = CommonTokenStream(lexer) + try: + tokenStream.fill() + except LexerNoViableAltException as e: + pos = lexer.getColumn() + msg = "Invalid tokens or characters at index " + str(pos) + " in path '" + path + "'" + raise Exception(msg, e) + + tokens = tokenStream.getTokens() + elements = list() + n = len(tokens) + i=0 + while i < n : + el = tokens[i] + next = None + if el.type in [XPathLexer.ROOT, XPathLexer.ANYWHERE]: + anywhere = el.type == XPathLexer.ANYWHERE + i += 1 + next = tokens[i] + invert = next.type==XPathLexer.BANG + if invert: + i += 1 + next = tokens[i] + pathElement = self.getXPathElement(next, anywhere) + pathElement.invert = invert + elements.append(pathElement) + i += 1 + + elif el.type in [XPathLexer.TOKEN_REF, XPathLexer.RULE_REF, XPathLexer.WILDCARD] : + elements.append( self.getXPathElement(el, False) ) + i += 1 + + elif el.type==Token.EOF : + break + + else: + raise Exception("Unknown path element " + str(el)) + + return elements + + # + # Convert word like {@code#} or {@code ID} or {@code expr} to a path + # element. {@code anywhere} is {@code true} if {@code //} precedes the + # word. + # + def getXPathElement(self, wordToken:Token, anywhere:bool): + if wordToken.type==Token.EOF: + raise Exception("Missing path element at end of path") + word = wordToken.text + ttype = self.parser.getTokenType(word) + ruleIndex = self.parser.getRuleIndex(word) + + if wordToken.type==XPathLexer.WILDCARD : + + return XPathWildcardAnywhereElement() if anywhere else XPathWildcardElement() + + elif wordToken.type in [XPathLexer.TOKEN_REF, XPathLexer.STRING]: + + if ttype==Token.INVALID_TYPE: + raise Exception( word + " at index " + str(wordToken.startIndex) + " isn't a valid token name") + return XPathTokenAnywhereElement(word, ttype) if anywhere else XPathTokenElement(word, ttype) + + else: + + if ruleIndex==-1: + raise Exception( word + " at index " + str(wordToken.getStartIndex()) + " isn't a valid rule name") + return XPathRuleAnywhereElement(word, ruleIndex) if anywhere else XPathRuleElement(word, ruleIndex) + + + @staticmethod + def findAll(tree:ParseTree, xpath:str, parser:Parser): + p = XPath(parser, xpath) + return p.evaluate(tree) + + # + # Return a list of all nodes starting at {@code t} as root that satisfy the + # path. The root {@code /} is relative to the node passed to + # {@link #evaluate}. + # + def evaluate(self, t:ParseTree): + dummyRoot = ParserRuleContext() + dummyRoot.children = [t] # don't set t's parent. + + work = [dummyRoot] + + for i in range(0, len(self.elements)): + next = set() + for node in work: + if len( node.children) > 0 : + # only try to match next element if it has children + # e.g., //func/*/stat might have a token node for which + # we can't go looking for stat nodes. + matching = self.elements[i].evaluate(node) + next |= matching + i += 1 + work = next + + return work + + +class XPathElement(object): + + def __init__(self, nodeName:str): + self.nodeName = nodeName + self.invert = False + + def __str__(self): + return type(self).__name__ + "[" + ("!" if self.invert else "") + self.nodeName + "]" + + + +# +# Either {@code ID} at start of path or {@code ...//ID} in middle of path. +# +class XPathRuleAnywhereElement(XPathElement): + + def __init__(self, ruleName:str, ruleIndex:int): + super().__init__(ruleName) + self.ruleIndex = ruleIndex + + def evaluate(self, t:ParseTree): + return Trees.findAllRuleNodes(t, self.ruleIndex) + + +class XPathRuleElement(XPathElement): + + def __init__(self, ruleName:str, ruleIndex:int): + super().__init__(ruleName) + self.ruleIndex = ruleIndex + + def evaluate(self, t:ParseTree): + # return all children of t that match nodeName + return [c for c in Trees.getChildren(t) if isinstance(c, ParserRuleContext) and (c.ruleIndex == self.ruleIndex) == (not self.invert)] + + +class XPathTokenAnywhereElement(XPathElement): + + def __init__(self, ruleName:str, tokenType:int): + super().__init__(ruleName) + self.tokenType = tokenType + + def evaluate(self, t:ParseTree): + return Trees.findAllTokenNodes(t, self.tokenType) + + +class XPathTokenElement(XPathElement): + + def __init__(self, ruleName:str, tokenType:int): + super().__init__(ruleName) + self.tokenType = tokenType + + def evaluate(self, t:ParseTree): + # return all children of t that match nodeName + return [c for c in Trees.getChildren(t) if isinstance(c, TerminalNode) and (c.symbol.type == self.tokenType) == (not self.invert)] + + +class XPathWildcardAnywhereElement(XPathElement): + + def __init__(self): + super().__init__(XPath.WILDCARD) + + def evaluate(self, t:ParseTree): + if self.invert: + return list() # !* is weird but valid (empty) + else: + return Trees.descendants(t) + + +class XPathWildcardElement(XPathElement): + + def __init__(self): + super().__init__(XPath.WILDCARD) + + + def evaluate(self, t:ParseTree): + if self.invert: + return list() # !* is weird but valid (empty) + else: + return Trees.getChildren(t) diff --git a/src/antlr4/xpath/__init__.py b/src/antlr4/xpath/__init__.py new file mode 100644 index 00000000..216c000d --- /dev/null +++ b/src/antlr4/xpath/__init__.py @@ -0,0 +1 @@ +__author__ = 'ericvergnaud' diff --git a/src/coolc.sh b/src/coolc.sh index 3088de4f..32158b64 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -5,7 +5,8 @@ OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas -echo "Copyright (c) 2019: Nombre1, Nombre2, Nombre3" # TODO: líneas a los valores correctos +echo "Copyright (c) 2019: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" # TODO: líneas a los valores correctos # Llamar al compilador -echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +#echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +python COOLCompiler.py INPUT_FILE OUTPUT_FILE From da58db6d51aeb5c5439a56a1a7e4e2cf31ec5177 Mon Sep 17 00:00:00 2001 From: LSilvaO Date: Sat, 29 Feb 2020 14:17:50 -0500 Subject: [PATCH 02/77] cambio --- doc/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Readme.md b/doc/Readme.md index 59c61e34..a2f68fed 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -4,7 +4,7 @@ **Nombre** | **Grupo** | **Github** --|--|-- -Liset Silva Oropesa | C411 | [@github_user](https://github.com/) +Liset Silva Oropesa | C411 | [@github_user](https://github.com/Liset97) Pablo Antonio de Armas Suarez | C411 | [@github_user](https://github.com/) Yenli Gil Machado | C412 | [@github_user](https://github.com/) From 1b45de56d59d9677b0fef001670d5cd3c0a0957f Mon Sep 17 00:00:00 2001 From: LSilvaO Date: Sat, 29 Feb 2020 14:27:19 -0500 Subject: [PATCH 03/77] modifica --- doc/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Readme.md b/doc/Readme.md index a2f68fed..b953665a 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -4,7 +4,7 @@ **Nombre** | **Grupo** | **Github** --|--|-- -Liset Silva Oropesa | C411 | [@github_user](https://github.com/Liset97) +Liset Silva Oropesa | C411 | [@Liset97](https://github.com/Liset97) Pablo Antonio de Armas Suarez | C411 | [@github_user](https://github.com/) Yenli Gil Machado | C412 | [@github_user](https://github.com/) From 2d113f5a5867a9db8f2dba697692a61f8d3475d5 Mon Sep 17 00:00:00 2001 From: LSilvaO Date: Sat, 29 Feb 2020 20:00:50 -0500 Subject: [PATCH 04/77] dos nombres --- doc/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Readme.md b/doc/Readme.md index b953665a..e32260f4 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -6,7 +6,7 @@ --|--|-- Liset Silva Oropesa | C411 | [@Liset97](https://github.com/Liset97) Pablo Antonio de Armas Suarez | C411 | [@github_user](https://github.com/) -Yenli Gil Machado | C412 | [@github_user](https://github.com/) +Yenli Gil Machado | C412 | [@YenGM](https://github.com/YenGM) ## Readme From 1be300733c16c41d89b0c7adfa1e6fee86e2a5f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sat, 29 Feb 2020 23:40:55 -0500 Subject: [PATCH 05/77] Se agregaron las clases para el lexer y el parser Se agregaron clases para el procesamiento de los errores Se agregaron algunos tests que faltaban --- COOL.interp | 113 ++ COOL.py | 1828 ++++++++++++++++++++++++++++++++ COOL.tokens | 69 ++ COOLCompiler.py | 36 + COOLLexer.py | 34 + COOLLexerErrorListener.py | 7 + COOLListener.py | 289 +++++ COOLParser.py | 24 + COOLParserErrorListener.py | 12 + COOL_LEX.interp | 182 ++++ COOL_LEX.py | 284 +++++ COOL_LEX.tokens | 69 ++ tests/lexer/test1.cl | 9 + tests/lexer/test1_error.txt | 3 + tests/lexer/test3.cl | 46 + tests/lexer/test3_error.txt | 1 + tests/lexer/test5.cl | 4 + tests/lexer/test5_error.txt | 1 + tests/lexer/test6.cl | 6 + tests/lexer/test6_error.txt | 5 + tests/parser/err2.cl | 14 + tests/parser/err2_error.txt | 2 + tests/parser/isprime.cl | 40 + tests/parser/isprime_error.txt | 1 + tests/parser/prod.cl | 21 + tests/parser/prod_error.txt | 1 + tests/parser/test2.cl | 20 + tests/parser/test2_error.txt | 4 + tests/parser/test4.cl | 5 + tests/parser/test4_error.txt | 1 + 30 files changed, 3131 insertions(+) create mode 100644 COOL.interp create mode 100644 COOL.py create mode 100644 COOL.tokens create mode 100644 COOLCompiler.py create mode 100644 COOLLexer.py create mode 100644 COOLLexerErrorListener.py create mode 100644 COOLListener.py create mode 100644 COOLParser.py create mode 100644 COOLParserErrorListener.py create mode 100644 COOL_LEX.interp create mode 100644 COOL_LEX.py create mode 100644 COOL_LEX.tokens create mode 100644 tests/lexer/test1.cl create mode 100644 tests/lexer/test1_error.txt create mode 100644 tests/lexer/test3.cl create mode 100644 tests/lexer/test3_error.txt create mode 100644 tests/lexer/test5.cl create mode 100644 tests/lexer/test5_error.txt create mode 100644 tests/lexer/test6.cl create mode 100644 tests/lexer/test6_error.txt create mode 100644 tests/parser/err2.cl create mode 100644 tests/parser/err2_error.txt create mode 100644 tests/parser/isprime.cl create mode 100644 tests/parser/isprime_error.txt create mode 100644 tests/parser/prod.cl create mode 100644 tests/parser/prod_error.txt create mode 100644 tests/parser/test2.cl create mode 100644 tests/parser/test2_error.txt create mode 100644 tests/parser/test4.cl create mode 100644 tests/parser/test4_error.txt diff --git a/COOL.interp b/COOL.interp new file mode 100644 index 00000000..bba307e6 --- /dev/null +++ b/COOL.interp @@ -0,0 +1,113 @@ +token literal names: +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +'<-' +'=>' +'+' +'-' +'*' +'/' +'<' +'<=' +'=' +'~' +'(' +')' +'{' +'}' +'@' +'.' +',' +':' +';' +null +null +'(*' +null +'*)' + +token symbolic names: +null +CLASS +ELSE +FALSE +FI +IF +IN +INHERITS +ISVOID +LET +LOOP +POOL +THEN +WHILE +CASE +ESAC +NEW +OF +NOT +TRUE +STRING +BREAK_STRING +INT +TYPEID +OBJECTID +ASSIGNMENT +CASE_ARROW +ADD +MINUS +MULTIPLY +DIVISION +LESS_THAN +LESS_EQUAL +EQUAL +INTEGER_NEGATIVE +OPEN_ROUND +CLOSE_ROUND +OPEN_CURLY +CLOSE_CURLY +AT +DOT +COMMA +COLON +SEMICOLON +WHITESPACE +ONE_LINE_COMMENT +OPEN_COMMENT +COMMENT +CLOSE_COMMENT + +rule names: +program +programBlocks +classDefine +feature +formal +expression + + +atn: +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 50, 225, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 7, 7, 86, 10, 7, 12, 7, 14, 7, 89, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 110, 10, 7, 13, 7, 14, 7, 111, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 122, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 130, 10, 7, 7, 7, 132, 10, 7, 12, 7, 14, 7, 135, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 149, 10, 7, 13, 7, 14, 7, 150, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 175, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 201, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 209, 10, 7, 12, 7, 14, 7, 212, 11, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 7, 7, 220, 10, 7, 12, 7, 14, 7, 223, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 259, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 174, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 45, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 25, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 25, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 39, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 45, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 40, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 26, 2, 2, 40, 51, 7, 37, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 43, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 38, 2, 2, 55, 56, 7, 44, 2, 2, 56, 57, 7, 25, 2, 2, 57, 58, 7, 39, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 40, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 26, 2, 2, 62, 63, 7, 44, 2, 2, 63, 66, 7, 25, 2, 2, 64, 65, 7, 27, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 26, 2, 2, 71, 72, 7, 44, 2, 2, 72, 73, 7, 25, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 26, 2, 2, 76, 87, 7, 37, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 43, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 90, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 175, 7, 38, 2, 2, 91, 92, 7, 7, 2, 2, 92, 93, 5, 12, 7, 2, 93, 94, 7, 14, 2, 2, 94, 95, 5, 12, 7, 2, 95, 96, 7, 4, 2, 2, 96, 97, 5, 12, 7, 2, 97, 98, 7, 6, 2, 2, 98, 175, 3, 2, 2, 2, 99, 100, 7, 15, 2, 2, 100, 101, 5, 12, 7, 2, 101, 102, 7, 12, 2, 2, 102, 103, 5, 12, 7, 2, 103, 104, 7, 13, 2, 2, 104, 175, 3, 2, 2, 2, 105, 109, 7, 39, 2, 2, 106, 107, 5, 12, 7, 2, 107, 108, 7, 45, 2, 2, 108, 110, 3, 2, 2, 2, 109, 106, 3, 2, 2, 2, 110, 111, 3, 2, 2, 2, 111, 109, 3, 2, 2, 2, 111, 112, 3, 2, 2, 2, 112, 113, 3, 2, 2, 2, 113, 114, 7, 40, 2, 2, 114, 175, 3, 2, 2, 2, 115, 116, 7, 11, 2, 2, 116, 117, 7, 26, 2, 2, 117, 118, 7, 44, 2, 2, 118, 121, 7, 25, 2, 2, 119, 120, 7, 27, 2, 2, 120, 122, 5, 12, 7, 2, 121, 119, 3, 2, 2, 2, 121, 122, 3, 2, 2, 2, 122, 133, 3, 2, 2, 2, 123, 124, 7, 43, 2, 2, 124, 125, 7, 26, 2, 2, 125, 126, 7, 44, 2, 2, 126, 129, 7, 25, 2, 2, 127, 128, 7, 27, 2, 2, 128, 130, 5, 12, 7, 2, 129, 127, 3, 2, 2, 2, 129, 130, 3, 2, 2, 2, 130, 132, 3, 2, 2, 2, 131, 123, 3, 2, 2, 2, 132, 135, 3, 2, 2, 2, 133, 131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 136, 3, 2, 2, 2, 135, 133, 3, 2, 2, 2, 136, 137, 7, 8, 2, 2, 137, 175, 5, 12, 7, 22, 138, 139, 7, 16, 2, 2, 139, 140, 5, 12, 7, 2, 140, 148, 7, 19, 2, 2, 141, 142, 7, 26, 2, 2, 142, 143, 7, 44, 2, 2, 143, 144, 7, 25, 2, 2, 144, 145, 7, 28, 2, 2, 145, 146, 5, 12, 7, 2, 146, 147, 7, 45, 2, 2, 147, 149, 3, 2, 2, 2, 148, 141, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 150, 148, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 7, 17, 2, 2, 153, 175, 3, 2, 2, 2, 154, 155, 7, 18, 2, 2, 155, 175, 7, 25, 2, 2, 156, 157, 7, 36, 2, 2, 157, 175, 5, 12, 7, 19, 158, 159, 7, 10, 2, 2, 159, 175, 5, 12, 7, 18, 160, 161, 7, 20, 2, 2, 161, 175, 5, 12, 7, 10, 162, 163, 7, 37, 2, 2, 163, 164, 5, 12, 7, 2, 164, 165, 7, 38, 2, 2, 165, 175, 3, 2, 2, 2, 166, 175, 7, 26, 2, 2, 167, 175, 7, 24, 2, 2, 168, 175, 7, 22, 2, 2, 169, 175, 7, 21, 2, 2, 170, 175, 7, 5, 2, 2, 171, 172, 7, 26, 2, 2, 172, 173, 7, 27, 2, 2, 173, 175, 5, 12, 7, 3, 174, 74, 3, 2, 2, 2, 174, 91, 3, 2, 2, 2, 174, 99, 3, 2, 2, 2, 174, 105, 3, 2, 2, 2, 174, 115, 3, 2, 2, 2, 174, 138, 3, 2, 2, 2, 174, 154, 3, 2, 2, 2, 174, 156, 3, 2, 2, 2, 174, 158, 3, 2, 2, 2, 174, 160, 3, 2, 2, 2, 174, 162, 3, 2, 2, 2, 174, 166, 3, 2, 2, 2, 174, 167, 3, 2, 2, 2, 174, 168, 3, 2, 2, 2, 174, 169, 3, 2, 2, 2, 174, 170, 3, 2, 2, 2, 174, 171, 3, 2, 2, 2, 175, 221, 3, 2, 2, 2, 176, 177, 12, 17, 2, 2, 177, 178, 7, 31, 2, 2, 178, 220, 5, 12, 7, 18, 179, 180, 12, 16, 2, 2, 180, 181, 7, 32, 2, 2, 181, 220, 5, 12, 7, 17, 182, 183, 12, 15, 2, 2, 183, 184, 7, 29, 2, 2, 184, 220, 5, 12, 7, 16, 185, 186, 12, 14, 2, 2, 186, 187, 7, 30, 2, 2, 187, 220, 5, 12, 7, 15, 188, 189, 12, 13, 2, 2, 189, 190, 7, 33, 2, 2, 190, 220, 5, 12, 7, 14, 191, 192, 12, 12, 2, 2, 192, 193, 7, 34, 2, 2, 193, 220, 5, 12, 7, 13, 194, 195, 12, 11, 2, 2, 195, 196, 7, 35, 2, 2, 196, 220, 5, 12, 7, 12, 197, 200, 12, 27, 2, 2, 198, 199, 7, 41, 2, 2, 199, 201, 7, 25, 2, 2, 200, 198, 3, 2, 2, 2, 200, 201, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 7, 42, 2, 2, 203, 204, 7, 26, 2, 2, 204, 215, 7, 37, 2, 2, 205, 210, 5, 12, 7, 2, 206, 207, 7, 43, 2, 2, 207, 209, 5, 12, 7, 2, 208, 206, 3, 2, 2, 2, 209, 212, 3, 2, 2, 2, 210, 208, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 214, 3, 2, 2, 2, 212, 210, 3, 2, 2, 2, 213, 205, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 218, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 218, 220, 7, 38, 2, 2, 219, 176, 3, 2, 2, 2, 219, 179, 3, 2, 2, 2, 219, 182, 3, 2, 2, 2, 219, 185, 3, 2, 2, 2, 219, 188, 3, 2, 2, 2, 219, 191, 3, 2, 2, 2, 219, 194, 3, 2, 2, 2, 219, 197, 3, 2, 2, 2, 220, 223, 3, 2, 2, 2, 221, 219, 3, 2, 2, 2, 221, 222, 3, 2, 2, 2, 222, 13, 3, 2, 2, 2, 223, 221, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 87, 111, 121, 129, 133, 150, 174, 200, 210, 215, 219, 221] \ No newline at end of file diff --git a/COOL.py b/COOL.py new file mode 100644 index 00000000..7fca203d --- /dev/null +++ b/COOL.py @@ -0,0 +1,1828 @@ +# Generated from COOL.g4 by ANTLR 4.7.2 +# encoding: utf-8 +from antlr4 import * +from io import StringIO +from typing.io import TextIO +import sys + + +def serializedATN(): + with StringIO() as buf: + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\62") + buf.write("\u00e1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") + buf.write("\3\2\3\2\3\2\3\3\3\3\3\3\5\3\25\n\3\3\4\3\4\3\4\3\4\5") + buf.write("\4\33\n\4\3\4\3\4\3\4\3\4\7\4!\n\4\f\4\16\4$\13\4\3\4") + buf.write("\3\4\3\5\3\5\3\5\3\5\3\5\7\5-\n\5\f\5\16\5\60\13\5\7\5") + buf.write("\62\n\5\f\5\16\5\65\13\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3") + buf.write("\5\3\5\3\5\3\5\3\5\5\5C\n\5\5\5E\n\5\3\6\3\6\3\6\3\6\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\7\7Q\n\7\f\7\16\7T\13\7\7\7V\n") + buf.write("\7\f\7\16\7Y\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\6\7n\n\7\r\7") + buf.write("\16\7o\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\5\7z\n\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\5\7\u0082\n\7\7\7\u0084\n\7\f\7\16") + buf.write("\7\u0087\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\6\7\u0095\n\7\r\7\16\7\u0096\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\5\7\u00af\n\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\5\7\u00c9\n\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\7\7\u00d1\n\7\f\7\16\7\u00d4\13\7\7\7\u00d6\n\7\f") + buf.write("\7\16\7\u00d9\13\7\3\7\7\7\u00dc\n\7\f\7\16\7\u00df\13") + buf.write("\7\3\7\2\3\f\b\2\4\6\b\n\f\2\2\2\u0103\2\16\3\2\2\2\4") + buf.write("\21\3\2\2\2\6\26\3\2\2\2\bD\3\2\2\2\nF\3\2\2\2\f\u00ae") + buf.write("\3\2\2\2\16\17\5\4\3\2\17\20\7\2\2\3\20\3\3\2\2\2\21\22") + buf.write("\5\6\4\2\22\24\7-\2\2\23\25\5\4\3\2\24\23\3\2\2\2\24\25") + buf.write("\3\2\2\2\25\5\3\2\2\2\26\27\7\3\2\2\27\32\7\31\2\2\30") + buf.write("\31\7\t\2\2\31\33\7\31\2\2\32\30\3\2\2\2\32\33\3\2\2\2") + buf.write("\33\34\3\2\2\2\34\"\7\'\2\2\35\36\5\b\5\2\36\37\7-\2\2") + buf.write("\37!\3\2\2\2 \35\3\2\2\2!$\3\2\2\2\" \3\2\2\2\"#\3\2\2") + buf.write("\2#%\3\2\2\2$\"\3\2\2\2%&\7(\2\2&\7\3\2\2\2\'(\7\32\2") + buf.write("\2(\63\7%\2\2).\5\n\6\2*+\7+\2\2+-\5\n\6\2,*\3\2\2\2-") + buf.write("\60\3\2\2\2.,\3\2\2\2./\3\2\2\2/\62\3\2\2\2\60.\3\2\2") + buf.write("\2\61)\3\2\2\2\62\65\3\2\2\2\63\61\3\2\2\2\63\64\3\2\2") + buf.write("\2\64\66\3\2\2\2\65\63\3\2\2\2\66\67\7&\2\2\678\7,\2\2") + buf.write("89\7\31\2\29:\7\'\2\2:;\5\f\7\2;<\7(\2\2\7") + buf.write("\32\2\2>?\7,\2\2?B\7\31\2\2@A\7\33\2\2AC\5\f\7\2B@\3\2") + buf.write("\2\2BC\3\2\2\2CE\3\2\2\2D\'\3\2\2\2D=\3\2\2\2E\t\3\2\2") + buf.write("\2FG\7\32\2\2GH\7,\2\2HI\7\31\2\2I\13\3\2\2\2JK\b\7\1") + buf.write("\2KL\7\32\2\2LW\7%\2\2MR\5\f\7\2NO\7+\2\2OQ\5\f\7\2PN") + buf.write("\3\2\2\2QT\3\2\2\2RP\3\2\2\2RS\3\2\2\2SV\3\2\2\2TR\3\2") + buf.write("\2\2UM\3\2\2\2VY\3\2\2\2WU\3\2\2\2WX\3\2\2\2XZ\3\2\2\2") + buf.write("YW\3\2\2\2Z\u00af\7&\2\2[\\\7\7\2\2\\]\5\f\7\2]^\7\16") + buf.write("\2\2^_\5\f\7\2_`\7\4\2\2`a\5\f\7\2ab\7\6\2\2b\u00af\3") + buf.write("\2\2\2cd\7\17\2\2de\5\f\7\2ef\7\f\2\2fg\5\f\7\2gh\7\r") + buf.write("\2\2h\u00af\3\2\2\2im\7\'\2\2jk\5\f\7\2kl\7-\2\2ln\3\2") + buf.write("\2\2mj\3\2\2\2no\3\2\2\2om\3\2\2\2op\3\2\2\2pq\3\2\2\2") + buf.write("qr\7(\2\2r\u00af\3\2\2\2st\7\13\2\2tu\7\32\2\2uv\7,\2") + buf.write("\2vy\7\31\2\2wx\7\33\2\2xz\5\f\7\2yw\3\2\2\2yz\3\2\2\2") + buf.write("z\u0085\3\2\2\2{|\7+\2\2|}\7\32\2\2}~\7,\2\2~\u0081\7") + buf.write("\31\2\2\177\u0080\7\33\2\2\u0080\u0082\5\f\7\2\u0081\177") + buf.write("\3\2\2\2\u0081\u0082\3\2\2\2\u0082\u0084\3\2\2\2\u0083") + buf.write("{\3\2\2\2\u0084\u0087\3\2\2\2\u0085\u0083\3\2\2\2\u0085") + buf.write("\u0086\3\2\2\2\u0086\u0088\3\2\2\2\u0087\u0085\3\2\2\2") + buf.write("\u0088\u0089\7\b\2\2\u0089\u00af\5\f\7\26\u008a\u008b") + buf.write("\7\20\2\2\u008b\u008c\5\f\7\2\u008c\u0094\7\23\2\2\u008d") + buf.write("\u008e\7\32\2\2\u008e\u008f\7,\2\2\u008f\u0090\7\31\2") + buf.write("\2\u0090\u0091\7\34\2\2\u0091\u0092\5\f\7\2\u0092\u0093") + buf.write("\7-\2\2\u0093\u0095\3\2\2\2\u0094\u008d\3\2\2\2\u0095") + buf.write("\u0096\3\2\2\2\u0096\u0094\3\2\2\2\u0096\u0097\3\2\2\2") + buf.write("\u0097\u0098\3\2\2\2\u0098\u0099\7\21\2\2\u0099\u00af") + buf.write("\3\2\2\2\u009a\u009b\7\22\2\2\u009b\u00af\7\31\2\2\u009c") + buf.write("\u009d\7$\2\2\u009d\u00af\5\f\7\23\u009e\u009f\7\n\2\2") + buf.write("\u009f\u00af\5\f\7\22\u00a0\u00a1\7\24\2\2\u00a1\u00af") + buf.write("\5\f\7\n\u00a2\u00a3\7%\2\2\u00a3\u00a4\5\f\7\2\u00a4") + buf.write("\u00a5\7&\2\2\u00a5\u00af\3\2\2\2\u00a6\u00af\7\32\2\2") + buf.write("\u00a7\u00af\7\30\2\2\u00a8\u00af\7\26\2\2\u00a9\u00af") + buf.write("\7\25\2\2\u00aa\u00af\7\5\2\2\u00ab\u00ac\7\32\2\2\u00ac") + buf.write("\u00ad\7\33\2\2\u00ad\u00af\5\f\7\3\u00aeJ\3\2\2\2\u00ae") + buf.write("[\3\2\2\2\u00aec\3\2\2\2\u00aei\3\2\2\2\u00aes\3\2\2\2") + buf.write("\u00ae\u008a\3\2\2\2\u00ae\u009a\3\2\2\2\u00ae\u009c\3") + buf.write("\2\2\2\u00ae\u009e\3\2\2\2\u00ae\u00a0\3\2\2\2\u00ae\u00a2") + buf.write("\3\2\2\2\u00ae\u00a6\3\2\2\2\u00ae\u00a7\3\2\2\2\u00ae") + buf.write("\u00a8\3\2\2\2\u00ae\u00a9\3\2\2\2\u00ae\u00aa\3\2\2\2") + buf.write("\u00ae\u00ab\3\2\2\2\u00af\u00dd\3\2\2\2\u00b0\u00b1\f") + buf.write("\21\2\2\u00b1\u00b2\7\37\2\2\u00b2\u00dc\5\f\7\22\u00b3") + buf.write("\u00b4\f\20\2\2\u00b4\u00b5\7 \2\2\u00b5\u00dc\5\f\7\21") + buf.write("\u00b6\u00b7\f\17\2\2\u00b7\u00b8\7\35\2\2\u00b8\u00dc") + buf.write("\5\f\7\20\u00b9\u00ba\f\16\2\2\u00ba\u00bb\7\36\2\2\u00bb") + buf.write("\u00dc\5\f\7\17\u00bc\u00bd\f\r\2\2\u00bd\u00be\7!\2\2") + buf.write("\u00be\u00dc\5\f\7\16\u00bf\u00c0\f\f\2\2\u00c0\u00c1") + buf.write("\7\"\2\2\u00c1\u00dc\5\f\7\r\u00c2\u00c3\f\13\2\2\u00c3") + buf.write("\u00c4\7#\2\2\u00c4\u00dc\5\f\7\f\u00c5\u00c8\f\33\2\2") + buf.write("\u00c6\u00c7\7)\2\2\u00c7\u00c9\7\31\2\2\u00c8\u00c6\3") + buf.write("\2\2\2\u00c8\u00c9\3\2\2\2\u00c9\u00ca\3\2\2\2\u00ca\u00cb") + buf.write("\7*\2\2\u00cb\u00cc\7\32\2\2\u00cc\u00d7\7%\2\2\u00cd") + buf.write("\u00d2\5\f\7\2\u00ce\u00cf\7+\2\2\u00cf\u00d1\5\f\7\2") + buf.write("\u00d0\u00ce\3\2\2\2\u00d1\u00d4\3\2\2\2\u00d2\u00d0\3") + buf.write("\2\2\2\u00d2\u00d3\3\2\2\2\u00d3\u00d6\3\2\2\2\u00d4\u00d2") + buf.write("\3\2\2\2\u00d5\u00cd\3\2\2\2\u00d6\u00d9\3\2\2\2\u00d7") + buf.write("\u00d5\3\2\2\2\u00d7\u00d8\3\2\2\2\u00d8\u00da\3\2\2\2") + buf.write("\u00d9\u00d7\3\2\2\2\u00da\u00dc\7&\2\2\u00db\u00b0\3") + buf.write("\2\2\2\u00db\u00b3\3\2\2\2\u00db\u00b6\3\2\2\2\u00db\u00b9") + buf.write("\3\2\2\2\u00db\u00bc\3\2\2\2\u00db\u00bf\3\2\2\2\u00db") + buf.write("\u00c2\3\2\2\2\u00db\u00c5\3\2\2\2\u00dc\u00df\3\2\2\2") + buf.write("\u00dd\u00db\3\2\2\2\u00dd\u00de\3\2\2\2\u00de\r\3\2\2") + buf.write("\2\u00df\u00dd\3\2\2\2\26\24\32\".\63BDRWoy\u0081\u0085") + buf.write("\u0096\u00ae\u00c8\u00d2\u00d7\u00db\u00dd") + return buf.getvalue() + + +class COOL ( Parser ): + + grammarFileName = "COOL.g4" + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] + + sharedContextCache = PredictionContextCache() + + literalNames = [ "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", + "'<'", "'<='", "'='", "'~'", "'('", "')'", "'{'", "'}'", + "'@'", "'.'", "','", "':'", "';'", "", "", + "'(*'", "", "'*)'" ] + + symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", + "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", + "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", + "TRUE", "STRING", "BREAK_STRING", "INT", "TYPEID", + "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", + "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", + "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", + "OPEN_CURLY", "CLOSE_CURLY", "AT", "DOT", "COMMA", + "COLON", "SEMICOLON", "WHITESPACE", "ONE_LINE_COMMENT", + "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT" ] + + RULE_program = 0 + RULE_programBlocks = 1 + RULE_classDefine = 2 + RULE_feature = 3 + RULE_formal = 4 + RULE_expression = 5 + + ruleNames = [ "program", "programBlocks", "classDefine", "feature", + "formal", "expression" ] + + EOF = Token.EOF + CLASS=1 + ELSE=2 + FALSE=3 + FI=4 + IF=5 + IN=6 + INHERITS=7 + ISVOID=8 + LET=9 + LOOP=10 + POOL=11 + THEN=12 + WHILE=13 + CASE=14 + ESAC=15 + NEW=16 + OF=17 + NOT=18 + TRUE=19 + STRING=20 + BREAK_STRING=21 + INT=22 + TYPEID=23 + OBJECTID=24 + ASSIGNMENT=25 + CASE_ARROW=26 + ADD=27 + MINUS=28 + MULTIPLY=29 + DIVISION=30 + LESS_THAN=31 + LESS_EQUAL=32 + EQUAL=33 + INTEGER_NEGATIVE=34 + OPEN_ROUND=35 + CLOSE_ROUND=36 + OPEN_CURLY=37 + CLOSE_CURLY=38 + AT=39 + DOT=40 + COMMA=41 + COLON=42 + SEMICOLON=43 + WHITESPACE=44 + ONE_LINE_COMMENT=45 + OPEN_COMMENT=46 + COMMENT=47 + CLOSE_COMMENT=48 + + def __init__(self, input:TokenStream, output:TextIO = sys.stdout): + super().__init__(input, output) + self.checkVersion("4.7.2") + self._interp = ParserATNSimulator(self, self.atn, self.decisionsToDFA, self.sharedContextCache) + self._predicates = None + + + + + class ProgramContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def programBlocks(self): + return self.getTypedRuleContext(COOL.ProgramBlocksContext,0) + + + def EOF(self): + return self.getToken(COOL.EOF, 0) + + def getRuleIndex(self): + return COOL.RULE_program + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterProgram" ): + listener.enterProgram(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitProgram" ): + listener.exitProgram(self) + + + + + def program(self): + + localctx = COOL.ProgramContext(self, self._ctx, self.state) + self.enterRule(localctx, 0, self.RULE_program) + try: + self.enterOuterAlt(localctx, 1) + self.state = 12 + self.programBlocks() + self.state = 13 + self.match(COOL.EOF) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class ProgramBlocksContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return COOL.RULE_programBlocks + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) + + + + class ClassesContext(ProgramBlocksContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ProgramBlocksContext + super().__init__(parser) + self.copyFrom(ctx) + + def classDefine(self): + return self.getTypedRuleContext(COOL.ClassDefineContext,0) + + def SEMICOLON(self): + return self.getToken(COOL.SEMICOLON, 0) + def programBlocks(self): + return self.getTypedRuleContext(COOL.ProgramBlocksContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterClasses" ): + listener.enterClasses(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitClasses" ): + listener.exitClasses(self) + + + + def programBlocks(self): + + localctx = COOL.ProgramBlocksContext(self, self._ctx, self.state) + self.enterRule(localctx, 2, self.RULE_programBlocks) + self._la = 0 # Token type + try: + localctx = COOL.ClassesContext(self, localctx) + self.enterOuterAlt(localctx, 1) + self.state = 15 + self.classDefine() + self.state = 16 + self.match(COOL.SEMICOLON) + self.state = 18 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOL.CLASS: + self.state = 17 + self.programBlocks() + + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class ClassDefineContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def CLASS(self): + return self.getToken(COOL.CLASS, 0) + + def TYPEID(self, i:int=None): + if i is None: + return self.getTokens(COOL.TYPEID) + else: + return self.getToken(COOL.TYPEID, i) + + def OPEN_CURLY(self): + return self.getToken(COOL.OPEN_CURLY, 0) + + def CLOSE_CURLY(self): + return self.getToken(COOL.CLOSE_CURLY, 0) + + def INHERITS(self): + return self.getToken(COOL.INHERITS, 0) + + def feature(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.FeatureContext) + else: + return self.getTypedRuleContext(COOL.FeatureContext,i) + + + def SEMICOLON(self, i:int=None): + if i is None: + return self.getTokens(COOL.SEMICOLON) + else: + return self.getToken(COOL.SEMICOLON, i) + + def getRuleIndex(self): + return COOL.RULE_classDefine + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterClassDefine" ): + listener.enterClassDefine(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitClassDefine" ): + listener.exitClassDefine(self) + + + + + def classDefine(self): + + localctx = COOL.ClassDefineContext(self, self._ctx, self.state) + self.enterRule(localctx, 4, self.RULE_classDefine) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 20 + self.match(COOL.CLASS) + self.state = 21 + self.match(COOL.TYPEID) + self.state = 24 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOL.INHERITS: + self.state = 22 + self.match(COOL.INHERITS) + self.state = 23 + self.match(COOL.TYPEID) + + + self.state = 26 + self.match(COOL.OPEN_CURLY) + self.state = 32 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOL.OBJECTID: + self.state = 27 + self.feature() + self.state = 28 + self.match(COOL.SEMICOLON) + self.state = 34 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 35 + self.match(COOL.CLOSE_CURLY) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class FeatureContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return COOL.RULE_feature + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) + + + + class MethodContext(FeatureContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.FeatureContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + def OPEN_ROUND(self): + return self.getToken(COOL.OPEN_ROUND, 0) + def CLOSE_ROUND(self): + return self.getToken(COOL.CLOSE_ROUND, 0) + def COLON(self): + return self.getToken(COOL.COLON, 0) + def TYPEID(self): + return self.getToken(COOL.TYPEID, 0) + def OPEN_CURLY(self): + return self.getToken(COOL.OPEN_CURLY, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + def CLOSE_CURLY(self): + return self.getToken(COOL.CLOSE_CURLY, 0) + def formal(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.FormalContext) + else: + return self.getTypedRuleContext(COOL.FormalContext,i) + + def COMMA(self, i:int=None): + if i is None: + return self.getTokens(COOL.COMMA) + else: + return self.getToken(COOL.COMMA, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMethod" ): + listener.enterMethod(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMethod" ): + listener.exitMethod(self) + + + class PropertyContext(FeatureContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.FeatureContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + def COLON(self): + return self.getToken(COOL.COLON, 0) + def TYPEID(self): + return self.getToken(COOL.TYPEID, 0) + def ASSIGNMENT(self): + return self.getToken(COOL.ASSIGNMENT, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterProperty" ): + listener.enterProperty(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitProperty" ): + listener.exitProperty(self) + + + + def feature(self): + + localctx = COOL.FeatureContext(self, self._ctx, self.state) + self.enterRule(localctx, 6, self.RULE_feature) + self._la = 0 # Token type + try: + self.state = 66 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input,6,self._ctx) + if la_ == 1: + localctx = COOL.MethodContext(self, localctx) + self.enterOuterAlt(localctx, 1) + self.state = 37 + self.match(COOL.OBJECTID) + self.state = 38 + self.match(COOL.OPEN_ROUND) + self.state = 49 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOL.OBJECTID: + self.state = 39 + self.formal() + self.state = 44 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOL.COMMA: + self.state = 40 + self.match(COOL.COMMA) + self.state = 41 + self.formal() + self.state = 46 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 51 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 52 + self.match(COOL.CLOSE_ROUND) + self.state = 53 + self.match(COOL.COLON) + self.state = 54 + self.match(COOL.TYPEID) + self.state = 55 + self.match(COOL.OPEN_CURLY) + self.state = 56 + self.expression(0) + self.state = 57 + self.match(COOL.CLOSE_CURLY) + pass + + elif la_ == 2: + localctx = COOL.PropertyContext(self, localctx) + self.enterOuterAlt(localctx, 2) + self.state = 59 + self.match(COOL.OBJECTID) + self.state = 60 + self.match(COOL.COLON) + self.state = 61 + self.match(COOL.TYPEID) + self.state = 64 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOL.ASSIGNMENT: + self.state = 62 + self.match(COOL.ASSIGNMENT) + self.state = 63 + self.expression(0) + + + pass + + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class FormalContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + + def COLON(self): + return self.getToken(COOL.COLON, 0) + + def TYPEID(self): + return self.getToken(COOL.TYPEID, 0) + + def getRuleIndex(self): + return COOL.RULE_formal + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterFormal" ): + listener.enterFormal(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitFormal" ): + listener.exitFormal(self) + + + + + def formal(self): + + localctx = COOL.FormalContext(self, self._ctx, self.state) + self.enterRule(localctx, 8, self.RULE_formal) + try: + self.enterOuterAlt(localctx, 1) + self.state = 68 + self.match(COOL.OBJECTID) + self.state = 69 + self.match(COOL.COLON) + self.state = 70 + self.match(COOL.TYPEID) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class ExpressionContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return COOL.RULE_expression + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) + + + class LetInContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def LET(self): + return self.getToken(COOL.LET, 0) + def OBJECTID(self, i:int=None): + if i is None: + return self.getTokens(COOL.OBJECTID) + else: + return self.getToken(COOL.OBJECTID, i) + def COLON(self, i:int=None): + if i is None: + return self.getTokens(COOL.COLON) + else: + return self.getToken(COOL.COLON, i) + def TYPEID(self, i:int=None): + if i is None: + return self.getTokens(COOL.TYPEID) + else: + return self.getToken(COOL.TYPEID, i) + def IN(self): + return self.getToken(COOL.IN, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def ASSIGNMENT(self, i:int=None): + if i is None: + return self.getTokens(COOL.ASSIGNMENT) + else: + return self.getToken(COOL.ASSIGNMENT, i) + def COMMA(self, i:int=None): + if i is None: + return self.getTokens(COOL.COMMA) + else: + return self.getToken(COOL.COMMA, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterLetIn" ): + listener.enterLetIn(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitLetIn" ): + listener.exitLetIn(self) + + + class MinusContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def MINUS(self): + return self.getToken(COOL.MINUS, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMinus" ): + listener.enterMinus(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMinus" ): + listener.exitMinus(self) + + + class StringContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def STRING(self): + return self.getToken(COOL.STRING, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterString" ): + listener.enterString(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitString" ): + listener.exitString(self) + + + class IsvoidContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def ISVOID(self): + return self.getToken(COOL.ISVOID, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterIsvoid" ): + listener.enterIsvoid(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitIsvoid" ): + listener.exitIsvoid(self) + + + class WhileContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def WHILE(self): + return self.getToken(COOL.WHILE, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def LOOP(self): + return self.getToken(COOL.LOOP, 0) + def POOL(self): + return self.getToken(COOL.POOL, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterWhile" ): + listener.enterWhile(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitWhile" ): + listener.exitWhile(self) + + + class DivisionContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def DIVISION(self): + return self.getToken(COOL.DIVISION, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterDivision" ): + listener.enterDivision(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitDivision" ): + listener.exitDivision(self) + + + class NegativeContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def INTEGER_NEGATIVE(self): + return self.getToken(COOL.INTEGER_NEGATIVE, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterNegative" ): + listener.enterNegative(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitNegative" ): + listener.exitNegative(self) + + + class BoolNotContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def NOT(self): + return self.getToken(COOL.NOT, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterBoolNot" ): + listener.enterBoolNot(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitBoolNot" ): + listener.exitBoolNot(self) + + + class LessThanContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def LESS_THAN(self): + return self.getToken(COOL.LESS_THAN, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterLessThan" ): + listener.enterLessThan(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitLessThan" ): + listener.exitLessThan(self) + + + class BlockContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OPEN_CURLY(self): + return self.getToken(COOL.OPEN_CURLY, 0) + def CLOSE_CURLY(self): + return self.getToken(COOL.CLOSE_CURLY, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def SEMICOLON(self, i:int=None): + if i is None: + return self.getTokens(COOL.SEMICOLON) + else: + return self.getToken(COOL.SEMICOLON, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterBlock" ): + listener.enterBlock(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitBlock" ): + listener.exitBlock(self) + + + class IdContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterId" ): + listener.enterId(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitId" ): + listener.exitId(self) + + + class MultiplyContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def MULTIPLY(self): + return self.getToken(COOL.MULTIPLY, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMultiply" ): + listener.enterMultiply(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMultiply" ): + listener.exitMultiply(self) + + + class IfContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def IF(self): + return self.getToken(COOL.IF, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def THEN(self): + return self.getToken(COOL.THEN, 0) + def ELSE(self): + return self.getToken(COOL.ELSE, 0) + def FI(self): + return self.getToken(COOL.FI, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterIf" ): + listener.enterIf(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitIf" ): + listener.exitIf(self) + + + class CaseContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def CASE(self): + return self.getToken(COOL.CASE, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def OF(self): + return self.getToken(COOL.OF, 0) + def ESAC(self): + return self.getToken(COOL.ESAC, 0) + def OBJECTID(self, i:int=None): + if i is None: + return self.getTokens(COOL.OBJECTID) + else: + return self.getToken(COOL.OBJECTID, i) + def COLON(self, i:int=None): + if i is None: + return self.getTokens(COOL.COLON) + else: + return self.getToken(COOL.COLON, i) + def TYPEID(self, i:int=None): + if i is None: + return self.getTokens(COOL.TYPEID) + else: + return self.getToken(COOL.TYPEID, i) + def CASE_ARROW(self, i:int=None): + if i is None: + return self.getTokens(COOL.CASE_ARROW) + else: + return self.getToken(COOL.CASE_ARROW, i) + def SEMICOLON(self, i:int=None): + if i is None: + return self.getTokens(COOL.SEMICOLON) + else: + return self.getToken(COOL.SEMICOLON, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterCase" ): + listener.enterCase(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitCase" ): + listener.exitCase(self) + + + class OwnMethodCallContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + def OPEN_ROUND(self): + return self.getToken(COOL.OPEN_ROUND, 0) + def CLOSE_ROUND(self): + return self.getToken(COOL.CLOSE_ROUND, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def COMMA(self, i:int=None): + if i is None: + return self.getTokens(COOL.COMMA) + else: + return self.getToken(COOL.COMMA, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterOwnMethodCall" ): + listener.enterOwnMethodCall(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitOwnMethodCall" ): + listener.exitOwnMethodCall(self) + + + class AddContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def ADD(self): + return self.getToken(COOL.ADD, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterAdd" ): + listener.enterAdd(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitAdd" ): + listener.exitAdd(self) + + + class NewContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def NEW(self): + return self.getToken(COOL.NEW, 0) + def TYPEID(self): + return self.getToken(COOL.TYPEID, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterNew" ): + listener.enterNew(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitNew" ): + listener.exitNew(self) + + + class ParenthesesContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OPEN_ROUND(self): + return self.getToken(COOL.OPEN_ROUND, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + def CLOSE_ROUND(self): + return self.getToken(COOL.CLOSE_ROUND, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterParentheses" ): + listener.enterParentheses(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitParentheses" ): + listener.exitParentheses(self) + + + class AssignmentContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + def ASSIGNMENT(self): + return self.getToken(COOL.ASSIGNMENT, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterAssignment" ): + listener.enterAssignment(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitAssignment" ): + listener.exitAssignment(self) + + + class FalseContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def FALSE(self): + return self.getToken(COOL.FALSE, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterFalse" ): + listener.enterFalse(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitFalse" ): + listener.exitFalse(self) + + + class IntContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def INT(self): + return self.getToken(COOL.INT, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterInt" ): + listener.enterInt(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitInt" ): + listener.exitInt(self) + + + class EqualContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def EQUAL(self): + return self.getToken(COOL.EQUAL, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterEqual" ): + listener.enterEqual(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitEqual" ): + listener.exitEqual(self) + + + class TrueContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def TRUE(self): + return self.getToken(COOL.TRUE, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterTrue" ): + listener.enterTrue(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitTrue" ): + listener.exitTrue(self) + + + class LessEqualContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def LESS_EQUAL(self): + return self.getToken(COOL.LESS_EQUAL, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterLessEqual" ): + listener.enterLessEqual(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitLessEqual" ): + listener.exitLessEqual(self) + + + class MethodCallContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def DOT(self): + return self.getToken(COOL.DOT, 0) + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + def OPEN_ROUND(self): + return self.getToken(COOL.OPEN_ROUND, 0) + def CLOSE_ROUND(self): + return self.getToken(COOL.CLOSE_ROUND, 0) + def AT(self): + return self.getToken(COOL.AT, 0) + def TYPEID(self): + return self.getToken(COOL.TYPEID, 0) + def COMMA(self, i:int=None): + if i is None: + return self.getTokens(COOL.COMMA) + else: + return self.getToken(COOL.COMMA, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMethodCall" ): + listener.enterMethodCall(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMethodCall" ): + listener.exitMethodCall(self) + + + + def expression(self, _p:int=0): + _parentctx = self._ctx + _parentState = self.state + localctx = COOL.ExpressionContext(self, self._ctx, _parentState) + _prevctx = localctx + _startState = 10 + self.enterRecursionRule(localctx, 10, self.RULE_expression, _p) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 172 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input,14,self._ctx) + if la_ == 1: + localctx = COOL.OwnMethodCallContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + + self.state = 73 + self.match(COOL.OBJECTID) + self.state = 74 + self.match(COOL.OPEN_ROUND) + self.state = 85 + self._errHandler.sync(self) + _la = self._input.LA(1) + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0): + self.state = 75 + self.expression(0) + self.state = 80 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOL.COMMA: + self.state = 76 + self.match(COOL.COMMA) + self.state = 77 + self.expression(0) + self.state = 82 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 87 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 88 + self.match(COOL.CLOSE_ROUND) + pass + + elif la_ == 2: + localctx = COOL.IfContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 89 + self.match(COOL.IF) + self.state = 90 + self.expression(0) + self.state = 91 + self.match(COOL.THEN) + self.state = 92 + self.expression(0) + self.state = 93 + self.match(COOL.ELSE) + self.state = 94 + self.expression(0) + self.state = 95 + self.match(COOL.FI) + pass + + elif la_ == 3: + localctx = COOL.WhileContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 97 + self.match(COOL.WHILE) + self.state = 98 + self.expression(0) + self.state = 99 + self.match(COOL.LOOP) + self.state = 100 + self.expression(0) + self.state = 101 + self.match(COOL.POOL) + pass + + elif la_ == 4: + localctx = COOL.BlockContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 103 + self.match(COOL.OPEN_CURLY) + self.state = 107 + self._errHandler.sync(self) + _la = self._input.LA(1) + while True: + self.state = 104 + self.expression(0) + self.state = 105 + self.match(COOL.SEMICOLON) + self.state = 109 + self._errHandler.sync(self) + _la = self._input.LA(1) + if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0)): + break + + self.state = 111 + self.match(COOL.CLOSE_CURLY) + pass + + elif la_ == 5: + localctx = COOL.LetInContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 113 + self.match(COOL.LET) + self.state = 114 + self.match(COOL.OBJECTID) + self.state = 115 + self.match(COOL.COLON) + self.state = 116 + self.match(COOL.TYPEID) + self.state = 119 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOL.ASSIGNMENT: + self.state = 117 + self.match(COOL.ASSIGNMENT) + self.state = 118 + self.expression(0) + + + self.state = 131 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOL.COMMA: + self.state = 121 + self.match(COOL.COMMA) + self.state = 122 + self.match(COOL.OBJECTID) + self.state = 123 + self.match(COOL.COLON) + self.state = 124 + self.match(COOL.TYPEID) + self.state = 127 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOL.ASSIGNMENT: + self.state = 125 + self.match(COOL.ASSIGNMENT) + self.state = 126 + self.expression(0) + + + self.state = 133 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 134 + self.match(COOL.IN) + self.state = 135 + self.expression(20) + pass + + elif la_ == 6: + localctx = COOL.CaseContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 136 + self.match(COOL.CASE) + self.state = 137 + self.expression(0) + self.state = 138 + self.match(COOL.OF) + self.state = 146 + self._errHandler.sync(self) + _la = self._input.LA(1) + while True: + self.state = 139 + self.match(COOL.OBJECTID) + self.state = 140 + self.match(COOL.COLON) + self.state = 141 + self.match(COOL.TYPEID) + self.state = 142 + self.match(COOL.CASE_ARROW) + self.state = 143 + self.expression(0) + self.state = 144 + self.match(COOL.SEMICOLON) + self.state = 148 + self._errHandler.sync(self) + _la = self._input.LA(1) + if not (_la==COOL.OBJECTID): + break + + self.state = 150 + self.match(COOL.ESAC) + pass + + elif la_ == 7: + localctx = COOL.NewContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 152 + self.match(COOL.NEW) + self.state = 153 + self.match(COOL.TYPEID) + pass + + elif la_ == 8: + localctx = COOL.NegativeContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 154 + self.match(COOL.INTEGER_NEGATIVE) + self.state = 155 + self.expression(17) + pass + + elif la_ == 9: + localctx = COOL.IsvoidContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 156 + self.match(COOL.ISVOID) + self.state = 157 + self.expression(16) + pass + + elif la_ == 10: + localctx = COOL.BoolNotContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 158 + self.match(COOL.NOT) + self.state = 159 + self.expression(8) + pass + + elif la_ == 11: + localctx = COOL.ParenthesesContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 160 + self.match(COOL.OPEN_ROUND) + self.state = 161 + self.expression(0) + self.state = 162 + self.match(COOL.CLOSE_ROUND) + pass + + elif la_ == 12: + localctx = COOL.IdContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 164 + self.match(COOL.OBJECTID) + pass + + elif la_ == 13: + localctx = COOL.IntContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 165 + self.match(COOL.INT) + pass + + elif la_ == 14: + localctx = COOL.StringContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 166 + self.match(COOL.STRING) + pass + + elif la_ == 15: + localctx = COOL.TrueContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 167 + self.match(COOL.TRUE) + pass + + elif la_ == 16: + localctx = COOL.FalseContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 168 + self.match(COOL.FALSE) + pass + + elif la_ == 17: + localctx = COOL.AssignmentContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 169 + self.match(COOL.OBJECTID) + self.state = 170 + self.match(COOL.ASSIGNMENT) + self.state = 171 + self.expression(1) + pass + + + self._ctx.stop = self._input.LT(-1) + self.state = 219 + self._errHandler.sync(self) + _alt = self._interp.adaptivePredict(self._input,19,self._ctx) + while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: + if _alt==1: + if self._parseListeners is not None: + self.triggerExitRuleEvent() + _prevctx = localctx + self.state = 217 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input,18,self._ctx) + if la_ == 1: + localctx = COOL.MultiplyContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 174 + if not self.precpred(self._ctx, 15): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 15)") + self.state = 175 + self.match(COOL.MULTIPLY) + self.state = 176 + self.expression(16) + pass + + elif la_ == 2: + localctx = COOL.DivisionContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 177 + if not self.precpred(self._ctx, 14): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 14)") + self.state = 178 + self.match(COOL.DIVISION) + self.state = 179 + self.expression(15) + pass + + elif la_ == 3: + localctx = COOL.AddContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 180 + if not self.precpred(self._ctx, 13): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 13)") + self.state = 181 + self.match(COOL.ADD) + self.state = 182 + self.expression(14) + pass + + elif la_ == 4: + localctx = COOL.MinusContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 183 + if not self.precpred(self._ctx, 12): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 12)") + self.state = 184 + self.match(COOL.MINUS) + self.state = 185 + self.expression(13) + pass + + elif la_ == 5: + localctx = COOL.LessThanContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 186 + if not self.precpred(self._ctx, 11): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 11)") + self.state = 187 + self.match(COOL.LESS_THAN) + self.state = 188 + self.expression(12) + pass + + elif la_ == 6: + localctx = COOL.LessEqualContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 189 + if not self.precpred(self._ctx, 10): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 10)") + self.state = 190 + self.match(COOL.LESS_EQUAL) + self.state = 191 + self.expression(11) + pass + + elif la_ == 7: + localctx = COOL.EqualContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 192 + if not self.precpred(self._ctx, 9): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 9)") + self.state = 193 + self.match(COOL.EQUAL) + self.state = 194 + self.expression(10) + pass + + elif la_ == 8: + localctx = COOL.MethodCallContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 195 + if not self.precpred(self._ctx, 25): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 25)") + self.state = 198 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOL.AT: + self.state = 196 + self.match(COOL.AT) + self.state = 197 + self.match(COOL.TYPEID) + + + self.state = 200 + self.match(COOL.DOT) + self.state = 201 + self.match(COOL.OBJECTID) + self.state = 202 + self.match(COOL.OPEN_ROUND) + self.state = 213 + self._errHandler.sync(self) + _la = self._input.LA(1) + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0): + self.state = 203 + self.expression(0) + self.state = 208 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOL.COMMA: + self.state = 204 + self.match(COOL.COMMA) + self.state = 205 + self.expression(0) + self.state = 210 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 215 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 216 + self.match(COOL.CLOSE_ROUND) + pass + + + self.state = 221 + self._errHandler.sync(self) + _alt = self._interp.adaptivePredict(self._input,19,self._ctx) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.unrollRecursionContexts(_parentctx) + return localctx + + + + def sempred(self, localctx:RuleContext, ruleIndex:int, predIndex:int): + if self._predicates == None: + self._predicates = dict() + self._predicates[5] = self.expression_sempred + pred = self._predicates.get(ruleIndex, None) + if pred is None: + raise Exception("No predicate with index:" + str(ruleIndex)) + else: + return pred(localctx, predIndex) + + def expression_sempred(self, localctx:ExpressionContext, predIndex:int): + if predIndex == 0: + return self.precpred(self._ctx, 15) + + + if predIndex == 1: + return self.precpred(self._ctx, 14) + + + if predIndex == 2: + return self.precpred(self._ctx, 13) + + + if predIndex == 3: + return self.precpred(self._ctx, 12) + + + if predIndex == 4: + return self.precpred(self._ctx, 11) + + + if predIndex == 5: + return self.precpred(self._ctx, 10) + + + if predIndex == 6: + return self.precpred(self._ctx, 9) + + + if predIndex == 7: + return self.precpred(self._ctx, 25) + + + + + diff --git a/COOL.tokens b/COOL.tokens new file mode 100644 index 00000000..bbdda836 --- /dev/null +++ b/COOL.tokens @@ -0,0 +1,69 @@ +CLASS=1 +ELSE=2 +FALSE=3 +FI=4 +IF=5 +IN=6 +INHERITS=7 +ISVOID=8 +LET=9 +LOOP=10 +POOL=11 +THEN=12 +WHILE=13 +CASE=14 +ESAC=15 +NEW=16 +OF=17 +NOT=18 +TRUE=19 +STRING=20 +BREAK_STRING=21 +INT=22 +TYPEID=23 +OBJECTID=24 +ASSIGNMENT=25 +CASE_ARROW=26 +ADD=27 +MINUS=28 +MULTIPLY=29 +DIVISION=30 +LESS_THAN=31 +LESS_EQUAL=32 +EQUAL=33 +INTEGER_NEGATIVE=34 +OPEN_ROUND=35 +CLOSE_ROUND=36 +OPEN_CURLY=37 +CLOSE_CURLY=38 +AT=39 +DOT=40 +COMMA=41 +COLON=42 +SEMICOLON=43 +WHITESPACE=44 +ONE_LINE_COMMENT=45 +OPEN_COMMENT=46 +COMMENT=47 +CLOSE_COMMENT=48 +'<-'=25 +'=>'=26 +'+'=27 +'-'=28 +'*'=29 +'/'=30 +'<'=31 +'<='=32 +'='=33 +'~'=34 +'('=35 +')'=36 +'{'=37 +'}'=38 +'@'=39 +'.'=40 +','=41 +':'=42 +';'=43 +'(*'=46 +'*)'=48 diff --git a/COOLCompiler.py b/COOLCompiler.py new file mode 100644 index 00000000..5a9b2584 --- /dev/null +++ b/COOLCompiler.py @@ -0,0 +1,36 @@ +import sys +import os.path +from antlr4 import * +from COOLLexer import COOLLexer +from COOLLexerErrorListener import COOLLexerErrorListener +from COOLParser import COOLParser +from COOLParserErrorListener import COOLParserErrorListener +from COOLListener import COOLListener + +def main(argv): + if not os.path.isfile(argv[1]): + print("invalid input filename") + return + + input = FileStream(argv[1]) + + lexer = COOLLexer(input) + lexer.removeErrorListeners() + lexer.addErrorListener(COOLLexerErrorListener()) + token = lexer.nextToken() + while token.type != Token.EOF: + token = lexer.nextToken() + + if lexer.hasErrors: + return + + lexer.reset(); + stream = CommonTokenStream(lexer) + parser = COOLParser(stream) + parser.removeErrorListeners() + parser.addErrorListener(COOLParserErrorListener()) + + tree = parser.program() + +if __name__ == '__main__': + main(sys.argv) diff --git a/COOLLexer.py b/COOLLexer.py new file mode 100644 index 00000000..bcb2349c --- /dev/null +++ b/COOLLexer.py @@ -0,0 +1,34 @@ +import sys +from io import StringIO +from typing.io import TextIO +from antlr4 import * +from COOL_LEX import COOL_LEX +from antlr4.CommonTokenFactory import CommonTokenFactory +from antlr4.atn.LexerATNSimulator import LexerATNSimulator +from antlr4.InputStream import InputStream +from antlr4.Recognizer import Recognizer +from antlr4.Token import Token +from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException + +class COOLLexer(COOL_LEX): + def __init__(self, input=None, output:TextIO = sys.stdout): + super().__init__(input, output) + self._hasErrors = False + + def notifyListeners(self, e:LexerNoViableAltException): + self._hasErrors = True + + start = self._tokenStartCharIndex + stop = self._input.index + text = self._input.getText(start, stop) + msg = "'" + self.getErrorDisplay(text) + "'" + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, self._token, self._tokenStartLine, self._tokenStartColumn, msg, e) + + def reset(self): + super().reset() + self._hasErrors = False + + @property + def hasErrors(self): + return self._hasErrors \ No newline at end of file diff --git a/COOLLexerErrorListener.py b/COOLLexerErrorListener.py new file mode 100644 index 00000000..451cdba7 --- /dev/null +++ b/COOLLexerErrorListener.py @@ -0,0 +1,7 @@ +import sys +from antlr4 import * +from antlr4.error.ErrorListener import ErrorListener + +class COOLLexerErrorListener(ErrorListener): + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): + print("(" + str(line) + ", " + str(column+1) + ") - LexicographicError: " + msg, file=sys.stderr) \ No newline at end of file diff --git a/COOLListener.py b/COOLListener.py new file mode 100644 index 00000000..e5e5d915 --- /dev/null +++ b/COOLListener.py @@ -0,0 +1,289 @@ +# Generated from COOL.g4 by ANTLR 4.7.2 +from antlr4 import * +if __name__ is not None and "." in __name__: + from .COOL import COOL +else: + from COOL import COOL + +# This class defines a complete listener for a parse tree produced by COOL. +class COOLListener(ParseTreeListener): + + # Enter a parse tree produced by COOL#program. + def enterProgram(self, ctx:COOL.ProgramContext): + pass + + # Exit a parse tree produced by COOL#program. + def exitProgram(self, ctx:COOL.ProgramContext): + pass + + + # Enter a parse tree produced by COOL#classes. + def enterClasses(self, ctx:COOL.ClassesContext): + pass + + # Exit a parse tree produced by COOL#classes. + def exitClasses(self, ctx:COOL.ClassesContext): + pass + + + # Enter a parse tree produced by COOL#classDefine. + def enterClassDefine(self, ctx:COOL.ClassDefineContext): + pass + + # Exit a parse tree produced by COOL#classDefine. + def exitClassDefine(self, ctx:COOL.ClassDefineContext): + pass + + + # Enter a parse tree produced by COOL#method. + def enterMethod(self, ctx:COOL.MethodContext): + pass + + # Exit a parse tree produced by COOL#method. + def exitMethod(self, ctx:COOL.MethodContext): + pass + + + # Enter a parse tree produced by COOL#property. + def enterProperty(self, ctx:COOL.PropertyContext): + pass + + # Exit a parse tree produced by COOL#property. + def exitProperty(self, ctx:COOL.PropertyContext): + pass + + + # Enter a parse tree produced by COOL#formal. + def enterFormal(self, ctx:COOL.FormalContext): + pass + + # Exit a parse tree produced by COOL#formal. + def exitFormal(self, ctx:COOL.FormalContext): + pass + + + # Enter a parse tree produced by COOL#letIn. + def enterLetIn(self, ctx:COOL.LetInContext): + pass + + # Exit a parse tree produced by COOL#letIn. + def exitLetIn(self, ctx:COOL.LetInContext): + pass + + + # Enter a parse tree produced by COOL#minus. + def enterMinus(self, ctx:COOL.MinusContext): + pass + + # Exit a parse tree produced by COOL#minus. + def exitMinus(self, ctx:COOL.MinusContext): + pass + + + # Enter a parse tree produced by COOL#string. + def enterString(self, ctx:COOL.StringContext): + pass + + # Exit a parse tree produced by COOL#string. + def exitString(self, ctx:COOL.StringContext): + pass + + + # Enter a parse tree produced by COOL#isvoid. + def enterIsvoid(self, ctx:COOL.IsvoidContext): + pass + + # Exit a parse tree produced by COOL#isvoid. + def exitIsvoid(self, ctx:COOL.IsvoidContext): + pass + + + # Enter a parse tree produced by COOL#while. + def enterWhile(self, ctx:COOL.WhileContext): + pass + + # Exit a parse tree produced by COOL#while. + def exitWhile(self, ctx:COOL.WhileContext): + pass + + + # Enter a parse tree produced by COOL#division. + def enterDivision(self, ctx:COOL.DivisionContext): + pass + + # Exit a parse tree produced by COOL#division. + def exitDivision(self, ctx:COOL.DivisionContext): + pass + + + # Enter a parse tree produced by COOL#negative. + def enterNegative(self, ctx:COOL.NegativeContext): + pass + + # Exit a parse tree produced by COOL#negative. + def exitNegative(self, ctx:COOL.NegativeContext): + pass + + + # Enter a parse tree produced by COOL#boolNot. + def enterBoolNot(self, ctx:COOL.BoolNotContext): + pass + + # Exit a parse tree produced by COOL#boolNot. + def exitBoolNot(self, ctx:COOL.BoolNotContext): + pass + + + # Enter a parse tree produced by COOL#lessThan. + def enterLessThan(self, ctx:COOL.LessThanContext): + pass + + # Exit a parse tree produced by COOL#lessThan. + def exitLessThan(self, ctx:COOL.LessThanContext): + pass + + + # Enter a parse tree produced by COOL#block. + def enterBlock(self, ctx:COOL.BlockContext): + pass + + # Exit a parse tree produced by COOL#block. + def exitBlock(self, ctx:COOL.BlockContext): + pass + + + # Enter a parse tree produced by COOL#id. + def enterId(self, ctx:COOL.IdContext): + pass + + # Exit a parse tree produced by COOL#id. + def exitId(self, ctx:COOL.IdContext): + pass + + + # Enter a parse tree produced by COOL#multiply. + def enterMultiply(self, ctx:COOL.MultiplyContext): + pass + + # Exit a parse tree produced by COOL#multiply. + def exitMultiply(self, ctx:COOL.MultiplyContext): + pass + + + # Enter a parse tree produced by COOL#if. + def enterIf(self, ctx:COOL.IfContext): + pass + + # Exit a parse tree produced by COOL#if. + def exitIf(self, ctx:COOL.IfContext): + pass + + + # Enter a parse tree produced by COOL#case. + def enterCase(self, ctx:COOL.CaseContext): + pass + + # Exit a parse tree produced by COOL#case. + def exitCase(self, ctx:COOL.CaseContext): + pass + + + # Enter a parse tree produced by COOL#ownMethodCall. + def enterOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): + pass + + # Exit a parse tree produced by COOL#ownMethodCall. + def exitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): + pass + + + # Enter a parse tree produced by COOL#add. + def enterAdd(self, ctx:COOL.AddContext): + pass + + # Exit a parse tree produced by COOL#add. + def exitAdd(self, ctx:COOL.AddContext): + pass + + + # Enter a parse tree produced by COOL#new. + def enterNew(self, ctx:COOL.NewContext): + pass + + # Exit a parse tree produced by COOL#new. + def exitNew(self, ctx:COOL.NewContext): + pass + + + # Enter a parse tree produced by COOL#parentheses. + def enterParentheses(self, ctx:COOL.ParenthesesContext): + pass + + # Exit a parse tree produced by COOL#parentheses. + def exitParentheses(self, ctx:COOL.ParenthesesContext): + pass + + + # Enter a parse tree produced by COOL#assignment. + def enterAssignment(self, ctx:COOL.AssignmentContext): + pass + + # Exit a parse tree produced by COOL#assignment. + def exitAssignment(self, ctx:COOL.AssignmentContext): + pass + + + # Enter a parse tree produced by COOL#false. + def enterFalse(self, ctx:COOL.FalseContext): + pass + + # Exit a parse tree produced by COOL#false. + def exitFalse(self, ctx:COOL.FalseContext): + pass + + + # Enter a parse tree produced by COOL#int. + def enterInt(self, ctx:COOL.IntContext): + pass + + # Exit a parse tree produced by COOL#int. + def exitInt(self, ctx:COOL.IntContext): + pass + + + # Enter a parse tree produced by COOL#equal. + def enterEqual(self, ctx:COOL.EqualContext): + pass + + # Exit a parse tree produced by COOL#equal. + def exitEqual(self, ctx:COOL.EqualContext): + pass + + + # Enter a parse tree produced by COOL#true. + def enterTrue(self, ctx:COOL.TrueContext): + pass + + # Exit a parse tree produced by COOL#true. + def exitTrue(self, ctx:COOL.TrueContext): + pass + + + # Enter a parse tree produced by COOL#lessEqual. + def enterLessEqual(self, ctx:COOL.LessEqualContext): + pass + + # Exit a parse tree produced by COOL#lessEqual. + def exitLessEqual(self, ctx:COOL.LessEqualContext): + pass + + + # Enter a parse tree produced by COOL#methodCall. + def enterMethodCall(self, ctx:COOL.MethodCallContext): + pass + + # Exit a parse tree produced by COOL#methodCall. + def exitMethodCall(self, ctx:COOL.MethodCallContext): + pass + + diff --git a/COOLParser.py b/COOLParser.py new file mode 100644 index 00000000..7f3ad8ac --- /dev/null +++ b/COOLParser.py @@ -0,0 +1,24 @@ +import sys +from io import StringIO +from typing.io import TextIO +from antlr4 import * +from COOL import COOL +from antlr4.CommonTokenFactory import CommonTokenFactory +from antlr4.atn.LexerATNSimulator import LexerATNSimulator +from antlr4.InputStream import InputStream +from antlr4.Recognizer import Recognizer +from antlr4.Token import Token +from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException + +class COOLParser(COOL): + def __init__(self, input=None, output:TextIO = sys.stdout): + super().__init__(input, output) + + def notifyErrorListeners(self, msg:str, offendingToken:Token = None, e:RecognitionException = None): + if offendingToken is None: + offendingToken = self.getCurrentToken() + self._syntaxErrors += 1 + line = offendingToken.line + column = offendingToken.column + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, offendingToken, line, column, msg, e) \ No newline at end of file diff --git a/COOLParserErrorListener.py b/COOLParserErrorListener.py new file mode 100644 index 00000000..5bae5069 --- /dev/null +++ b/COOLParserErrorListener.py @@ -0,0 +1,12 @@ +import sys +from antlr4 import * +from antlr4.error.ErrorListener import ErrorListener + +class COOLParserErrorListener(ErrorListener): + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): + msg = offendingSymbol.text + if msg == "": + msg = "EOF" + else: + msg = "\"" + msg + "\"" + print("(" + str(line) + ", " + str(column+1) + ") - SyntacticError: ERROR at or near " +msg, file=sys.stderr) \ No newline at end of file diff --git a/COOL_LEX.interp b/COOL_LEX.interp new file mode 100644 index 00000000..5e362562 --- /dev/null +++ b/COOL_LEX.interp @@ -0,0 +1,182 @@ +token literal names: +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +'<-' +'=>' +'+' +'-' +'*' +'/' +'<' +'<=' +'=' +'~' +'(' +')' +'{' +'}' +'@' +'.' +',' +':' +';' +null +null +'(*' +null +'*)' + +token symbolic names: +null +CLASS +ELSE +FALSE +FI +IF +IN +INHERITS +ISVOID +LET +LOOP +POOL +THEN +WHILE +CASE +ESAC +NEW +OF +NOT +TRUE +STRING +BREAK_STRING +INT +TYPEID +OBJECTID +ASSIGNMENT +CASE_ARROW +ADD +MINUS +MULTIPLY +DIVISION +LESS_THAN +LESS_EQUAL +EQUAL +INTEGER_NEGATIVE +OPEN_ROUND +CLOSE_ROUND +OPEN_CURLY +CLOSE_CURLY +AT +DOT +COMMA +COLON +SEMICOLON +WHITESPACE +ONE_LINE_COMMENT +OPEN_COMMENT +COMMENT +CLOSE_COMMENT + +rule names: +CLASS +ELSE +FALSE +FI +IF +IN +INHERITS +ISVOID +LET +LOOP +POOL +THEN +WHILE +CASE +ESAC +NEW +OF +NOT +TRUE +STRING +BREAK_STRING +INT +TYPEID +OBJECTID +ASSIGNMENT +CASE_ARROW +ADD +MINUS +MULTIPLY +DIVISION +LESS_THAN +LESS_EQUAL +EQUAL +INTEGER_NEGATIVE +OPEN_ROUND +CLOSE_ROUND +OPEN_CURLY +CLOSE_CURLY +AT +DOT +COMMA +COLON +SEMICOLON +A +C +D +E +F +H +I +L +N +O +P +R +S +T +U +V +W +ESC +UNICODE +HEX +WHITESPACE +ONE_LINE_COMMENT +OPEN_COMMENT +COMMENT +CLOSE_COMMENT + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN + +mode names: +DEFAULT_MODE +MULTILINE_COMMENT + +atn: +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 50, 406, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 7, 21, 238, 10, 21, 12, 21, 14, 21, 241, 11, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 5, 22, 252, 10, 22, 3, 23, 6, 23, 255, 10, 23, 13, 23, 14, 23, 256, 3, 24, 3, 24, 7, 24, 261, 10, 24, 12, 24, 14, 24, 264, 11, 24, 3, 25, 3, 25, 7, 25, 268, 10, 25, 12, 25, 14, 25, 271, 11, 25, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 62, 5, 62, 351, 10, 62, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 6, 65, 362, 10, 65, 13, 65, 14, 65, 363, 3, 65, 3, 65, 3, 66, 3, 66, 3, 66, 3, 66, 7, 66, 372, 10, 66, 12, 66, 14, 66, 375, 11, 66, 3, 66, 5, 66, 378, 10, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 6, 68, 393, 10, 68, 13, 68, 14, 68, 394, 5, 68, 397, 10, 68, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 394, 2, 70, 4, 3, 6, 4, 8, 5, 10, 6, 12, 7, 14, 8, 16, 9, 18, 10, 20, 11, 22, 12, 24, 13, 26, 14, 28, 15, 30, 16, 32, 17, 34, 18, 36, 19, 38, 20, 40, 21, 42, 22, 44, 23, 46, 24, 48, 25, 50, 26, 52, 27, 54, 28, 56, 29, 58, 30, 60, 31, 62, 32, 64, 33, 66, 34, 68, 35, 70, 36, 72, 37, 74, 38, 76, 39, 78, 40, 80, 41, 82, 42, 84, 43, 86, 44, 88, 45, 90, 2, 92, 2, 94, 2, 96, 2, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 46, 132, 47, 134, 48, 136, 49, 138, 50, 4, 2, 3, 28, 6, 2, 12, 12, 15, 15, 36, 36, 94, 94, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 398, 2, 4, 3, 2, 2, 2, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 50, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 130, 3, 2, 2, 2, 2, 132, 3, 2, 2, 2, 2, 134, 3, 2, 2, 2, 3, 136, 3, 2, 2, 2, 3, 138, 3, 2, 2, 2, 4, 140, 3, 2, 2, 2, 6, 146, 3, 2, 2, 2, 8, 151, 3, 2, 2, 2, 10, 157, 3, 2, 2, 2, 12, 160, 3, 2, 2, 2, 14, 163, 3, 2, 2, 2, 16, 166, 3, 2, 2, 2, 18, 175, 3, 2, 2, 2, 20, 182, 3, 2, 2, 2, 22, 186, 3, 2, 2, 2, 24, 191, 3, 2, 2, 2, 26, 196, 3, 2, 2, 2, 28, 201, 3, 2, 2, 2, 30, 207, 3, 2, 2, 2, 32, 212, 3, 2, 2, 2, 34, 217, 3, 2, 2, 2, 36, 221, 3, 2, 2, 2, 38, 224, 3, 2, 2, 2, 40, 228, 3, 2, 2, 2, 42, 233, 3, 2, 2, 2, 44, 251, 3, 2, 2, 2, 46, 254, 3, 2, 2, 2, 48, 258, 3, 2, 2, 2, 50, 265, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 275, 3, 2, 2, 2, 56, 278, 3, 2, 2, 2, 58, 280, 3, 2, 2, 2, 60, 282, 3, 2, 2, 2, 62, 284, 3, 2, 2, 2, 64, 286, 3, 2, 2, 2, 66, 288, 3, 2, 2, 2, 68, 291, 3, 2, 2, 2, 70, 293, 3, 2, 2, 2, 72, 295, 3, 2, 2, 2, 74, 297, 3, 2, 2, 2, 76, 299, 3, 2, 2, 2, 78, 301, 3, 2, 2, 2, 80, 303, 3, 2, 2, 2, 82, 305, 3, 2, 2, 2, 84, 307, 3, 2, 2, 2, 86, 309, 3, 2, 2, 2, 88, 311, 3, 2, 2, 2, 90, 313, 3, 2, 2, 2, 92, 315, 3, 2, 2, 2, 94, 317, 3, 2, 2, 2, 96, 319, 3, 2, 2, 2, 98, 321, 3, 2, 2, 2, 100, 323, 3, 2, 2, 2, 102, 325, 3, 2, 2, 2, 104, 327, 3, 2, 2, 2, 106, 329, 3, 2, 2, 2, 108, 331, 3, 2, 2, 2, 110, 333, 3, 2, 2, 2, 112, 335, 3, 2, 2, 2, 114, 337, 3, 2, 2, 2, 116, 339, 3, 2, 2, 2, 118, 341, 3, 2, 2, 2, 120, 343, 3, 2, 2, 2, 122, 345, 3, 2, 2, 2, 124, 347, 3, 2, 2, 2, 126, 352, 3, 2, 2, 2, 128, 358, 3, 2, 2, 2, 130, 361, 3, 2, 2, 2, 132, 367, 3, 2, 2, 2, 134, 381, 3, 2, 2, 2, 136, 396, 3, 2, 2, 2, 138, 400, 3, 2, 2, 2, 140, 141, 5, 92, 46, 2, 141, 142, 5, 104, 52, 2, 142, 143, 5, 90, 45, 2, 143, 144, 5, 114, 57, 2, 144, 145, 5, 114, 57, 2, 145, 5, 3, 2, 2, 2, 146, 147, 5, 96, 48, 2, 147, 148, 5, 104, 52, 2, 148, 149, 5, 114, 57, 2, 149, 150, 5, 96, 48, 2, 150, 7, 3, 2, 2, 2, 151, 152, 7, 104, 2, 2, 152, 153, 5, 90, 45, 2, 153, 154, 5, 104, 52, 2, 154, 155, 5, 114, 57, 2, 155, 156, 5, 96, 48, 2, 156, 9, 3, 2, 2, 2, 157, 158, 5, 98, 49, 2, 158, 159, 5, 102, 51, 2, 159, 11, 3, 2, 2, 2, 160, 161, 5, 102, 51, 2, 161, 162, 5, 98, 49, 2, 162, 13, 3, 2, 2, 2, 163, 164, 5, 102, 51, 2, 164, 165, 5, 106, 53, 2, 165, 15, 3, 2, 2, 2, 166, 167, 5, 102, 51, 2, 167, 168, 5, 106, 53, 2, 168, 169, 5, 100, 50, 2, 169, 170, 5, 96, 48, 2, 170, 171, 5, 112, 56, 2, 171, 172, 5, 102, 51, 2, 172, 173, 5, 116, 58, 2, 173, 174, 5, 114, 57, 2, 174, 17, 3, 2, 2, 2, 175, 176, 5, 102, 51, 2, 176, 177, 5, 114, 57, 2, 177, 178, 5, 120, 60, 2, 178, 179, 5, 108, 54, 2, 179, 180, 5, 102, 51, 2, 180, 181, 5, 94, 47, 2, 181, 19, 3, 2, 2, 2, 182, 183, 5, 104, 52, 2, 183, 184, 5, 96, 48, 2, 184, 185, 5, 116, 58, 2, 185, 21, 3, 2, 2, 2, 186, 187, 5, 104, 52, 2, 187, 188, 5, 108, 54, 2, 188, 189, 5, 108, 54, 2, 189, 190, 5, 110, 55, 2, 190, 23, 3, 2, 2, 2, 191, 192, 5, 110, 55, 2, 192, 193, 5, 108, 54, 2, 193, 194, 5, 108, 54, 2, 194, 195, 5, 104, 52, 2, 195, 25, 3, 2, 2, 2, 196, 197, 5, 116, 58, 2, 197, 198, 5, 100, 50, 2, 198, 199, 5, 96, 48, 2, 199, 200, 5, 106, 53, 2, 200, 27, 3, 2, 2, 2, 201, 202, 5, 122, 61, 2, 202, 203, 5, 100, 50, 2, 203, 204, 5, 102, 51, 2, 204, 205, 5, 104, 52, 2, 205, 206, 5, 96, 48, 2, 206, 29, 3, 2, 2, 2, 207, 208, 5, 92, 46, 2, 208, 209, 5, 90, 45, 2, 209, 210, 5, 114, 57, 2, 210, 211, 5, 96, 48, 2, 211, 31, 3, 2, 2, 2, 212, 213, 5, 96, 48, 2, 213, 214, 5, 114, 57, 2, 214, 215, 5, 90, 45, 2, 215, 216, 5, 92, 46, 2, 216, 33, 3, 2, 2, 2, 217, 218, 5, 106, 53, 2, 218, 219, 5, 96, 48, 2, 219, 220, 5, 122, 61, 2, 220, 35, 3, 2, 2, 2, 221, 222, 5, 108, 54, 2, 222, 223, 5, 98, 49, 2, 223, 37, 3, 2, 2, 2, 224, 225, 5, 106, 53, 2, 225, 226, 5, 108, 54, 2, 226, 227, 5, 116, 58, 2, 227, 39, 3, 2, 2, 2, 228, 229, 7, 118, 2, 2, 229, 230, 5, 112, 56, 2, 230, 231, 5, 118, 59, 2, 231, 232, 5, 96, 48, 2, 232, 41, 3, 2, 2, 2, 233, 239, 7, 36, 2, 2, 234, 238, 5, 124, 62, 2, 235, 238, 5, 44, 22, 2, 236, 238, 10, 2, 2, 2, 237, 234, 3, 2, 2, 2, 237, 235, 3, 2, 2, 2, 237, 236, 3, 2, 2, 2, 238, 241, 3, 2, 2, 2, 239, 237, 3, 2, 2, 2, 239, 240, 3, 2, 2, 2, 240, 242, 3, 2, 2, 2, 241, 239, 3, 2, 2, 2, 242, 243, 7, 36, 2, 2, 243, 43, 3, 2, 2, 2, 244, 245, 7, 94, 2, 2, 245, 246, 7, 15, 2, 2, 246, 252, 7, 12, 2, 2, 247, 248, 7, 94, 2, 2, 248, 252, 7, 15, 2, 2, 249, 250, 7, 94, 2, 2, 250, 252, 7, 12, 2, 2, 251, 244, 3, 2, 2, 2, 251, 247, 3, 2, 2, 2, 251, 249, 3, 2, 2, 2, 252, 45, 3, 2, 2, 2, 253, 255, 9, 3, 2, 2, 254, 253, 3, 2, 2, 2, 255, 256, 3, 2, 2, 2, 256, 254, 3, 2, 2, 2, 256, 257, 3, 2, 2, 2, 257, 47, 3, 2, 2, 2, 258, 262, 9, 4, 2, 2, 259, 261, 9, 5, 2, 2, 260, 259, 3, 2, 2, 2, 261, 264, 3, 2, 2, 2, 262, 260, 3, 2, 2, 2, 262, 263, 3, 2, 2, 2, 263, 49, 3, 2, 2, 2, 264, 262, 3, 2, 2, 2, 265, 269, 9, 6, 2, 2, 266, 268, 9, 5, 2, 2, 267, 266, 3, 2, 2, 2, 268, 271, 3, 2, 2, 2, 269, 267, 3, 2, 2, 2, 269, 270, 3, 2, 2, 2, 270, 51, 3, 2, 2, 2, 271, 269, 3, 2, 2, 2, 272, 273, 7, 62, 2, 2, 273, 274, 7, 47, 2, 2, 274, 53, 3, 2, 2, 2, 275, 276, 7, 63, 2, 2, 276, 277, 7, 64, 2, 2, 277, 55, 3, 2, 2, 2, 278, 279, 7, 45, 2, 2, 279, 57, 3, 2, 2, 2, 280, 281, 7, 47, 2, 2, 281, 59, 3, 2, 2, 2, 282, 283, 7, 44, 2, 2, 283, 61, 3, 2, 2, 2, 284, 285, 7, 49, 2, 2, 285, 63, 3, 2, 2, 2, 286, 287, 7, 62, 2, 2, 287, 65, 3, 2, 2, 2, 288, 289, 7, 62, 2, 2, 289, 290, 7, 63, 2, 2, 290, 67, 3, 2, 2, 2, 291, 292, 7, 63, 2, 2, 292, 69, 3, 2, 2, 2, 293, 294, 7, 128, 2, 2, 294, 71, 3, 2, 2, 2, 295, 296, 7, 42, 2, 2, 296, 73, 3, 2, 2, 2, 297, 298, 7, 43, 2, 2, 298, 75, 3, 2, 2, 2, 299, 300, 7, 125, 2, 2, 300, 77, 3, 2, 2, 2, 301, 302, 7, 127, 2, 2, 302, 79, 3, 2, 2, 2, 303, 304, 7, 66, 2, 2, 304, 81, 3, 2, 2, 2, 305, 306, 7, 48, 2, 2, 306, 83, 3, 2, 2, 2, 307, 308, 7, 46, 2, 2, 308, 85, 3, 2, 2, 2, 309, 310, 7, 60, 2, 2, 310, 87, 3, 2, 2, 2, 311, 312, 7, 61, 2, 2, 312, 89, 3, 2, 2, 2, 313, 314, 9, 7, 2, 2, 314, 91, 3, 2, 2, 2, 315, 316, 9, 8, 2, 2, 316, 93, 3, 2, 2, 2, 317, 318, 9, 9, 2, 2, 318, 95, 3, 2, 2, 2, 319, 320, 9, 10, 2, 2, 320, 97, 3, 2, 2, 2, 321, 322, 9, 11, 2, 2, 322, 99, 3, 2, 2, 2, 323, 324, 9, 12, 2, 2, 324, 101, 3, 2, 2, 2, 325, 326, 9, 13, 2, 2, 326, 103, 3, 2, 2, 2, 327, 328, 9, 14, 2, 2, 328, 105, 3, 2, 2, 2, 329, 330, 9, 15, 2, 2, 330, 107, 3, 2, 2, 2, 331, 332, 9, 16, 2, 2, 332, 109, 3, 2, 2, 2, 333, 334, 9, 17, 2, 2, 334, 111, 3, 2, 2, 2, 335, 336, 9, 18, 2, 2, 336, 113, 3, 2, 2, 2, 337, 338, 9, 19, 2, 2, 338, 115, 3, 2, 2, 2, 339, 340, 9, 20, 2, 2, 340, 117, 3, 2, 2, 2, 341, 342, 9, 21, 2, 2, 342, 119, 3, 2, 2, 2, 343, 344, 9, 22, 2, 2, 344, 121, 3, 2, 2, 2, 345, 346, 9, 23, 2, 2, 346, 123, 3, 2, 2, 2, 347, 350, 7, 94, 2, 2, 348, 351, 9, 24, 2, 2, 349, 351, 5, 126, 63, 2, 350, 348, 3, 2, 2, 2, 350, 349, 3, 2, 2, 2, 351, 125, 3, 2, 2, 2, 352, 353, 7, 119, 2, 2, 353, 354, 5, 128, 64, 2, 354, 355, 5, 128, 64, 2, 355, 356, 5, 128, 64, 2, 356, 357, 5, 128, 64, 2, 357, 127, 3, 2, 2, 2, 358, 359, 9, 25, 2, 2, 359, 129, 3, 2, 2, 2, 360, 362, 9, 26, 2, 2, 361, 360, 3, 2, 2, 2, 362, 363, 3, 2, 2, 2, 363, 361, 3, 2, 2, 2, 363, 364, 3, 2, 2, 2, 364, 365, 3, 2, 2, 2, 365, 366, 8, 65, 2, 2, 366, 131, 3, 2, 2, 2, 367, 368, 7, 47, 2, 2, 368, 369, 7, 47, 2, 2, 369, 373, 3, 2, 2, 2, 370, 372, 10, 27, 2, 2, 371, 370, 3, 2, 2, 2, 372, 375, 3, 2, 2, 2, 373, 371, 3, 2, 2, 2, 373, 374, 3, 2, 2, 2, 374, 377, 3, 2, 2, 2, 375, 373, 3, 2, 2, 2, 376, 378, 7, 12, 2, 2, 377, 376, 3, 2, 2, 2, 377, 378, 3, 2, 2, 2, 378, 379, 3, 2, 2, 2, 379, 380, 8, 66, 2, 2, 380, 133, 3, 2, 2, 2, 381, 382, 7, 42, 2, 2, 382, 383, 7, 44, 2, 2, 383, 384, 3, 2, 2, 2, 384, 385, 8, 67, 2, 2, 385, 386, 8, 67, 3, 2, 386, 135, 3, 2, 2, 2, 387, 388, 5, 134, 67, 2, 388, 389, 5, 136, 68, 2, 389, 390, 5, 138, 69, 2, 390, 397, 3, 2, 2, 2, 391, 393, 11, 2, 2, 2, 392, 391, 3, 2, 2, 2, 393, 394, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 394, 392, 3, 2, 2, 2, 395, 397, 3, 2, 2, 2, 396, 387, 3, 2, 2, 2, 396, 392, 3, 2, 2, 2, 397, 398, 3, 2, 2, 2, 398, 399, 8, 68, 2, 2, 399, 137, 3, 2, 2, 2, 400, 401, 7, 44, 2, 2, 401, 402, 7, 43, 2, 2, 402, 403, 3, 2, 2, 2, 403, 404, 8, 69, 2, 2, 404, 405, 8, 69, 4, 2, 405, 139, 3, 2, 2, 2, 16, 2, 3, 237, 239, 251, 256, 262, 269, 350, 363, 373, 377, 394, 396, 5, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file diff --git a/COOL_LEX.py b/COOL_LEX.py new file mode 100644 index 00000000..b5bb708c --- /dev/null +++ b/COOL_LEX.py @@ -0,0 +1,284 @@ +# Generated from COOL_LEX.g4 by ANTLR 4.7.2 +from antlr4 import * +from io import StringIO +from typing.io import TextIO +import sys + + + +def serializedATN(): + with StringIO() as buf: + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\62") + buf.write("\u0196\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6") + buf.write("\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r") + buf.write("\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22") + buf.write("\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30") + buf.write("\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35") + buf.write("\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\4") + buf.write("%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t,\4-\t") + buf.write("-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63") + buf.write("\4\64\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4") + buf.write(":\t:\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4") + buf.write("C\tC\4D\tD\4E\tE\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3") + buf.write("\3\3\3\3\4\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\6\3\6\3\6") + buf.write("\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3") + buf.write("\t\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\13") + buf.write("\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\16") + buf.write("\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20") + buf.write("\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\22\3\22\3\22") + buf.write("\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\25\3\25") + buf.write("\3\25\3\25\7\25\u00ee\n\25\f\25\16\25\u00f1\13\25\3\25") + buf.write("\3\25\3\26\3\26\3\26\3\26\3\26\3\26\3\26\5\26\u00fc\n") + buf.write("\26\3\27\6\27\u00ff\n\27\r\27\16\27\u0100\3\30\3\30\7") + buf.write("\30\u0105\n\30\f\30\16\30\u0108\13\30\3\31\3\31\7\31\u010c") + buf.write("\n\31\f\31\16\31\u010f\13\31\3\32\3\32\3\32\3\33\3\33") + buf.write("\3\33\3\34\3\34\3\35\3\35\3\36\3\36\3\37\3\37\3 \3 \3") + buf.write("!\3!\3!\3\"\3\"\3#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(") + buf.write("\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3\60\3") + buf.write("\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65\3\66") + buf.write("\3\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<\3<\3=\3=\3") + buf.write(">\3>\3>\5>\u015f\n>\3?\3?\3?\3?\3?\3?\3@\3@\3A\6A\u016a") + buf.write("\nA\rA\16A\u016b\3A\3A\3B\3B\3B\3B\7B\u0174\nB\fB\16B") + buf.write("\u0177\13B\3B\5B\u017a\nB\3B\3B\3C\3C\3C\3C\3C\3C\3D\3") + buf.write("D\3D\3D\3D\6D\u0189\nD\rD\16D\u018a\5D\u018d\nD\3D\3D") + buf.write("\3E\3E\3E\3E\3E\3E\3\u018a\2F\4\3\6\4\b\5\n\6\f\7\16\b") + buf.write("\20\t\22\n\24\13\26\f\30\r\32\16\34\17\36\20 \21\"\22") + buf.write("$\23&\24(\25*\26,\27.\30\60\31\62\32\64\33\66\348\35:") + buf.write("\36<\37> @!B\"D#F$H%J&L\'N(P)R*T+V,X-Z\2\\\2^\2`\2b\2") + buf.write("d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2|\2~\2\u0080\2\u0082") + buf.write(".\u0084/\u0086\60\u0088\61\u008a\62\4\2\3\34\6\2\f\f\17") + buf.write("\17$$^^\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4") + buf.write("\2EEee\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNn") + buf.write("n\4\2PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2") + buf.write("WWww\4\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;C") + buf.write("Hch\5\2\13\f\16\17\"\"\3\2\f\f\2\u018e\2\4\3\2\2\2\2\6") + buf.write("\3\2\2\2\2\b\3\2\2\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16\3\2") + buf.write("\2\2\2\20\3\2\2\2\2\22\3\2\2\2\2\24\3\2\2\2\2\26\3\2\2") + buf.write("\2\2\30\3\2\2\2\2\32\3\2\2\2\2\34\3\2\2\2\2\36\3\2\2\2") + buf.write("\2 \3\2\2\2\2\"\3\2\2\2\2$\3\2\2\2\2&\3\2\2\2\2(\3\2\2") + buf.write("\2\2*\3\2\2\2\2,\3\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2\62") + buf.write("\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\28\3\2\2\2\2:\3\2\2") + buf.write("\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2\2\2\2B\3\2\2\2\2D\3\2") + buf.write("\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3\2\2\2\2L\3\2\2\2\2N\3") + buf.write("\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2\2\2\2V\3\2\2\2\2X") + buf.write("\3\2\2\2\2\u0082\3\2\2\2\2\u0084\3\2\2\2\2\u0086\3\2\2") + buf.write("\2\3\u0088\3\2\2\2\3\u008a\3\2\2\2\4\u008c\3\2\2\2\6\u0092") + buf.write("\3\2\2\2\b\u0097\3\2\2\2\n\u009d\3\2\2\2\f\u00a0\3\2\2") + buf.write("\2\16\u00a3\3\2\2\2\20\u00a6\3\2\2\2\22\u00af\3\2\2\2") + buf.write("\24\u00b6\3\2\2\2\26\u00ba\3\2\2\2\30\u00bf\3\2\2\2\32") + buf.write("\u00c4\3\2\2\2\34\u00c9\3\2\2\2\36\u00cf\3\2\2\2 \u00d4") + buf.write("\3\2\2\2\"\u00d9\3\2\2\2$\u00dd\3\2\2\2&\u00e0\3\2\2\2") + buf.write("(\u00e4\3\2\2\2*\u00e9\3\2\2\2,\u00fb\3\2\2\2.\u00fe\3") + buf.write("\2\2\2\60\u0102\3\2\2\2\62\u0109\3\2\2\2\64\u0110\3\2") + buf.write("\2\2\66\u0113\3\2\2\28\u0116\3\2\2\2:\u0118\3\2\2\2<\u011a") + buf.write("\3\2\2\2>\u011c\3\2\2\2@\u011e\3\2\2\2B\u0120\3\2\2\2") + buf.write("D\u0123\3\2\2\2F\u0125\3\2\2\2H\u0127\3\2\2\2J\u0129\3") + buf.write("\2\2\2L\u012b\3\2\2\2N\u012d\3\2\2\2P\u012f\3\2\2\2R\u0131") + buf.write("\3\2\2\2T\u0133\3\2\2\2V\u0135\3\2\2\2X\u0137\3\2\2\2") + buf.write("Z\u0139\3\2\2\2\\\u013b\3\2\2\2^\u013d\3\2\2\2`\u013f") + buf.write("\3\2\2\2b\u0141\3\2\2\2d\u0143\3\2\2\2f\u0145\3\2\2\2") + buf.write("h\u0147\3\2\2\2j\u0149\3\2\2\2l\u014b\3\2\2\2n\u014d\3") + buf.write("\2\2\2p\u014f\3\2\2\2r\u0151\3\2\2\2t\u0153\3\2\2\2v\u0155") + buf.write("\3\2\2\2x\u0157\3\2\2\2z\u0159\3\2\2\2|\u015b\3\2\2\2") + buf.write("~\u0160\3\2\2\2\u0080\u0166\3\2\2\2\u0082\u0169\3\2\2") + buf.write("\2\u0084\u016f\3\2\2\2\u0086\u017d\3\2\2\2\u0088\u018c") + buf.write("\3\2\2\2\u008a\u0190\3\2\2\2\u008c\u008d\5\\.\2\u008d") + buf.write("\u008e\5h\64\2\u008e\u008f\5Z-\2\u008f\u0090\5r9\2\u0090") + buf.write("\u0091\5r9\2\u0091\5\3\2\2\2\u0092\u0093\5`\60\2\u0093") + buf.write("\u0094\5h\64\2\u0094\u0095\5r9\2\u0095\u0096\5`\60\2\u0096") + buf.write("\7\3\2\2\2\u0097\u0098\7h\2\2\u0098\u0099\5Z-\2\u0099") + buf.write("\u009a\5h\64\2\u009a\u009b\5r9\2\u009b\u009c\5`\60\2\u009c") + buf.write("\t\3\2\2\2\u009d\u009e\5b\61\2\u009e\u009f\5f\63\2\u009f") + buf.write("\13\3\2\2\2\u00a0\u00a1\5f\63\2\u00a1\u00a2\5b\61\2\u00a2") + buf.write("\r\3\2\2\2\u00a3\u00a4\5f\63\2\u00a4\u00a5\5j\65\2\u00a5") + buf.write("\17\3\2\2\2\u00a6\u00a7\5f\63\2\u00a7\u00a8\5j\65\2\u00a8") + buf.write("\u00a9\5d\62\2\u00a9\u00aa\5`\60\2\u00aa\u00ab\5p8\2\u00ab") + buf.write("\u00ac\5f\63\2\u00ac\u00ad\5t:\2\u00ad\u00ae\5r9\2\u00ae") + buf.write("\21\3\2\2\2\u00af\u00b0\5f\63\2\u00b0\u00b1\5r9\2\u00b1") + buf.write("\u00b2\5x<\2\u00b2\u00b3\5l\66\2\u00b3\u00b4\5f\63\2\u00b4") + buf.write("\u00b5\5^/\2\u00b5\23\3\2\2\2\u00b6\u00b7\5h\64\2\u00b7") + buf.write("\u00b8\5`\60\2\u00b8\u00b9\5t:\2\u00b9\25\3\2\2\2\u00ba") + buf.write("\u00bb\5h\64\2\u00bb\u00bc\5l\66\2\u00bc\u00bd\5l\66\2") + buf.write("\u00bd\u00be\5n\67\2\u00be\27\3\2\2\2\u00bf\u00c0\5n\67") + buf.write("\2\u00c0\u00c1\5l\66\2\u00c1\u00c2\5l\66\2\u00c2\u00c3") + buf.write("\5h\64\2\u00c3\31\3\2\2\2\u00c4\u00c5\5t:\2\u00c5\u00c6") + buf.write("\5d\62\2\u00c6\u00c7\5`\60\2\u00c7\u00c8\5j\65\2\u00c8") + buf.write("\33\3\2\2\2\u00c9\u00ca\5z=\2\u00ca\u00cb\5d\62\2\u00cb") + buf.write("\u00cc\5f\63\2\u00cc\u00cd\5h\64\2\u00cd\u00ce\5`\60\2") + buf.write("\u00ce\35\3\2\2\2\u00cf\u00d0\5\\.\2\u00d0\u00d1\5Z-\2") + buf.write("\u00d1\u00d2\5r9\2\u00d2\u00d3\5`\60\2\u00d3\37\3\2\2") + buf.write("\2\u00d4\u00d5\5`\60\2\u00d5\u00d6\5r9\2\u00d6\u00d7\5") + buf.write("Z-\2\u00d7\u00d8\5\\.\2\u00d8!\3\2\2\2\u00d9\u00da\5j") + buf.write("\65\2\u00da\u00db\5`\60\2\u00db\u00dc\5z=\2\u00dc#\3\2") + buf.write("\2\2\u00dd\u00de\5l\66\2\u00de\u00df\5b\61\2\u00df%\3") + buf.write("\2\2\2\u00e0\u00e1\5j\65\2\u00e1\u00e2\5l\66\2\u00e2\u00e3") + buf.write("\5t:\2\u00e3\'\3\2\2\2\u00e4\u00e5\7v\2\2\u00e5\u00e6") + buf.write("\5p8\2\u00e6\u00e7\5v;\2\u00e7\u00e8\5`\60\2\u00e8)\3") + buf.write("\2\2\2\u00e9\u00ef\7$\2\2\u00ea\u00ee\5|>\2\u00eb\u00ee") + buf.write("\5,\26\2\u00ec\u00ee\n\2\2\2\u00ed\u00ea\3\2\2\2\u00ed") + buf.write("\u00eb\3\2\2\2\u00ed\u00ec\3\2\2\2\u00ee\u00f1\3\2\2\2") + buf.write("\u00ef\u00ed\3\2\2\2\u00ef\u00f0\3\2\2\2\u00f0\u00f2\3") + buf.write("\2\2\2\u00f1\u00ef\3\2\2\2\u00f2\u00f3\7$\2\2\u00f3+\3") + buf.write("\2\2\2\u00f4\u00f5\7^\2\2\u00f5\u00f6\7\17\2\2\u00f6\u00fc") + buf.write("\7\f\2\2\u00f7\u00f8\7^\2\2\u00f8\u00fc\7\17\2\2\u00f9") + buf.write("\u00fa\7^\2\2\u00fa\u00fc\7\f\2\2\u00fb\u00f4\3\2\2\2") + buf.write("\u00fb\u00f7\3\2\2\2\u00fb\u00f9\3\2\2\2\u00fc-\3\2\2") + buf.write("\2\u00fd\u00ff\t\3\2\2\u00fe\u00fd\3\2\2\2\u00ff\u0100") + buf.write("\3\2\2\2\u0100\u00fe\3\2\2\2\u0100\u0101\3\2\2\2\u0101") + buf.write("/\3\2\2\2\u0102\u0106\t\4\2\2\u0103\u0105\t\5\2\2\u0104") + buf.write("\u0103\3\2\2\2\u0105\u0108\3\2\2\2\u0106\u0104\3\2\2\2") + buf.write("\u0106\u0107\3\2\2\2\u0107\61\3\2\2\2\u0108\u0106\3\2") + buf.write("\2\2\u0109\u010d\t\6\2\2\u010a\u010c\t\5\2\2\u010b\u010a") + buf.write("\3\2\2\2\u010c\u010f\3\2\2\2\u010d\u010b\3\2\2\2\u010d") + buf.write("\u010e\3\2\2\2\u010e\63\3\2\2\2\u010f\u010d\3\2\2\2\u0110") + buf.write("\u0111\7>\2\2\u0111\u0112\7/\2\2\u0112\65\3\2\2\2\u0113") + buf.write("\u0114\7?\2\2\u0114\u0115\7@\2\2\u0115\67\3\2\2\2\u0116") + buf.write("\u0117\7-\2\2\u01179\3\2\2\2\u0118\u0119\7/\2\2\u0119") + buf.write(";\3\2\2\2\u011a\u011b\7,\2\2\u011b=\3\2\2\2\u011c\u011d") + buf.write("\7\61\2\2\u011d?\3\2\2\2\u011e\u011f\7>\2\2\u011fA\3\2") + buf.write("\2\2\u0120\u0121\7>\2\2\u0121\u0122\7?\2\2\u0122C\3\2") + buf.write("\2\2\u0123\u0124\7?\2\2\u0124E\3\2\2\2\u0125\u0126\7\u0080") + buf.write("\2\2\u0126G\3\2\2\2\u0127\u0128\7*\2\2\u0128I\3\2\2\2") + buf.write("\u0129\u012a\7+\2\2\u012aK\3\2\2\2\u012b\u012c\7}\2\2") + buf.write("\u012cM\3\2\2\2\u012d\u012e\7\177\2\2\u012eO\3\2\2\2\u012f") + buf.write("\u0130\7B\2\2\u0130Q\3\2\2\2\u0131\u0132\7\60\2\2\u0132") + buf.write("S\3\2\2\2\u0133\u0134\7.\2\2\u0134U\3\2\2\2\u0135\u0136") + buf.write("\7<\2\2\u0136W\3\2\2\2\u0137\u0138\7=\2\2\u0138Y\3\2\2") + buf.write("\2\u0139\u013a\t\7\2\2\u013a[\3\2\2\2\u013b\u013c\t\b") + buf.write("\2\2\u013c]\3\2\2\2\u013d\u013e\t\t\2\2\u013e_\3\2\2\2") + buf.write("\u013f\u0140\t\n\2\2\u0140a\3\2\2\2\u0141\u0142\t\13\2") + buf.write("\2\u0142c\3\2\2\2\u0143\u0144\t\f\2\2\u0144e\3\2\2\2\u0145") + buf.write("\u0146\t\r\2\2\u0146g\3\2\2\2\u0147\u0148\t\16\2\2\u0148") + buf.write("i\3\2\2\2\u0149\u014a\t\17\2\2\u014ak\3\2\2\2\u014b\u014c") + buf.write("\t\20\2\2\u014cm\3\2\2\2\u014d\u014e\t\21\2\2\u014eo\3") + buf.write("\2\2\2\u014f\u0150\t\22\2\2\u0150q\3\2\2\2\u0151\u0152") + buf.write("\t\23\2\2\u0152s\3\2\2\2\u0153\u0154\t\24\2\2\u0154u\3") + buf.write("\2\2\2\u0155\u0156\t\25\2\2\u0156w\3\2\2\2\u0157\u0158") + buf.write("\t\26\2\2\u0158y\3\2\2\2\u0159\u015a\t\27\2\2\u015a{\3") + buf.write("\2\2\2\u015b\u015e\7^\2\2\u015c\u015f\t\30\2\2\u015d\u015f") + buf.write("\5~?\2\u015e\u015c\3\2\2\2\u015e\u015d\3\2\2\2\u015f}") + buf.write("\3\2\2\2\u0160\u0161\7w\2\2\u0161\u0162\5\u0080@\2\u0162") + buf.write("\u0163\5\u0080@\2\u0163\u0164\5\u0080@\2\u0164\u0165\5") + buf.write("\u0080@\2\u0165\177\3\2\2\2\u0166\u0167\t\31\2\2\u0167") + buf.write("\u0081\3\2\2\2\u0168\u016a\t\32\2\2\u0169\u0168\3\2\2") + buf.write("\2\u016a\u016b\3\2\2\2\u016b\u0169\3\2\2\2\u016b\u016c") + buf.write("\3\2\2\2\u016c\u016d\3\2\2\2\u016d\u016e\bA\2\2\u016e") + buf.write("\u0083\3\2\2\2\u016f\u0170\7/\2\2\u0170\u0171\7/\2\2\u0171") + buf.write("\u0175\3\2\2\2\u0172\u0174\n\33\2\2\u0173\u0172\3\2\2") + buf.write("\2\u0174\u0177\3\2\2\2\u0175\u0173\3\2\2\2\u0175\u0176") + buf.write("\3\2\2\2\u0176\u0179\3\2\2\2\u0177\u0175\3\2\2\2\u0178") + buf.write("\u017a\7\f\2\2\u0179\u0178\3\2\2\2\u0179\u017a\3\2\2\2") + buf.write("\u017a\u017b\3\2\2\2\u017b\u017c\bB\2\2\u017c\u0085\3") + buf.write("\2\2\2\u017d\u017e\7*\2\2\u017e\u017f\7,\2\2\u017f\u0180") + buf.write("\3\2\2\2\u0180\u0181\bC\2\2\u0181\u0182\bC\3\2\u0182\u0087") + buf.write("\3\2\2\2\u0183\u0184\5\u0086C\2\u0184\u0185\5\u0088D\2") + buf.write("\u0185\u0186\5\u008aE\2\u0186\u018d\3\2\2\2\u0187\u0189") + buf.write("\13\2\2\2\u0188\u0187\3\2\2\2\u0189\u018a\3\2\2\2\u018a") + buf.write("\u018b\3\2\2\2\u018a\u0188\3\2\2\2\u018b\u018d\3\2\2\2") + buf.write("\u018c\u0183\3\2\2\2\u018c\u0188\3\2\2\2\u018d\u018e\3") + buf.write("\2\2\2\u018e\u018f\bD\2\2\u018f\u0089\3\2\2\2\u0190\u0191") + buf.write("\7,\2\2\u0191\u0192\7+\2\2\u0192\u0193\3\2\2\2\u0193\u0194") + buf.write("\bE\2\2\u0194\u0195\bE\4\2\u0195\u008b\3\2\2\2\20\2\3") + buf.write("\u00ed\u00ef\u00fb\u0100\u0106\u010d\u015e\u016b\u0175") + buf.write("\u0179\u018a\u018c\5\b\2\2\7\3\2\6\2\2") + return buf.getvalue() + + +class COOL_LEX(Lexer): + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] + + MULTILINE_COMMENT = 1 + + CLASS = 1 + ELSE = 2 + FALSE = 3 + FI = 4 + IF = 5 + IN = 6 + INHERITS = 7 + ISVOID = 8 + LET = 9 + LOOP = 10 + POOL = 11 + THEN = 12 + WHILE = 13 + CASE = 14 + ESAC = 15 + NEW = 16 + OF = 17 + NOT = 18 + TRUE = 19 + STRING = 20 + BREAK_STRING = 21 + INT = 22 + TYPEID = 23 + OBJECTID = 24 + ASSIGNMENT = 25 + CASE_ARROW = 26 + ADD = 27 + MINUS = 28 + MULTIPLY = 29 + DIVISION = 30 + LESS_THAN = 31 + LESS_EQUAL = 32 + EQUAL = 33 + INTEGER_NEGATIVE = 34 + OPEN_ROUND = 35 + CLOSE_ROUND = 36 + OPEN_CURLY = 37 + CLOSE_CURLY = 38 + AT = 39 + DOT = 40 + COMMA = 41 + COLON = 42 + SEMICOLON = 43 + WHITESPACE = 44 + ONE_LINE_COMMENT = 45 + OPEN_COMMENT = 46 + COMMENT = 47 + CLOSE_COMMENT = 48 + + channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] + + modeNames = [ "DEFAULT_MODE", "MULTILINE_COMMENT" ] + + literalNames = [ "", + "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", "'<='", "'='", + "'~'", "'('", "')'", "'{'", "'}'", "'@'", "'.'", "','", "':'", + "';'", "'(*'", "'*)'" ] + + symbolicNames = [ "", + "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", + "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", + "OF", "NOT", "TRUE", "STRING", "BREAK_STRING", "INT", "TYPEID", + "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", + "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", + "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", "CLOSE_CURLY", "AT", + "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", "ONE_LINE_COMMENT", + "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT" ] + + ruleNames = [ "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", + "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", + "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", "BREAK_STRING", + "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", + "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", + "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", + "OPEN_CURLY", "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", + "SEMICOLON", "A", "C", "D", "E", "F", "H", "I", "L", "N", + "O", "P", "R", "S", "T", "U", "V", "W", "ESC", "UNICODE", + "HEX", "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", + "COMMENT", "CLOSE_COMMENT" ] + + grammarFileName = "COOL_LEX.g4" + + def __init__(self, input=None, output:TextIO = sys.stdout): + super().__init__(input, output) + self.checkVersion("4.7.2") + self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) + self._actions = None + self._predicates = None + + diff --git a/COOL_LEX.tokens b/COOL_LEX.tokens new file mode 100644 index 00000000..bbdda836 --- /dev/null +++ b/COOL_LEX.tokens @@ -0,0 +1,69 @@ +CLASS=1 +ELSE=2 +FALSE=3 +FI=4 +IF=5 +IN=6 +INHERITS=7 +ISVOID=8 +LET=9 +LOOP=10 +POOL=11 +THEN=12 +WHILE=13 +CASE=14 +ESAC=15 +NEW=16 +OF=17 +NOT=18 +TRUE=19 +STRING=20 +BREAK_STRING=21 +INT=22 +TYPEID=23 +OBJECTID=24 +ASSIGNMENT=25 +CASE_ARROW=26 +ADD=27 +MINUS=28 +MULTIPLY=29 +DIVISION=30 +LESS_THAN=31 +LESS_EQUAL=32 +EQUAL=33 +INTEGER_NEGATIVE=34 +OPEN_ROUND=35 +CLOSE_ROUND=36 +OPEN_CURLY=37 +CLOSE_CURLY=38 +AT=39 +DOT=40 +COMMA=41 +COLON=42 +SEMICOLON=43 +WHITESPACE=44 +ONE_LINE_COMMENT=45 +OPEN_COMMENT=46 +COMMENT=47 +CLOSE_COMMENT=48 +'<-'=25 +'=>'=26 +'+'=27 +'-'=28 +'*'=29 +'/'=30 +'<'=31 +'<='=32 +'='=33 +'~'=34 +'('=35 +')'=36 +'{'=37 +'}'=38 +'@'=39 +'.'=40 +','=41 +':'=42 +';'=43 +'(*'=46 +'*)'=48 diff --git a/tests/lexer/test1.cl b/tests/lexer/test1.cl new file mode 100644 index 00000000..43ea44f6 --- /dev/null +++ b/tests/lexer/test1.cl @@ -0,0 +1,9 @@ +class Main { + str <- "The big brown fox + jumped over the fence"; + main() : Object { + { + out_string("Yay! This is the newest shites ); + } + }; +}; diff --git a/tests/lexer/test1_error.txt b/tests/lexer/test1_error.txt new file mode 100644 index 00000000..5145209d --- /dev/null +++ b/tests/lexer/test1_error.txt @@ -0,0 +1,3 @@ +(3, 4) - LexicographicError: Unterminated string constant +(4, 2) - LexicographicError: Unterminated string constant +(7, 4) - LexicographicError: Unterminated string constant \ No newline at end of file diff --git a/tests/lexer/test3.cl b/tests/lexer/test3.cl new file mode 100644 index 00000000..1fb6cedb --- /dev/null +++ b/tests/lexer/test3.cl @@ -0,0 +1,46 @@ +class Error() { + + (* There was once a comment, + that was quite long. + But, the reader soon discovered that + the comment was indeed longer than + previously assumed. Now, the reader + was in a real dilemma; is the comment + ever gonna end? If I stop reading, will + it end? + He started imagining all sorts of things. + He thought about heisenberg's cat and how + how that relates to the end of the sentence. + He thought to himself "I'm gonna stop reading". + "If I keep reading this comment, I'm gonna know + the fate of this sentence; That will be disastorous." + He knew that such a comment was gonna extend to + another file. It was too awesome to be contained in + a single file. And he would have kept reading too... + if only... + cool wasn't a super-duper-fab-awesomest language; + but cool is that language; + "This comment shall go not cross this file" said cool. + Alas! The reader could read no more. + There was once a comment, + that was quite long. + But, the reader soon discovered that + the comment was indeed longer than + previously assumed. Now, the reader + was in a real dilemma; is the comment + ever gonna end? If I stop reading, will + it end? + He started imagining all sorts of things. + He thought about heisenberg's cat and how + how that relates to the end of the sentence. + He thought to himself "I'm gonna stop reading". + "If I keep reading this comment, I'm gonna know + the fate of this sentence; That will be disastorous." + He knew that such a comment was gonna extend to + another file. It was too awesome to be contained in + a single file. And he would have kept reading too... + if only... + cool wasn't a super-duper-fab-awesomest language; + but cool is that language; + "This comment shall go not cross this file" said cool. + Alas! The reader could read no more. \ No newline at end of file diff --git a/tests/lexer/test3_error.txt b/tests/lexer/test3_error.txt new file mode 100644 index 00000000..dc48da75 --- /dev/null +++ b/tests/lexer/test3_error.txt @@ -0,0 +1 @@ +(46, 40) - LexicographicError: EOF in comment diff --git a/tests/lexer/test5.cl b/tests/lexer/test5.cl new file mode 100644 index 00000000..879e27a6 --- /dev/null +++ b/tests/lexer/test5.cl @@ -0,0 +1,4 @@ +"lkjdsafkljdsalfj\u0000dsafdsaf\u0000djafslkjdsalf\nsdajf\" lkjfdsasdkjfl"123 +adsfasklj# +LKldsajf +"lkdsajf" \ No newline at end of file diff --git a/tests/lexer/test5_error.txt b/tests/lexer/test5_error.txt new file mode 100644 index 00000000..99af5fbd --- /dev/null +++ b/tests/lexer/test5_error.txt @@ -0,0 +1 @@ +(2, 10) - LexicographicError: ERROR "#" diff --git a/tests/lexer/test6.cl b/tests/lexer/test6.cl new file mode 100644 index 00000000..d420df7c --- /dev/null +++ b/tests/lexer/test6.cl @@ -0,0 +1,6 @@ +"kjas\"lnnsdj\nfljrdsaf" +$ +$ +% +% +"alkjfldajf""dasfadsf \ No newline at end of file diff --git a/tests/lexer/test6_error.txt b/tests/lexer/test6_error.txt new file mode 100644 index 00000000..4ca5899e --- /dev/null +++ b/tests/lexer/test6_error.txt @@ -0,0 +1,5 @@ +(2, 1) - LexicographicError: ERROR "$" +(3, 1) - LexicographicError: ERROR "$" +(4, 1) - LexicographicError: ERROR "%" +(5, 1) - LexicographicError: ERROR "%" +(6, 22) - LexicographicError: EOF in string constant diff --git a/tests/parser/err2.cl b/tests/parser/err2.cl new file mode 100644 index 00000000..40149b89 --- /dev/null +++ b/tests/parser/err2.cl @@ -0,0 +1,14 @@ +class Main { + main(): Object { + (new alpha).print() + }; + +}; + +(* Class names must begin with uppercase letters *) +class alpha inherits IO { + print() : Object { + out_string("reached!!\n"); + }; +}; + diff --git a/tests/parser/err2_error.txt b/tests/parser/err2_error.txt new file mode 100644 index 00000000..92e47e37 --- /dev/null +++ b/tests/parser/err2_error.txt @@ -0,0 +1,2 @@ +(3, 10) - SyntacticError: ERROR at or near "alpha" +(9, 7) - SyntacticError: ERROR at or near "alpha" \ No newline at end of file diff --git a/tests/parser/isprime.cl b/tests/parser/isprime.cl new file mode 100644 index 00000000..5adaeda9 --- /dev/null +++ b/tests/parser/isprime.cl @@ -0,0 +1,40 @@ +class Main inherits IO { + main() : Object { + { + out_string("Enter a number to check if number is prime\n"); + let i : Int <- in_int() in { + if(i <= 1) then { + out_string("Invalid Input\n"); + abort(); + } else { + if (isPrime(i) = 1) then + out_string("Number is prime\n") + else + out_string("Number is composite\n") + fi; + } + fi; + }; + } + }; + + mod(i : Int, ) : Int { -- Formal list must be comma separated. A comma does not terminate a list of formals. + i - (i/k)*k + }; + + isPrime(i : Int) : Int { + { + let x : Int <- 2, + c : Int <- 1 in + { + while (not (x = i)) loop + if (mod(i, x) = 0) then { + c <- 0; + x <- i; + } else x <- x + 1 fi + pool; + c; + }; + } + }; +}; diff --git a/tests/parser/isprime_error.txt b/tests/parser/isprime_error.txt new file mode 100644 index 00000000..ea89e135 --- /dev/null +++ b/tests/parser/isprime_error.txt @@ -0,0 +1 @@ +(21, 15) - SyntacticError: Error at or near ')' diff --git a/tests/parser/prod.cl b/tests/parser/prod.cl new file mode 100644 index 00000000..effe5a7c --- /dev/null +++ b/tests/parser/prod.cl @@ -0,0 +1,21 @@ +class Main inherits IO { + main() : Object { + { + out_string("Enter number of numbers to multiply\n"); + out_int(prod(in_int())); + out_string("\n"); + } + }; + + prod(i : Int) : Int { + let y : Int <- 1 in { + while (not (i = 0) ) loop { + out_string("Enter Number: "); + y <- y * in_int(Main : Int); -- the parser correctly catches the error here + i <- i - 1; + } + pool; + y; + } + }; +}; diff --git a/tests/parser/prod_error.txt b/tests/parser/prod_error.txt new file mode 100644 index 00000000..ab4e7867 --- /dev/null +++ b/tests/parser/prod_error.txt @@ -0,0 +1 @@ +(14, 23) - SyntacticError: ERROR at or near "Main" \ No newline at end of file diff --git a/tests/parser/test2.cl b/tests/parser/test2.cl new file mode 100644 index 00000000..8fdb792e --- /dev/null +++ b/tests/parser/test2.cl @@ -0,0 +1,20 @@ +class Main inherits IO { + str <- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + main() : Object { + { + out_string("Enter number of numbers to multiply\n"); + out_int(prod(in_int())); + out_string("\n"); + } + }; + prod(i : Int) : Int { + let y : Int <- 1 in { + while (not (i = 0) ) loop { + out_string("Enter Number: "); + y <- y * in_int(); + i <- i - 1; + } + y; + } + }; +} diff --git a/tests/parser/test2_error.txt b/tests/parser/test2_error.txt new file mode 100644 index 00000000..2bfe70f3 --- /dev/null +++ b/tests/parser/test2_error.txt @@ -0,0 +1,4 @@ +(2, 6) - SyntacticError: ERROR at or near "<-" +(17, 4) - SyntacticError: ERROR at or near "y" +(21, 1) - SyntacticError: ERROR at or near EOF + diff --git a/tests/parser/test4.cl b/tests/parser/test4.cl new file mode 100644 index 00000000..aad6c503 --- /dev/null +++ b/tests/parser/test4.cl @@ -0,0 +1,5 @@ +classs Doom { + i : Int <- 0; + main() : Object { + if i = 0 then out_string("This is da real *h*t") + diff --git a/tests/parser/test4_error.txt b/tests/parser/test4_error.txt new file mode 100644 index 00000000..af75ca92 --- /dev/null +++ b/tests/parser/test4_error.txt @@ -0,0 +1 @@ +(1, 1) - SyntacticError: ERROR at or near "classs" \ No newline at end of file From b6eb94d67f10347a8369cb44347fbde01886edd0 Mon Sep 17 00:00:00 2001 From: LSilvaO Date: Sat, 29 Feb 2020 23:43:49 -0500 Subject: [PATCH 06/77] todos los miembros --- doc/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Readme.md b/doc/Readme.md index e32260f4..f9186022 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -5,7 +5,7 @@ **Nombre** | **Grupo** | **Github** --|--|-- Liset Silva Oropesa | C411 | [@Liset97](https://github.com/Liset97) -Pablo Antonio de Armas Suarez | C411 | [@github_user](https://github.com/) +Pablo Antonio de Armas Suarez | C411 | [@pablodearmas](https://github.com/pablodearmas) Yenli Gil Machado | C412 | [@YenGM](https://github.com/YenGM) ## Readme From 6de05c4b1d7fcf6281563fa11683c507dc305fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 1 Mar 2020 00:02:36 -0500 Subject: [PATCH 07/77] Movimiento de los fuente a las carpeta src --- COOL.interp | 113 -- COOL.tokens | 69 - COOLCompiler.py | 36 - COOLLexer.py | 34 - COOLListener.py | 289 --- COOLParser.py | 24 - src/COOL.interp | 50 +- COOL.py => src/COOL.py | 0 src/COOL.tokens | 137 +- src/COOLCompiler.py | 21 + src/COOLLexer.py | 289 +-- .../COOLLexerErrorListener.py | 0 src/COOLListener.py | 265 ++- src/COOLParser.py | 1773 +---------------- .../COOLParserErrorListener.py | 0 COOL_LEX.interp => src/COOL_LEX.interp | 0 COOL_LEX.py => src/COOL_LEX.py | 0 COOL_LEX.tokens => src/COOL_LEX.tokens | 0 18 files changed, 292 insertions(+), 2808 deletions(-) delete mode 100644 COOL.interp delete mode 100644 COOL.tokens delete mode 100644 COOLCompiler.py delete mode 100644 COOLLexer.py delete mode 100644 COOLListener.py delete mode 100644 COOLParser.py rename COOL.py => src/COOL.py (100%) rename COOLLexerErrorListener.py => src/COOLLexerErrorListener.py (100%) rename COOLParserErrorListener.py => src/COOLParserErrorListener.py (100%) rename COOL_LEX.interp => src/COOL_LEX.interp (100%) rename COOL_LEX.py => src/COOL_LEX.py (100%) rename COOL_LEX.tokens => src/COOL_LEX.tokens (100%) diff --git a/COOL.interp b/COOL.interp deleted file mode 100644 index bba307e6..00000000 --- a/COOL.interp +++ /dev/null @@ -1,113 +0,0 @@ -token literal names: -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -'<-' -'=>' -'+' -'-' -'*' -'/' -'<' -'<=' -'=' -'~' -'(' -')' -'{' -'}' -'@' -'.' -',' -':' -';' -null -null -'(*' -null -'*)' - -token symbolic names: -null -CLASS -ELSE -FALSE -FI -IF -IN -INHERITS -ISVOID -LET -LOOP -POOL -THEN -WHILE -CASE -ESAC -NEW -OF -NOT -TRUE -STRING -BREAK_STRING -INT -TYPEID -OBJECTID -ASSIGNMENT -CASE_ARROW -ADD -MINUS -MULTIPLY -DIVISION -LESS_THAN -LESS_EQUAL -EQUAL -INTEGER_NEGATIVE -OPEN_ROUND -CLOSE_ROUND -OPEN_CURLY -CLOSE_CURLY -AT -DOT -COMMA -COLON -SEMICOLON -WHITESPACE -ONE_LINE_COMMENT -OPEN_COMMENT -COMMENT -CLOSE_COMMENT - -rule names: -program -programBlocks -classDefine -feature -formal -expression - - -atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 50, 225, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 7, 7, 86, 10, 7, 12, 7, 14, 7, 89, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 110, 10, 7, 13, 7, 14, 7, 111, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 122, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 130, 10, 7, 7, 7, 132, 10, 7, 12, 7, 14, 7, 135, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 149, 10, 7, 13, 7, 14, 7, 150, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 175, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 201, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 209, 10, 7, 12, 7, 14, 7, 212, 11, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 7, 7, 220, 10, 7, 12, 7, 14, 7, 223, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 259, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 174, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 45, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 25, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 25, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 39, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 45, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 40, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 26, 2, 2, 40, 51, 7, 37, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 43, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 38, 2, 2, 55, 56, 7, 44, 2, 2, 56, 57, 7, 25, 2, 2, 57, 58, 7, 39, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 40, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 26, 2, 2, 62, 63, 7, 44, 2, 2, 63, 66, 7, 25, 2, 2, 64, 65, 7, 27, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 26, 2, 2, 71, 72, 7, 44, 2, 2, 72, 73, 7, 25, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 26, 2, 2, 76, 87, 7, 37, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 43, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 90, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 175, 7, 38, 2, 2, 91, 92, 7, 7, 2, 2, 92, 93, 5, 12, 7, 2, 93, 94, 7, 14, 2, 2, 94, 95, 5, 12, 7, 2, 95, 96, 7, 4, 2, 2, 96, 97, 5, 12, 7, 2, 97, 98, 7, 6, 2, 2, 98, 175, 3, 2, 2, 2, 99, 100, 7, 15, 2, 2, 100, 101, 5, 12, 7, 2, 101, 102, 7, 12, 2, 2, 102, 103, 5, 12, 7, 2, 103, 104, 7, 13, 2, 2, 104, 175, 3, 2, 2, 2, 105, 109, 7, 39, 2, 2, 106, 107, 5, 12, 7, 2, 107, 108, 7, 45, 2, 2, 108, 110, 3, 2, 2, 2, 109, 106, 3, 2, 2, 2, 110, 111, 3, 2, 2, 2, 111, 109, 3, 2, 2, 2, 111, 112, 3, 2, 2, 2, 112, 113, 3, 2, 2, 2, 113, 114, 7, 40, 2, 2, 114, 175, 3, 2, 2, 2, 115, 116, 7, 11, 2, 2, 116, 117, 7, 26, 2, 2, 117, 118, 7, 44, 2, 2, 118, 121, 7, 25, 2, 2, 119, 120, 7, 27, 2, 2, 120, 122, 5, 12, 7, 2, 121, 119, 3, 2, 2, 2, 121, 122, 3, 2, 2, 2, 122, 133, 3, 2, 2, 2, 123, 124, 7, 43, 2, 2, 124, 125, 7, 26, 2, 2, 125, 126, 7, 44, 2, 2, 126, 129, 7, 25, 2, 2, 127, 128, 7, 27, 2, 2, 128, 130, 5, 12, 7, 2, 129, 127, 3, 2, 2, 2, 129, 130, 3, 2, 2, 2, 130, 132, 3, 2, 2, 2, 131, 123, 3, 2, 2, 2, 132, 135, 3, 2, 2, 2, 133, 131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 136, 3, 2, 2, 2, 135, 133, 3, 2, 2, 2, 136, 137, 7, 8, 2, 2, 137, 175, 5, 12, 7, 22, 138, 139, 7, 16, 2, 2, 139, 140, 5, 12, 7, 2, 140, 148, 7, 19, 2, 2, 141, 142, 7, 26, 2, 2, 142, 143, 7, 44, 2, 2, 143, 144, 7, 25, 2, 2, 144, 145, 7, 28, 2, 2, 145, 146, 5, 12, 7, 2, 146, 147, 7, 45, 2, 2, 147, 149, 3, 2, 2, 2, 148, 141, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 150, 148, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 7, 17, 2, 2, 153, 175, 3, 2, 2, 2, 154, 155, 7, 18, 2, 2, 155, 175, 7, 25, 2, 2, 156, 157, 7, 36, 2, 2, 157, 175, 5, 12, 7, 19, 158, 159, 7, 10, 2, 2, 159, 175, 5, 12, 7, 18, 160, 161, 7, 20, 2, 2, 161, 175, 5, 12, 7, 10, 162, 163, 7, 37, 2, 2, 163, 164, 5, 12, 7, 2, 164, 165, 7, 38, 2, 2, 165, 175, 3, 2, 2, 2, 166, 175, 7, 26, 2, 2, 167, 175, 7, 24, 2, 2, 168, 175, 7, 22, 2, 2, 169, 175, 7, 21, 2, 2, 170, 175, 7, 5, 2, 2, 171, 172, 7, 26, 2, 2, 172, 173, 7, 27, 2, 2, 173, 175, 5, 12, 7, 3, 174, 74, 3, 2, 2, 2, 174, 91, 3, 2, 2, 2, 174, 99, 3, 2, 2, 2, 174, 105, 3, 2, 2, 2, 174, 115, 3, 2, 2, 2, 174, 138, 3, 2, 2, 2, 174, 154, 3, 2, 2, 2, 174, 156, 3, 2, 2, 2, 174, 158, 3, 2, 2, 2, 174, 160, 3, 2, 2, 2, 174, 162, 3, 2, 2, 2, 174, 166, 3, 2, 2, 2, 174, 167, 3, 2, 2, 2, 174, 168, 3, 2, 2, 2, 174, 169, 3, 2, 2, 2, 174, 170, 3, 2, 2, 2, 174, 171, 3, 2, 2, 2, 175, 221, 3, 2, 2, 2, 176, 177, 12, 17, 2, 2, 177, 178, 7, 31, 2, 2, 178, 220, 5, 12, 7, 18, 179, 180, 12, 16, 2, 2, 180, 181, 7, 32, 2, 2, 181, 220, 5, 12, 7, 17, 182, 183, 12, 15, 2, 2, 183, 184, 7, 29, 2, 2, 184, 220, 5, 12, 7, 16, 185, 186, 12, 14, 2, 2, 186, 187, 7, 30, 2, 2, 187, 220, 5, 12, 7, 15, 188, 189, 12, 13, 2, 2, 189, 190, 7, 33, 2, 2, 190, 220, 5, 12, 7, 14, 191, 192, 12, 12, 2, 2, 192, 193, 7, 34, 2, 2, 193, 220, 5, 12, 7, 13, 194, 195, 12, 11, 2, 2, 195, 196, 7, 35, 2, 2, 196, 220, 5, 12, 7, 12, 197, 200, 12, 27, 2, 2, 198, 199, 7, 41, 2, 2, 199, 201, 7, 25, 2, 2, 200, 198, 3, 2, 2, 2, 200, 201, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 7, 42, 2, 2, 203, 204, 7, 26, 2, 2, 204, 215, 7, 37, 2, 2, 205, 210, 5, 12, 7, 2, 206, 207, 7, 43, 2, 2, 207, 209, 5, 12, 7, 2, 208, 206, 3, 2, 2, 2, 209, 212, 3, 2, 2, 2, 210, 208, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 214, 3, 2, 2, 2, 212, 210, 3, 2, 2, 2, 213, 205, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 218, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 218, 220, 7, 38, 2, 2, 219, 176, 3, 2, 2, 2, 219, 179, 3, 2, 2, 2, 219, 182, 3, 2, 2, 2, 219, 185, 3, 2, 2, 2, 219, 188, 3, 2, 2, 2, 219, 191, 3, 2, 2, 2, 219, 194, 3, 2, 2, 2, 219, 197, 3, 2, 2, 2, 220, 223, 3, 2, 2, 2, 221, 219, 3, 2, 2, 2, 221, 222, 3, 2, 2, 2, 222, 13, 3, 2, 2, 2, 223, 221, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 87, 111, 121, 129, 133, 150, 174, 200, 210, 215, 219, 221] \ No newline at end of file diff --git a/COOL.tokens b/COOL.tokens deleted file mode 100644 index bbdda836..00000000 --- a/COOL.tokens +++ /dev/null @@ -1,69 +0,0 @@ -CLASS=1 -ELSE=2 -FALSE=3 -FI=4 -IF=5 -IN=6 -INHERITS=7 -ISVOID=8 -LET=9 -LOOP=10 -POOL=11 -THEN=12 -WHILE=13 -CASE=14 -ESAC=15 -NEW=16 -OF=17 -NOT=18 -TRUE=19 -STRING=20 -BREAK_STRING=21 -INT=22 -TYPEID=23 -OBJECTID=24 -ASSIGNMENT=25 -CASE_ARROW=26 -ADD=27 -MINUS=28 -MULTIPLY=29 -DIVISION=30 -LESS_THAN=31 -LESS_EQUAL=32 -EQUAL=33 -INTEGER_NEGATIVE=34 -OPEN_ROUND=35 -CLOSE_ROUND=36 -OPEN_CURLY=37 -CLOSE_CURLY=38 -AT=39 -DOT=40 -COMMA=41 -COLON=42 -SEMICOLON=43 -WHITESPACE=44 -ONE_LINE_COMMENT=45 -OPEN_COMMENT=46 -COMMENT=47 -CLOSE_COMMENT=48 -'<-'=25 -'=>'=26 -'+'=27 -'-'=28 -'*'=29 -'/'=30 -'<'=31 -'<='=32 -'='=33 -'~'=34 -'('=35 -')'=36 -'{'=37 -'}'=38 -'@'=39 -'.'=40 -','=41 -':'=42 -';'=43 -'(*'=46 -'*)'=48 diff --git a/COOLCompiler.py b/COOLCompiler.py deleted file mode 100644 index 5a9b2584..00000000 --- a/COOLCompiler.py +++ /dev/null @@ -1,36 +0,0 @@ -import sys -import os.path -from antlr4 import * -from COOLLexer import COOLLexer -from COOLLexerErrorListener import COOLLexerErrorListener -from COOLParser import COOLParser -from COOLParserErrorListener import COOLParserErrorListener -from COOLListener import COOLListener - -def main(argv): - if not os.path.isfile(argv[1]): - print("invalid input filename") - return - - input = FileStream(argv[1]) - - lexer = COOLLexer(input) - lexer.removeErrorListeners() - lexer.addErrorListener(COOLLexerErrorListener()) - token = lexer.nextToken() - while token.type != Token.EOF: - token = lexer.nextToken() - - if lexer.hasErrors: - return - - lexer.reset(); - stream = CommonTokenStream(lexer) - parser = COOLParser(stream) - parser.removeErrorListeners() - parser.addErrorListener(COOLParserErrorListener()) - - tree = parser.program() - -if __name__ == '__main__': - main(sys.argv) diff --git a/COOLLexer.py b/COOLLexer.py deleted file mode 100644 index bcb2349c..00000000 --- a/COOLLexer.py +++ /dev/null @@ -1,34 +0,0 @@ -import sys -from io import StringIO -from typing.io import TextIO -from antlr4 import * -from COOL_LEX import COOL_LEX -from antlr4.CommonTokenFactory import CommonTokenFactory -from antlr4.atn.LexerATNSimulator import LexerATNSimulator -from antlr4.InputStream import InputStream -from antlr4.Recognizer import Recognizer -from antlr4.Token import Token -from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException - -class COOLLexer(COOL_LEX): - def __init__(self, input=None, output:TextIO = sys.stdout): - super().__init__(input, output) - self._hasErrors = False - - def notifyListeners(self, e:LexerNoViableAltException): - self._hasErrors = True - - start = self._tokenStartCharIndex - stop = self._input.index - text = self._input.getText(start, stop) - msg = "'" + self.getErrorDisplay(text) + "'" - listener = self.getErrorListenerDispatch() - listener.syntaxError(self, self._token, self._tokenStartLine, self._tokenStartColumn, msg, e) - - def reset(self): - super().reset() - self._hasErrors = False - - @property - def hasErrors(self): - return self._hasErrors \ No newline at end of file diff --git a/COOLListener.py b/COOLListener.py deleted file mode 100644 index e5e5d915..00000000 --- a/COOLListener.py +++ /dev/null @@ -1,289 +0,0 @@ -# Generated from COOL.g4 by ANTLR 4.7.2 -from antlr4 import * -if __name__ is not None and "." in __name__: - from .COOL import COOL -else: - from COOL import COOL - -# This class defines a complete listener for a parse tree produced by COOL. -class COOLListener(ParseTreeListener): - - # Enter a parse tree produced by COOL#program. - def enterProgram(self, ctx:COOL.ProgramContext): - pass - - # Exit a parse tree produced by COOL#program. - def exitProgram(self, ctx:COOL.ProgramContext): - pass - - - # Enter a parse tree produced by COOL#classes. - def enterClasses(self, ctx:COOL.ClassesContext): - pass - - # Exit a parse tree produced by COOL#classes. - def exitClasses(self, ctx:COOL.ClassesContext): - pass - - - # Enter a parse tree produced by COOL#classDefine. - def enterClassDefine(self, ctx:COOL.ClassDefineContext): - pass - - # Exit a parse tree produced by COOL#classDefine. - def exitClassDefine(self, ctx:COOL.ClassDefineContext): - pass - - - # Enter a parse tree produced by COOL#method. - def enterMethod(self, ctx:COOL.MethodContext): - pass - - # Exit a parse tree produced by COOL#method. - def exitMethod(self, ctx:COOL.MethodContext): - pass - - - # Enter a parse tree produced by COOL#property. - def enterProperty(self, ctx:COOL.PropertyContext): - pass - - # Exit a parse tree produced by COOL#property. - def exitProperty(self, ctx:COOL.PropertyContext): - pass - - - # Enter a parse tree produced by COOL#formal. - def enterFormal(self, ctx:COOL.FormalContext): - pass - - # Exit a parse tree produced by COOL#formal. - def exitFormal(self, ctx:COOL.FormalContext): - pass - - - # Enter a parse tree produced by COOL#letIn. - def enterLetIn(self, ctx:COOL.LetInContext): - pass - - # Exit a parse tree produced by COOL#letIn. - def exitLetIn(self, ctx:COOL.LetInContext): - pass - - - # Enter a parse tree produced by COOL#minus. - def enterMinus(self, ctx:COOL.MinusContext): - pass - - # Exit a parse tree produced by COOL#minus. - def exitMinus(self, ctx:COOL.MinusContext): - pass - - - # Enter a parse tree produced by COOL#string. - def enterString(self, ctx:COOL.StringContext): - pass - - # Exit a parse tree produced by COOL#string. - def exitString(self, ctx:COOL.StringContext): - pass - - - # Enter a parse tree produced by COOL#isvoid. - def enterIsvoid(self, ctx:COOL.IsvoidContext): - pass - - # Exit a parse tree produced by COOL#isvoid. - def exitIsvoid(self, ctx:COOL.IsvoidContext): - pass - - - # Enter a parse tree produced by COOL#while. - def enterWhile(self, ctx:COOL.WhileContext): - pass - - # Exit a parse tree produced by COOL#while. - def exitWhile(self, ctx:COOL.WhileContext): - pass - - - # Enter a parse tree produced by COOL#division. - def enterDivision(self, ctx:COOL.DivisionContext): - pass - - # Exit a parse tree produced by COOL#division. - def exitDivision(self, ctx:COOL.DivisionContext): - pass - - - # Enter a parse tree produced by COOL#negative. - def enterNegative(self, ctx:COOL.NegativeContext): - pass - - # Exit a parse tree produced by COOL#negative. - def exitNegative(self, ctx:COOL.NegativeContext): - pass - - - # Enter a parse tree produced by COOL#boolNot. - def enterBoolNot(self, ctx:COOL.BoolNotContext): - pass - - # Exit a parse tree produced by COOL#boolNot. - def exitBoolNot(self, ctx:COOL.BoolNotContext): - pass - - - # Enter a parse tree produced by COOL#lessThan. - def enterLessThan(self, ctx:COOL.LessThanContext): - pass - - # Exit a parse tree produced by COOL#lessThan. - def exitLessThan(self, ctx:COOL.LessThanContext): - pass - - - # Enter a parse tree produced by COOL#block. - def enterBlock(self, ctx:COOL.BlockContext): - pass - - # Exit a parse tree produced by COOL#block. - def exitBlock(self, ctx:COOL.BlockContext): - pass - - - # Enter a parse tree produced by COOL#id. - def enterId(self, ctx:COOL.IdContext): - pass - - # Exit a parse tree produced by COOL#id. - def exitId(self, ctx:COOL.IdContext): - pass - - - # Enter a parse tree produced by COOL#multiply. - def enterMultiply(self, ctx:COOL.MultiplyContext): - pass - - # Exit a parse tree produced by COOL#multiply. - def exitMultiply(self, ctx:COOL.MultiplyContext): - pass - - - # Enter a parse tree produced by COOL#if. - def enterIf(self, ctx:COOL.IfContext): - pass - - # Exit a parse tree produced by COOL#if. - def exitIf(self, ctx:COOL.IfContext): - pass - - - # Enter a parse tree produced by COOL#case. - def enterCase(self, ctx:COOL.CaseContext): - pass - - # Exit a parse tree produced by COOL#case. - def exitCase(self, ctx:COOL.CaseContext): - pass - - - # Enter a parse tree produced by COOL#ownMethodCall. - def enterOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): - pass - - # Exit a parse tree produced by COOL#ownMethodCall. - def exitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): - pass - - - # Enter a parse tree produced by COOL#add. - def enterAdd(self, ctx:COOL.AddContext): - pass - - # Exit a parse tree produced by COOL#add. - def exitAdd(self, ctx:COOL.AddContext): - pass - - - # Enter a parse tree produced by COOL#new. - def enterNew(self, ctx:COOL.NewContext): - pass - - # Exit a parse tree produced by COOL#new. - def exitNew(self, ctx:COOL.NewContext): - pass - - - # Enter a parse tree produced by COOL#parentheses. - def enterParentheses(self, ctx:COOL.ParenthesesContext): - pass - - # Exit a parse tree produced by COOL#parentheses. - def exitParentheses(self, ctx:COOL.ParenthesesContext): - pass - - - # Enter a parse tree produced by COOL#assignment. - def enterAssignment(self, ctx:COOL.AssignmentContext): - pass - - # Exit a parse tree produced by COOL#assignment. - def exitAssignment(self, ctx:COOL.AssignmentContext): - pass - - - # Enter a parse tree produced by COOL#false. - def enterFalse(self, ctx:COOL.FalseContext): - pass - - # Exit a parse tree produced by COOL#false. - def exitFalse(self, ctx:COOL.FalseContext): - pass - - - # Enter a parse tree produced by COOL#int. - def enterInt(self, ctx:COOL.IntContext): - pass - - # Exit a parse tree produced by COOL#int. - def exitInt(self, ctx:COOL.IntContext): - pass - - - # Enter a parse tree produced by COOL#equal. - def enterEqual(self, ctx:COOL.EqualContext): - pass - - # Exit a parse tree produced by COOL#equal. - def exitEqual(self, ctx:COOL.EqualContext): - pass - - - # Enter a parse tree produced by COOL#true. - def enterTrue(self, ctx:COOL.TrueContext): - pass - - # Exit a parse tree produced by COOL#true. - def exitTrue(self, ctx:COOL.TrueContext): - pass - - - # Enter a parse tree produced by COOL#lessEqual. - def enterLessEqual(self, ctx:COOL.LessEqualContext): - pass - - # Exit a parse tree produced by COOL#lessEqual. - def exitLessEqual(self, ctx:COOL.LessEqualContext): - pass - - - # Enter a parse tree produced by COOL#methodCall. - def enterMethodCall(self, ctx:COOL.MethodCallContext): - pass - - # Exit a parse tree produced by COOL#methodCall. - def exitMethodCall(self, ctx:COOL.MethodCallContext): - pass - - diff --git a/COOLParser.py b/COOLParser.py deleted file mode 100644 index 7f3ad8ac..00000000 --- a/COOLParser.py +++ /dev/null @@ -1,24 +0,0 @@ -import sys -from io import StringIO -from typing.io import TextIO -from antlr4 import * -from COOL import COOL -from antlr4.CommonTokenFactory import CommonTokenFactory -from antlr4.atn.LexerATNSimulator import LexerATNSimulator -from antlr4.InputStream import InputStream -from antlr4.Recognizer import Recognizer -from antlr4.Token import Token -from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException - -class COOLParser(COOL): - def __init__(self, input=None, output:TextIO = sys.stdout): - super().__init__(input, output) - - def notifyErrorListeners(self, msg:str, offendingToken:Token = None, e:RecognitionException = None): - if offendingToken is None: - offendingToken = self.getCurrentToken() - self._syntaxErrors += 1 - line = offendingToken.line - column = offendingToken.column - listener = self.getErrorListenerDispatch() - listener.syntaxError(self, offendingToken, line, column, msg, e) \ No newline at end of file diff --git a/src/COOL.interp b/src/COOL.interp index f2d42957..bba307e6 100644 --- a/src/COOL.interp +++ b/src/COOL.interp @@ -1,14 +1,6 @@ token literal names: null -';' -'{' -'}' -'(' -',' -')' -':' -'@' -'.' +null null null null @@ -42,23 +34,23 @@ null '<=' '=' '~' -'(*' -'*)' +'(' +')' +'{' +'}' +'@' +'.' +',' +':' +';' null null +'(*' null +'*)' token symbolic names: null -null -null -null -null -null -null -null -null -null CLASS ELSE FALSE @@ -79,6 +71,7 @@ OF NOT TRUE STRING +BREAK_STRING INT TYPEID OBJECTID @@ -92,11 +85,20 @@ LESS_THAN LESS_EQUAL EQUAL INTEGER_NEGATIVE +OPEN_ROUND +CLOSE_ROUND +OPEN_CURLY +CLOSE_CURLY +AT +DOT +COMMA +COLON +SEMICOLON +WHITESPACE +ONE_LINE_COMMENT OPEN_COMMENT -CLOSE_COMMENT COMMENT -ONE_LINE_COMMENT -WHITESPACE +CLOSE_COMMENT rule names: program @@ -108,4 +110,4 @@ expression atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 49, 226, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 22, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 28, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 34, 10, 4, 12, 4, 14, 4, 37, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 46, 10, 5, 12, 5, 14, 5, 49, 11, 5, 7, 5, 51, 10, 5, 12, 5, 14, 5, 54, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 68, 10, 5, 5, 5, 70, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 82, 10, 7, 12, 7, 14, 7, 85, 11, 7, 7, 7, 87, 10, 7, 12, 7, 14, 7, 90, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 111, 10, 7, 13, 7, 14, 7, 112, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 123, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 131, 10, 7, 7, 7, 133, 10, 7, 12, 7, 14, 7, 136, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 150, 10, 7, 13, 7, 14, 7, 151, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 176, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 202, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 210, 10, 7, 12, 7, 14, 7, 213, 11, 7, 7, 7, 215, 10, 7, 12, 7, 14, 7, 218, 11, 7, 3, 7, 7, 7, 221, 10, 7, 12, 7, 14, 7, 224, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 260, 2, 14, 3, 2, 2, 2, 4, 21, 3, 2, 2, 2, 6, 23, 3, 2, 2, 2, 8, 69, 3, 2, 2, 2, 10, 71, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 3, 3, 2, 2, 2, 16, 17, 5, 6, 4, 2, 17, 18, 7, 3, 2, 2, 18, 19, 5, 4, 3, 2, 19, 22, 3, 2, 2, 2, 20, 22, 7, 2, 2, 3, 21, 16, 3, 2, 2, 2, 21, 20, 3, 2, 2, 2, 22, 5, 3, 2, 2, 2, 23, 24, 7, 12, 2, 2, 24, 27, 7, 33, 2, 2, 25, 26, 7, 18, 2, 2, 26, 28, 7, 33, 2, 2, 27, 25, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 29, 3, 2, 2, 2, 29, 35, 7, 4, 2, 2, 30, 31, 5, 8, 5, 2, 31, 32, 7, 3, 2, 2, 32, 34, 3, 2, 2, 2, 33, 30, 3, 2, 2, 2, 34, 37, 3, 2, 2, 2, 35, 33, 3, 2, 2, 2, 35, 36, 3, 2, 2, 2, 36, 38, 3, 2, 2, 2, 37, 35, 3, 2, 2, 2, 38, 39, 7, 5, 2, 2, 39, 7, 3, 2, 2, 2, 40, 41, 7, 34, 2, 2, 41, 52, 7, 6, 2, 2, 42, 47, 5, 10, 6, 2, 43, 44, 7, 7, 2, 2, 44, 46, 5, 10, 6, 2, 45, 43, 3, 2, 2, 2, 46, 49, 3, 2, 2, 2, 47, 45, 3, 2, 2, 2, 47, 48, 3, 2, 2, 2, 48, 51, 3, 2, 2, 2, 49, 47, 3, 2, 2, 2, 50, 42, 3, 2, 2, 2, 51, 54, 3, 2, 2, 2, 52, 50, 3, 2, 2, 2, 52, 53, 3, 2, 2, 2, 53, 55, 3, 2, 2, 2, 54, 52, 3, 2, 2, 2, 55, 56, 7, 8, 2, 2, 56, 57, 7, 9, 2, 2, 57, 58, 7, 33, 2, 2, 58, 59, 7, 4, 2, 2, 59, 60, 5, 12, 7, 2, 60, 61, 7, 5, 2, 2, 61, 70, 3, 2, 2, 2, 62, 63, 7, 34, 2, 2, 63, 64, 7, 9, 2, 2, 64, 67, 7, 33, 2, 2, 65, 66, 7, 35, 2, 2, 66, 68, 5, 12, 7, 2, 67, 65, 3, 2, 2, 2, 67, 68, 3, 2, 2, 2, 68, 70, 3, 2, 2, 2, 69, 40, 3, 2, 2, 2, 69, 62, 3, 2, 2, 2, 70, 9, 3, 2, 2, 2, 71, 72, 7, 34, 2, 2, 72, 73, 7, 9, 2, 2, 73, 74, 7, 33, 2, 2, 74, 11, 3, 2, 2, 2, 75, 76, 8, 7, 1, 2, 76, 77, 7, 34, 2, 2, 77, 88, 7, 6, 2, 2, 78, 83, 5, 12, 7, 2, 79, 80, 7, 7, 2, 2, 80, 82, 5, 12, 7, 2, 81, 79, 3, 2, 2, 2, 82, 85, 3, 2, 2, 2, 83, 81, 3, 2, 2, 2, 83, 84, 3, 2, 2, 2, 84, 87, 3, 2, 2, 2, 85, 83, 3, 2, 2, 2, 86, 78, 3, 2, 2, 2, 87, 90, 3, 2, 2, 2, 88, 86, 3, 2, 2, 2, 88, 89, 3, 2, 2, 2, 89, 91, 3, 2, 2, 2, 90, 88, 3, 2, 2, 2, 91, 176, 7, 8, 2, 2, 92, 93, 7, 16, 2, 2, 93, 94, 5, 12, 7, 2, 94, 95, 7, 23, 2, 2, 95, 96, 5, 12, 7, 2, 96, 97, 7, 13, 2, 2, 97, 98, 5, 12, 7, 2, 98, 99, 7, 15, 2, 2, 99, 176, 3, 2, 2, 2, 100, 101, 7, 24, 2, 2, 101, 102, 5, 12, 7, 2, 102, 103, 7, 21, 2, 2, 103, 104, 5, 12, 7, 2, 104, 105, 7, 22, 2, 2, 105, 176, 3, 2, 2, 2, 106, 110, 7, 4, 2, 2, 107, 108, 5, 12, 7, 2, 108, 109, 7, 3, 2, 2, 109, 111, 3, 2, 2, 2, 110, 107, 3, 2, 2, 2, 111, 112, 3, 2, 2, 2, 112, 110, 3, 2, 2, 2, 112, 113, 3, 2, 2, 2, 113, 114, 3, 2, 2, 2, 114, 115, 7, 5, 2, 2, 115, 176, 3, 2, 2, 2, 116, 117, 7, 20, 2, 2, 117, 118, 7, 34, 2, 2, 118, 119, 7, 9, 2, 2, 119, 122, 7, 33, 2, 2, 120, 121, 7, 35, 2, 2, 121, 123, 5, 12, 7, 2, 122, 120, 3, 2, 2, 2, 122, 123, 3, 2, 2, 2, 123, 134, 3, 2, 2, 2, 124, 125, 7, 7, 2, 2, 125, 126, 7, 34, 2, 2, 126, 127, 7, 9, 2, 2, 127, 130, 7, 33, 2, 2, 128, 129, 7, 35, 2, 2, 129, 131, 5, 12, 7, 2, 130, 128, 3, 2, 2, 2, 130, 131, 3, 2, 2, 2, 131, 133, 3, 2, 2, 2, 132, 124, 3, 2, 2, 2, 133, 136, 3, 2, 2, 2, 134, 132, 3, 2, 2, 2, 134, 135, 3, 2, 2, 2, 135, 137, 3, 2, 2, 2, 136, 134, 3, 2, 2, 2, 137, 138, 7, 17, 2, 2, 138, 176, 5, 12, 7, 22, 139, 140, 7, 25, 2, 2, 140, 141, 5, 12, 7, 2, 141, 149, 7, 28, 2, 2, 142, 143, 7, 34, 2, 2, 143, 144, 7, 9, 2, 2, 144, 145, 7, 33, 2, 2, 145, 146, 7, 36, 2, 2, 146, 147, 5, 12, 7, 2, 147, 148, 7, 3, 2, 2, 148, 150, 3, 2, 2, 2, 149, 142, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 149, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 3, 2, 2, 2, 153, 154, 7, 26, 2, 2, 154, 176, 3, 2, 2, 2, 155, 156, 7, 27, 2, 2, 156, 176, 7, 33, 2, 2, 157, 158, 7, 44, 2, 2, 158, 176, 5, 12, 7, 19, 159, 160, 7, 19, 2, 2, 160, 176, 5, 12, 7, 18, 161, 162, 7, 29, 2, 2, 162, 176, 5, 12, 7, 10, 163, 164, 7, 6, 2, 2, 164, 165, 5, 12, 7, 2, 165, 166, 7, 8, 2, 2, 166, 176, 3, 2, 2, 2, 167, 176, 7, 34, 2, 2, 168, 176, 7, 32, 2, 2, 169, 176, 7, 31, 2, 2, 170, 176, 7, 30, 2, 2, 171, 176, 7, 14, 2, 2, 172, 173, 7, 34, 2, 2, 173, 174, 7, 35, 2, 2, 174, 176, 5, 12, 7, 3, 175, 75, 3, 2, 2, 2, 175, 92, 3, 2, 2, 2, 175, 100, 3, 2, 2, 2, 175, 106, 3, 2, 2, 2, 175, 116, 3, 2, 2, 2, 175, 139, 3, 2, 2, 2, 175, 155, 3, 2, 2, 2, 175, 157, 3, 2, 2, 2, 175, 159, 3, 2, 2, 2, 175, 161, 3, 2, 2, 2, 175, 163, 3, 2, 2, 2, 175, 167, 3, 2, 2, 2, 175, 168, 3, 2, 2, 2, 175, 169, 3, 2, 2, 2, 175, 170, 3, 2, 2, 2, 175, 171, 3, 2, 2, 2, 175, 172, 3, 2, 2, 2, 176, 222, 3, 2, 2, 2, 177, 178, 12, 17, 2, 2, 178, 179, 7, 39, 2, 2, 179, 221, 5, 12, 7, 18, 180, 181, 12, 16, 2, 2, 181, 182, 7, 40, 2, 2, 182, 221, 5, 12, 7, 17, 183, 184, 12, 15, 2, 2, 184, 185, 7, 37, 2, 2, 185, 221, 5, 12, 7, 16, 186, 187, 12, 14, 2, 2, 187, 188, 7, 38, 2, 2, 188, 221, 5, 12, 7, 15, 189, 190, 12, 13, 2, 2, 190, 191, 7, 41, 2, 2, 191, 221, 5, 12, 7, 14, 192, 193, 12, 12, 2, 2, 193, 194, 7, 42, 2, 2, 194, 221, 5, 12, 7, 13, 195, 196, 12, 11, 2, 2, 196, 197, 7, 43, 2, 2, 197, 221, 5, 12, 7, 12, 198, 201, 12, 27, 2, 2, 199, 200, 7, 10, 2, 2, 200, 202, 7, 33, 2, 2, 201, 199, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 3, 2, 2, 2, 203, 204, 7, 11, 2, 2, 204, 205, 7, 34, 2, 2, 205, 216, 7, 6, 2, 2, 206, 211, 5, 12, 7, 2, 207, 208, 7, 7, 2, 2, 208, 210, 5, 12, 7, 2, 209, 207, 3, 2, 2, 2, 210, 213, 3, 2, 2, 2, 211, 209, 3, 2, 2, 2, 211, 212, 3, 2, 2, 2, 212, 215, 3, 2, 2, 2, 213, 211, 3, 2, 2, 2, 214, 206, 3, 2, 2, 2, 215, 218, 3, 2, 2, 2, 216, 214, 3, 2, 2, 2, 216, 217, 3, 2, 2, 2, 217, 219, 3, 2, 2, 2, 218, 216, 3, 2, 2, 2, 219, 221, 7, 8, 2, 2, 220, 177, 3, 2, 2, 2, 220, 180, 3, 2, 2, 2, 220, 183, 3, 2, 2, 2, 220, 186, 3, 2, 2, 2, 220, 189, 3, 2, 2, 2, 220, 192, 3, 2, 2, 2, 220, 195, 3, 2, 2, 2, 220, 198, 3, 2, 2, 2, 221, 224, 3, 2, 2, 2, 222, 220, 3, 2, 2, 2, 222, 223, 3, 2, 2, 2, 223, 13, 3, 2, 2, 2, 224, 222, 3, 2, 2, 2, 22, 21, 27, 35, 47, 52, 67, 69, 83, 88, 112, 122, 130, 134, 151, 175, 201, 211, 216, 220, 222] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 50, 225, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 7, 7, 86, 10, 7, 12, 7, 14, 7, 89, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 110, 10, 7, 13, 7, 14, 7, 111, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 122, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 130, 10, 7, 7, 7, 132, 10, 7, 12, 7, 14, 7, 135, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 149, 10, 7, 13, 7, 14, 7, 150, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 175, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 201, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 209, 10, 7, 12, 7, 14, 7, 212, 11, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 7, 7, 220, 10, 7, 12, 7, 14, 7, 223, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 259, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 174, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 45, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 25, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 25, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 39, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 45, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 40, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 26, 2, 2, 40, 51, 7, 37, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 43, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 38, 2, 2, 55, 56, 7, 44, 2, 2, 56, 57, 7, 25, 2, 2, 57, 58, 7, 39, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 40, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 26, 2, 2, 62, 63, 7, 44, 2, 2, 63, 66, 7, 25, 2, 2, 64, 65, 7, 27, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 26, 2, 2, 71, 72, 7, 44, 2, 2, 72, 73, 7, 25, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 26, 2, 2, 76, 87, 7, 37, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 43, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 90, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 175, 7, 38, 2, 2, 91, 92, 7, 7, 2, 2, 92, 93, 5, 12, 7, 2, 93, 94, 7, 14, 2, 2, 94, 95, 5, 12, 7, 2, 95, 96, 7, 4, 2, 2, 96, 97, 5, 12, 7, 2, 97, 98, 7, 6, 2, 2, 98, 175, 3, 2, 2, 2, 99, 100, 7, 15, 2, 2, 100, 101, 5, 12, 7, 2, 101, 102, 7, 12, 2, 2, 102, 103, 5, 12, 7, 2, 103, 104, 7, 13, 2, 2, 104, 175, 3, 2, 2, 2, 105, 109, 7, 39, 2, 2, 106, 107, 5, 12, 7, 2, 107, 108, 7, 45, 2, 2, 108, 110, 3, 2, 2, 2, 109, 106, 3, 2, 2, 2, 110, 111, 3, 2, 2, 2, 111, 109, 3, 2, 2, 2, 111, 112, 3, 2, 2, 2, 112, 113, 3, 2, 2, 2, 113, 114, 7, 40, 2, 2, 114, 175, 3, 2, 2, 2, 115, 116, 7, 11, 2, 2, 116, 117, 7, 26, 2, 2, 117, 118, 7, 44, 2, 2, 118, 121, 7, 25, 2, 2, 119, 120, 7, 27, 2, 2, 120, 122, 5, 12, 7, 2, 121, 119, 3, 2, 2, 2, 121, 122, 3, 2, 2, 2, 122, 133, 3, 2, 2, 2, 123, 124, 7, 43, 2, 2, 124, 125, 7, 26, 2, 2, 125, 126, 7, 44, 2, 2, 126, 129, 7, 25, 2, 2, 127, 128, 7, 27, 2, 2, 128, 130, 5, 12, 7, 2, 129, 127, 3, 2, 2, 2, 129, 130, 3, 2, 2, 2, 130, 132, 3, 2, 2, 2, 131, 123, 3, 2, 2, 2, 132, 135, 3, 2, 2, 2, 133, 131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 136, 3, 2, 2, 2, 135, 133, 3, 2, 2, 2, 136, 137, 7, 8, 2, 2, 137, 175, 5, 12, 7, 22, 138, 139, 7, 16, 2, 2, 139, 140, 5, 12, 7, 2, 140, 148, 7, 19, 2, 2, 141, 142, 7, 26, 2, 2, 142, 143, 7, 44, 2, 2, 143, 144, 7, 25, 2, 2, 144, 145, 7, 28, 2, 2, 145, 146, 5, 12, 7, 2, 146, 147, 7, 45, 2, 2, 147, 149, 3, 2, 2, 2, 148, 141, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 150, 148, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 7, 17, 2, 2, 153, 175, 3, 2, 2, 2, 154, 155, 7, 18, 2, 2, 155, 175, 7, 25, 2, 2, 156, 157, 7, 36, 2, 2, 157, 175, 5, 12, 7, 19, 158, 159, 7, 10, 2, 2, 159, 175, 5, 12, 7, 18, 160, 161, 7, 20, 2, 2, 161, 175, 5, 12, 7, 10, 162, 163, 7, 37, 2, 2, 163, 164, 5, 12, 7, 2, 164, 165, 7, 38, 2, 2, 165, 175, 3, 2, 2, 2, 166, 175, 7, 26, 2, 2, 167, 175, 7, 24, 2, 2, 168, 175, 7, 22, 2, 2, 169, 175, 7, 21, 2, 2, 170, 175, 7, 5, 2, 2, 171, 172, 7, 26, 2, 2, 172, 173, 7, 27, 2, 2, 173, 175, 5, 12, 7, 3, 174, 74, 3, 2, 2, 2, 174, 91, 3, 2, 2, 2, 174, 99, 3, 2, 2, 2, 174, 105, 3, 2, 2, 2, 174, 115, 3, 2, 2, 2, 174, 138, 3, 2, 2, 2, 174, 154, 3, 2, 2, 2, 174, 156, 3, 2, 2, 2, 174, 158, 3, 2, 2, 2, 174, 160, 3, 2, 2, 2, 174, 162, 3, 2, 2, 2, 174, 166, 3, 2, 2, 2, 174, 167, 3, 2, 2, 2, 174, 168, 3, 2, 2, 2, 174, 169, 3, 2, 2, 2, 174, 170, 3, 2, 2, 2, 174, 171, 3, 2, 2, 2, 175, 221, 3, 2, 2, 2, 176, 177, 12, 17, 2, 2, 177, 178, 7, 31, 2, 2, 178, 220, 5, 12, 7, 18, 179, 180, 12, 16, 2, 2, 180, 181, 7, 32, 2, 2, 181, 220, 5, 12, 7, 17, 182, 183, 12, 15, 2, 2, 183, 184, 7, 29, 2, 2, 184, 220, 5, 12, 7, 16, 185, 186, 12, 14, 2, 2, 186, 187, 7, 30, 2, 2, 187, 220, 5, 12, 7, 15, 188, 189, 12, 13, 2, 2, 189, 190, 7, 33, 2, 2, 190, 220, 5, 12, 7, 14, 191, 192, 12, 12, 2, 2, 192, 193, 7, 34, 2, 2, 193, 220, 5, 12, 7, 13, 194, 195, 12, 11, 2, 2, 195, 196, 7, 35, 2, 2, 196, 220, 5, 12, 7, 12, 197, 200, 12, 27, 2, 2, 198, 199, 7, 41, 2, 2, 199, 201, 7, 25, 2, 2, 200, 198, 3, 2, 2, 2, 200, 201, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 7, 42, 2, 2, 203, 204, 7, 26, 2, 2, 204, 215, 7, 37, 2, 2, 205, 210, 5, 12, 7, 2, 206, 207, 7, 43, 2, 2, 207, 209, 5, 12, 7, 2, 208, 206, 3, 2, 2, 2, 209, 212, 3, 2, 2, 2, 210, 208, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 214, 3, 2, 2, 2, 212, 210, 3, 2, 2, 2, 213, 205, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 218, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 218, 220, 7, 38, 2, 2, 219, 176, 3, 2, 2, 2, 219, 179, 3, 2, 2, 2, 219, 182, 3, 2, 2, 2, 219, 185, 3, 2, 2, 2, 219, 188, 3, 2, 2, 2, 219, 191, 3, 2, 2, 2, 219, 194, 3, 2, 2, 2, 219, 197, 3, 2, 2, 2, 220, 223, 3, 2, 2, 2, 221, 219, 3, 2, 2, 2, 221, 222, 3, 2, 2, 2, 222, 13, 3, 2, 2, 2, 223, 221, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 87, 111, 121, 129, 133, 150, 174, 200, 210, 215, 219, 221] \ No newline at end of file diff --git a/COOL.py b/src/COOL.py similarity index 100% rename from COOL.py rename to src/COOL.py diff --git a/src/COOL.tokens b/src/COOL.tokens index 320277ee..bbdda836 100644 --- a/src/COOL.tokens +++ b/src/COOL.tokens @@ -1,68 +1,69 @@ -T__0=1 -T__1=2 -T__2=3 -T__3=4 -T__4=5 -T__5=6 -T__6=7 -T__7=8 -T__8=9 -CLASS=10 -ELSE=11 -FALSE=12 -FI=13 -IF=14 -IN=15 -INHERITS=16 -ISVOID=17 -LET=18 -LOOP=19 -POOL=20 -THEN=21 -WHILE=22 -CASE=23 -ESAC=24 -NEW=25 -OF=26 -NOT=27 -TRUE=28 -STRING=29 -INT=30 -TYPEID=31 -OBJECTID=32 -ASSIGNMENT=33 -CASE_ARROW=34 -ADD=35 -MINUS=36 -MULTIPLY=37 -DIVISION=38 -LESS_THAN=39 -LESS_EQUAL=40 -EQUAL=41 -INTEGER_NEGATIVE=42 -OPEN_COMMENT=43 -CLOSE_COMMENT=44 -COMMENT=45 -ONE_LINE_COMMENT=46 -WHITESPACE=47 -';'=1 -'{'=2 -'}'=3 -'('=4 -','=5 -')'=6 -':'=7 -'@'=8 -'.'=9 -'<-'=33 -'=>'=34 -'+'=35 -'-'=36 -'*'=37 -'/'=38 -'<'=39 -'<='=40 -'='=41 -'~'=42 -'(*'=43 -'*)'=44 +CLASS=1 +ELSE=2 +FALSE=3 +FI=4 +IF=5 +IN=6 +INHERITS=7 +ISVOID=8 +LET=9 +LOOP=10 +POOL=11 +THEN=12 +WHILE=13 +CASE=14 +ESAC=15 +NEW=16 +OF=17 +NOT=18 +TRUE=19 +STRING=20 +BREAK_STRING=21 +INT=22 +TYPEID=23 +OBJECTID=24 +ASSIGNMENT=25 +CASE_ARROW=26 +ADD=27 +MINUS=28 +MULTIPLY=29 +DIVISION=30 +LESS_THAN=31 +LESS_EQUAL=32 +EQUAL=33 +INTEGER_NEGATIVE=34 +OPEN_ROUND=35 +CLOSE_ROUND=36 +OPEN_CURLY=37 +CLOSE_CURLY=38 +AT=39 +DOT=40 +COMMA=41 +COLON=42 +SEMICOLON=43 +WHITESPACE=44 +ONE_LINE_COMMENT=45 +OPEN_COMMENT=46 +COMMENT=47 +CLOSE_COMMENT=48 +'<-'=25 +'=>'=26 +'+'=27 +'-'=28 +'*'=29 +'/'=30 +'<'=31 +'<='=32 +'='=33 +'~'=34 +'('=35 +')'=36 +'{'=37 +'}'=38 +'@'=39 +'.'=40 +','=41 +':'=42 +';'=43 +'(*'=46 +'*)'=48 diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index dd3d486b..5a9b2584 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -1,14 +1,35 @@ import sys +import os.path from antlr4 import * from COOLLexer import COOLLexer +from COOLLexerErrorListener import COOLLexerErrorListener from COOLParser import COOLParser +from COOLParserErrorListener import COOLParserErrorListener from COOLListener import COOLListener def main(argv): + if not os.path.isfile(argv[1]): + print("invalid input filename") + return + input = FileStream(argv[1]) + lexer = COOLLexer(input) + lexer.removeErrorListeners() + lexer.addErrorListener(COOLLexerErrorListener()) + token = lexer.nextToken() + while token.type != Token.EOF: + token = lexer.nextToken() + + if lexer.hasErrors: + return + + lexer.reset(); stream = CommonTokenStream(lexer) parser = COOLParser(stream) + parser.removeErrorListeners() + parser.addErrorListener(COOLParserErrorListener()) + tree = parser.program() if __name__ == '__main__': diff --git a/src/COOLLexer.py b/src/COOLLexer.py index d53e933d..bcb2349c 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -1,267 +1,34 @@ -# Generated from C:\Software\ANTLR\cool\COOL.g4 by ANTLR 4.7.2 -from antlr4 import * +import sys from io import StringIO from typing.io import TextIO -import sys - - - -def serializedATN(): - with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\61") - buf.write("\u0182\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7") - buf.write("\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r") - buf.write("\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23") - buf.write("\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30") - buf.write("\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36") - buf.write("\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\4%\t%") - buf.write("\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t,\4-\t-\4.") - buf.write("\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64") - buf.write("\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:") - buf.write("\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\t") - buf.write("C\4D\tD\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\7\3") - buf.write("\7\3\b\3\b\3\t\3\t\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3") - buf.write("\13\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3") - buf.write("\16\3\16\3\17\3\17\3\17\3\20\3\20\3\20\3\21\3\21\3\21") - buf.write("\3\21\3\21\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\22") - buf.write("\3\22\3\22\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24") - buf.write("\3\25\3\25\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3\27") - buf.write("\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3\30\3\31") - buf.write("\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32\3\33\3\33\3\33") - buf.write("\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\35\3\36\3\36") - buf.write("\3\36\7\36\u00fc\n\36\f\36\16\36\u00ff\13\36\3\36\3\36") - buf.write("\3\37\6\37\u0104\n\37\r\37\16\37\u0105\3 \3 \7 \u010a") - buf.write("\n \f \16 \u010d\13 \3!\3!\7!\u0111\n!\f!\16!\u0114\13") - buf.write("!\3\"\3\"\3\"\3#\3#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3") - buf.write("(\3)\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3") - buf.write("\60\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65") - buf.write("\3\66\3\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<\3<\3=") - buf.write("\3=\3=\5=\u0152\n=\3>\3>\3>\3>\3>\3>\3?\3?\3@\3@\3@\3") - buf.write("A\3A\3A\3B\3B\3B\7B\u0165\nB\fB\16B\u0168\13B\3B\3B\3") - buf.write("B\3B\3C\3C\3C\3C\7C\u0172\nC\fC\16C\u0175\13C\3C\5C\u0178") - buf.write("\nC\3C\3C\3D\6D\u017d\nD\rD\16D\u017e\3D\3D\3\u0166\2") - buf.write("E\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31") - buf.write("\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31") - buf.write("\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O") - buf.write(")Q*S+U,W\2Y\2[\2]\2_\2a\2c\2e\2g\2i\2k\2m\2o\2q\2s\2u") - buf.write("\2w\2y\2{\2}\2\177-\u0081.\u0083/\u0085\60\u0087\61\3") - buf.write("\2\34\4\2$$^^\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2") - buf.write("CCcc\4\2EEee\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4") - buf.write("\2NNnn\4\2PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVv") - buf.write("v\4\2WWww\4\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2") - buf.write("\62;CHch\3\2\f\f\5\2\13\f\16\17\"\"\2\u0178\2\3\3\2\2") - buf.write("\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2") - buf.write("\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25") - buf.write("\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3") - buf.write("\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2") - buf.write("\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2") - buf.write("\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\2") - buf.write("9\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2") - buf.write("\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2") - buf.write("\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2") - buf.write("\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085") - buf.write("\3\2\2\2\2\u0087\3\2\2\2\3\u0089\3\2\2\2\5\u008b\3\2\2") - buf.write("\2\7\u008d\3\2\2\2\t\u008f\3\2\2\2\13\u0091\3\2\2\2\r") - buf.write("\u0093\3\2\2\2\17\u0095\3\2\2\2\21\u0097\3\2\2\2\23\u0099") - buf.write("\3\2\2\2\25\u009b\3\2\2\2\27\u00a1\3\2\2\2\31\u00a6\3") - buf.write("\2\2\2\33\u00ac\3\2\2\2\35\u00af\3\2\2\2\37\u00b2\3\2") - buf.write("\2\2!\u00b5\3\2\2\2#\u00be\3\2\2\2%\u00c5\3\2\2\2\'\u00c9") - buf.write("\3\2\2\2)\u00ce\3\2\2\2+\u00d3\3\2\2\2-\u00d8\3\2\2\2") - buf.write("/\u00de\3\2\2\2\61\u00e3\3\2\2\2\63\u00e8\3\2\2\2\65\u00ec") - buf.write("\3\2\2\2\67\u00ef\3\2\2\29\u00f3\3\2\2\2;\u00f8\3\2\2") - buf.write("\2=\u0103\3\2\2\2?\u0107\3\2\2\2A\u010e\3\2\2\2C\u0115") - buf.write("\3\2\2\2E\u0118\3\2\2\2G\u011b\3\2\2\2I\u011d\3\2\2\2") - buf.write("K\u011f\3\2\2\2M\u0121\3\2\2\2O\u0123\3\2\2\2Q\u0125\3") - buf.write("\2\2\2S\u0128\3\2\2\2U\u012a\3\2\2\2W\u012c\3\2\2\2Y\u012e") - buf.write("\3\2\2\2[\u0130\3\2\2\2]\u0132\3\2\2\2_\u0134\3\2\2\2") - buf.write("a\u0136\3\2\2\2c\u0138\3\2\2\2e\u013a\3\2\2\2g\u013c\3") - buf.write("\2\2\2i\u013e\3\2\2\2k\u0140\3\2\2\2m\u0142\3\2\2\2o\u0144") - buf.write("\3\2\2\2q\u0146\3\2\2\2s\u0148\3\2\2\2u\u014a\3\2\2\2") - buf.write("w\u014c\3\2\2\2y\u014e\3\2\2\2{\u0153\3\2\2\2}\u0159\3") - buf.write("\2\2\2\177\u015b\3\2\2\2\u0081\u015e\3\2\2\2\u0083\u0161") - buf.write("\3\2\2\2\u0085\u016d\3\2\2\2\u0087\u017c\3\2\2\2\u0089") - buf.write("\u008a\7=\2\2\u008a\4\3\2\2\2\u008b\u008c\7}\2\2\u008c") - buf.write("\6\3\2\2\2\u008d\u008e\7\177\2\2\u008e\b\3\2\2\2\u008f") - buf.write("\u0090\7*\2\2\u0090\n\3\2\2\2\u0091\u0092\7.\2\2\u0092") - buf.write("\f\3\2\2\2\u0093\u0094\7+\2\2\u0094\16\3\2\2\2\u0095\u0096") - buf.write("\7<\2\2\u0096\20\3\2\2\2\u0097\u0098\7B\2\2\u0098\22\3") - buf.write("\2\2\2\u0099\u009a\7\60\2\2\u009a\24\3\2\2\2\u009b\u009c") - buf.write("\5Y-\2\u009c\u009d\5e\63\2\u009d\u009e\5W,\2\u009e\u009f") - buf.write("\5o8\2\u009f\u00a0\5o8\2\u00a0\26\3\2\2\2\u00a1\u00a2") - buf.write("\5]/\2\u00a2\u00a3\5e\63\2\u00a3\u00a4\5o8\2\u00a4\u00a5") - buf.write("\5]/\2\u00a5\30\3\2\2\2\u00a6\u00a7\7h\2\2\u00a7\u00a8") - buf.write("\5W,\2\u00a8\u00a9\5e\63\2\u00a9\u00aa\5o8\2\u00aa\u00ab") - buf.write("\5]/\2\u00ab\32\3\2\2\2\u00ac\u00ad\5_\60\2\u00ad\u00ae") - buf.write("\5c\62\2\u00ae\34\3\2\2\2\u00af\u00b0\5c\62\2\u00b0\u00b1") - buf.write("\5_\60\2\u00b1\36\3\2\2\2\u00b2\u00b3\5c\62\2\u00b3\u00b4") - buf.write("\5g\64\2\u00b4 \3\2\2\2\u00b5\u00b6\5c\62\2\u00b6\u00b7") - buf.write("\5g\64\2\u00b7\u00b8\5a\61\2\u00b8\u00b9\5]/\2\u00b9\u00ba") - buf.write("\5m\67\2\u00ba\u00bb\5c\62\2\u00bb\u00bc\5q9\2\u00bc\u00bd") - buf.write("\5o8\2\u00bd\"\3\2\2\2\u00be\u00bf\5c\62\2\u00bf\u00c0") - buf.write("\5o8\2\u00c0\u00c1\5u;\2\u00c1\u00c2\5i\65\2\u00c2\u00c3") - buf.write("\5c\62\2\u00c3\u00c4\5[.\2\u00c4$\3\2\2\2\u00c5\u00c6") - buf.write("\5e\63\2\u00c6\u00c7\5]/\2\u00c7\u00c8\5q9\2\u00c8&\3") - buf.write("\2\2\2\u00c9\u00ca\5e\63\2\u00ca\u00cb\5i\65\2\u00cb\u00cc") - buf.write("\5i\65\2\u00cc\u00cd\5k\66\2\u00cd(\3\2\2\2\u00ce\u00cf") - buf.write("\5k\66\2\u00cf\u00d0\5i\65\2\u00d0\u00d1\5i\65\2\u00d1") - buf.write("\u00d2\5e\63\2\u00d2*\3\2\2\2\u00d3\u00d4\5q9\2\u00d4") - buf.write("\u00d5\5a\61\2\u00d5\u00d6\5]/\2\u00d6\u00d7\5g\64\2\u00d7") - buf.write(",\3\2\2\2\u00d8\u00d9\5w<\2\u00d9\u00da\5a\61\2\u00da") - buf.write("\u00db\5c\62\2\u00db\u00dc\5e\63\2\u00dc\u00dd\5]/\2\u00dd") - buf.write(".\3\2\2\2\u00de\u00df\5Y-\2\u00df\u00e0\5W,\2\u00e0\u00e1") - buf.write("\5o8\2\u00e1\u00e2\5]/\2\u00e2\60\3\2\2\2\u00e3\u00e4") - buf.write("\5]/\2\u00e4\u00e5\5o8\2\u00e5\u00e6\5W,\2\u00e6\u00e7") - buf.write("\5Y-\2\u00e7\62\3\2\2\2\u00e8\u00e9\5g\64\2\u00e9\u00ea") - buf.write("\5]/\2\u00ea\u00eb\5w<\2\u00eb\64\3\2\2\2\u00ec\u00ed") - buf.write("\5i\65\2\u00ed\u00ee\5_\60\2\u00ee\66\3\2\2\2\u00ef\u00f0") - buf.write("\5g\64\2\u00f0\u00f1\5i\65\2\u00f1\u00f2\5q9\2\u00f28") - buf.write("\3\2\2\2\u00f3\u00f4\7v\2\2\u00f4\u00f5\5m\67\2\u00f5") - buf.write("\u00f6\5s:\2\u00f6\u00f7\5]/\2\u00f7:\3\2\2\2\u00f8\u00fd") - buf.write("\7$\2\2\u00f9\u00fc\5y=\2\u00fa\u00fc\n\2\2\2\u00fb\u00f9") - buf.write("\3\2\2\2\u00fb\u00fa\3\2\2\2\u00fc\u00ff\3\2\2\2\u00fd") - buf.write("\u00fb\3\2\2\2\u00fd\u00fe\3\2\2\2\u00fe\u0100\3\2\2\2") - buf.write("\u00ff\u00fd\3\2\2\2\u0100\u0101\7$\2\2\u0101<\3\2\2\2") - buf.write("\u0102\u0104\t\3\2\2\u0103\u0102\3\2\2\2\u0104\u0105\3") - buf.write("\2\2\2\u0105\u0103\3\2\2\2\u0105\u0106\3\2\2\2\u0106>") - buf.write("\3\2\2\2\u0107\u010b\t\4\2\2\u0108\u010a\t\5\2\2\u0109") - buf.write("\u0108\3\2\2\2\u010a\u010d\3\2\2\2\u010b\u0109\3\2\2\2") - buf.write("\u010b\u010c\3\2\2\2\u010c@\3\2\2\2\u010d\u010b\3\2\2") - buf.write("\2\u010e\u0112\t\6\2\2\u010f\u0111\t\5\2\2\u0110\u010f") - buf.write("\3\2\2\2\u0111\u0114\3\2\2\2\u0112\u0110\3\2\2\2\u0112") - buf.write("\u0113\3\2\2\2\u0113B\3\2\2\2\u0114\u0112\3\2\2\2\u0115") - buf.write("\u0116\7>\2\2\u0116\u0117\7/\2\2\u0117D\3\2\2\2\u0118") - buf.write("\u0119\7?\2\2\u0119\u011a\7@\2\2\u011aF\3\2\2\2\u011b") - buf.write("\u011c\7-\2\2\u011cH\3\2\2\2\u011d\u011e\7/\2\2\u011e") - buf.write("J\3\2\2\2\u011f\u0120\7,\2\2\u0120L\3\2\2\2\u0121\u0122") - buf.write("\7\61\2\2\u0122N\3\2\2\2\u0123\u0124\7>\2\2\u0124P\3\2") - buf.write("\2\2\u0125\u0126\7>\2\2\u0126\u0127\7?\2\2\u0127R\3\2") - buf.write("\2\2\u0128\u0129\7?\2\2\u0129T\3\2\2\2\u012a\u012b\7\u0080") - buf.write("\2\2\u012bV\3\2\2\2\u012c\u012d\t\7\2\2\u012dX\3\2\2\2") - buf.write("\u012e\u012f\t\b\2\2\u012fZ\3\2\2\2\u0130\u0131\t\t\2") - buf.write("\2\u0131\\\3\2\2\2\u0132\u0133\t\n\2\2\u0133^\3\2\2\2") - buf.write("\u0134\u0135\t\13\2\2\u0135`\3\2\2\2\u0136\u0137\t\f\2") - buf.write("\2\u0137b\3\2\2\2\u0138\u0139\t\r\2\2\u0139d\3\2\2\2\u013a") - buf.write("\u013b\t\16\2\2\u013bf\3\2\2\2\u013c\u013d\t\17\2\2\u013d") - buf.write("h\3\2\2\2\u013e\u013f\t\20\2\2\u013fj\3\2\2\2\u0140\u0141") - buf.write("\t\21\2\2\u0141l\3\2\2\2\u0142\u0143\t\22\2\2\u0143n\3") - buf.write("\2\2\2\u0144\u0145\t\23\2\2\u0145p\3\2\2\2\u0146\u0147") - buf.write("\t\24\2\2\u0147r\3\2\2\2\u0148\u0149\t\25\2\2\u0149t\3") - buf.write("\2\2\2\u014a\u014b\t\26\2\2\u014bv\3\2\2\2\u014c\u014d") - buf.write("\t\27\2\2\u014dx\3\2\2\2\u014e\u0151\7^\2\2\u014f\u0152") - buf.write("\t\30\2\2\u0150\u0152\5{>\2\u0151\u014f\3\2\2\2\u0151") - buf.write("\u0150\3\2\2\2\u0152z\3\2\2\2\u0153\u0154\7w\2\2\u0154") - buf.write("\u0155\5}?\2\u0155\u0156\5}?\2\u0156\u0157\5}?\2\u0157") - buf.write("\u0158\5}?\2\u0158|\3\2\2\2\u0159\u015a\t\31\2\2\u015a") - buf.write("~\3\2\2\2\u015b\u015c\7*\2\2\u015c\u015d\7,\2\2\u015d") - buf.write("\u0080\3\2\2\2\u015e\u015f\7,\2\2\u015f\u0160\7+\2\2\u0160") - buf.write("\u0082\3\2\2\2\u0161\u0166\5\177@\2\u0162\u0165\5\u0083") - buf.write("B\2\u0163\u0165\13\2\2\2\u0164\u0162\3\2\2\2\u0164\u0163") - buf.write("\3\2\2\2\u0165\u0168\3\2\2\2\u0166\u0167\3\2\2\2\u0166") - buf.write("\u0164\3\2\2\2\u0167\u0169\3\2\2\2\u0168\u0166\3\2\2\2") - buf.write("\u0169\u016a\5\u0081A\2\u016a\u016b\3\2\2\2\u016b\u016c") - buf.write("\bB\2\2\u016c\u0084\3\2\2\2\u016d\u016e\7/\2\2\u016e\u016f") - buf.write("\7/\2\2\u016f\u0173\3\2\2\2\u0170\u0172\n\32\2\2\u0171") - buf.write("\u0170\3\2\2\2\u0172\u0175\3\2\2\2\u0173\u0171\3\2\2\2") - buf.write("\u0173\u0174\3\2\2\2\u0174\u0177\3\2\2\2\u0175\u0173\3") - buf.write("\2\2\2\u0176\u0178\7\f\2\2\u0177\u0176\3\2\2\2\u0177\u0178") - buf.write("\3\2\2\2\u0178\u0179\3\2\2\2\u0179\u017a\bC\2\2\u017a") - buf.write("\u0086\3\2\2\2\u017b\u017d\t\33\2\2\u017c\u017b\3\2\2") - buf.write("\2\u017d\u017e\3\2\2\2\u017e\u017c\3\2\2\2\u017e\u017f") - buf.write("\3\2\2\2\u017f\u0180\3\2\2\2\u0180\u0181\bD\2\2\u0181") - buf.write("\u0088\3\2\2\2\16\2\u00fb\u00fd\u0105\u010b\u0112\u0151") - buf.write("\u0164\u0166\u0173\u0177\u017e\3\b\2\2") - return buf.getvalue() - - -class COOLLexer(Lexer): - - atn = ATNDeserializer().deserialize(serializedATN()) - - decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] - - T__0 = 1 - T__1 = 2 - T__2 = 3 - T__3 = 4 - T__4 = 5 - T__5 = 6 - T__6 = 7 - T__7 = 8 - T__8 = 9 - CLASS = 10 - ELSE = 11 - FALSE = 12 - FI = 13 - IF = 14 - IN = 15 - INHERITS = 16 - ISVOID = 17 - LET = 18 - LOOP = 19 - POOL = 20 - THEN = 21 - WHILE = 22 - CASE = 23 - ESAC = 24 - NEW = 25 - OF = 26 - NOT = 27 - TRUE = 28 - STRING = 29 - INT = 30 - TYPEID = 31 - OBJECTID = 32 - ASSIGNMENT = 33 - CASE_ARROW = 34 - ADD = 35 - MINUS = 36 - MULTIPLY = 37 - DIVISION = 38 - LESS_THAN = 39 - LESS_EQUAL = 40 - EQUAL = 41 - INTEGER_NEGATIVE = 42 - OPEN_COMMENT = 43 - CLOSE_COMMENT = 44 - COMMENT = 45 - ONE_LINE_COMMENT = 46 - WHITESPACE = 47 - - channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] - - modeNames = [ "DEFAULT_MODE" ] - - literalNames = [ "", - "';'", "'{'", "'}'", "'('", "','", "')'", "':'", "'@'", "'.'", - "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", "'<='", "'='", - "'~'", "'(*'", "'*)'" ] - - symbolicNames = [ "", - "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", - "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", - "OF", "NOT", "TRUE", "STRING", "INT", "TYPEID", "OBJECTID", - "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", - "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_COMMENT", - "CLOSE_COMMENT", "COMMENT", "ONE_LINE_COMMENT", "WHITESPACE" ] - - ruleNames = [ "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", - "T__7", "T__8", "CLASS", "ELSE", "FALSE", "FI", "IF", - "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", - "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", - "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", - "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", - "EQUAL", "INTEGER_NEGATIVE", "A", "C", "D", "E", "F", - "H", "I", "L", "N", "O", "P", "R", "S", "T", "U", "V", - "W", "ESC", "UNICODE", "HEX", "OPEN_COMMENT", "CLOSE_COMMENT", - "COMMENT", "ONE_LINE_COMMENT", "WHITESPACE" ] - - grammarFileName = "COOL.g4" - +from antlr4 import * +from COOL_LEX import COOL_LEX +from antlr4.CommonTokenFactory import CommonTokenFactory +from antlr4.atn.LexerATNSimulator import LexerATNSimulator +from antlr4.InputStream import InputStream +from antlr4.Recognizer import Recognizer +from antlr4.Token import Token +from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException + +class COOLLexer(COOL_LEX): def __init__(self, input=None, output:TextIO = sys.stdout): super().__init__(input, output) - self.checkVersion("4.7.2") - self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) - self._actions = None - self._predicates = None + self._hasErrors = False + + def notifyListeners(self, e:LexerNoViableAltException): + self._hasErrors = True + + start = self._tokenStartCharIndex + stop = self._input.index + text = self._input.getText(start, stop) + msg = "'" + self.getErrorDisplay(text) + "'" + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, self._token, self._tokenStartLine, self._tokenStartColumn, msg, e) + def reset(self): + super().reset() + self._hasErrors = False + @property + def hasErrors(self): + return self._hasErrors \ No newline at end of file diff --git a/COOLLexerErrorListener.py b/src/COOLLexerErrorListener.py similarity index 100% rename from COOLLexerErrorListener.py rename to src/COOLLexerErrorListener.py diff --git a/src/COOLListener.py b/src/COOLListener.py index 50a72320..e5e5d915 100644 --- a/src/COOLListener.py +++ b/src/COOLListener.py @@ -1,298 +1,289 @@ -# Generated from C:\Software\ANTLR\cool\COOL.g4 by ANTLR 4.7.2 +# Generated from COOL.g4 by ANTLR 4.7.2 from antlr4 import * if __name__ is not None and "." in __name__: - from .COOLParser import COOLParser + from .COOL import COOL else: - from COOLParser import COOLParser + from COOL import COOL -# This class defines a complete listener for a parse tree produced by COOLParser. +# This class defines a complete listener for a parse tree produced by COOL. class COOLListener(ParseTreeListener): - # Enter a parse tree produced by COOLParser#program. - def enterProgram(self, ctx:COOLParser.ProgramContext): + # Enter a parse tree produced by COOL#program. + def enterProgram(self, ctx:COOL.ProgramContext): pass - # Exit a parse tree produced by COOLParser#program. - def exitProgram(self, ctx:COOLParser.ProgramContext): + # Exit a parse tree produced by COOL#program. + def exitProgram(self, ctx:COOL.ProgramContext): pass - # Enter a parse tree produced by COOLParser#classes. - def enterClasses(self, ctx:COOLParser.ClassesContext): + # Enter a parse tree produced by COOL#classes. + def enterClasses(self, ctx:COOL.ClassesContext): pass - # Exit a parse tree produced by COOLParser#classes. - def exitClasses(self, ctx:COOLParser.ClassesContext): + # Exit a parse tree produced by COOL#classes. + def exitClasses(self, ctx:COOL.ClassesContext): pass - # Enter a parse tree produced by COOLParser#eof. - def enterEof(self, ctx:COOLParser.EofContext): + # Enter a parse tree produced by COOL#classDefine. + def enterClassDefine(self, ctx:COOL.ClassDefineContext): pass - # Exit a parse tree produced by COOLParser#eof. - def exitEof(self, ctx:COOLParser.EofContext): + # Exit a parse tree produced by COOL#classDefine. + def exitClassDefine(self, ctx:COOL.ClassDefineContext): pass - # Enter a parse tree produced by COOLParser#classDefine. - def enterClassDefine(self, ctx:COOLParser.ClassDefineContext): + # Enter a parse tree produced by COOL#method. + def enterMethod(self, ctx:COOL.MethodContext): pass - # Exit a parse tree produced by COOLParser#classDefine. - def exitClassDefine(self, ctx:COOLParser.ClassDefineContext): + # Exit a parse tree produced by COOL#method. + def exitMethod(self, ctx:COOL.MethodContext): pass - # Enter a parse tree produced by COOLParser#method. - def enterMethod(self, ctx:COOLParser.MethodContext): + # Enter a parse tree produced by COOL#property. + def enterProperty(self, ctx:COOL.PropertyContext): pass - # Exit a parse tree produced by COOLParser#method. - def exitMethod(self, ctx:COOLParser.MethodContext): + # Exit a parse tree produced by COOL#property. + def exitProperty(self, ctx:COOL.PropertyContext): pass - # Enter a parse tree produced by COOLParser#property. - def enterProperty(self, ctx:COOLParser.PropertyContext): + # Enter a parse tree produced by COOL#formal. + def enterFormal(self, ctx:COOL.FormalContext): pass - # Exit a parse tree produced by COOLParser#property. - def exitProperty(self, ctx:COOLParser.PropertyContext): + # Exit a parse tree produced by COOL#formal. + def exitFormal(self, ctx:COOL.FormalContext): pass - # Enter a parse tree produced by COOLParser#formal. - def enterFormal(self, ctx:COOLParser.FormalContext): + # Enter a parse tree produced by COOL#letIn. + def enterLetIn(self, ctx:COOL.LetInContext): pass - # Exit a parse tree produced by COOLParser#formal. - def exitFormal(self, ctx:COOLParser.FormalContext): + # Exit a parse tree produced by COOL#letIn. + def exitLetIn(self, ctx:COOL.LetInContext): pass - # Enter a parse tree produced by COOLParser#letIn. - def enterLetIn(self, ctx:COOLParser.LetInContext): + # Enter a parse tree produced by COOL#minus. + def enterMinus(self, ctx:COOL.MinusContext): pass - # Exit a parse tree produced by COOLParser#letIn. - def exitLetIn(self, ctx:COOLParser.LetInContext): + # Exit a parse tree produced by COOL#minus. + def exitMinus(self, ctx:COOL.MinusContext): pass - # Enter a parse tree produced by COOLParser#minus. - def enterMinus(self, ctx:COOLParser.MinusContext): + # Enter a parse tree produced by COOL#string. + def enterString(self, ctx:COOL.StringContext): pass - # Exit a parse tree produced by COOLParser#minus. - def exitMinus(self, ctx:COOLParser.MinusContext): + # Exit a parse tree produced by COOL#string. + def exitString(self, ctx:COOL.StringContext): pass - # Enter a parse tree produced by COOLParser#string. - def enterString(self, ctx:COOLParser.StringContext): + # Enter a parse tree produced by COOL#isvoid. + def enterIsvoid(self, ctx:COOL.IsvoidContext): pass - # Exit a parse tree produced by COOLParser#string. - def exitString(self, ctx:COOLParser.StringContext): + # Exit a parse tree produced by COOL#isvoid. + def exitIsvoid(self, ctx:COOL.IsvoidContext): pass - # Enter a parse tree produced by COOLParser#isvoid. - def enterIsvoid(self, ctx:COOLParser.IsvoidContext): + # Enter a parse tree produced by COOL#while. + def enterWhile(self, ctx:COOL.WhileContext): pass - # Exit a parse tree produced by COOLParser#isvoid. - def exitIsvoid(self, ctx:COOLParser.IsvoidContext): + # Exit a parse tree produced by COOL#while. + def exitWhile(self, ctx:COOL.WhileContext): pass - # Enter a parse tree produced by COOLParser#while. - def enterWhile(self, ctx:COOLParser.WhileContext): + # Enter a parse tree produced by COOL#division. + def enterDivision(self, ctx:COOL.DivisionContext): pass - # Exit a parse tree produced by COOLParser#while. - def exitWhile(self, ctx:COOLParser.WhileContext): + # Exit a parse tree produced by COOL#division. + def exitDivision(self, ctx:COOL.DivisionContext): pass - # Enter a parse tree produced by COOLParser#division. - def enterDivision(self, ctx:COOLParser.DivisionContext): + # Enter a parse tree produced by COOL#negative. + def enterNegative(self, ctx:COOL.NegativeContext): pass - # Exit a parse tree produced by COOLParser#division. - def exitDivision(self, ctx:COOLParser.DivisionContext): + # Exit a parse tree produced by COOL#negative. + def exitNegative(self, ctx:COOL.NegativeContext): pass - # Enter a parse tree produced by COOLParser#negative. - def enterNegative(self, ctx:COOLParser.NegativeContext): + # Enter a parse tree produced by COOL#boolNot. + def enterBoolNot(self, ctx:COOL.BoolNotContext): pass - # Exit a parse tree produced by COOLParser#negative. - def exitNegative(self, ctx:COOLParser.NegativeContext): + # Exit a parse tree produced by COOL#boolNot. + def exitBoolNot(self, ctx:COOL.BoolNotContext): pass - # Enter a parse tree produced by COOLParser#boolNot. - def enterBoolNot(self, ctx:COOLParser.BoolNotContext): + # Enter a parse tree produced by COOL#lessThan. + def enterLessThan(self, ctx:COOL.LessThanContext): pass - # Exit a parse tree produced by COOLParser#boolNot. - def exitBoolNot(self, ctx:COOLParser.BoolNotContext): + # Exit a parse tree produced by COOL#lessThan. + def exitLessThan(self, ctx:COOL.LessThanContext): pass - # Enter a parse tree produced by COOLParser#lessThan. - def enterLessThan(self, ctx:COOLParser.LessThanContext): + # Enter a parse tree produced by COOL#block. + def enterBlock(self, ctx:COOL.BlockContext): pass - # Exit a parse tree produced by COOLParser#lessThan. - def exitLessThan(self, ctx:COOLParser.LessThanContext): + # Exit a parse tree produced by COOL#block. + def exitBlock(self, ctx:COOL.BlockContext): pass - # Enter a parse tree produced by COOLParser#block. - def enterBlock(self, ctx:COOLParser.BlockContext): + # Enter a parse tree produced by COOL#id. + def enterId(self, ctx:COOL.IdContext): pass - # Exit a parse tree produced by COOLParser#block. - def exitBlock(self, ctx:COOLParser.BlockContext): + # Exit a parse tree produced by COOL#id. + def exitId(self, ctx:COOL.IdContext): pass - # Enter a parse tree produced by COOLParser#id. - def enterId(self, ctx:COOLParser.IdContext): + # Enter a parse tree produced by COOL#multiply. + def enterMultiply(self, ctx:COOL.MultiplyContext): pass - # Exit a parse tree produced by COOLParser#id. - def exitId(self, ctx:COOLParser.IdContext): + # Exit a parse tree produced by COOL#multiply. + def exitMultiply(self, ctx:COOL.MultiplyContext): pass - # Enter a parse tree produced by COOLParser#multiply. - def enterMultiply(self, ctx:COOLParser.MultiplyContext): + # Enter a parse tree produced by COOL#if. + def enterIf(self, ctx:COOL.IfContext): pass - # Exit a parse tree produced by COOLParser#multiply. - def exitMultiply(self, ctx:COOLParser.MultiplyContext): + # Exit a parse tree produced by COOL#if. + def exitIf(self, ctx:COOL.IfContext): pass - # Enter a parse tree produced by COOLParser#if. - def enterIf(self, ctx:COOLParser.IfContext): + # Enter a parse tree produced by COOL#case. + def enterCase(self, ctx:COOL.CaseContext): pass - # Exit a parse tree produced by COOLParser#if. - def exitIf(self, ctx:COOLParser.IfContext): + # Exit a parse tree produced by COOL#case. + def exitCase(self, ctx:COOL.CaseContext): pass - # Enter a parse tree produced by COOLParser#case. - def enterCase(self, ctx:COOLParser.CaseContext): + # Enter a parse tree produced by COOL#ownMethodCall. + def enterOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): pass - # Exit a parse tree produced by COOLParser#case. - def exitCase(self, ctx:COOLParser.CaseContext): + # Exit a parse tree produced by COOL#ownMethodCall. + def exitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): pass - # Enter a parse tree produced by COOLParser#ownMethodCall. - def enterOwnMethodCall(self, ctx:COOLParser.OwnMethodCallContext): + # Enter a parse tree produced by COOL#add. + def enterAdd(self, ctx:COOL.AddContext): pass - # Exit a parse tree produced by COOLParser#ownMethodCall. - def exitOwnMethodCall(self, ctx:COOLParser.OwnMethodCallContext): + # Exit a parse tree produced by COOL#add. + def exitAdd(self, ctx:COOL.AddContext): pass - # Enter a parse tree produced by COOLParser#add. - def enterAdd(self, ctx:COOLParser.AddContext): + # Enter a parse tree produced by COOL#new. + def enterNew(self, ctx:COOL.NewContext): pass - # Exit a parse tree produced by COOLParser#add. - def exitAdd(self, ctx:COOLParser.AddContext): + # Exit a parse tree produced by COOL#new. + def exitNew(self, ctx:COOL.NewContext): pass - # Enter a parse tree produced by COOLParser#new. - def enterNew(self, ctx:COOLParser.NewContext): + # Enter a parse tree produced by COOL#parentheses. + def enterParentheses(self, ctx:COOL.ParenthesesContext): pass - # Exit a parse tree produced by COOLParser#new. - def exitNew(self, ctx:COOLParser.NewContext): + # Exit a parse tree produced by COOL#parentheses. + def exitParentheses(self, ctx:COOL.ParenthesesContext): pass - # Enter a parse tree produced by COOLParser#parentheses. - def enterParentheses(self, ctx:COOLParser.ParenthesesContext): + # Enter a parse tree produced by COOL#assignment. + def enterAssignment(self, ctx:COOL.AssignmentContext): pass - # Exit a parse tree produced by COOLParser#parentheses. - def exitParentheses(self, ctx:COOLParser.ParenthesesContext): + # Exit a parse tree produced by COOL#assignment. + def exitAssignment(self, ctx:COOL.AssignmentContext): pass - # Enter a parse tree produced by COOLParser#assignment. - def enterAssignment(self, ctx:COOLParser.AssignmentContext): + # Enter a parse tree produced by COOL#false. + def enterFalse(self, ctx:COOL.FalseContext): pass - # Exit a parse tree produced by COOLParser#assignment. - def exitAssignment(self, ctx:COOLParser.AssignmentContext): + # Exit a parse tree produced by COOL#false. + def exitFalse(self, ctx:COOL.FalseContext): pass - # Enter a parse tree produced by COOLParser#false. - def enterFalse(self, ctx:COOLParser.FalseContext): + # Enter a parse tree produced by COOL#int. + def enterInt(self, ctx:COOL.IntContext): pass - # Exit a parse tree produced by COOLParser#false. - def exitFalse(self, ctx:COOLParser.FalseContext): + # Exit a parse tree produced by COOL#int. + def exitInt(self, ctx:COOL.IntContext): pass - # Enter a parse tree produced by COOLParser#int. - def enterInt(self, ctx:COOLParser.IntContext): + # Enter a parse tree produced by COOL#equal. + def enterEqual(self, ctx:COOL.EqualContext): pass - # Exit a parse tree produced by COOLParser#int. - def exitInt(self, ctx:COOLParser.IntContext): + # Exit a parse tree produced by COOL#equal. + def exitEqual(self, ctx:COOL.EqualContext): pass - # Enter a parse tree produced by COOLParser#equal. - def enterEqual(self, ctx:COOLParser.EqualContext): + # Enter a parse tree produced by COOL#true. + def enterTrue(self, ctx:COOL.TrueContext): pass - # Exit a parse tree produced by COOLParser#equal. - def exitEqual(self, ctx:COOLParser.EqualContext): + # Exit a parse tree produced by COOL#true. + def exitTrue(self, ctx:COOL.TrueContext): pass - # Enter a parse tree produced by COOLParser#true. - def enterTrue(self, ctx:COOLParser.TrueContext): + # Enter a parse tree produced by COOL#lessEqual. + def enterLessEqual(self, ctx:COOL.LessEqualContext): pass - # Exit a parse tree produced by COOLParser#true. - def exitTrue(self, ctx:COOLParser.TrueContext): + # Exit a parse tree produced by COOL#lessEqual. + def exitLessEqual(self, ctx:COOL.LessEqualContext): pass - # Enter a parse tree produced by COOLParser#lessEqual. - def enterLessEqual(self, ctx:COOLParser.LessEqualContext): + # Enter a parse tree produced by COOL#methodCall. + def enterMethodCall(self, ctx:COOL.MethodCallContext): pass - # Exit a parse tree produced by COOLParser#lessEqual. - def exitLessEqual(self, ctx:COOLParser.LessEqualContext): - pass - - - # Enter a parse tree produced by COOLParser#methodCall. - def enterMethodCall(self, ctx:COOLParser.MethodCallContext): - pass - - # Exit a parse tree produced by COOLParser#methodCall. - def exitMethodCall(self, ctx:COOLParser.MethodCallContext): + # Exit a parse tree produced by COOL#methodCall. + def exitMethodCall(self, ctx:COOL.MethodCallContext): pass diff --git a/src/COOLParser.py b/src/COOLParser.py index d30ff78b..7f3ad8ac 100644 --- a/src/COOLParser.py +++ b/src/COOLParser.py @@ -1,1757 +1,24 @@ -# Generated from C:\Software\ANTLR\cool\COOL.g4 by ANTLR 4.7.2 -# encoding: utf-8 -from antlr4 import * +import sys from io import StringIO from typing.io import TextIO -import sys - - -def serializedATN(): - with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\61") - buf.write("\u00e2\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") - buf.write("\3\2\3\2\3\3\3\3\3\3\3\3\3\3\5\3\26\n\3\3\4\3\4\3\4\3") - buf.write("\4\5\4\34\n\4\3\4\3\4\3\4\3\4\7\4\"\n\4\f\4\16\4%\13\4") - buf.write("\3\4\3\4\3\5\3\5\3\5\3\5\3\5\7\5.\n\5\f\5\16\5\61\13\5") - buf.write("\7\5\63\n\5\f\5\16\5\66\13\5\3\5\3\5\3\5\3\5\3\5\3\5\3") - buf.write("\5\3\5\3\5\3\5\3\5\3\5\5\5D\n\5\5\5F\n\5\3\6\3\6\3\6\3") - buf.write("\6\3\7\3\7\3\7\3\7\3\7\3\7\7\7R\n\7\f\7\16\7U\13\7\7\7") - buf.write("W\n\7\f\7\16\7Z\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") - buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\6\7o\n\7\r") - buf.write("\7\16\7p\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\5\7{\n\7\3\7") - buf.write("\3\7\3\7\3\7\3\7\3\7\5\7\u0083\n\7\7\7\u0085\n\7\f\7\16") - buf.write("\7\u0088\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\6\7\u0096\n\7\r\7\16\7\u0097\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") - buf.write("\7\3\7\3\7\3\7\3\7\5\7\u00b0\n\7\3\7\3\7\3\7\3\7\3\7\3") - buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\3\7\3\7\3\7\5\7\u00ca\n\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\7\7\u00d2\n\7\f\7\16\7\u00d5\13\7\7\7\u00d7\n\7\f") - buf.write("\7\16\7\u00da\13\7\3\7\7\7\u00dd\n\7\f\7\16\7\u00e0\13") - buf.write("\7\3\7\2\3\f\b\2\4\6\b\n\f\2\2\2\u0104\2\16\3\2\2\2\4") - buf.write("\25\3\2\2\2\6\27\3\2\2\2\bE\3\2\2\2\nG\3\2\2\2\f\u00af") - buf.write("\3\2\2\2\16\17\5\4\3\2\17\3\3\2\2\2\20\21\5\6\4\2\21\22") - buf.write("\7\3\2\2\22\23\5\4\3\2\23\26\3\2\2\2\24\26\7\2\2\3\25") - buf.write("\20\3\2\2\2\25\24\3\2\2\2\26\5\3\2\2\2\27\30\7\f\2\2\30") - buf.write("\33\7!\2\2\31\32\7\22\2\2\32\34\7!\2\2\33\31\3\2\2\2\33") - buf.write("\34\3\2\2\2\34\35\3\2\2\2\35#\7\4\2\2\36\37\5\b\5\2\37") - buf.write(" \7\3\2\2 \"\3\2\2\2!\36\3\2\2\2\"%\3\2\2\2#!\3\2\2\2") - buf.write("#$\3\2\2\2$&\3\2\2\2%#\3\2\2\2&\'\7\5\2\2\'\7\3\2\2\2") - buf.write("()\7\"\2\2)\64\7\6\2\2*/\5\n\6\2+,\7\7\2\2,.\5\n\6\2-") - buf.write("+\3\2\2\2.\61\3\2\2\2/-\3\2\2\2/\60\3\2\2\2\60\63\3\2") - buf.write("\2\2\61/\3\2\2\2\62*\3\2\2\2\63\66\3\2\2\2\64\62\3\2\2") - buf.write("\2\64\65\3\2\2\2\65\67\3\2\2\2\66\64\3\2\2\2\678\7\b\2") - buf.write("\289\7\t\2\29:\7!\2\2:;\7\4\2\2;<\5\f\7\2<=\7\5\2\2=F") - buf.write("\3\2\2\2>?\7\"\2\2?@\7\t\2\2@C\7!\2\2AB\7#\2\2BD\5\f\7") - buf.write("\2CA\3\2\2\2CD\3\2\2\2DF\3\2\2\2E(\3\2\2\2E>\3\2\2\2F") - buf.write("\t\3\2\2\2GH\7\"\2\2HI\7\t\2\2IJ\7!\2\2J\13\3\2\2\2KL") - buf.write("\b\7\1\2LM\7\"\2\2MX\7\6\2\2NS\5\f\7\2OP\7\7\2\2PR\5\f") - buf.write("\7\2QO\3\2\2\2RU\3\2\2\2SQ\3\2\2\2ST\3\2\2\2TW\3\2\2\2") - buf.write("US\3\2\2\2VN\3\2\2\2WZ\3\2\2\2XV\3\2\2\2XY\3\2\2\2Y[\3") - buf.write("\2\2\2ZX\3\2\2\2[\u00b0\7\b\2\2\\]\7\20\2\2]^\5\f\7\2") - buf.write("^_\7\27\2\2_`\5\f\7\2`a\7\r\2\2ab\5\f\7\2bc\7\17\2\2c") - buf.write("\u00b0\3\2\2\2de\7\30\2\2ef\5\f\7\2fg\7\25\2\2gh\5\f\7") - buf.write("\2hi\7\26\2\2i\u00b0\3\2\2\2jn\7\4\2\2kl\5\f\7\2lm\7\3") - buf.write("\2\2mo\3\2\2\2nk\3\2\2\2op\3\2\2\2pn\3\2\2\2pq\3\2\2\2") - buf.write("qr\3\2\2\2rs\7\5\2\2s\u00b0\3\2\2\2tu\7\24\2\2uv\7\"\2") - buf.write("\2vw\7\t\2\2wz\7!\2\2xy\7#\2\2y{\5\f\7\2zx\3\2\2\2z{\3") - buf.write("\2\2\2{\u0086\3\2\2\2|}\7\7\2\2}~\7\"\2\2~\177\7\t\2\2") - buf.write("\177\u0082\7!\2\2\u0080\u0081\7#\2\2\u0081\u0083\5\f\7") - buf.write("\2\u0082\u0080\3\2\2\2\u0082\u0083\3\2\2\2\u0083\u0085") - buf.write("\3\2\2\2\u0084|\3\2\2\2\u0085\u0088\3\2\2\2\u0086\u0084") - buf.write("\3\2\2\2\u0086\u0087\3\2\2\2\u0087\u0089\3\2\2\2\u0088") - buf.write("\u0086\3\2\2\2\u0089\u008a\7\21\2\2\u008a\u00b0\5\f\7") - buf.write("\26\u008b\u008c\7\31\2\2\u008c\u008d\5\f\7\2\u008d\u0095") - buf.write("\7\34\2\2\u008e\u008f\7\"\2\2\u008f\u0090\7\t\2\2\u0090") - buf.write("\u0091\7!\2\2\u0091\u0092\7$\2\2\u0092\u0093\5\f\7\2\u0093") - buf.write("\u0094\7\3\2\2\u0094\u0096\3\2\2\2\u0095\u008e\3\2\2\2") - buf.write("\u0096\u0097\3\2\2\2\u0097\u0095\3\2\2\2\u0097\u0098\3") - buf.write("\2\2\2\u0098\u0099\3\2\2\2\u0099\u009a\7\32\2\2\u009a") - buf.write("\u00b0\3\2\2\2\u009b\u009c\7\33\2\2\u009c\u00b0\7!\2\2") - buf.write("\u009d\u009e\7,\2\2\u009e\u00b0\5\f\7\23\u009f\u00a0\7") - buf.write("\23\2\2\u00a0\u00b0\5\f\7\22\u00a1\u00a2\7\35\2\2\u00a2") - buf.write("\u00b0\5\f\7\n\u00a3\u00a4\7\6\2\2\u00a4\u00a5\5\f\7\2") - buf.write("\u00a5\u00a6\7\b\2\2\u00a6\u00b0\3\2\2\2\u00a7\u00b0\7") - buf.write("\"\2\2\u00a8\u00b0\7 \2\2\u00a9\u00b0\7\37\2\2\u00aa\u00b0") - buf.write("\7\36\2\2\u00ab\u00b0\7\16\2\2\u00ac\u00ad\7\"\2\2\u00ad") - buf.write("\u00ae\7#\2\2\u00ae\u00b0\5\f\7\3\u00afK\3\2\2\2\u00af") - buf.write("\\\3\2\2\2\u00afd\3\2\2\2\u00afj\3\2\2\2\u00aft\3\2\2") - buf.write("\2\u00af\u008b\3\2\2\2\u00af\u009b\3\2\2\2\u00af\u009d") - buf.write("\3\2\2\2\u00af\u009f\3\2\2\2\u00af\u00a1\3\2\2\2\u00af") - buf.write("\u00a3\3\2\2\2\u00af\u00a7\3\2\2\2\u00af\u00a8\3\2\2\2") - buf.write("\u00af\u00a9\3\2\2\2\u00af\u00aa\3\2\2\2\u00af\u00ab\3") - buf.write("\2\2\2\u00af\u00ac\3\2\2\2\u00b0\u00de\3\2\2\2\u00b1\u00b2") - buf.write("\f\21\2\2\u00b2\u00b3\7\'\2\2\u00b3\u00dd\5\f\7\22\u00b4") - buf.write("\u00b5\f\20\2\2\u00b5\u00b6\7(\2\2\u00b6\u00dd\5\f\7\21") - buf.write("\u00b7\u00b8\f\17\2\2\u00b8\u00b9\7%\2\2\u00b9\u00dd\5") - buf.write("\f\7\20\u00ba\u00bb\f\16\2\2\u00bb\u00bc\7&\2\2\u00bc") - buf.write("\u00dd\5\f\7\17\u00bd\u00be\f\r\2\2\u00be\u00bf\7)\2\2") - buf.write("\u00bf\u00dd\5\f\7\16\u00c0\u00c1\f\f\2\2\u00c1\u00c2") - buf.write("\7*\2\2\u00c2\u00dd\5\f\7\r\u00c3\u00c4\f\13\2\2\u00c4") - buf.write("\u00c5\7+\2\2\u00c5\u00dd\5\f\7\f\u00c6\u00c9\f\33\2\2") - buf.write("\u00c7\u00c8\7\n\2\2\u00c8\u00ca\7!\2\2\u00c9\u00c7\3") - buf.write("\2\2\2\u00c9\u00ca\3\2\2\2\u00ca\u00cb\3\2\2\2\u00cb\u00cc") - buf.write("\7\13\2\2\u00cc\u00cd\7\"\2\2\u00cd\u00d8\7\6\2\2\u00ce") - buf.write("\u00d3\5\f\7\2\u00cf\u00d0\7\7\2\2\u00d0\u00d2\5\f\7\2") - buf.write("\u00d1\u00cf\3\2\2\2\u00d2\u00d5\3\2\2\2\u00d3\u00d1\3") - buf.write("\2\2\2\u00d3\u00d4\3\2\2\2\u00d4\u00d7\3\2\2\2\u00d5\u00d3") - buf.write("\3\2\2\2\u00d6\u00ce\3\2\2\2\u00d7\u00da\3\2\2\2\u00d8") - buf.write("\u00d6\3\2\2\2\u00d8\u00d9\3\2\2\2\u00d9\u00db\3\2\2\2") - buf.write("\u00da\u00d8\3\2\2\2\u00db\u00dd\7\b\2\2\u00dc\u00b1\3") - buf.write("\2\2\2\u00dc\u00b4\3\2\2\2\u00dc\u00b7\3\2\2\2\u00dc\u00ba") - buf.write("\3\2\2\2\u00dc\u00bd\3\2\2\2\u00dc\u00c0\3\2\2\2\u00dc") - buf.write("\u00c3\3\2\2\2\u00dc\u00c6\3\2\2\2\u00dd\u00e0\3\2\2\2") - buf.write("\u00de\u00dc\3\2\2\2\u00de\u00df\3\2\2\2\u00df\r\3\2\2") - buf.write("\2\u00e0\u00de\3\2\2\2\26\25\33#/\64CESXpz\u0082\u0086") - buf.write("\u0097\u00af\u00c9\u00d3\u00d8\u00dc\u00de") - return buf.getvalue() - - -class COOLParser ( Parser ): - - grammarFileName = "COOL.g4" - - atn = ATNDeserializer().deserialize(serializedATN()) - - decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] - - sharedContextCache = PredictionContextCache() - - literalNames = [ "", "';'", "'{'", "'}'", "'('", "','", "')'", - "':'", "'@'", "'.'", "", "", "", - "", "", "", "", - "", "", "", "", - "", "", "", "", - "", "", "", "", - "", "", "", "", - "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", - "'<='", "'='", "'~'", "'(*'", "'*)'" ] - - symbolicNames = [ "", "", "", "", - "", "", "", "", - "", "", "CLASS", "ELSE", "FALSE", - "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", - "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", - "NOT", "TRUE", "STRING", "INT", "TYPEID", "OBJECTID", - "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", - "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", - "OPEN_COMMENT", "CLOSE_COMMENT", "COMMENT", "ONE_LINE_COMMENT", - "WHITESPACE" ] - - RULE_program = 0 - RULE_programBlocks = 1 - RULE_classDefine = 2 - RULE_feature = 3 - RULE_formal = 4 - RULE_expression = 5 - - ruleNames = [ "program", "programBlocks", "classDefine", "feature", - "formal", "expression" ] - - EOF = Token.EOF - T__0=1 - T__1=2 - T__2=3 - T__3=4 - T__4=5 - T__5=6 - T__6=7 - T__7=8 - T__8=9 - CLASS=10 - ELSE=11 - FALSE=12 - FI=13 - IF=14 - IN=15 - INHERITS=16 - ISVOID=17 - LET=18 - LOOP=19 - POOL=20 - THEN=21 - WHILE=22 - CASE=23 - ESAC=24 - NEW=25 - OF=26 - NOT=27 - TRUE=28 - STRING=29 - INT=30 - TYPEID=31 - OBJECTID=32 - ASSIGNMENT=33 - CASE_ARROW=34 - ADD=35 - MINUS=36 - MULTIPLY=37 - DIVISION=38 - LESS_THAN=39 - LESS_EQUAL=40 - EQUAL=41 - INTEGER_NEGATIVE=42 - OPEN_COMMENT=43 - CLOSE_COMMENT=44 - COMMENT=45 - ONE_LINE_COMMENT=46 - WHITESPACE=47 - - def __init__(self, input:TokenStream, output:TextIO = sys.stdout): +from antlr4 import * +from COOL import COOL +from antlr4.CommonTokenFactory import CommonTokenFactory +from antlr4.atn.LexerATNSimulator import LexerATNSimulator +from antlr4.InputStream import InputStream +from antlr4.Recognizer import Recognizer +from antlr4.Token import Token +from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException + +class COOLParser(COOL): + def __init__(self, input=None, output:TextIO = sys.stdout): super().__init__(input, output) - self.checkVersion("4.7.2") - self._interp = ParserATNSimulator(self, self.atn, self.decisionsToDFA, self.sharedContextCache) - self._predicates = None - - - - - class ProgramContext(ParserRuleContext): - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - def programBlocks(self): - return self.getTypedRuleContext(COOLParser.ProgramBlocksContext,0) - - - def getRuleIndex(self): - return COOLParser.RULE_program - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterProgram" ): - listener.enterProgram(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitProgram" ): - listener.exitProgram(self) - - - - - def program(self): - - localctx = COOLParser.ProgramContext(self, self._ctx, self.state) - self.enterRule(localctx, 0, self.RULE_program) - try: - self.enterOuterAlt(localctx, 1) - self.state = 12 - self.programBlocks() - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.exitRule() - return localctx - - - class ProgramBlocksContext(ParserRuleContext): - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - - def getRuleIndex(self): - return COOLParser.RULE_programBlocks - - - def copyFrom(self, ctx:ParserRuleContext): - super().copyFrom(ctx) - - - - class ClassesContext(ProgramBlocksContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ProgramBlocksContext - super().__init__(parser) - self.copyFrom(ctx) - - def classDefine(self): - return self.getTypedRuleContext(COOLParser.ClassDefineContext,0) - - def programBlocks(self): - return self.getTypedRuleContext(COOLParser.ProgramBlocksContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterClasses" ): - listener.enterClasses(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitClasses" ): - listener.exitClasses(self) - - - class EofContext(ProgramBlocksContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ProgramBlocksContext - super().__init__(parser) - self.copyFrom(ctx) - - def EOF(self): - return self.getToken(COOLParser.EOF, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterEof" ): - listener.enterEof(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitEof" ): - listener.exitEof(self) - - - - def programBlocks(self): - - localctx = COOLParser.ProgramBlocksContext(self, self._ctx, self.state) - self.enterRule(localctx, 2, self.RULE_programBlocks) - try: - self.state = 19 - self._errHandler.sync(self) - token = self._input.LA(1) - if token in [COOLParser.CLASS]: - localctx = COOLParser.ClassesContext(self, localctx) - self.enterOuterAlt(localctx, 1) - self.state = 14 - self.classDefine() - self.state = 15 - self.match(COOLParser.T__0) - self.state = 16 - self.programBlocks() - pass - elif token in [COOLParser.EOF]: - localctx = COOLParser.EofContext(self, localctx) - self.enterOuterAlt(localctx, 2) - self.state = 18 - self.match(COOLParser.EOF) - pass - else: - raise NoViableAltException(self) - - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.exitRule() - return localctx - - - class ClassDefineContext(ParserRuleContext): - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - def CLASS(self): - return self.getToken(COOLParser.CLASS, 0) - - def TYPEID(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.TYPEID) - else: - return self.getToken(COOLParser.TYPEID, i) - - def INHERITS(self): - return self.getToken(COOLParser.INHERITS, 0) - - def feature(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.FeatureContext) - else: - return self.getTypedRuleContext(COOLParser.FeatureContext,i) - - - def getRuleIndex(self): - return COOLParser.RULE_classDefine - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterClassDefine" ): - listener.enterClassDefine(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitClassDefine" ): - listener.exitClassDefine(self) - - - - - def classDefine(self): - - localctx = COOLParser.ClassDefineContext(self, self._ctx, self.state) - self.enterRule(localctx, 4, self.RULE_classDefine) - self._la = 0 # Token type - try: - self.enterOuterAlt(localctx, 1) - self.state = 21 - self.match(COOLParser.CLASS) - self.state = 22 - self.match(COOLParser.TYPEID) - self.state = 25 - self._errHandler.sync(self) - _la = self._input.LA(1) - if _la==COOLParser.INHERITS: - self.state = 23 - self.match(COOLParser.INHERITS) - self.state = 24 - self.match(COOLParser.TYPEID) - - - self.state = 27 - self.match(COOLParser.T__1) - self.state = 33 - self._errHandler.sync(self) - _la = self._input.LA(1) - while _la==COOLParser.OBJECTID: - self.state = 28 - self.feature() - self.state = 29 - self.match(COOLParser.T__0) - self.state = 35 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 36 - self.match(COOLParser.T__2) - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.exitRule() - return localctx - - - class FeatureContext(ParserRuleContext): - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - - def getRuleIndex(self): - return COOLParser.RULE_feature - - - def copyFrom(self, ctx:ParserRuleContext): - super().copyFrom(ctx) - - - - class MethodContext(FeatureContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.FeatureContext - super().__init__(parser) - self.copyFrom(ctx) - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - def TYPEID(self): - return self.getToken(COOLParser.TYPEID, 0) - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - def formal(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.FormalContext) - else: - return self.getTypedRuleContext(COOLParser.FormalContext,i) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterMethod" ): - listener.enterMethod(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitMethod" ): - listener.exitMethod(self) - - - class PropertyContext(FeatureContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.FeatureContext - super().__init__(parser) - self.copyFrom(ctx) - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - def TYPEID(self): - return self.getToken(COOLParser.TYPEID, 0) - def ASSIGNMENT(self): - return self.getToken(COOLParser.ASSIGNMENT, 0) - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterProperty" ): - listener.enterProperty(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitProperty" ): - listener.exitProperty(self) - - - - def feature(self): - - localctx = COOLParser.FeatureContext(self, self._ctx, self.state) - self.enterRule(localctx, 6, self.RULE_feature) - self._la = 0 # Token type - try: - self.state = 67 - self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,6,self._ctx) - if la_ == 1: - localctx = COOLParser.MethodContext(self, localctx) - self.enterOuterAlt(localctx, 1) - self.state = 38 - self.match(COOLParser.OBJECTID) - self.state = 39 - self.match(COOLParser.T__3) - self.state = 50 - self._errHandler.sync(self) - _la = self._input.LA(1) - while _la==COOLParser.OBJECTID: - self.state = 40 - self.formal() - self.state = 45 - self._errHandler.sync(self) - _la = self._input.LA(1) - while _la==COOLParser.T__4: - self.state = 41 - self.match(COOLParser.T__4) - self.state = 42 - self.formal() - self.state = 47 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 52 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 53 - self.match(COOLParser.T__5) - self.state = 54 - self.match(COOLParser.T__6) - self.state = 55 - self.match(COOLParser.TYPEID) - self.state = 56 - self.match(COOLParser.T__1) - self.state = 57 - self.expression(0) - self.state = 58 - self.match(COOLParser.T__2) - pass - - elif la_ == 2: - localctx = COOLParser.PropertyContext(self, localctx) - self.enterOuterAlt(localctx, 2) - self.state = 60 - self.match(COOLParser.OBJECTID) - self.state = 61 - self.match(COOLParser.T__6) - self.state = 62 - self.match(COOLParser.TYPEID) - self.state = 65 - self._errHandler.sync(self) - _la = self._input.LA(1) - if _la==COOLParser.ASSIGNMENT: - self.state = 63 - self.match(COOLParser.ASSIGNMENT) - self.state = 64 - self.expression(0) - - - pass - - - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.exitRule() - return localctx - - - class FormalContext(ParserRuleContext): - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - - def TYPEID(self): - return self.getToken(COOLParser.TYPEID, 0) - - def getRuleIndex(self): - return COOLParser.RULE_formal - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterFormal" ): - listener.enterFormal(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitFormal" ): - listener.exitFormal(self) - - - - - def formal(self): - - localctx = COOLParser.FormalContext(self, self._ctx, self.state) - self.enterRule(localctx, 8, self.RULE_formal) - try: - self.enterOuterAlt(localctx, 1) - self.state = 69 - self.match(COOLParser.OBJECTID) - self.state = 70 - self.match(COOLParser.T__6) - self.state = 71 - self.match(COOLParser.TYPEID) - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.exitRule() - return localctx - - - class ExpressionContext(ParserRuleContext): - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - - def getRuleIndex(self): - return COOLParser.RULE_expression - - - def copyFrom(self, ctx:ParserRuleContext): - super().copyFrom(ctx) - - - class LetInContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def LET(self): - return self.getToken(COOLParser.LET, 0) - def OBJECTID(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.OBJECTID) - else: - return self.getToken(COOLParser.OBJECTID, i) - def TYPEID(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.TYPEID) - else: - return self.getToken(COOLParser.TYPEID, i) - def IN(self): - return self.getToken(COOLParser.IN, 0) - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def ASSIGNMENT(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.ASSIGNMENT) - else: - return self.getToken(COOLParser.ASSIGNMENT, i) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterLetIn" ): - listener.enterLetIn(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitLetIn" ): - listener.exitLetIn(self) - - - class MinusContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def MINUS(self): - return self.getToken(COOLParser.MINUS, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterMinus" ): - listener.enterMinus(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitMinus" ): - listener.exitMinus(self) - - - class StringContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def STRING(self): - return self.getToken(COOLParser.STRING, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterString" ): - listener.enterString(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitString" ): - listener.exitString(self) - - - class IsvoidContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def ISVOID(self): - return self.getToken(COOLParser.ISVOID, 0) - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterIsvoid" ): - listener.enterIsvoid(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitIsvoid" ): - listener.exitIsvoid(self) - - - class WhileContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def WHILE(self): - return self.getToken(COOLParser.WHILE, 0) - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def LOOP(self): - return self.getToken(COOLParser.LOOP, 0) - def POOL(self): - return self.getToken(COOLParser.POOL, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterWhile" ): - listener.enterWhile(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitWhile" ): - listener.exitWhile(self) - - - class DivisionContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def DIVISION(self): - return self.getToken(COOLParser.DIVISION, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterDivision" ): - listener.enterDivision(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitDivision" ): - listener.exitDivision(self) - - - class NegativeContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def INTEGER_NEGATIVE(self): - return self.getToken(COOLParser.INTEGER_NEGATIVE, 0) - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterNegative" ): - listener.enterNegative(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitNegative" ): - listener.exitNegative(self) - - - class BoolNotContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def NOT(self): - return self.getToken(COOLParser.NOT, 0) - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterBoolNot" ): - listener.enterBoolNot(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitBoolNot" ): - listener.exitBoolNot(self) - - - class LessThanContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def LESS_THAN(self): - return self.getToken(COOLParser.LESS_THAN, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterLessThan" ): - listener.enterLessThan(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitLessThan" ): - listener.exitLessThan(self) - - - class BlockContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterBlock" ): - listener.enterBlock(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitBlock" ): - listener.exitBlock(self) - - - class IdContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterId" ): - listener.enterId(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitId" ): - listener.exitId(self) - - - class MultiplyContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def MULTIPLY(self): - return self.getToken(COOLParser.MULTIPLY, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterMultiply" ): - listener.enterMultiply(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitMultiply" ): - listener.exitMultiply(self) - - - class IfContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def IF(self): - return self.getToken(COOLParser.IF, 0) - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def THEN(self): - return self.getToken(COOLParser.THEN, 0) - def ELSE(self): - return self.getToken(COOLParser.ELSE, 0) - def FI(self): - return self.getToken(COOLParser.FI, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterIf" ): - listener.enterIf(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitIf" ): - listener.exitIf(self) - - - class CaseContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def CASE(self): - return self.getToken(COOLParser.CASE, 0) - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def OF(self): - return self.getToken(COOLParser.OF, 0) - def ESAC(self): - return self.getToken(COOLParser.ESAC, 0) - def OBJECTID(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.OBJECTID) - else: - return self.getToken(COOLParser.OBJECTID, i) - def TYPEID(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.TYPEID) - else: - return self.getToken(COOLParser.TYPEID, i) - def CASE_ARROW(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.CASE_ARROW) - else: - return self.getToken(COOLParser.CASE_ARROW, i) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterCase" ): - listener.enterCase(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitCase" ): - listener.exitCase(self) - - - class OwnMethodCallContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterOwnMethodCall" ): - listener.enterOwnMethodCall(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitOwnMethodCall" ): - listener.exitOwnMethodCall(self) - - - class AddContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def ADD(self): - return self.getToken(COOLParser.ADD, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterAdd" ): - listener.enterAdd(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitAdd" ): - listener.exitAdd(self) - - - class NewContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def NEW(self): - return self.getToken(COOLParser.NEW, 0) - def TYPEID(self): - return self.getToken(COOLParser.TYPEID, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterNew" ): - listener.enterNew(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitNew" ): - listener.exitNew(self) - - - class ParenthesesContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterParentheses" ): - listener.enterParentheses(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitParentheses" ): - listener.exitParentheses(self) - - - class AssignmentContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - def ASSIGNMENT(self): - return self.getToken(COOLParser.ASSIGNMENT, 0) - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterAssignment" ): - listener.enterAssignment(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitAssignment" ): - listener.exitAssignment(self) - - - class FalseContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def FALSE(self): - return self.getToken(COOLParser.FALSE, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterFalse" ): - listener.enterFalse(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitFalse" ): - listener.exitFalse(self) - - - class IntContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def INT(self): - return self.getToken(COOLParser.INT, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterInt" ): - listener.enterInt(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitInt" ): - listener.exitInt(self) - - - class EqualContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def EQUAL(self): - return self.getToken(COOLParser.EQUAL, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterEqual" ): - listener.enterEqual(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitEqual" ): - listener.exitEqual(self) - - - class TrueContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def TRUE(self): - return self.getToken(COOLParser.TRUE, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterTrue" ): - listener.enterTrue(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitTrue" ): - listener.exitTrue(self) - - - class LessEqualContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def LESS_EQUAL(self): - return self.getToken(COOLParser.LESS_EQUAL, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterLessEqual" ): - listener.enterLessEqual(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitLessEqual" ): - listener.exitLessEqual(self) - - - class MethodCallContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - def TYPEID(self): - return self.getToken(COOLParser.TYPEID, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterMethodCall" ): - listener.enterMethodCall(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitMethodCall" ): - listener.exitMethodCall(self) - - - - def expression(self, _p:int=0): - _parentctx = self._ctx - _parentState = self.state - localctx = COOLParser.ExpressionContext(self, self._ctx, _parentState) - _prevctx = localctx - _startState = 10 - self.enterRecursionRule(localctx, 10, self.RULE_expression, _p) - self._la = 0 # Token type - try: - self.enterOuterAlt(localctx, 1) - self.state = 173 - self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,14,self._ctx) - if la_ == 1: - localctx = COOLParser.OwnMethodCallContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - - self.state = 74 - self.match(COOLParser.OBJECTID) - self.state = 75 - self.match(COOLParser.T__3) - self.state = 86 - self._errHandler.sync(self) - _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOLParser.T__1) | (1 << COOLParser.T__3) | (1 << COOLParser.FALSE) | (1 << COOLParser.IF) | (1 << COOLParser.ISVOID) | (1 << COOLParser.LET) | (1 << COOLParser.WHILE) | (1 << COOLParser.CASE) | (1 << COOLParser.NEW) | (1 << COOLParser.NOT) | (1 << COOLParser.TRUE) | (1 << COOLParser.STRING) | (1 << COOLParser.INT) | (1 << COOLParser.OBJECTID) | (1 << COOLParser.INTEGER_NEGATIVE))) != 0): - self.state = 76 - self.expression(0) - self.state = 81 - self._errHandler.sync(self) - _la = self._input.LA(1) - while _la==COOLParser.T__4: - self.state = 77 - self.match(COOLParser.T__4) - self.state = 78 - self.expression(0) - self.state = 83 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 88 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 89 - self.match(COOLParser.T__5) - pass - - elif la_ == 2: - localctx = COOLParser.IfContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 90 - self.match(COOLParser.IF) - self.state = 91 - self.expression(0) - self.state = 92 - self.match(COOLParser.THEN) - self.state = 93 - self.expression(0) - self.state = 94 - self.match(COOLParser.ELSE) - self.state = 95 - self.expression(0) - self.state = 96 - self.match(COOLParser.FI) - pass - - elif la_ == 3: - localctx = COOLParser.WhileContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 98 - self.match(COOLParser.WHILE) - self.state = 99 - self.expression(0) - self.state = 100 - self.match(COOLParser.LOOP) - self.state = 101 - self.expression(0) - self.state = 102 - self.match(COOLParser.POOL) - pass - - elif la_ == 4: - localctx = COOLParser.BlockContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 104 - self.match(COOLParser.T__1) - self.state = 108 - self._errHandler.sync(self) - _la = self._input.LA(1) - while True: - self.state = 105 - self.expression(0) - self.state = 106 - self.match(COOLParser.T__0) - self.state = 110 - self._errHandler.sync(self) - _la = self._input.LA(1) - if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOLParser.T__1) | (1 << COOLParser.T__3) | (1 << COOLParser.FALSE) | (1 << COOLParser.IF) | (1 << COOLParser.ISVOID) | (1 << COOLParser.LET) | (1 << COOLParser.WHILE) | (1 << COOLParser.CASE) | (1 << COOLParser.NEW) | (1 << COOLParser.NOT) | (1 << COOLParser.TRUE) | (1 << COOLParser.STRING) | (1 << COOLParser.INT) | (1 << COOLParser.OBJECTID) | (1 << COOLParser.INTEGER_NEGATIVE))) != 0)): - break - - self.state = 112 - self.match(COOLParser.T__2) - pass - - elif la_ == 5: - localctx = COOLParser.LetInContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 114 - self.match(COOLParser.LET) - self.state = 115 - self.match(COOLParser.OBJECTID) - self.state = 116 - self.match(COOLParser.T__6) - self.state = 117 - self.match(COOLParser.TYPEID) - self.state = 120 - self._errHandler.sync(self) - _la = self._input.LA(1) - if _la==COOLParser.ASSIGNMENT: - self.state = 118 - self.match(COOLParser.ASSIGNMENT) - self.state = 119 - self.expression(0) - - - self.state = 132 - self._errHandler.sync(self) - _la = self._input.LA(1) - while _la==COOLParser.T__4: - self.state = 122 - self.match(COOLParser.T__4) - self.state = 123 - self.match(COOLParser.OBJECTID) - self.state = 124 - self.match(COOLParser.T__6) - self.state = 125 - self.match(COOLParser.TYPEID) - self.state = 128 - self._errHandler.sync(self) - _la = self._input.LA(1) - if _la==COOLParser.ASSIGNMENT: - self.state = 126 - self.match(COOLParser.ASSIGNMENT) - self.state = 127 - self.expression(0) - - - self.state = 134 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 135 - self.match(COOLParser.IN) - self.state = 136 - self.expression(20) - pass - - elif la_ == 6: - localctx = COOLParser.CaseContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 137 - self.match(COOLParser.CASE) - self.state = 138 - self.expression(0) - self.state = 139 - self.match(COOLParser.OF) - self.state = 147 - self._errHandler.sync(self) - _la = self._input.LA(1) - while True: - self.state = 140 - self.match(COOLParser.OBJECTID) - self.state = 141 - self.match(COOLParser.T__6) - self.state = 142 - self.match(COOLParser.TYPEID) - self.state = 143 - self.match(COOLParser.CASE_ARROW) - self.state = 144 - self.expression(0) - self.state = 145 - self.match(COOLParser.T__0) - self.state = 149 - self._errHandler.sync(self) - _la = self._input.LA(1) - if not (_la==COOLParser.OBJECTID): - break - - self.state = 151 - self.match(COOLParser.ESAC) - pass - - elif la_ == 7: - localctx = COOLParser.NewContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 153 - self.match(COOLParser.NEW) - self.state = 154 - self.match(COOLParser.TYPEID) - pass - - elif la_ == 8: - localctx = COOLParser.NegativeContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 155 - self.match(COOLParser.INTEGER_NEGATIVE) - self.state = 156 - self.expression(17) - pass - - elif la_ == 9: - localctx = COOLParser.IsvoidContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 157 - self.match(COOLParser.ISVOID) - self.state = 158 - self.expression(16) - pass - - elif la_ == 10: - localctx = COOLParser.BoolNotContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 159 - self.match(COOLParser.NOT) - self.state = 160 - self.expression(8) - pass - - elif la_ == 11: - localctx = COOLParser.ParenthesesContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 161 - self.match(COOLParser.T__3) - self.state = 162 - self.expression(0) - self.state = 163 - self.match(COOLParser.T__5) - pass - - elif la_ == 12: - localctx = COOLParser.IdContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 165 - self.match(COOLParser.OBJECTID) - pass - - elif la_ == 13: - localctx = COOLParser.IntContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 166 - self.match(COOLParser.INT) - pass - - elif la_ == 14: - localctx = COOLParser.StringContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 167 - self.match(COOLParser.STRING) - pass - - elif la_ == 15: - localctx = COOLParser.TrueContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 168 - self.match(COOLParser.TRUE) - pass - - elif la_ == 16: - localctx = COOLParser.FalseContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 169 - self.match(COOLParser.FALSE) - pass - - elif la_ == 17: - localctx = COOLParser.AssignmentContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 170 - self.match(COOLParser.OBJECTID) - self.state = 171 - self.match(COOLParser.ASSIGNMENT) - self.state = 172 - self.expression(1) - pass - - - self._ctx.stop = self._input.LT(-1) - self.state = 220 - self._errHandler.sync(self) - _alt = self._interp.adaptivePredict(self._input,19,self._ctx) - while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: - if _alt==1: - if self._parseListeners is not None: - self.triggerExitRuleEvent() - _prevctx = localctx - self.state = 218 - self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,18,self._ctx) - if la_ == 1: - localctx = COOLParser.MultiplyContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 175 - if not self.precpred(self._ctx, 15): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 15)") - self.state = 176 - self.match(COOLParser.MULTIPLY) - self.state = 177 - self.expression(16) - pass - - elif la_ == 2: - localctx = COOLParser.DivisionContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 178 - if not self.precpred(self._ctx, 14): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 14)") - self.state = 179 - self.match(COOLParser.DIVISION) - self.state = 180 - self.expression(15) - pass - - elif la_ == 3: - localctx = COOLParser.AddContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 181 - if not self.precpred(self._ctx, 13): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 13)") - self.state = 182 - self.match(COOLParser.ADD) - self.state = 183 - self.expression(14) - pass - - elif la_ == 4: - localctx = COOLParser.MinusContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 184 - if not self.precpred(self._ctx, 12): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 12)") - self.state = 185 - self.match(COOLParser.MINUS) - self.state = 186 - self.expression(13) - pass - - elif la_ == 5: - localctx = COOLParser.LessThanContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 187 - if not self.precpred(self._ctx, 11): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 11)") - self.state = 188 - self.match(COOLParser.LESS_THAN) - self.state = 189 - self.expression(12) - pass - - elif la_ == 6: - localctx = COOLParser.LessEqualContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 190 - if not self.precpred(self._ctx, 10): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 10)") - self.state = 191 - self.match(COOLParser.LESS_EQUAL) - self.state = 192 - self.expression(11) - pass - - elif la_ == 7: - localctx = COOLParser.EqualContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 193 - if not self.precpred(self._ctx, 9): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 9)") - self.state = 194 - self.match(COOLParser.EQUAL) - self.state = 195 - self.expression(10) - pass - - elif la_ == 8: - localctx = COOLParser.MethodCallContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 196 - if not self.precpred(self._ctx, 25): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 25)") - self.state = 199 - self._errHandler.sync(self) - _la = self._input.LA(1) - if _la==COOLParser.T__7: - self.state = 197 - self.match(COOLParser.T__7) - self.state = 198 - self.match(COOLParser.TYPEID) - - - self.state = 201 - self.match(COOLParser.T__8) - self.state = 202 - self.match(COOLParser.OBJECTID) - self.state = 203 - self.match(COOLParser.T__3) - self.state = 214 - self._errHandler.sync(self) - _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOLParser.T__1) | (1 << COOLParser.T__3) | (1 << COOLParser.FALSE) | (1 << COOLParser.IF) | (1 << COOLParser.ISVOID) | (1 << COOLParser.LET) | (1 << COOLParser.WHILE) | (1 << COOLParser.CASE) | (1 << COOLParser.NEW) | (1 << COOLParser.NOT) | (1 << COOLParser.TRUE) | (1 << COOLParser.STRING) | (1 << COOLParser.INT) | (1 << COOLParser.OBJECTID) | (1 << COOLParser.INTEGER_NEGATIVE))) != 0): - self.state = 204 - self.expression(0) - self.state = 209 - self._errHandler.sync(self) - _la = self._input.LA(1) - while _la==COOLParser.T__4: - self.state = 205 - self.match(COOLParser.T__4) - self.state = 206 - self.expression(0) - self.state = 211 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 216 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 217 - self.match(COOLParser.T__5) - pass - - - self.state = 222 - self._errHandler.sync(self) - _alt = self._interp.adaptivePredict(self._input,19,self._ctx) - - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.unrollRecursionContexts(_parentctx) - return localctx - - - - def sempred(self, localctx:RuleContext, ruleIndex:int, predIndex:int): - if self._predicates == None: - self._predicates = dict() - self._predicates[5] = self.expression_sempred - pred = self._predicates.get(ruleIndex, None) - if pred is None: - raise Exception("No predicate with index:" + str(ruleIndex)) - else: - return pred(localctx, predIndex) - - def expression_sempred(self, localctx:ExpressionContext, predIndex:int): - if predIndex == 0: - return self.precpred(self._ctx, 15) - - - if predIndex == 1: - return self.precpred(self._ctx, 14) - - - if predIndex == 2: - return self.precpred(self._ctx, 13) - - - if predIndex == 3: - return self.precpred(self._ctx, 12) - - - if predIndex == 4: - return self.precpred(self._ctx, 11) - - - if predIndex == 5: - return self.precpred(self._ctx, 10) - - - if predIndex == 6: - return self.precpred(self._ctx, 9) - - - if predIndex == 7: - return self.precpred(self._ctx, 25) - - - - + def notifyErrorListeners(self, msg:str, offendingToken:Token = None, e:RecognitionException = None): + if offendingToken is None: + offendingToken = self.getCurrentToken() + self._syntaxErrors += 1 + line = offendingToken.line + column = offendingToken.column + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, offendingToken, line, column, msg, e) \ No newline at end of file diff --git a/COOLParserErrorListener.py b/src/COOLParserErrorListener.py similarity index 100% rename from COOLParserErrorListener.py rename to src/COOLParserErrorListener.py diff --git a/COOL_LEX.interp b/src/COOL_LEX.interp similarity index 100% rename from COOL_LEX.interp rename to src/COOL_LEX.interp diff --git a/COOL_LEX.py b/src/COOL_LEX.py similarity index 100% rename from COOL_LEX.py rename to src/COOL_LEX.py diff --git a/COOL_LEX.tokens b/src/COOL_LEX.tokens similarity index 100% rename from COOL_LEX.tokens rename to src/COOL_LEX.tokens From b584b040949107e714dad828d77c3c919032b51c Mon Sep 17 00:00:00 2001 From: pablodearmas <57228410+pablodearmas@users.noreply.github.com> Date: Sun, 1 Mar 2020 00:17:01 -0500 Subject: [PATCH 08/77] =?UTF-8?q?Se=20actualiz=C3=B3=20nombre=20y=20versi?= =?UTF-8?q?=C3=B3n=20del=20compilador?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coolc.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coolc.sh b/src/coolc.sh index 32158b64..7f167c0e 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,8 +4,8 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas -echo "Copyright (c) 2019: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" # TODO: líneas a los valores correctos +echo "COOLCompiler 1.0.1" +echo "Copyright (c) 2019: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" # Llamar al compilador #echo "Compiling $INPUT_FILE into $OUTPUT_FILE" From 6a63002dc4d5ea3d9804fd6d10021791f1af2052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 1 Mar 2020 03:09:50 -0500 Subject: [PATCH 09/77] =?UTF-8?q?Se=20arreglaron=20varios=20errores=20Se?= =?UTF-8?q?=20modificaron=20el=20lexer=20y=20el=20parser=20para=20que=20se?= =?UTF-8?q?an=20compatibles=20con=20lo=20que=20esperan=20los=20test=20auto?= =?UTF-8?q?m=C3=A1ticos=20Se=20mejor=C3=B3=20el=20c=C3=B3digo=20para=20sop?= =?UTF-8?q?ortar=20PyTest=20en=20Windows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/COOLCompiler.py | 9 ++++++--- src/COOLLexerErrorListener.py | 2 +- src/COOLParser.py | 5 ++++- src/COOLParserErrorListener.py | 2 +- src/coolc.sh | 2 +- tests/codegen_test.py | 4 ++-- tests/lexer/comment1.cl | 4 ++-- tests/lexer_test.py | 4 ++-- tests/parser_test.py | 4 ++-- tests/semantic_test.py | 4 ++-- 10 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 5a9b2584..6e21c735 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -1,5 +1,6 @@ import sys import os.path +import errno from antlr4 import * from COOLLexer import COOLLexer from COOLLexerErrorListener import COOLLexerErrorListener @@ -9,8 +10,8 @@ def main(argv): if not os.path.isfile(argv[1]): - print("invalid input filename") - return + print("invalid input filename: " + argv[1]) + return sys.exit(errno.EPERM) input = FileStream(argv[1]) @@ -22,7 +23,7 @@ def main(argv): token = lexer.nextToken() if lexer.hasErrors: - return + return sys.exit(errno.EPERM) lexer.reset(); stream = CommonTokenStream(lexer) @@ -31,6 +32,8 @@ def main(argv): parser.addErrorListener(COOLParserErrorListener()) tree = parser.program() + if parser.getNumberOfSyntaxErrors() > 0: + return sys.exit(errno.EPERM) if __name__ == '__main__': main(sys.argv) diff --git a/src/COOLLexerErrorListener.py b/src/COOLLexerErrorListener.py index 451cdba7..2eec5575 100644 --- a/src/COOLLexerErrorListener.py +++ b/src/COOLLexerErrorListener.py @@ -4,4 +4,4 @@ class COOLLexerErrorListener(ErrorListener): def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): - print("(" + str(line) + ", " + str(column+1) + ") - LexicographicError: " + msg, file=sys.stderr) \ No newline at end of file + print("(" + str(line) + ", " + str(column+1) + ") - LexicographicError: " + msg, file=sys.stdout) \ No newline at end of file diff --git a/src/COOLParser.py b/src/COOLParser.py index 7f3ad8ac..6decdd97 100644 --- a/src/COOLParser.py +++ b/src/COOLParser.py @@ -13,12 +13,15 @@ class COOLParser(COOL): def __init__(self, input=None, output:TextIO = sys.stdout): super().__init__(input, output) + self._hasErrors = False def notifyErrorListeners(self, msg:str, offendingToken:Token = None, e:RecognitionException = None): + self._hasErrors = True + if offendingToken is None: offendingToken = self.getCurrentToken() self._syntaxErrors += 1 line = offendingToken.line column = offendingToken.column listener = self.getErrorListenerDispatch() - listener.syntaxError(self, offendingToken, line, column, msg, e) \ No newline at end of file + listener.syntaxError(self, offendingToken, line, column, msg, e) diff --git a/src/COOLParserErrorListener.py b/src/COOLParserErrorListener.py index 5bae5069..0c4b79e9 100644 --- a/src/COOLParserErrorListener.py +++ b/src/COOLParserErrorListener.py @@ -9,4 +9,4 @@ def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): msg = "EOF" else: msg = "\"" + msg + "\"" - print("(" + str(line) + ", " + str(column+1) + ") - SyntacticError: ERROR at or near " +msg, file=sys.stderr) \ No newline at end of file + print("(" + str(line) + ", " + str(column+1) + ") - SyntacticError: ERROR at or near " +msg, file=sys.stdout) \ No newline at end of file diff --git a/src/coolc.sh b/src/coolc.sh index 7f167c0e..2b13ab2e 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -9,4 +9,4 @@ echo "Copyright (c) 2019: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli # Llamar al compilador #echo "Compiling $INPUT_FILE into $OUTPUT_FILE" -python COOLCompiler.py INPUT_FILE OUTPUT_FILE +python COOLCompiler.py $INPUT_FILE $OUTPUT_FILE diff --git a/tests/codegen_test.py b/tests/codegen_test.py index 6d864cb0..b7f535bf 100644 --- a/tests/codegen_test.py +++ b/tests/codegen_test.py @@ -2,7 +2,7 @@ import os from utils import compare_errors -tests_dir = __file__.rpartition('/')[0] + '/codegen/' +tests_dir = os.path.join(__file__.rpartition(os.path.sep)[0], 'codegen') tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] # @pytest.mark.lexer @@ -12,4 +12,4 @@ @pytest.mark.run(order=4) @pytest.mark.parametrize("cool_file", tests) def test_codegen(compiler_path, cool_file): - compare_errors(compiler_path, tests_dir + cool_file, None) \ No newline at end of file + compare_errors(compiler_path, os.path.join(tests_dir, cool_file), None) diff --git a/tests/lexer/comment1.cl b/tests/lexer/comment1.cl index 69533f23..086922ea 100644 --- a/tests/lexer/comment1.cl +++ b/tests/lexer/comment1.cl @@ -1,9 +1,9 @@ ---Any characters between two dashes “--” and the next newline +--Any characters between two dashes "--" and the next newline --(or EOF, if there is no next newline) are treated as comments (*(*(* Comments may also be written by enclosing -text in (∗ . . . ∗). The latter form of comment may be nested. +text in (* . . . *). The latter form of comment may be nested. Comments cannot cross file boundaries. *)*)*) diff --git a/tests/lexer_test.py b/tests/lexer_test.py index 2a27223d..9ade030a 100644 --- a/tests/lexer_test.py +++ b/tests/lexer_test.py @@ -2,7 +2,7 @@ import os from utils import compare_errors -tests_dir = __file__.rpartition('/')[0] + '/lexer/' +tests_dir = os.path.join(__file__.rpartition(os.path.sep)[0], 'lexer') tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] @pytest.mark.lexer @@ -10,4 +10,4 @@ @pytest.mark.run(order=1) @pytest.mark.parametrize("cool_file", tests) def test_lexer_errors(compiler_path, cool_file): - compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file + compare_errors(compiler_path, os.path.join(tests_dir, cool_file), os.path.join(tests_dir, cool_file[:-3] + '_error.txt')) \ No newline at end of file diff --git a/tests/parser_test.py b/tests/parser_test.py index 129c0f20..0f5efa63 100644 --- a/tests/parser_test.py +++ b/tests/parser_test.py @@ -2,7 +2,7 @@ import os from utils import compare_errors -tests_dir = __file__.rpartition('/')[0] + '/parser/' +tests_dir = os.path.join(__file__.rpartition(os.path.sep)[0], 'parser') tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] @pytest.mark.parser @@ -10,4 +10,4 @@ @pytest.mark.run(order=2) @pytest.mark.parametrize("cool_file", tests) def test_parser_errors(compiler_path, cool_file): - compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file + compare_errors(compiler_path, os.path.join(tests_dir, cool_file), os.path.join(tests_dir, cool_file[:-3] + '_error.txt')) diff --git a/tests/semantic_test.py b/tests/semantic_test.py index 6c71f896..4acb7f7e 100644 --- a/tests/semantic_test.py +++ b/tests/semantic_test.py @@ -2,7 +2,7 @@ import os from utils import compare_errors -tests_dir = __file__.rpartition('/')[0] + '/semantic/' +tests_dir = os.path.join(__file__.rpartition(os.path.sep)[0], 'semantic') tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] @pytest.mark.semantic @@ -10,4 +10,4 @@ @pytest.mark.run(order=3) @pytest.mark.parametrize("cool_file", []) def test_semantic_errors(compiler_path, cool_file): - compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file + compare_errors(compiler_path, os.path.join(tests_dir, cool_file), os.path.join(tests_dir, cool_file[:-3] + '_error.txt')) From a3af1e64762f9fc546288885017377c439c31283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 2 Mar 2020 00:37:14 -0500 Subject: [PATCH 10/77] Se arreglaron errores en el lexer y el parser para los casos de prueba --- src/COOL.interp | 12 +- src/COOL.py | 488 ++++++++++++++++---------------- src/COOL.tokens | 102 +++---- src/COOLCompiler.py | 2 +- src/COOLLexer.py | 39 ++- src/COOL_LEX.interp | 20 +- src/COOL_LEX.py | 465 ++++++++++++++++-------------- src/COOL_LEX.tokens | 102 +++---- src/coolc.sh | 4 +- tests/parser/program1_error.txt | 2 +- 10 files changed, 665 insertions(+), 571 deletions(-) diff --git a/src/COOL.interp b/src/COOL.interp index bba307e6..740232fd 100644 --- a/src/COOL.interp +++ b/src/COOL.interp @@ -24,6 +24,7 @@ null null null null +null '<-' '=>' '+' @@ -48,6 +49,9 @@ null '(*' null '*)' +null +null +null token symbolic names: null @@ -71,7 +75,8 @@ OF NOT TRUE STRING -BREAK_STRING +STRING_SIMPLE +STRING_FIRSTLINE INT TYPEID OBJECTID @@ -99,6 +104,9 @@ ONE_LINE_COMMENT OPEN_COMMENT COMMENT CLOSE_COMMENT +STRING_INNERLINE +STRING_LASTLINE +STRING_MULTILINE rule names: program @@ -110,4 +118,4 @@ expression atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 50, 225, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 7, 7, 86, 10, 7, 12, 7, 14, 7, 89, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 110, 10, 7, 13, 7, 14, 7, 111, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 122, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 130, 10, 7, 7, 7, 132, 10, 7, 12, 7, 14, 7, 135, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 149, 10, 7, 13, 7, 14, 7, 150, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 175, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 201, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 209, 10, 7, 12, 7, 14, 7, 212, 11, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 7, 7, 220, 10, 7, 12, 7, 14, 7, 223, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 259, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 174, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 45, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 25, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 25, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 39, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 45, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 40, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 26, 2, 2, 40, 51, 7, 37, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 43, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 38, 2, 2, 55, 56, 7, 44, 2, 2, 56, 57, 7, 25, 2, 2, 57, 58, 7, 39, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 40, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 26, 2, 2, 62, 63, 7, 44, 2, 2, 63, 66, 7, 25, 2, 2, 64, 65, 7, 27, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 26, 2, 2, 71, 72, 7, 44, 2, 2, 72, 73, 7, 25, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 26, 2, 2, 76, 87, 7, 37, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 43, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 90, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 175, 7, 38, 2, 2, 91, 92, 7, 7, 2, 2, 92, 93, 5, 12, 7, 2, 93, 94, 7, 14, 2, 2, 94, 95, 5, 12, 7, 2, 95, 96, 7, 4, 2, 2, 96, 97, 5, 12, 7, 2, 97, 98, 7, 6, 2, 2, 98, 175, 3, 2, 2, 2, 99, 100, 7, 15, 2, 2, 100, 101, 5, 12, 7, 2, 101, 102, 7, 12, 2, 2, 102, 103, 5, 12, 7, 2, 103, 104, 7, 13, 2, 2, 104, 175, 3, 2, 2, 2, 105, 109, 7, 39, 2, 2, 106, 107, 5, 12, 7, 2, 107, 108, 7, 45, 2, 2, 108, 110, 3, 2, 2, 2, 109, 106, 3, 2, 2, 2, 110, 111, 3, 2, 2, 2, 111, 109, 3, 2, 2, 2, 111, 112, 3, 2, 2, 2, 112, 113, 3, 2, 2, 2, 113, 114, 7, 40, 2, 2, 114, 175, 3, 2, 2, 2, 115, 116, 7, 11, 2, 2, 116, 117, 7, 26, 2, 2, 117, 118, 7, 44, 2, 2, 118, 121, 7, 25, 2, 2, 119, 120, 7, 27, 2, 2, 120, 122, 5, 12, 7, 2, 121, 119, 3, 2, 2, 2, 121, 122, 3, 2, 2, 2, 122, 133, 3, 2, 2, 2, 123, 124, 7, 43, 2, 2, 124, 125, 7, 26, 2, 2, 125, 126, 7, 44, 2, 2, 126, 129, 7, 25, 2, 2, 127, 128, 7, 27, 2, 2, 128, 130, 5, 12, 7, 2, 129, 127, 3, 2, 2, 2, 129, 130, 3, 2, 2, 2, 130, 132, 3, 2, 2, 2, 131, 123, 3, 2, 2, 2, 132, 135, 3, 2, 2, 2, 133, 131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 136, 3, 2, 2, 2, 135, 133, 3, 2, 2, 2, 136, 137, 7, 8, 2, 2, 137, 175, 5, 12, 7, 22, 138, 139, 7, 16, 2, 2, 139, 140, 5, 12, 7, 2, 140, 148, 7, 19, 2, 2, 141, 142, 7, 26, 2, 2, 142, 143, 7, 44, 2, 2, 143, 144, 7, 25, 2, 2, 144, 145, 7, 28, 2, 2, 145, 146, 5, 12, 7, 2, 146, 147, 7, 45, 2, 2, 147, 149, 3, 2, 2, 2, 148, 141, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 150, 148, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 7, 17, 2, 2, 153, 175, 3, 2, 2, 2, 154, 155, 7, 18, 2, 2, 155, 175, 7, 25, 2, 2, 156, 157, 7, 36, 2, 2, 157, 175, 5, 12, 7, 19, 158, 159, 7, 10, 2, 2, 159, 175, 5, 12, 7, 18, 160, 161, 7, 20, 2, 2, 161, 175, 5, 12, 7, 10, 162, 163, 7, 37, 2, 2, 163, 164, 5, 12, 7, 2, 164, 165, 7, 38, 2, 2, 165, 175, 3, 2, 2, 2, 166, 175, 7, 26, 2, 2, 167, 175, 7, 24, 2, 2, 168, 175, 7, 22, 2, 2, 169, 175, 7, 21, 2, 2, 170, 175, 7, 5, 2, 2, 171, 172, 7, 26, 2, 2, 172, 173, 7, 27, 2, 2, 173, 175, 5, 12, 7, 3, 174, 74, 3, 2, 2, 2, 174, 91, 3, 2, 2, 2, 174, 99, 3, 2, 2, 2, 174, 105, 3, 2, 2, 2, 174, 115, 3, 2, 2, 2, 174, 138, 3, 2, 2, 2, 174, 154, 3, 2, 2, 2, 174, 156, 3, 2, 2, 2, 174, 158, 3, 2, 2, 2, 174, 160, 3, 2, 2, 2, 174, 162, 3, 2, 2, 2, 174, 166, 3, 2, 2, 2, 174, 167, 3, 2, 2, 2, 174, 168, 3, 2, 2, 2, 174, 169, 3, 2, 2, 2, 174, 170, 3, 2, 2, 2, 174, 171, 3, 2, 2, 2, 175, 221, 3, 2, 2, 2, 176, 177, 12, 17, 2, 2, 177, 178, 7, 31, 2, 2, 178, 220, 5, 12, 7, 18, 179, 180, 12, 16, 2, 2, 180, 181, 7, 32, 2, 2, 181, 220, 5, 12, 7, 17, 182, 183, 12, 15, 2, 2, 183, 184, 7, 29, 2, 2, 184, 220, 5, 12, 7, 16, 185, 186, 12, 14, 2, 2, 186, 187, 7, 30, 2, 2, 187, 220, 5, 12, 7, 15, 188, 189, 12, 13, 2, 2, 189, 190, 7, 33, 2, 2, 190, 220, 5, 12, 7, 14, 191, 192, 12, 12, 2, 2, 192, 193, 7, 34, 2, 2, 193, 220, 5, 12, 7, 13, 194, 195, 12, 11, 2, 2, 195, 196, 7, 35, 2, 2, 196, 220, 5, 12, 7, 12, 197, 200, 12, 27, 2, 2, 198, 199, 7, 41, 2, 2, 199, 201, 7, 25, 2, 2, 200, 198, 3, 2, 2, 2, 200, 201, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 7, 42, 2, 2, 203, 204, 7, 26, 2, 2, 204, 215, 7, 37, 2, 2, 205, 210, 5, 12, 7, 2, 206, 207, 7, 43, 2, 2, 207, 209, 5, 12, 7, 2, 208, 206, 3, 2, 2, 2, 209, 212, 3, 2, 2, 2, 210, 208, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 214, 3, 2, 2, 2, 212, 210, 3, 2, 2, 2, 213, 205, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 218, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 218, 220, 7, 38, 2, 2, 219, 176, 3, 2, 2, 2, 219, 179, 3, 2, 2, 2, 219, 182, 3, 2, 2, 2, 219, 185, 3, 2, 2, 2, 219, 188, 3, 2, 2, 2, 219, 191, 3, 2, 2, 2, 219, 194, 3, 2, 2, 2, 219, 197, 3, 2, 2, 2, 220, 223, 3, 2, 2, 2, 221, 219, 3, 2, 2, 2, 221, 222, 3, 2, 2, 2, 222, 13, 3, 2, 2, 2, 223, 221, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 87, 111, 121, 129, 133, 150, 174, 200, 210, 215, 219, 221] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 54, 219, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 5, 7, 86, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 107, 10, 7, 13, 7, 14, 7, 108, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 119, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 127, 10, 7, 7, 7, 129, 10, 7, 12, 7, 14, 7, 132, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 146, 10, 7, 13, 7, 14, 7, 147, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 172, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 198, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 206, 10, 7, 12, 7, 14, 7, 209, 11, 7, 5, 7, 211, 10, 7, 3, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 253, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 171, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 46, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 26, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 26, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 40, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 46, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 41, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 27, 2, 2, 40, 51, 7, 38, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 44, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 39, 2, 2, 55, 56, 7, 45, 2, 2, 56, 57, 7, 26, 2, 2, 57, 58, 7, 40, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 41, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 27, 2, 2, 62, 63, 7, 45, 2, 2, 63, 66, 7, 26, 2, 2, 64, 65, 7, 28, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 27, 2, 2, 71, 72, 7, 45, 2, 2, 72, 73, 7, 26, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 27, 2, 2, 76, 85, 7, 38, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 44, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 85, 86, 3, 2, 2, 2, 86, 87, 3, 2, 2, 2, 87, 172, 7, 39, 2, 2, 88, 89, 7, 7, 2, 2, 89, 90, 5, 12, 7, 2, 90, 91, 7, 14, 2, 2, 91, 92, 5, 12, 7, 2, 92, 93, 7, 4, 2, 2, 93, 94, 5, 12, 7, 2, 94, 95, 7, 6, 2, 2, 95, 172, 3, 2, 2, 2, 96, 97, 7, 15, 2, 2, 97, 98, 5, 12, 7, 2, 98, 99, 7, 12, 2, 2, 99, 100, 5, 12, 7, 2, 100, 101, 7, 13, 2, 2, 101, 172, 3, 2, 2, 2, 102, 106, 7, 40, 2, 2, 103, 104, 5, 12, 7, 2, 104, 105, 7, 46, 2, 2, 105, 107, 3, 2, 2, 2, 106, 103, 3, 2, 2, 2, 107, 108, 3, 2, 2, 2, 108, 106, 3, 2, 2, 2, 108, 109, 3, 2, 2, 2, 109, 110, 3, 2, 2, 2, 110, 111, 7, 41, 2, 2, 111, 172, 3, 2, 2, 2, 112, 113, 7, 11, 2, 2, 113, 114, 7, 27, 2, 2, 114, 115, 7, 45, 2, 2, 115, 118, 7, 26, 2, 2, 116, 117, 7, 28, 2, 2, 117, 119, 5, 12, 7, 2, 118, 116, 3, 2, 2, 2, 118, 119, 3, 2, 2, 2, 119, 130, 3, 2, 2, 2, 120, 121, 7, 44, 2, 2, 121, 122, 7, 27, 2, 2, 122, 123, 7, 45, 2, 2, 123, 126, 7, 26, 2, 2, 124, 125, 7, 28, 2, 2, 125, 127, 5, 12, 7, 2, 126, 124, 3, 2, 2, 2, 126, 127, 3, 2, 2, 2, 127, 129, 3, 2, 2, 2, 128, 120, 3, 2, 2, 2, 129, 132, 3, 2, 2, 2, 130, 128, 3, 2, 2, 2, 130, 131, 3, 2, 2, 2, 131, 133, 3, 2, 2, 2, 132, 130, 3, 2, 2, 2, 133, 134, 7, 8, 2, 2, 134, 172, 5, 12, 7, 22, 135, 136, 7, 16, 2, 2, 136, 137, 5, 12, 7, 2, 137, 145, 7, 19, 2, 2, 138, 139, 7, 27, 2, 2, 139, 140, 7, 45, 2, 2, 140, 141, 7, 26, 2, 2, 141, 142, 7, 29, 2, 2, 142, 143, 5, 12, 7, 2, 143, 144, 7, 46, 2, 2, 144, 146, 3, 2, 2, 2, 145, 138, 3, 2, 2, 2, 146, 147, 3, 2, 2, 2, 147, 145, 3, 2, 2, 2, 147, 148, 3, 2, 2, 2, 148, 149, 3, 2, 2, 2, 149, 150, 7, 17, 2, 2, 150, 172, 3, 2, 2, 2, 151, 152, 7, 18, 2, 2, 152, 172, 7, 26, 2, 2, 153, 154, 7, 37, 2, 2, 154, 172, 5, 12, 7, 19, 155, 156, 7, 10, 2, 2, 156, 172, 5, 12, 7, 18, 157, 158, 7, 20, 2, 2, 158, 172, 5, 12, 7, 10, 159, 160, 7, 38, 2, 2, 160, 161, 5, 12, 7, 2, 161, 162, 7, 39, 2, 2, 162, 172, 3, 2, 2, 2, 163, 172, 7, 27, 2, 2, 164, 172, 7, 25, 2, 2, 165, 172, 7, 22, 2, 2, 166, 172, 7, 21, 2, 2, 167, 172, 7, 5, 2, 2, 168, 169, 7, 27, 2, 2, 169, 170, 7, 28, 2, 2, 170, 172, 5, 12, 7, 3, 171, 74, 3, 2, 2, 2, 171, 88, 3, 2, 2, 2, 171, 96, 3, 2, 2, 2, 171, 102, 3, 2, 2, 2, 171, 112, 3, 2, 2, 2, 171, 135, 3, 2, 2, 2, 171, 151, 3, 2, 2, 2, 171, 153, 3, 2, 2, 2, 171, 155, 3, 2, 2, 2, 171, 157, 3, 2, 2, 2, 171, 159, 3, 2, 2, 2, 171, 163, 3, 2, 2, 2, 171, 164, 3, 2, 2, 2, 171, 165, 3, 2, 2, 2, 171, 166, 3, 2, 2, 2, 171, 167, 3, 2, 2, 2, 171, 168, 3, 2, 2, 2, 172, 215, 3, 2, 2, 2, 173, 174, 12, 17, 2, 2, 174, 175, 7, 32, 2, 2, 175, 214, 5, 12, 7, 18, 176, 177, 12, 16, 2, 2, 177, 178, 7, 33, 2, 2, 178, 214, 5, 12, 7, 17, 179, 180, 12, 15, 2, 2, 180, 181, 7, 30, 2, 2, 181, 214, 5, 12, 7, 16, 182, 183, 12, 14, 2, 2, 183, 184, 7, 31, 2, 2, 184, 214, 5, 12, 7, 15, 185, 186, 12, 13, 2, 2, 186, 187, 7, 34, 2, 2, 187, 214, 5, 12, 7, 14, 188, 189, 12, 12, 2, 2, 189, 190, 7, 35, 2, 2, 190, 214, 5, 12, 7, 13, 191, 192, 12, 11, 2, 2, 192, 193, 7, 36, 2, 2, 193, 214, 5, 12, 7, 12, 194, 197, 12, 27, 2, 2, 195, 196, 7, 42, 2, 2, 196, 198, 7, 26, 2, 2, 197, 195, 3, 2, 2, 2, 197, 198, 3, 2, 2, 2, 198, 199, 3, 2, 2, 2, 199, 200, 7, 43, 2, 2, 200, 201, 7, 27, 2, 2, 201, 210, 7, 38, 2, 2, 202, 207, 5, 12, 7, 2, 203, 204, 7, 44, 2, 2, 204, 206, 5, 12, 7, 2, 205, 203, 3, 2, 2, 2, 206, 209, 3, 2, 2, 2, 207, 205, 3, 2, 2, 2, 207, 208, 3, 2, 2, 2, 208, 211, 3, 2, 2, 2, 209, 207, 3, 2, 2, 2, 210, 202, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 212, 3, 2, 2, 2, 212, 214, 7, 39, 2, 2, 213, 173, 3, 2, 2, 2, 213, 176, 3, 2, 2, 2, 213, 179, 3, 2, 2, 2, 213, 182, 3, 2, 2, 2, 213, 185, 3, 2, 2, 2, 213, 188, 3, 2, 2, 2, 213, 191, 3, 2, 2, 2, 213, 194, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 13, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 85, 108, 118, 126, 130, 147, 171, 197, 207, 210, 213, 215] \ No newline at end of file diff --git a/src/COOL.py b/src/COOL.py index 7fca203d..a342382b 100644 --- a/src/COOL.py +++ b/src/COOL.py @@ -8,102 +8,99 @@ def serializedATN(): with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\62") - buf.write("\u00e1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\66") + buf.write("\u00db\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") buf.write("\3\2\3\2\3\2\3\3\3\3\3\3\5\3\25\n\3\3\4\3\4\3\4\3\4\5") buf.write("\4\33\n\4\3\4\3\4\3\4\3\4\7\4!\n\4\f\4\16\4$\13\4\3\4") buf.write("\3\4\3\5\3\5\3\5\3\5\3\5\7\5-\n\5\f\5\16\5\60\13\5\7\5") buf.write("\62\n\5\f\5\16\5\65\13\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3") buf.write("\5\3\5\3\5\3\5\3\5\5\5C\n\5\5\5E\n\5\3\6\3\6\3\6\3\6\3") - buf.write("\7\3\7\3\7\3\7\3\7\3\7\7\7Q\n\7\f\7\16\7T\13\7\7\7V\n") - buf.write("\7\f\7\16\7Y\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\6\7n\n\7\r\7") - buf.write("\16\7o\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\5\7z\n\7\3\7\3") - buf.write("\7\3\7\3\7\3\7\3\7\5\7\u0082\n\7\7\7\u0084\n\7\f\7\16") - buf.write("\7\u0087\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\6\7\u0095\n\7\r\7\16\7\u0096\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") - buf.write("\7\3\7\3\7\3\7\3\7\5\7\u00af\n\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\7\7Q\n\7\f\7\16\7T\13\7\5\7V\n") buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\3\7\3\7\3\7\5\7\u00c9\n\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\7\7\u00d1\n\7\f\7\16\7\u00d4\13\7\7\7\u00d6\n\7\f") - buf.write("\7\16\7\u00d9\13\7\3\7\7\7\u00dc\n\7\f\7\16\7\u00df\13") - buf.write("\7\3\7\2\3\f\b\2\4\6\b\n\f\2\2\2\u0103\2\16\3\2\2\2\4") - buf.write("\21\3\2\2\2\6\26\3\2\2\2\bD\3\2\2\2\nF\3\2\2\2\f\u00ae") - buf.write("\3\2\2\2\16\17\5\4\3\2\17\20\7\2\2\3\20\3\3\2\2\2\21\22") - buf.write("\5\6\4\2\22\24\7-\2\2\23\25\5\4\3\2\24\23\3\2\2\2\24\25") - buf.write("\3\2\2\2\25\5\3\2\2\2\26\27\7\3\2\2\27\32\7\31\2\2\30") - buf.write("\31\7\t\2\2\31\33\7\31\2\2\32\30\3\2\2\2\32\33\3\2\2\2") - buf.write("\33\34\3\2\2\2\34\"\7\'\2\2\35\36\5\b\5\2\36\37\7-\2\2") - buf.write("\37!\3\2\2\2 \35\3\2\2\2!$\3\2\2\2\" \3\2\2\2\"#\3\2\2") - buf.write("\2#%\3\2\2\2$\"\3\2\2\2%&\7(\2\2&\7\3\2\2\2\'(\7\32\2") - buf.write("\2(\63\7%\2\2).\5\n\6\2*+\7+\2\2+-\5\n\6\2,*\3\2\2\2-") - buf.write("\60\3\2\2\2.,\3\2\2\2./\3\2\2\2/\62\3\2\2\2\60.\3\2\2") - buf.write("\2\61)\3\2\2\2\62\65\3\2\2\2\63\61\3\2\2\2\63\64\3\2\2") - buf.write("\2\64\66\3\2\2\2\65\63\3\2\2\2\66\67\7&\2\2\678\7,\2\2") - buf.write("89\7\31\2\29:\7\'\2\2:;\5\f\7\2;<\7(\2\2\7") - buf.write("\32\2\2>?\7,\2\2?B\7\31\2\2@A\7\33\2\2AC\5\f\7\2B@\3\2") - buf.write("\2\2BC\3\2\2\2CE\3\2\2\2D\'\3\2\2\2D=\3\2\2\2E\t\3\2\2") - buf.write("\2FG\7\32\2\2GH\7,\2\2HI\7\31\2\2I\13\3\2\2\2JK\b\7\1") - buf.write("\2KL\7\32\2\2LW\7%\2\2MR\5\f\7\2NO\7+\2\2OQ\5\f\7\2PN") - buf.write("\3\2\2\2QT\3\2\2\2RP\3\2\2\2RS\3\2\2\2SV\3\2\2\2TR\3\2") - buf.write("\2\2UM\3\2\2\2VY\3\2\2\2WU\3\2\2\2WX\3\2\2\2XZ\3\2\2\2") - buf.write("YW\3\2\2\2Z\u00af\7&\2\2[\\\7\7\2\2\\]\5\f\7\2]^\7\16") - buf.write("\2\2^_\5\f\7\2_`\7\4\2\2`a\5\f\7\2ab\7\6\2\2b\u00af\3") - buf.write("\2\2\2cd\7\17\2\2de\5\f\7\2ef\7\f\2\2fg\5\f\7\2gh\7\r") - buf.write("\2\2h\u00af\3\2\2\2im\7\'\2\2jk\5\f\7\2kl\7-\2\2ln\3\2") - buf.write("\2\2mj\3\2\2\2no\3\2\2\2om\3\2\2\2op\3\2\2\2pq\3\2\2\2") - buf.write("qr\7(\2\2r\u00af\3\2\2\2st\7\13\2\2tu\7\32\2\2uv\7,\2") - buf.write("\2vy\7\31\2\2wx\7\33\2\2xz\5\f\7\2yw\3\2\2\2yz\3\2\2\2") - buf.write("z\u0085\3\2\2\2{|\7+\2\2|}\7\32\2\2}~\7,\2\2~\u0081\7") - buf.write("\31\2\2\177\u0080\7\33\2\2\u0080\u0082\5\f\7\2\u0081\177") - buf.write("\3\2\2\2\u0081\u0082\3\2\2\2\u0082\u0084\3\2\2\2\u0083") - buf.write("{\3\2\2\2\u0084\u0087\3\2\2\2\u0085\u0083\3\2\2\2\u0085") - buf.write("\u0086\3\2\2\2\u0086\u0088\3\2\2\2\u0087\u0085\3\2\2\2") - buf.write("\u0088\u0089\7\b\2\2\u0089\u00af\5\f\7\26\u008a\u008b") - buf.write("\7\20\2\2\u008b\u008c\5\f\7\2\u008c\u0094\7\23\2\2\u008d") - buf.write("\u008e\7\32\2\2\u008e\u008f\7,\2\2\u008f\u0090\7\31\2") - buf.write("\2\u0090\u0091\7\34\2\2\u0091\u0092\5\f\7\2\u0092\u0093") - buf.write("\7-\2\2\u0093\u0095\3\2\2\2\u0094\u008d\3\2\2\2\u0095") - buf.write("\u0096\3\2\2\2\u0096\u0094\3\2\2\2\u0096\u0097\3\2\2\2") - buf.write("\u0097\u0098\3\2\2\2\u0098\u0099\7\21\2\2\u0099\u00af") - buf.write("\3\2\2\2\u009a\u009b\7\22\2\2\u009b\u00af\7\31\2\2\u009c") - buf.write("\u009d\7$\2\2\u009d\u00af\5\f\7\23\u009e\u009f\7\n\2\2") - buf.write("\u009f\u00af\5\f\7\22\u00a0\u00a1\7\24\2\2\u00a1\u00af") - buf.write("\5\f\7\n\u00a2\u00a3\7%\2\2\u00a3\u00a4\5\f\7\2\u00a4") - buf.write("\u00a5\7&\2\2\u00a5\u00af\3\2\2\2\u00a6\u00af\7\32\2\2") - buf.write("\u00a7\u00af\7\30\2\2\u00a8\u00af\7\26\2\2\u00a9\u00af") - buf.write("\7\25\2\2\u00aa\u00af\7\5\2\2\u00ab\u00ac\7\32\2\2\u00ac") - buf.write("\u00ad\7\33\2\2\u00ad\u00af\5\f\7\3\u00aeJ\3\2\2\2\u00ae") - buf.write("[\3\2\2\2\u00aec\3\2\2\2\u00aei\3\2\2\2\u00aes\3\2\2\2") - buf.write("\u00ae\u008a\3\2\2\2\u00ae\u009a\3\2\2\2\u00ae\u009c\3") - buf.write("\2\2\2\u00ae\u009e\3\2\2\2\u00ae\u00a0\3\2\2\2\u00ae\u00a2") - buf.write("\3\2\2\2\u00ae\u00a6\3\2\2\2\u00ae\u00a7\3\2\2\2\u00ae") - buf.write("\u00a8\3\2\2\2\u00ae\u00a9\3\2\2\2\u00ae\u00aa\3\2\2\2") - buf.write("\u00ae\u00ab\3\2\2\2\u00af\u00dd\3\2\2\2\u00b0\u00b1\f") - buf.write("\21\2\2\u00b1\u00b2\7\37\2\2\u00b2\u00dc\5\f\7\22\u00b3") - buf.write("\u00b4\f\20\2\2\u00b4\u00b5\7 \2\2\u00b5\u00dc\5\f\7\21") - buf.write("\u00b6\u00b7\f\17\2\2\u00b7\u00b8\7\35\2\2\u00b8\u00dc") - buf.write("\5\f\7\20\u00b9\u00ba\f\16\2\2\u00ba\u00bb\7\36\2\2\u00bb") - buf.write("\u00dc\5\f\7\17\u00bc\u00bd\f\r\2\2\u00bd\u00be\7!\2\2") - buf.write("\u00be\u00dc\5\f\7\16\u00bf\u00c0\f\f\2\2\u00c0\u00c1") - buf.write("\7\"\2\2\u00c1\u00dc\5\f\7\r\u00c2\u00c3\f\13\2\2\u00c3") - buf.write("\u00c4\7#\2\2\u00c4\u00dc\5\f\7\f\u00c5\u00c8\f\33\2\2") - buf.write("\u00c6\u00c7\7)\2\2\u00c7\u00c9\7\31\2\2\u00c8\u00c6\3") - buf.write("\2\2\2\u00c8\u00c9\3\2\2\2\u00c9\u00ca\3\2\2\2\u00ca\u00cb") - buf.write("\7*\2\2\u00cb\u00cc\7\32\2\2\u00cc\u00d7\7%\2\2\u00cd") - buf.write("\u00d2\5\f\7\2\u00ce\u00cf\7+\2\2\u00cf\u00d1\5\f\7\2") - buf.write("\u00d0\u00ce\3\2\2\2\u00d1\u00d4\3\2\2\2\u00d2\u00d0\3") - buf.write("\2\2\2\u00d2\u00d3\3\2\2\2\u00d3\u00d6\3\2\2\2\u00d4\u00d2") - buf.write("\3\2\2\2\u00d5\u00cd\3\2\2\2\u00d6\u00d9\3\2\2\2\u00d7") - buf.write("\u00d5\3\2\2\2\u00d7\u00d8\3\2\2\2\u00d8\u00da\3\2\2\2") - buf.write("\u00d9\u00d7\3\2\2\2\u00da\u00dc\7&\2\2\u00db\u00b0\3") - buf.write("\2\2\2\u00db\u00b3\3\2\2\2\u00db\u00b6\3\2\2\2\u00db\u00b9") - buf.write("\3\2\2\2\u00db\u00bc\3\2\2\2\u00db\u00bf\3\2\2\2\u00db") - buf.write("\u00c2\3\2\2\2\u00db\u00c5\3\2\2\2\u00dc\u00df\3\2\2\2") - buf.write("\u00dd\u00db\3\2\2\2\u00dd\u00de\3\2\2\2\u00de\r\3\2\2") - buf.write("\2\u00df\u00dd\3\2\2\2\26\24\32\".\63BDRWoy\u0081\u0085") - buf.write("\u0096\u00ae\u00c8\u00d2\u00d7\u00db\u00dd") + buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\6\7k\n\7\r\7\16\7l\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\5\7w\n\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\5\7\177\n\7\7\7\u0081\n\7\f\7\16\7\u0084\13\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\6\7\u0092\n") + buf.write("\7\r\7\16\7\u0093\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\5") + buf.write("\7\u00ac\n\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\5\7\u00c6\n\7\3\7\3\7\3\7\3\7\3\7\3\7\7\7\u00ce\n\7\f") + buf.write("\7\16\7\u00d1\13\7\5\7\u00d3\n\7\3\7\7\7\u00d6\n\7\f\7") + buf.write("\16\7\u00d9\13\7\3\7\2\3\f\b\2\4\6\b\n\f\2\2\2\u00fd\2") + buf.write("\16\3\2\2\2\4\21\3\2\2\2\6\26\3\2\2\2\bD\3\2\2\2\nF\3") + buf.write("\2\2\2\f\u00ab\3\2\2\2\16\17\5\4\3\2\17\20\7\2\2\3\20") + buf.write("\3\3\2\2\2\21\22\5\6\4\2\22\24\7.\2\2\23\25\5\4\3\2\24") + buf.write("\23\3\2\2\2\24\25\3\2\2\2\25\5\3\2\2\2\26\27\7\3\2\2\27") + buf.write("\32\7\32\2\2\30\31\7\t\2\2\31\33\7\32\2\2\32\30\3\2\2") + buf.write("\2\32\33\3\2\2\2\33\34\3\2\2\2\34\"\7(\2\2\35\36\5\b\5") + buf.write("\2\36\37\7.\2\2\37!\3\2\2\2 \35\3\2\2\2!$\3\2\2\2\" \3") + buf.write("\2\2\2\"#\3\2\2\2#%\3\2\2\2$\"\3\2\2\2%&\7)\2\2&\7\3\2") + buf.write("\2\2\'(\7\33\2\2(\63\7&\2\2).\5\n\6\2*+\7,\2\2+-\5\n\6") + buf.write("\2,*\3\2\2\2-\60\3\2\2\2.,\3\2\2\2./\3\2\2\2/\62\3\2\2") + buf.write("\2\60.\3\2\2\2\61)\3\2\2\2\62\65\3\2\2\2\63\61\3\2\2\2") + buf.write("\63\64\3\2\2\2\64\66\3\2\2\2\65\63\3\2\2\2\66\67\7\'\2") + buf.write("\2\678\7-\2\289\7\32\2\29:\7(\2\2:;\5\f\7\2;<\7)\2\2<") + buf.write("E\3\2\2\2=>\7\33\2\2>?\7-\2\2?B\7\32\2\2@A\7\34\2\2AC") + buf.write("\5\f\7\2B@\3\2\2\2BC\3\2\2\2CE\3\2\2\2D\'\3\2\2\2D=\3") + buf.write("\2\2\2E\t\3\2\2\2FG\7\33\2\2GH\7-\2\2HI\7\32\2\2I\13\3") + buf.write("\2\2\2JK\b\7\1\2KL\7\33\2\2LU\7&\2\2MR\5\f\7\2NO\7,\2") + buf.write("\2OQ\5\f\7\2PN\3\2\2\2QT\3\2\2\2RP\3\2\2\2RS\3\2\2\2S") + buf.write("V\3\2\2\2TR\3\2\2\2UM\3\2\2\2UV\3\2\2\2VW\3\2\2\2W\u00ac") + buf.write("\7\'\2\2XY\7\7\2\2YZ\5\f\7\2Z[\7\16\2\2[\\\5\f\7\2\\]") + buf.write("\7\4\2\2]^\5\f\7\2^_\7\6\2\2_\u00ac\3\2\2\2`a\7\17\2\2") + buf.write("ab\5\f\7\2bc\7\f\2\2cd\5\f\7\2de\7\r\2\2e\u00ac\3\2\2") + buf.write("\2fj\7(\2\2gh\5\f\7\2hi\7.\2\2ik\3\2\2\2jg\3\2\2\2kl\3") + buf.write("\2\2\2lj\3\2\2\2lm\3\2\2\2mn\3\2\2\2no\7)\2\2o\u00ac\3") + buf.write("\2\2\2pq\7\13\2\2qr\7\33\2\2rs\7-\2\2sv\7\32\2\2tu\7\34") + buf.write("\2\2uw\5\f\7\2vt\3\2\2\2vw\3\2\2\2w\u0082\3\2\2\2xy\7") + buf.write(",\2\2yz\7\33\2\2z{\7-\2\2{~\7\32\2\2|}\7\34\2\2}\177\5") + buf.write("\f\7\2~|\3\2\2\2~\177\3\2\2\2\177\u0081\3\2\2\2\u0080") + buf.write("x\3\2\2\2\u0081\u0084\3\2\2\2\u0082\u0080\3\2\2\2\u0082") + buf.write("\u0083\3\2\2\2\u0083\u0085\3\2\2\2\u0084\u0082\3\2\2\2") + buf.write("\u0085\u0086\7\b\2\2\u0086\u00ac\5\f\7\26\u0087\u0088") + buf.write("\7\20\2\2\u0088\u0089\5\f\7\2\u0089\u0091\7\23\2\2\u008a") + buf.write("\u008b\7\33\2\2\u008b\u008c\7-\2\2\u008c\u008d\7\32\2") + buf.write("\2\u008d\u008e\7\35\2\2\u008e\u008f\5\f\7\2\u008f\u0090") + buf.write("\7.\2\2\u0090\u0092\3\2\2\2\u0091\u008a\3\2\2\2\u0092") + buf.write("\u0093\3\2\2\2\u0093\u0091\3\2\2\2\u0093\u0094\3\2\2\2") + buf.write("\u0094\u0095\3\2\2\2\u0095\u0096\7\21\2\2\u0096\u00ac") + buf.write("\3\2\2\2\u0097\u0098\7\22\2\2\u0098\u00ac\7\32\2\2\u0099") + buf.write("\u009a\7%\2\2\u009a\u00ac\5\f\7\23\u009b\u009c\7\n\2\2") + buf.write("\u009c\u00ac\5\f\7\22\u009d\u009e\7\24\2\2\u009e\u00ac") + buf.write("\5\f\7\n\u009f\u00a0\7&\2\2\u00a0\u00a1\5\f\7\2\u00a1") + buf.write("\u00a2\7\'\2\2\u00a2\u00ac\3\2\2\2\u00a3\u00ac\7\33\2") + buf.write("\2\u00a4\u00ac\7\31\2\2\u00a5\u00ac\7\26\2\2\u00a6\u00ac") + buf.write("\7\25\2\2\u00a7\u00ac\7\5\2\2\u00a8\u00a9\7\33\2\2\u00a9") + buf.write("\u00aa\7\34\2\2\u00aa\u00ac\5\f\7\3\u00abJ\3\2\2\2\u00ab") + buf.write("X\3\2\2\2\u00ab`\3\2\2\2\u00abf\3\2\2\2\u00abp\3\2\2\2") + buf.write("\u00ab\u0087\3\2\2\2\u00ab\u0097\3\2\2\2\u00ab\u0099\3") + buf.write("\2\2\2\u00ab\u009b\3\2\2\2\u00ab\u009d\3\2\2\2\u00ab\u009f") + buf.write("\3\2\2\2\u00ab\u00a3\3\2\2\2\u00ab\u00a4\3\2\2\2\u00ab") + buf.write("\u00a5\3\2\2\2\u00ab\u00a6\3\2\2\2\u00ab\u00a7\3\2\2\2") + buf.write("\u00ab\u00a8\3\2\2\2\u00ac\u00d7\3\2\2\2\u00ad\u00ae\f") + buf.write("\21\2\2\u00ae\u00af\7 \2\2\u00af\u00d6\5\f\7\22\u00b0") + buf.write("\u00b1\f\20\2\2\u00b1\u00b2\7!\2\2\u00b2\u00d6\5\f\7\21") + buf.write("\u00b3\u00b4\f\17\2\2\u00b4\u00b5\7\36\2\2\u00b5\u00d6") + buf.write("\5\f\7\20\u00b6\u00b7\f\16\2\2\u00b7\u00b8\7\37\2\2\u00b8") + buf.write("\u00d6\5\f\7\17\u00b9\u00ba\f\r\2\2\u00ba\u00bb\7\"\2") + buf.write("\2\u00bb\u00d6\5\f\7\16\u00bc\u00bd\f\f\2\2\u00bd\u00be") + buf.write("\7#\2\2\u00be\u00d6\5\f\7\r\u00bf\u00c0\f\13\2\2\u00c0") + buf.write("\u00c1\7$\2\2\u00c1\u00d6\5\f\7\f\u00c2\u00c5\f\33\2\2") + buf.write("\u00c3\u00c4\7*\2\2\u00c4\u00c6\7\32\2\2\u00c5\u00c3\3") + buf.write("\2\2\2\u00c5\u00c6\3\2\2\2\u00c6\u00c7\3\2\2\2\u00c7\u00c8") + buf.write("\7+\2\2\u00c8\u00c9\7\33\2\2\u00c9\u00d2\7&\2\2\u00ca") + buf.write("\u00cf\5\f\7\2\u00cb\u00cc\7,\2\2\u00cc\u00ce\5\f\7\2") + buf.write("\u00cd\u00cb\3\2\2\2\u00ce\u00d1\3\2\2\2\u00cf\u00cd\3") + buf.write("\2\2\2\u00cf\u00d0\3\2\2\2\u00d0\u00d3\3\2\2\2\u00d1\u00cf") + buf.write("\3\2\2\2\u00d2\u00ca\3\2\2\2\u00d2\u00d3\3\2\2\2\u00d3") + buf.write("\u00d4\3\2\2\2\u00d4\u00d6\7\'\2\2\u00d5\u00ad\3\2\2\2") + buf.write("\u00d5\u00b0\3\2\2\2\u00d5\u00b3\3\2\2\2\u00d5\u00b6\3") + buf.write("\2\2\2\u00d5\u00b9\3\2\2\2\u00d5\u00bc\3\2\2\2\u00d5\u00bf") + buf.write("\3\2\2\2\u00d5\u00c2\3\2\2\2\u00d6\u00d9\3\2\2\2\u00d7") + buf.write("\u00d5\3\2\2\2\u00d7\u00d8\3\2\2\2\u00d8\r\3\2\2\2\u00d9") + buf.write("\u00d7\3\2\2\2\26\24\32\".\63BDRUlv~\u0082\u0093\u00ab") + buf.write("\u00c5\u00cf\u00d2\u00d5\u00d7") return buf.getvalue() @@ -123,21 +120,22 @@ class COOL ( Parser ): "", "", "", "", "", "", "", "", "", "", "", "", - "", "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", - "'<'", "'<='", "'='", "'~'", "'('", "')'", "'{'", "'}'", - "'@'", "'.'", "','", "':'", "';'", "", "", - "'(*'", "", "'*)'" ] + "", "", "'<-'", "'=>'", "'+'", "'-'", + "'*'", "'/'", "'<'", "'<='", "'='", "'~'", "'('", "')'", + "'{'", "'}'", "'@'", "'.'", "','", "':'", "';'", "", + "", "'(*'", "", "'*)'" ] symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", - "TRUE", "STRING", "BREAK_STRING", "INT", "TYPEID", - "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", - "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", - "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", - "OPEN_CURLY", "CLOSE_CURLY", "AT", "DOT", "COMMA", - "COLON", "SEMICOLON", "WHITESPACE", "ONE_LINE_COMMENT", - "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT" ] + "TRUE", "STRING", "STRING_SIMPLE", "STRING_FIRSTLINE", + "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", + "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", + "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", + "CLOSE_ROUND", "OPEN_CURLY", "CLOSE_CURLY", "AT", + "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", + "ONE_LINE_COMMENT", "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT", + "STRING_INNERLINE", "STRING_LASTLINE", "STRING_MULTILINE" ] RULE_program = 0 RULE_programBlocks = 1 @@ -170,34 +168,38 @@ class COOL ( Parser ): NOT=18 TRUE=19 STRING=20 - BREAK_STRING=21 - INT=22 - TYPEID=23 - OBJECTID=24 - ASSIGNMENT=25 - CASE_ARROW=26 - ADD=27 - MINUS=28 - MULTIPLY=29 - DIVISION=30 - LESS_THAN=31 - LESS_EQUAL=32 - EQUAL=33 - INTEGER_NEGATIVE=34 - OPEN_ROUND=35 - CLOSE_ROUND=36 - OPEN_CURLY=37 - CLOSE_CURLY=38 - AT=39 - DOT=40 - COMMA=41 - COLON=42 - SEMICOLON=43 - WHITESPACE=44 - ONE_LINE_COMMENT=45 - OPEN_COMMENT=46 - COMMENT=47 - CLOSE_COMMENT=48 + STRING_SIMPLE=21 + STRING_FIRSTLINE=22 + INT=23 + TYPEID=24 + OBJECTID=25 + ASSIGNMENT=26 + CASE_ARROW=27 + ADD=28 + MINUS=29 + MULTIPLY=30 + DIVISION=31 + LESS_THAN=32 + LESS_EQUAL=33 + EQUAL=34 + INTEGER_NEGATIVE=35 + OPEN_ROUND=36 + CLOSE_ROUND=37 + OPEN_CURLY=38 + CLOSE_CURLY=39 + AT=40 + DOT=41 + COMMA=42 + COLON=43 + SEMICOLON=44 + WHITESPACE=45 + ONE_LINE_COMMENT=46 + OPEN_COMMENT=47 + COMMENT=48 + CLOSE_COMMENT=49 + STRING_INNERLINE=50 + STRING_LASTLINE=51 + STRING_MULTILINE=52 def __init__(self, input:TokenStream, output:TextIO = sys.stdout): super().__init__(input, output) @@ -1320,7 +1322,7 @@ def expression(self, _p:int=0): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 172 + self.state = 169 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,14,self._ctx) if la_ == 1: @@ -1332,10 +1334,10 @@ def expression(self, _p:int=0): self.match(COOL.OBJECTID) self.state = 74 self.match(COOL.OPEN_ROUND) - self.state = 85 + self.state = 83 self._errHandler.sync(self) _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0): + if (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0): self.state = 75 self.expression(0) self.state = 80 @@ -1350,11 +1352,9 @@ def expression(self, _p:int=0): self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 87 - self._errHandler.sync(self) - _la = self._input.LA(1) - self.state = 88 + + self.state = 85 self.match(COOL.CLOSE_ROUND) pass @@ -1362,19 +1362,19 @@ def expression(self, _p:int=0): localctx = COOL.IfContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 89 + self.state = 86 self.match(COOL.IF) - self.state = 90 + self.state = 87 self.expression(0) - self.state = 91 + self.state = 88 self.match(COOL.THEN) - self.state = 92 + self.state = 89 self.expression(0) - self.state = 93 + self.state = 90 self.match(COOL.ELSE) - self.state = 94 + self.state = 91 self.expression(0) - self.state = 95 + self.state = 92 self.match(COOL.FI) pass @@ -1382,15 +1382,15 @@ def expression(self, _p:int=0): localctx = COOL.WhileContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 97 + self.state = 94 self.match(COOL.WHILE) - self.state = 98 + self.state = 95 self.expression(0) - self.state = 99 + self.state = 96 self.match(COOL.LOOP) - self.state = 100 + self.state = 97 self.expression(0) - self.state = 101 + self.state = 98 self.match(COOL.POOL) pass @@ -1398,23 +1398,23 @@ def expression(self, _p:int=0): localctx = COOL.BlockContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 103 + self.state = 100 self.match(COOL.OPEN_CURLY) - self.state = 107 + self.state = 104 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 104 + self.state = 101 self.expression(0) - self.state = 105 + self.state = 102 self.match(COOL.SEMICOLON) - self.state = 109 + self.state = 106 self._errHandler.sync(self) _la = self._input.LA(1) if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0)): break - self.state = 111 + self.state = 108 self.match(COOL.CLOSE_CURLY) pass @@ -1422,53 +1422,53 @@ def expression(self, _p:int=0): localctx = COOL.LetInContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 113 + self.state = 110 self.match(COOL.LET) - self.state = 114 + self.state = 111 self.match(COOL.OBJECTID) - self.state = 115 + self.state = 112 self.match(COOL.COLON) - self.state = 116 + self.state = 113 self.match(COOL.TYPEID) - self.state = 119 + self.state = 116 self._errHandler.sync(self) _la = self._input.LA(1) if _la==COOL.ASSIGNMENT: - self.state = 117 + self.state = 114 self.match(COOL.ASSIGNMENT) - self.state = 118 + self.state = 115 self.expression(0) - self.state = 131 + self.state = 128 self._errHandler.sync(self) _la = self._input.LA(1) while _la==COOL.COMMA: - self.state = 121 + self.state = 118 self.match(COOL.COMMA) - self.state = 122 + self.state = 119 self.match(COOL.OBJECTID) - self.state = 123 + self.state = 120 self.match(COOL.COLON) - self.state = 124 + self.state = 121 self.match(COOL.TYPEID) - self.state = 127 + self.state = 124 self._errHandler.sync(self) _la = self._input.LA(1) if _la==COOL.ASSIGNMENT: - self.state = 125 + self.state = 122 self.match(COOL.ASSIGNMENT) - self.state = 126 + self.state = 123 self.expression(0) - self.state = 133 + self.state = 130 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 134 + self.state = 131 self.match(COOL.IN) - self.state = 135 + self.state = 132 self.expression(20) pass @@ -1476,35 +1476,35 @@ def expression(self, _p:int=0): localctx = COOL.CaseContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 136 + self.state = 133 self.match(COOL.CASE) - self.state = 137 + self.state = 134 self.expression(0) - self.state = 138 + self.state = 135 self.match(COOL.OF) - self.state = 146 + self.state = 143 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 139 + self.state = 136 self.match(COOL.OBJECTID) - self.state = 140 + self.state = 137 self.match(COOL.COLON) - self.state = 141 + self.state = 138 self.match(COOL.TYPEID) - self.state = 142 + self.state = 139 self.match(COOL.CASE_ARROW) - self.state = 143 + self.state = 140 self.expression(0) - self.state = 144 + self.state = 141 self.match(COOL.SEMICOLON) - self.state = 148 + self.state = 145 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==COOL.OBJECTID): break - self.state = 150 + self.state = 147 self.match(COOL.ESAC) pass @@ -1512,9 +1512,9 @@ def expression(self, _p:int=0): localctx = COOL.NewContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 152 + self.state = 149 self.match(COOL.NEW) - self.state = 153 + self.state = 150 self.match(COOL.TYPEID) pass @@ -1522,9 +1522,9 @@ def expression(self, _p:int=0): localctx = COOL.NegativeContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 154 + self.state = 151 self.match(COOL.INTEGER_NEGATIVE) - self.state = 155 + self.state = 152 self.expression(17) pass @@ -1532,9 +1532,9 @@ def expression(self, _p:int=0): localctx = COOL.IsvoidContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 156 + self.state = 153 self.match(COOL.ISVOID) - self.state = 157 + self.state = 154 self.expression(16) pass @@ -1542,9 +1542,9 @@ def expression(self, _p:int=0): localctx = COOL.BoolNotContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 158 + self.state = 155 self.match(COOL.NOT) - self.state = 159 + self.state = 156 self.expression(8) pass @@ -1552,11 +1552,11 @@ def expression(self, _p:int=0): localctx = COOL.ParenthesesContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 160 + self.state = 157 self.match(COOL.OPEN_ROUND) - self.state = 161 + self.state = 158 self.expression(0) - self.state = 162 + self.state = 159 self.match(COOL.CLOSE_ROUND) pass @@ -1564,7 +1564,7 @@ def expression(self, _p:int=0): localctx = COOL.IdContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 164 + self.state = 161 self.match(COOL.OBJECTID) pass @@ -1572,7 +1572,7 @@ def expression(self, _p:int=0): localctx = COOL.IntContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 165 + self.state = 162 self.match(COOL.INT) pass @@ -1580,7 +1580,7 @@ def expression(self, _p:int=0): localctx = COOL.StringContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 166 + self.state = 163 self.match(COOL.STRING) pass @@ -1588,7 +1588,7 @@ def expression(self, _p:int=0): localctx = COOL.TrueContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 167 + self.state = 164 self.match(COOL.TRUE) pass @@ -1596,7 +1596,7 @@ def expression(self, _p:int=0): localctx = COOL.FalseContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 168 + self.state = 165 self.match(COOL.FALSE) pass @@ -1604,17 +1604,17 @@ def expression(self, _p:int=0): localctx = COOL.AssignmentContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 169 + self.state = 166 self.match(COOL.OBJECTID) - self.state = 170 + self.state = 167 self.match(COOL.ASSIGNMENT) - self.state = 171 + self.state = 168 self.expression(1) pass self._ctx.stop = self._input.LT(-1) - self.state = 219 + self.state = 213 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,19,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: @@ -1622,151 +1622,149 @@ def expression(self, _p:int=0): if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx - self.state = 217 + self.state = 211 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,18,self._ctx) if la_ == 1: localctx = COOL.MultiplyContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 174 + self.state = 171 if not self.precpred(self._ctx, 15): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 15)") - self.state = 175 + self.state = 172 self.match(COOL.MULTIPLY) - self.state = 176 + self.state = 173 self.expression(16) pass elif la_ == 2: localctx = COOL.DivisionContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 177 + self.state = 174 if not self.precpred(self._ctx, 14): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 14)") - self.state = 178 + self.state = 175 self.match(COOL.DIVISION) - self.state = 179 + self.state = 176 self.expression(15) pass elif la_ == 3: localctx = COOL.AddContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 180 + self.state = 177 if not self.precpred(self._ctx, 13): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 13)") - self.state = 181 + self.state = 178 self.match(COOL.ADD) - self.state = 182 + self.state = 179 self.expression(14) pass elif la_ == 4: localctx = COOL.MinusContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 183 + self.state = 180 if not self.precpred(self._ctx, 12): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 12)") - self.state = 184 + self.state = 181 self.match(COOL.MINUS) - self.state = 185 + self.state = 182 self.expression(13) pass elif la_ == 5: localctx = COOL.LessThanContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 186 + self.state = 183 if not self.precpred(self._ctx, 11): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 11)") - self.state = 187 + self.state = 184 self.match(COOL.LESS_THAN) - self.state = 188 + self.state = 185 self.expression(12) pass elif la_ == 6: localctx = COOL.LessEqualContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 189 + self.state = 186 if not self.precpred(self._ctx, 10): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 10)") - self.state = 190 + self.state = 187 self.match(COOL.LESS_EQUAL) - self.state = 191 + self.state = 188 self.expression(11) pass elif la_ == 7: localctx = COOL.EqualContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 192 + self.state = 189 if not self.precpred(self._ctx, 9): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 9)") - self.state = 193 + self.state = 190 self.match(COOL.EQUAL) - self.state = 194 + self.state = 191 self.expression(10) pass elif la_ == 8: localctx = COOL.MethodCallContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 195 + self.state = 192 if not self.precpred(self._ctx, 25): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 25)") - self.state = 198 + self.state = 195 self._errHandler.sync(self) _la = self._input.LA(1) if _la==COOL.AT: - self.state = 196 + self.state = 193 self.match(COOL.AT) - self.state = 197 + self.state = 194 self.match(COOL.TYPEID) - self.state = 200 + self.state = 197 self.match(COOL.DOT) - self.state = 201 + self.state = 198 self.match(COOL.OBJECTID) - self.state = 202 + self.state = 199 self.match(COOL.OPEN_ROUND) - self.state = 213 + self.state = 208 self._errHandler.sync(self) _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0): - self.state = 203 + if (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0): + self.state = 200 self.expression(0) - self.state = 208 + self.state = 205 self._errHandler.sync(self) _la = self._input.LA(1) while _la==COOL.COMMA: - self.state = 204 + self.state = 201 self.match(COOL.COMMA) - self.state = 205 + self.state = 202 self.expression(0) - self.state = 210 + self.state = 207 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 215 - self._errHandler.sync(self) - _la = self._input.LA(1) - self.state = 216 + + self.state = 210 self.match(COOL.CLOSE_ROUND) pass - self.state = 221 + self.state = 215 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,19,self._ctx) diff --git a/src/COOL.tokens b/src/COOL.tokens index bbdda836..de4efcf0 100644 --- a/src/COOL.tokens +++ b/src/COOL.tokens @@ -18,52 +18,56 @@ OF=17 NOT=18 TRUE=19 STRING=20 -BREAK_STRING=21 -INT=22 -TYPEID=23 -OBJECTID=24 -ASSIGNMENT=25 -CASE_ARROW=26 -ADD=27 -MINUS=28 -MULTIPLY=29 -DIVISION=30 -LESS_THAN=31 -LESS_EQUAL=32 -EQUAL=33 -INTEGER_NEGATIVE=34 -OPEN_ROUND=35 -CLOSE_ROUND=36 -OPEN_CURLY=37 -CLOSE_CURLY=38 -AT=39 -DOT=40 -COMMA=41 -COLON=42 -SEMICOLON=43 -WHITESPACE=44 -ONE_LINE_COMMENT=45 -OPEN_COMMENT=46 -COMMENT=47 -CLOSE_COMMENT=48 -'<-'=25 -'=>'=26 -'+'=27 -'-'=28 -'*'=29 -'/'=30 -'<'=31 -'<='=32 -'='=33 -'~'=34 -'('=35 -')'=36 -'{'=37 -'}'=38 -'@'=39 -'.'=40 -','=41 -':'=42 -';'=43 -'(*'=46 -'*)'=48 +STRING_SIMPLE=21 +STRING_FIRSTLINE=22 +INT=23 +TYPEID=24 +OBJECTID=25 +ASSIGNMENT=26 +CASE_ARROW=27 +ADD=28 +MINUS=29 +MULTIPLY=30 +DIVISION=31 +LESS_THAN=32 +LESS_EQUAL=33 +EQUAL=34 +INTEGER_NEGATIVE=35 +OPEN_ROUND=36 +CLOSE_ROUND=37 +OPEN_CURLY=38 +CLOSE_CURLY=39 +AT=40 +DOT=41 +COMMA=42 +COLON=43 +SEMICOLON=44 +WHITESPACE=45 +ONE_LINE_COMMENT=46 +OPEN_COMMENT=47 +COMMENT=48 +CLOSE_COMMENT=49 +STRING_INNERLINE=50 +STRING_LASTLINE=51 +STRING_MULTILINE=52 +'<-'=26 +'=>'=27 +'+'=28 +'-'=29 +'*'=30 +'/'=31 +'<'=32 +'<='=33 +'='=34 +'~'=35 +'('=36 +')'=37 +'{'=38 +'}'=39 +'@'=40 +'.'=41 +','=42 +':'=43 +';'=44 +'(*'=47 +'*)'=49 diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 6e21c735..b2d7beab 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -20,8 +20,8 @@ def main(argv): lexer.addErrorListener(COOLLexerErrorListener()) token = lexer.nextToken() while token.type != Token.EOF: + #print(token.type) token = lexer.nextToken() - if lexer.hasErrors: return sys.exit(errno.EPERM) diff --git a/src/COOLLexer.py b/src/COOLLexer.py index bcb2349c..8456f1b6 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -14,6 +14,7 @@ class COOLLexer(COOL_LEX): def __init__(self, input=None, output:TextIO = sys.stdout): super().__init__(input, output) self._hasErrors = False + self._currentToken = None; def notifyListeners(self, e:LexerNoViableAltException): self._hasErrors = True @@ -21,13 +22,47 @@ def notifyListeners(self, e:LexerNoViableAltException): start = self._tokenStartCharIndex stop = self._input.index text = self._input.getText(start, stop) - msg = "'" + self.getErrorDisplay(text) + "'" + if self._currentToken.type in [COOL_LEX.STRING, COOL_LEX.STRING_FIRSTLINE, COOL_LEX.STRING_INNERLINE] or text[0] == '"': + if self.inputStream.size == self.inputStream.index: + msg = "EOF in string constant" + else: + msg = "Unterminated string constant" + else: + msg = "'" + self.getErrorDisplay(text) + "'" + if self._token == None: + line = self.line + col= self.column + else: + line = self._tokenStartLine + col = self._tokenStartColumn listener = self.getErrorListenerDispatch() - listener.syntaxError(self, self._token, self._tokenStartLine, self._tokenStartColumn, msg, e) + listener.syntaxError(self, self._token, line, col, msg, e) + + def nextToken(self): + while (True): + lastToken = self._currentToken + self._currentToken = super().nextToken() + if self._currentToken.type in [COOL_LEX.OPEN_COMMENT, COOL_LEX.CLOSE_COMMENT]: + continue + elif self._currentToken.type == COOL_LEX.STRING_FIRSTLINE: + continue + elif self._currentToken.type == COOL_LEX.STRING_INNERLINE: + continue + else: + break + + if self._currentToken.type == Token.EOF: + if lastToken != None and lastToken.type == COOL_LEX.OPEN_COMMENT: + self._hasErrors = True + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, self._currentToken, self._currentToken.line, self._currentToken.column, + "EOF in comment", None) + return self._currentToken; def reset(self): super().reset() self._hasErrors = False + self._currentToken = None; @property def hasErrors(self): diff --git a/src/COOL_LEX.interp b/src/COOL_LEX.interp index 5e362562..4d6e25e8 100644 --- a/src/COOL_LEX.interp +++ b/src/COOL_LEX.interp @@ -24,6 +24,7 @@ null null null null +null '<-' '=>' '+' @@ -48,6 +49,9 @@ null '(*' null '*)' +null +null +null token symbolic names: null @@ -71,7 +75,8 @@ OF NOT TRUE STRING -BREAK_STRING +STRING_SIMPLE +STRING_FIRSTLINE INT TYPEID OBJECTID @@ -99,6 +104,9 @@ ONE_LINE_COMMENT OPEN_COMMENT COMMENT CLOSE_COMMENT +STRING_INNERLINE +STRING_LASTLINE +STRING_MULTILINE rule names: CLASS @@ -121,7 +129,9 @@ OF NOT TRUE STRING -BREAK_STRING +STRING_SIMPLE +STRING_CONTENT +STRING_FIRSTLINE INT TYPEID OBJECTID @@ -169,6 +179,9 @@ ONE_LINE_COMMENT OPEN_COMMENT COMMENT CLOSE_COMMENT +STRING_INNERLINE +STRING_LASTLINE +STRING_MULTILINE channel names: DEFAULT_TOKEN_CHANNEL @@ -177,6 +190,7 @@ HIDDEN mode names: DEFAULT_MODE MULTILINE_COMMENT +MULTILINE_STR atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 50, 406, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 7, 21, 238, 10, 21, 12, 21, 14, 21, 241, 11, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 5, 22, 252, 10, 22, 3, 23, 6, 23, 255, 10, 23, 13, 23, 14, 23, 256, 3, 24, 3, 24, 7, 24, 261, 10, 24, 12, 24, 14, 24, 264, 11, 24, 3, 25, 3, 25, 7, 25, 268, 10, 25, 12, 25, 14, 25, 271, 11, 25, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 62, 5, 62, 351, 10, 62, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 6, 65, 362, 10, 65, 13, 65, 14, 65, 363, 3, 65, 3, 65, 3, 66, 3, 66, 3, 66, 3, 66, 7, 66, 372, 10, 66, 12, 66, 14, 66, 375, 11, 66, 3, 66, 5, 66, 378, 10, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 6, 68, 393, 10, 68, 13, 68, 14, 68, 394, 5, 68, 397, 10, 68, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 394, 2, 70, 4, 3, 6, 4, 8, 5, 10, 6, 12, 7, 14, 8, 16, 9, 18, 10, 20, 11, 22, 12, 24, 13, 26, 14, 28, 15, 30, 16, 32, 17, 34, 18, 36, 19, 38, 20, 40, 21, 42, 22, 44, 23, 46, 24, 48, 25, 50, 26, 52, 27, 54, 28, 56, 29, 58, 30, 60, 31, 62, 32, 64, 33, 66, 34, 68, 35, 70, 36, 72, 37, 74, 38, 76, 39, 78, 40, 80, 41, 82, 42, 84, 43, 86, 44, 88, 45, 90, 2, 92, 2, 94, 2, 96, 2, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 46, 132, 47, 134, 48, 136, 49, 138, 50, 4, 2, 3, 28, 6, 2, 12, 12, 15, 15, 36, 36, 94, 94, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 398, 2, 4, 3, 2, 2, 2, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 50, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 130, 3, 2, 2, 2, 2, 132, 3, 2, 2, 2, 2, 134, 3, 2, 2, 2, 3, 136, 3, 2, 2, 2, 3, 138, 3, 2, 2, 2, 4, 140, 3, 2, 2, 2, 6, 146, 3, 2, 2, 2, 8, 151, 3, 2, 2, 2, 10, 157, 3, 2, 2, 2, 12, 160, 3, 2, 2, 2, 14, 163, 3, 2, 2, 2, 16, 166, 3, 2, 2, 2, 18, 175, 3, 2, 2, 2, 20, 182, 3, 2, 2, 2, 22, 186, 3, 2, 2, 2, 24, 191, 3, 2, 2, 2, 26, 196, 3, 2, 2, 2, 28, 201, 3, 2, 2, 2, 30, 207, 3, 2, 2, 2, 32, 212, 3, 2, 2, 2, 34, 217, 3, 2, 2, 2, 36, 221, 3, 2, 2, 2, 38, 224, 3, 2, 2, 2, 40, 228, 3, 2, 2, 2, 42, 233, 3, 2, 2, 2, 44, 251, 3, 2, 2, 2, 46, 254, 3, 2, 2, 2, 48, 258, 3, 2, 2, 2, 50, 265, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 275, 3, 2, 2, 2, 56, 278, 3, 2, 2, 2, 58, 280, 3, 2, 2, 2, 60, 282, 3, 2, 2, 2, 62, 284, 3, 2, 2, 2, 64, 286, 3, 2, 2, 2, 66, 288, 3, 2, 2, 2, 68, 291, 3, 2, 2, 2, 70, 293, 3, 2, 2, 2, 72, 295, 3, 2, 2, 2, 74, 297, 3, 2, 2, 2, 76, 299, 3, 2, 2, 2, 78, 301, 3, 2, 2, 2, 80, 303, 3, 2, 2, 2, 82, 305, 3, 2, 2, 2, 84, 307, 3, 2, 2, 2, 86, 309, 3, 2, 2, 2, 88, 311, 3, 2, 2, 2, 90, 313, 3, 2, 2, 2, 92, 315, 3, 2, 2, 2, 94, 317, 3, 2, 2, 2, 96, 319, 3, 2, 2, 2, 98, 321, 3, 2, 2, 2, 100, 323, 3, 2, 2, 2, 102, 325, 3, 2, 2, 2, 104, 327, 3, 2, 2, 2, 106, 329, 3, 2, 2, 2, 108, 331, 3, 2, 2, 2, 110, 333, 3, 2, 2, 2, 112, 335, 3, 2, 2, 2, 114, 337, 3, 2, 2, 2, 116, 339, 3, 2, 2, 2, 118, 341, 3, 2, 2, 2, 120, 343, 3, 2, 2, 2, 122, 345, 3, 2, 2, 2, 124, 347, 3, 2, 2, 2, 126, 352, 3, 2, 2, 2, 128, 358, 3, 2, 2, 2, 130, 361, 3, 2, 2, 2, 132, 367, 3, 2, 2, 2, 134, 381, 3, 2, 2, 2, 136, 396, 3, 2, 2, 2, 138, 400, 3, 2, 2, 2, 140, 141, 5, 92, 46, 2, 141, 142, 5, 104, 52, 2, 142, 143, 5, 90, 45, 2, 143, 144, 5, 114, 57, 2, 144, 145, 5, 114, 57, 2, 145, 5, 3, 2, 2, 2, 146, 147, 5, 96, 48, 2, 147, 148, 5, 104, 52, 2, 148, 149, 5, 114, 57, 2, 149, 150, 5, 96, 48, 2, 150, 7, 3, 2, 2, 2, 151, 152, 7, 104, 2, 2, 152, 153, 5, 90, 45, 2, 153, 154, 5, 104, 52, 2, 154, 155, 5, 114, 57, 2, 155, 156, 5, 96, 48, 2, 156, 9, 3, 2, 2, 2, 157, 158, 5, 98, 49, 2, 158, 159, 5, 102, 51, 2, 159, 11, 3, 2, 2, 2, 160, 161, 5, 102, 51, 2, 161, 162, 5, 98, 49, 2, 162, 13, 3, 2, 2, 2, 163, 164, 5, 102, 51, 2, 164, 165, 5, 106, 53, 2, 165, 15, 3, 2, 2, 2, 166, 167, 5, 102, 51, 2, 167, 168, 5, 106, 53, 2, 168, 169, 5, 100, 50, 2, 169, 170, 5, 96, 48, 2, 170, 171, 5, 112, 56, 2, 171, 172, 5, 102, 51, 2, 172, 173, 5, 116, 58, 2, 173, 174, 5, 114, 57, 2, 174, 17, 3, 2, 2, 2, 175, 176, 5, 102, 51, 2, 176, 177, 5, 114, 57, 2, 177, 178, 5, 120, 60, 2, 178, 179, 5, 108, 54, 2, 179, 180, 5, 102, 51, 2, 180, 181, 5, 94, 47, 2, 181, 19, 3, 2, 2, 2, 182, 183, 5, 104, 52, 2, 183, 184, 5, 96, 48, 2, 184, 185, 5, 116, 58, 2, 185, 21, 3, 2, 2, 2, 186, 187, 5, 104, 52, 2, 187, 188, 5, 108, 54, 2, 188, 189, 5, 108, 54, 2, 189, 190, 5, 110, 55, 2, 190, 23, 3, 2, 2, 2, 191, 192, 5, 110, 55, 2, 192, 193, 5, 108, 54, 2, 193, 194, 5, 108, 54, 2, 194, 195, 5, 104, 52, 2, 195, 25, 3, 2, 2, 2, 196, 197, 5, 116, 58, 2, 197, 198, 5, 100, 50, 2, 198, 199, 5, 96, 48, 2, 199, 200, 5, 106, 53, 2, 200, 27, 3, 2, 2, 2, 201, 202, 5, 122, 61, 2, 202, 203, 5, 100, 50, 2, 203, 204, 5, 102, 51, 2, 204, 205, 5, 104, 52, 2, 205, 206, 5, 96, 48, 2, 206, 29, 3, 2, 2, 2, 207, 208, 5, 92, 46, 2, 208, 209, 5, 90, 45, 2, 209, 210, 5, 114, 57, 2, 210, 211, 5, 96, 48, 2, 211, 31, 3, 2, 2, 2, 212, 213, 5, 96, 48, 2, 213, 214, 5, 114, 57, 2, 214, 215, 5, 90, 45, 2, 215, 216, 5, 92, 46, 2, 216, 33, 3, 2, 2, 2, 217, 218, 5, 106, 53, 2, 218, 219, 5, 96, 48, 2, 219, 220, 5, 122, 61, 2, 220, 35, 3, 2, 2, 2, 221, 222, 5, 108, 54, 2, 222, 223, 5, 98, 49, 2, 223, 37, 3, 2, 2, 2, 224, 225, 5, 106, 53, 2, 225, 226, 5, 108, 54, 2, 226, 227, 5, 116, 58, 2, 227, 39, 3, 2, 2, 2, 228, 229, 7, 118, 2, 2, 229, 230, 5, 112, 56, 2, 230, 231, 5, 118, 59, 2, 231, 232, 5, 96, 48, 2, 232, 41, 3, 2, 2, 2, 233, 239, 7, 36, 2, 2, 234, 238, 5, 124, 62, 2, 235, 238, 5, 44, 22, 2, 236, 238, 10, 2, 2, 2, 237, 234, 3, 2, 2, 2, 237, 235, 3, 2, 2, 2, 237, 236, 3, 2, 2, 2, 238, 241, 3, 2, 2, 2, 239, 237, 3, 2, 2, 2, 239, 240, 3, 2, 2, 2, 240, 242, 3, 2, 2, 2, 241, 239, 3, 2, 2, 2, 242, 243, 7, 36, 2, 2, 243, 43, 3, 2, 2, 2, 244, 245, 7, 94, 2, 2, 245, 246, 7, 15, 2, 2, 246, 252, 7, 12, 2, 2, 247, 248, 7, 94, 2, 2, 248, 252, 7, 15, 2, 2, 249, 250, 7, 94, 2, 2, 250, 252, 7, 12, 2, 2, 251, 244, 3, 2, 2, 2, 251, 247, 3, 2, 2, 2, 251, 249, 3, 2, 2, 2, 252, 45, 3, 2, 2, 2, 253, 255, 9, 3, 2, 2, 254, 253, 3, 2, 2, 2, 255, 256, 3, 2, 2, 2, 256, 254, 3, 2, 2, 2, 256, 257, 3, 2, 2, 2, 257, 47, 3, 2, 2, 2, 258, 262, 9, 4, 2, 2, 259, 261, 9, 5, 2, 2, 260, 259, 3, 2, 2, 2, 261, 264, 3, 2, 2, 2, 262, 260, 3, 2, 2, 2, 262, 263, 3, 2, 2, 2, 263, 49, 3, 2, 2, 2, 264, 262, 3, 2, 2, 2, 265, 269, 9, 6, 2, 2, 266, 268, 9, 5, 2, 2, 267, 266, 3, 2, 2, 2, 268, 271, 3, 2, 2, 2, 269, 267, 3, 2, 2, 2, 269, 270, 3, 2, 2, 2, 270, 51, 3, 2, 2, 2, 271, 269, 3, 2, 2, 2, 272, 273, 7, 62, 2, 2, 273, 274, 7, 47, 2, 2, 274, 53, 3, 2, 2, 2, 275, 276, 7, 63, 2, 2, 276, 277, 7, 64, 2, 2, 277, 55, 3, 2, 2, 2, 278, 279, 7, 45, 2, 2, 279, 57, 3, 2, 2, 2, 280, 281, 7, 47, 2, 2, 281, 59, 3, 2, 2, 2, 282, 283, 7, 44, 2, 2, 283, 61, 3, 2, 2, 2, 284, 285, 7, 49, 2, 2, 285, 63, 3, 2, 2, 2, 286, 287, 7, 62, 2, 2, 287, 65, 3, 2, 2, 2, 288, 289, 7, 62, 2, 2, 289, 290, 7, 63, 2, 2, 290, 67, 3, 2, 2, 2, 291, 292, 7, 63, 2, 2, 292, 69, 3, 2, 2, 2, 293, 294, 7, 128, 2, 2, 294, 71, 3, 2, 2, 2, 295, 296, 7, 42, 2, 2, 296, 73, 3, 2, 2, 2, 297, 298, 7, 43, 2, 2, 298, 75, 3, 2, 2, 2, 299, 300, 7, 125, 2, 2, 300, 77, 3, 2, 2, 2, 301, 302, 7, 127, 2, 2, 302, 79, 3, 2, 2, 2, 303, 304, 7, 66, 2, 2, 304, 81, 3, 2, 2, 2, 305, 306, 7, 48, 2, 2, 306, 83, 3, 2, 2, 2, 307, 308, 7, 46, 2, 2, 308, 85, 3, 2, 2, 2, 309, 310, 7, 60, 2, 2, 310, 87, 3, 2, 2, 2, 311, 312, 7, 61, 2, 2, 312, 89, 3, 2, 2, 2, 313, 314, 9, 7, 2, 2, 314, 91, 3, 2, 2, 2, 315, 316, 9, 8, 2, 2, 316, 93, 3, 2, 2, 2, 317, 318, 9, 9, 2, 2, 318, 95, 3, 2, 2, 2, 319, 320, 9, 10, 2, 2, 320, 97, 3, 2, 2, 2, 321, 322, 9, 11, 2, 2, 322, 99, 3, 2, 2, 2, 323, 324, 9, 12, 2, 2, 324, 101, 3, 2, 2, 2, 325, 326, 9, 13, 2, 2, 326, 103, 3, 2, 2, 2, 327, 328, 9, 14, 2, 2, 328, 105, 3, 2, 2, 2, 329, 330, 9, 15, 2, 2, 330, 107, 3, 2, 2, 2, 331, 332, 9, 16, 2, 2, 332, 109, 3, 2, 2, 2, 333, 334, 9, 17, 2, 2, 334, 111, 3, 2, 2, 2, 335, 336, 9, 18, 2, 2, 336, 113, 3, 2, 2, 2, 337, 338, 9, 19, 2, 2, 338, 115, 3, 2, 2, 2, 339, 340, 9, 20, 2, 2, 340, 117, 3, 2, 2, 2, 341, 342, 9, 21, 2, 2, 342, 119, 3, 2, 2, 2, 343, 344, 9, 22, 2, 2, 344, 121, 3, 2, 2, 2, 345, 346, 9, 23, 2, 2, 346, 123, 3, 2, 2, 2, 347, 350, 7, 94, 2, 2, 348, 351, 9, 24, 2, 2, 349, 351, 5, 126, 63, 2, 350, 348, 3, 2, 2, 2, 350, 349, 3, 2, 2, 2, 351, 125, 3, 2, 2, 2, 352, 353, 7, 119, 2, 2, 353, 354, 5, 128, 64, 2, 354, 355, 5, 128, 64, 2, 355, 356, 5, 128, 64, 2, 356, 357, 5, 128, 64, 2, 357, 127, 3, 2, 2, 2, 358, 359, 9, 25, 2, 2, 359, 129, 3, 2, 2, 2, 360, 362, 9, 26, 2, 2, 361, 360, 3, 2, 2, 2, 362, 363, 3, 2, 2, 2, 363, 361, 3, 2, 2, 2, 363, 364, 3, 2, 2, 2, 364, 365, 3, 2, 2, 2, 365, 366, 8, 65, 2, 2, 366, 131, 3, 2, 2, 2, 367, 368, 7, 47, 2, 2, 368, 369, 7, 47, 2, 2, 369, 373, 3, 2, 2, 2, 370, 372, 10, 27, 2, 2, 371, 370, 3, 2, 2, 2, 372, 375, 3, 2, 2, 2, 373, 371, 3, 2, 2, 2, 373, 374, 3, 2, 2, 2, 374, 377, 3, 2, 2, 2, 375, 373, 3, 2, 2, 2, 376, 378, 7, 12, 2, 2, 377, 376, 3, 2, 2, 2, 377, 378, 3, 2, 2, 2, 378, 379, 3, 2, 2, 2, 379, 380, 8, 66, 2, 2, 380, 133, 3, 2, 2, 2, 381, 382, 7, 42, 2, 2, 382, 383, 7, 44, 2, 2, 383, 384, 3, 2, 2, 2, 384, 385, 8, 67, 2, 2, 385, 386, 8, 67, 3, 2, 386, 135, 3, 2, 2, 2, 387, 388, 5, 134, 67, 2, 388, 389, 5, 136, 68, 2, 389, 390, 5, 138, 69, 2, 390, 397, 3, 2, 2, 2, 391, 393, 11, 2, 2, 2, 392, 391, 3, 2, 2, 2, 393, 394, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 394, 392, 3, 2, 2, 2, 395, 397, 3, 2, 2, 2, 396, 387, 3, 2, 2, 2, 396, 392, 3, 2, 2, 2, 397, 398, 3, 2, 2, 2, 398, 399, 8, 68, 2, 2, 399, 137, 3, 2, 2, 2, 400, 401, 7, 44, 2, 2, 401, 402, 7, 43, 2, 2, 402, 403, 3, 2, 2, 2, 403, 404, 8, 69, 2, 2, 404, 405, 8, 69, 4, 2, 405, 139, 3, 2, 2, 2, 16, 2, 3, 237, 239, 251, 256, 262, 269, 350, 363, 373, 377, 394, 396, 5, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 54, 454, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 247, 10, 21, 3, 22, 3, 22, 7, 22, 251, 10, 22, 12, 22, 14, 22, 254, 11, 22, 3, 22, 3, 22, 3, 23, 3, 23, 5, 23, 260, 10, 23, 3, 24, 3, 24, 7, 24, 264, 10, 24, 12, 24, 14, 24, 267, 11, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 6, 25, 276, 10, 25, 13, 25, 14, 25, 277, 3, 26, 3, 26, 7, 26, 282, 10, 26, 12, 26, 14, 26, 285, 11, 26, 3, 27, 3, 27, 7, 27, 289, 10, 27, 12, 27, 14, 27, 292, 11, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 64, 5, 64, 372, 10, 64, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 66, 3, 66, 3, 67, 6, 67, 383, 10, 67, 13, 67, 14, 67, 384, 3, 67, 3, 67, 3, 68, 3, 68, 3, 68, 3, 68, 7, 68, 393, 10, 68, 12, 68, 14, 68, 396, 11, 68, 3, 68, 5, 68, 399, 10, 68, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 6, 70, 413, 10, 70, 13, 70, 14, 70, 414, 5, 70, 417, 10, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 72, 7, 72, 427, 10, 72, 12, 72, 14, 72, 430, 11, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 437, 10, 73, 12, 73, 14, 73, 440, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 3, 74, 7, 74, 448, 10, 74, 12, 74, 14, 74, 451, 11, 74, 3, 74, 3, 74, 3, 414, 2, 75, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 2, 49, 24, 51, 25, 53, 26, 55, 27, 57, 28, 59, 29, 61, 30, 63, 31, 65, 32, 67, 33, 69, 34, 71, 35, 73, 36, 75, 37, 77, 38, 79, 39, 81, 40, 83, 41, 85, 42, 87, 43, 89, 44, 91, 45, 93, 46, 95, 2, 97, 2, 99, 2, 101, 2, 103, 2, 105, 2, 107, 2, 109, 2, 111, 2, 113, 2, 115, 2, 117, 2, 119, 2, 121, 2, 123, 2, 125, 2, 127, 2, 129, 2, 131, 2, 133, 2, 135, 47, 137, 48, 139, 49, 141, 50, 143, 51, 145, 52, 147, 53, 149, 54, 5, 2, 3, 4, 28, 5, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 446, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 87, 3, 2, 2, 2, 2, 89, 3, 2, 2, 2, 2, 91, 3, 2, 2, 2, 2, 93, 3, 2, 2, 2, 2, 135, 3, 2, 2, 2, 2, 137, 3, 2, 2, 2, 2, 139, 3, 2, 2, 2, 3, 141, 3, 2, 2, 2, 3, 143, 3, 2, 2, 2, 4, 145, 3, 2, 2, 2, 4, 147, 3, 2, 2, 2, 4, 149, 3, 2, 2, 2, 5, 151, 3, 2, 2, 2, 7, 157, 3, 2, 2, 2, 9, 162, 3, 2, 2, 2, 11, 168, 3, 2, 2, 2, 13, 171, 3, 2, 2, 2, 15, 174, 3, 2, 2, 2, 17, 177, 3, 2, 2, 2, 19, 186, 3, 2, 2, 2, 21, 193, 3, 2, 2, 2, 23, 197, 3, 2, 2, 2, 25, 202, 3, 2, 2, 2, 27, 207, 3, 2, 2, 2, 29, 212, 3, 2, 2, 2, 31, 218, 3, 2, 2, 2, 33, 223, 3, 2, 2, 2, 35, 228, 3, 2, 2, 2, 37, 232, 3, 2, 2, 2, 39, 235, 3, 2, 2, 2, 41, 239, 3, 2, 2, 2, 43, 246, 3, 2, 2, 2, 45, 248, 3, 2, 2, 2, 47, 259, 3, 2, 2, 2, 49, 261, 3, 2, 2, 2, 51, 275, 3, 2, 2, 2, 53, 279, 3, 2, 2, 2, 55, 286, 3, 2, 2, 2, 57, 293, 3, 2, 2, 2, 59, 296, 3, 2, 2, 2, 61, 299, 3, 2, 2, 2, 63, 301, 3, 2, 2, 2, 65, 303, 3, 2, 2, 2, 67, 305, 3, 2, 2, 2, 69, 307, 3, 2, 2, 2, 71, 309, 3, 2, 2, 2, 73, 312, 3, 2, 2, 2, 75, 314, 3, 2, 2, 2, 77, 316, 3, 2, 2, 2, 79, 318, 3, 2, 2, 2, 81, 320, 3, 2, 2, 2, 83, 322, 3, 2, 2, 2, 85, 324, 3, 2, 2, 2, 87, 326, 3, 2, 2, 2, 89, 328, 3, 2, 2, 2, 91, 330, 3, 2, 2, 2, 93, 332, 3, 2, 2, 2, 95, 334, 3, 2, 2, 2, 97, 336, 3, 2, 2, 2, 99, 338, 3, 2, 2, 2, 101, 340, 3, 2, 2, 2, 103, 342, 3, 2, 2, 2, 105, 344, 3, 2, 2, 2, 107, 346, 3, 2, 2, 2, 109, 348, 3, 2, 2, 2, 111, 350, 3, 2, 2, 2, 113, 352, 3, 2, 2, 2, 115, 354, 3, 2, 2, 2, 117, 356, 3, 2, 2, 2, 119, 358, 3, 2, 2, 2, 121, 360, 3, 2, 2, 2, 123, 362, 3, 2, 2, 2, 125, 364, 3, 2, 2, 2, 127, 366, 3, 2, 2, 2, 129, 368, 3, 2, 2, 2, 131, 373, 3, 2, 2, 2, 133, 379, 3, 2, 2, 2, 135, 382, 3, 2, 2, 2, 137, 388, 3, 2, 2, 2, 139, 402, 3, 2, 2, 2, 141, 416, 3, 2, 2, 2, 143, 420, 3, 2, 2, 2, 145, 428, 3, 2, 2, 2, 147, 438, 3, 2, 2, 2, 149, 445, 3, 2, 2, 2, 151, 152, 5, 97, 48, 2, 152, 153, 5, 109, 54, 2, 153, 154, 5, 95, 47, 2, 154, 155, 5, 119, 59, 2, 155, 156, 5, 119, 59, 2, 156, 6, 3, 2, 2, 2, 157, 158, 5, 101, 50, 2, 158, 159, 5, 109, 54, 2, 159, 160, 5, 119, 59, 2, 160, 161, 5, 101, 50, 2, 161, 8, 3, 2, 2, 2, 162, 163, 7, 104, 2, 2, 163, 164, 5, 95, 47, 2, 164, 165, 5, 109, 54, 2, 165, 166, 5, 119, 59, 2, 166, 167, 5, 101, 50, 2, 167, 10, 3, 2, 2, 2, 168, 169, 5, 103, 51, 2, 169, 170, 5, 107, 53, 2, 170, 12, 3, 2, 2, 2, 171, 172, 5, 107, 53, 2, 172, 173, 5, 103, 51, 2, 173, 14, 3, 2, 2, 2, 174, 175, 5, 107, 53, 2, 175, 176, 5, 111, 55, 2, 176, 16, 3, 2, 2, 2, 177, 178, 5, 107, 53, 2, 178, 179, 5, 111, 55, 2, 179, 180, 5, 105, 52, 2, 180, 181, 5, 101, 50, 2, 181, 182, 5, 117, 58, 2, 182, 183, 5, 107, 53, 2, 183, 184, 5, 121, 60, 2, 184, 185, 5, 119, 59, 2, 185, 18, 3, 2, 2, 2, 186, 187, 5, 107, 53, 2, 187, 188, 5, 119, 59, 2, 188, 189, 5, 125, 62, 2, 189, 190, 5, 113, 56, 2, 190, 191, 5, 107, 53, 2, 191, 192, 5, 99, 49, 2, 192, 20, 3, 2, 2, 2, 193, 194, 5, 109, 54, 2, 194, 195, 5, 101, 50, 2, 195, 196, 5, 121, 60, 2, 196, 22, 3, 2, 2, 2, 197, 198, 5, 109, 54, 2, 198, 199, 5, 113, 56, 2, 199, 200, 5, 113, 56, 2, 200, 201, 5, 115, 57, 2, 201, 24, 3, 2, 2, 2, 202, 203, 5, 115, 57, 2, 203, 204, 5, 113, 56, 2, 204, 205, 5, 113, 56, 2, 205, 206, 5, 109, 54, 2, 206, 26, 3, 2, 2, 2, 207, 208, 5, 121, 60, 2, 208, 209, 5, 105, 52, 2, 209, 210, 5, 101, 50, 2, 210, 211, 5, 111, 55, 2, 211, 28, 3, 2, 2, 2, 212, 213, 5, 127, 63, 2, 213, 214, 5, 105, 52, 2, 214, 215, 5, 107, 53, 2, 215, 216, 5, 109, 54, 2, 216, 217, 5, 101, 50, 2, 217, 30, 3, 2, 2, 2, 218, 219, 5, 97, 48, 2, 219, 220, 5, 95, 47, 2, 220, 221, 5, 119, 59, 2, 221, 222, 5, 101, 50, 2, 222, 32, 3, 2, 2, 2, 223, 224, 5, 101, 50, 2, 224, 225, 5, 119, 59, 2, 225, 226, 5, 95, 47, 2, 226, 227, 5, 97, 48, 2, 227, 34, 3, 2, 2, 2, 228, 229, 5, 111, 55, 2, 229, 230, 5, 101, 50, 2, 230, 231, 5, 127, 63, 2, 231, 36, 3, 2, 2, 2, 232, 233, 5, 113, 56, 2, 233, 234, 5, 103, 51, 2, 234, 38, 3, 2, 2, 2, 235, 236, 5, 111, 55, 2, 236, 237, 5, 113, 56, 2, 237, 238, 5, 121, 60, 2, 238, 40, 3, 2, 2, 2, 239, 240, 7, 118, 2, 2, 240, 241, 5, 117, 58, 2, 241, 242, 5, 123, 61, 2, 242, 243, 5, 101, 50, 2, 243, 42, 3, 2, 2, 2, 244, 247, 5, 45, 22, 2, 245, 247, 5, 149, 74, 2, 246, 244, 3, 2, 2, 2, 246, 245, 3, 2, 2, 2, 247, 44, 3, 2, 2, 2, 248, 252, 7, 36, 2, 2, 249, 251, 5, 47, 23, 2, 250, 249, 3, 2, 2, 2, 251, 254, 3, 2, 2, 2, 252, 250, 3, 2, 2, 2, 252, 253, 3, 2, 2, 2, 253, 255, 3, 2, 2, 2, 254, 252, 3, 2, 2, 2, 255, 256, 7, 36, 2, 2, 256, 46, 3, 2, 2, 2, 257, 260, 5, 129, 64, 2, 258, 260, 10, 2, 2, 2, 259, 257, 3, 2, 2, 2, 259, 258, 3, 2, 2, 2, 260, 48, 3, 2, 2, 2, 261, 265, 7, 36, 2, 2, 262, 264, 5, 47, 23, 2, 263, 262, 3, 2, 2, 2, 264, 267, 3, 2, 2, 2, 265, 263, 3, 2, 2, 2, 265, 266, 3, 2, 2, 2, 266, 268, 3, 2, 2, 2, 267, 265, 3, 2, 2, 2, 268, 269, 7, 94, 2, 2, 269, 270, 7, 15, 2, 2, 270, 271, 7, 12, 2, 2, 271, 272, 3, 2, 2, 2, 272, 273, 8, 24, 2, 2, 273, 50, 3, 2, 2, 2, 274, 276, 9, 3, 2, 2, 275, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 275, 3, 2, 2, 2, 277, 278, 3, 2, 2, 2, 278, 52, 3, 2, 2, 2, 279, 283, 9, 4, 2, 2, 280, 282, 9, 5, 2, 2, 281, 280, 3, 2, 2, 2, 282, 285, 3, 2, 2, 2, 283, 281, 3, 2, 2, 2, 283, 284, 3, 2, 2, 2, 284, 54, 3, 2, 2, 2, 285, 283, 3, 2, 2, 2, 286, 290, 9, 6, 2, 2, 287, 289, 9, 5, 2, 2, 288, 287, 3, 2, 2, 2, 289, 292, 3, 2, 2, 2, 290, 288, 3, 2, 2, 2, 290, 291, 3, 2, 2, 2, 291, 56, 3, 2, 2, 2, 292, 290, 3, 2, 2, 2, 293, 294, 7, 62, 2, 2, 294, 295, 7, 47, 2, 2, 295, 58, 3, 2, 2, 2, 296, 297, 7, 63, 2, 2, 297, 298, 7, 64, 2, 2, 298, 60, 3, 2, 2, 2, 299, 300, 7, 45, 2, 2, 300, 62, 3, 2, 2, 2, 301, 302, 7, 47, 2, 2, 302, 64, 3, 2, 2, 2, 303, 304, 7, 44, 2, 2, 304, 66, 3, 2, 2, 2, 305, 306, 7, 49, 2, 2, 306, 68, 3, 2, 2, 2, 307, 308, 7, 62, 2, 2, 308, 70, 3, 2, 2, 2, 309, 310, 7, 62, 2, 2, 310, 311, 7, 63, 2, 2, 311, 72, 3, 2, 2, 2, 312, 313, 7, 63, 2, 2, 313, 74, 3, 2, 2, 2, 314, 315, 7, 128, 2, 2, 315, 76, 3, 2, 2, 2, 316, 317, 7, 42, 2, 2, 317, 78, 3, 2, 2, 2, 318, 319, 7, 43, 2, 2, 319, 80, 3, 2, 2, 2, 320, 321, 7, 125, 2, 2, 321, 82, 3, 2, 2, 2, 322, 323, 7, 127, 2, 2, 323, 84, 3, 2, 2, 2, 324, 325, 7, 66, 2, 2, 325, 86, 3, 2, 2, 2, 326, 327, 7, 48, 2, 2, 327, 88, 3, 2, 2, 2, 328, 329, 7, 46, 2, 2, 329, 90, 3, 2, 2, 2, 330, 331, 7, 60, 2, 2, 331, 92, 3, 2, 2, 2, 332, 333, 7, 61, 2, 2, 333, 94, 3, 2, 2, 2, 334, 335, 9, 7, 2, 2, 335, 96, 3, 2, 2, 2, 336, 337, 9, 8, 2, 2, 337, 98, 3, 2, 2, 2, 338, 339, 9, 9, 2, 2, 339, 100, 3, 2, 2, 2, 340, 341, 9, 10, 2, 2, 341, 102, 3, 2, 2, 2, 342, 343, 9, 11, 2, 2, 343, 104, 3, 2, 2, 2, 344, 345, 9, 12, 2, 2, 345, 106, 3, 2, 2, 2, 346, 347, 9, 13, 2, 2, 347, 108, 3, 2, 2, 2, 348, 349, 9, 14, 2, 2, 349, 110, 3, 2, 2, 2, 350, 351, 9, 15, 2, 2, 351, 112, 3, 2, 2, 2, 352, 353, 9, 16, 2, 2, 353, 114, 3, 2, 2, 2, 354, 355, 9, 17, 2, 2, 355, 116, 3, 2, 2, 2, 356, 357, 9, 18, 2, 2, 357, 118, 3, 2, 2, 2, 358, 359, 9, 19, 2, 2, 359, 120, 3, 2, 2, 2, 360, 361, 9, 20, 2, 2, 361, 122, 3, 2, 2, 2, 362, 363, 9, 21, 2, 2, 363, 124, 3, 2, 2, 2, 364, 365, 9, 22, 2, 2, 365, 126, 3, 2, 2, 2, 366, 367, 9, 23, 2, 2, 367, 128, 3, 2, 2, 2, 368, 371, 7, 94, 2, 2, 369, 372, 9, 24, 2, 2, 370, 372, 5, 131, 65, 2, 371, 369, 3, 2, 2, 2, 371, 370, 3, 2, 2, 2, 372, 130, 3, 2, 2, 2, 373, 374, 7, 119, 2, 2, 374, 375, 5, 133, 66, 2, 375, 376, 5, 133, 66, 2, 376, 377, 5, 133, 66, 2, 377, 378, 5, 133, 66, 2, 378, 132, 3, 2, 2, 2, 379, 380, 9, 25, 2, 2, 380, 134, 3, 2, 2, 2, 381, 383, 9, 26, 2, 2, 382, 381, 3, 2, 2, 2, 383, 384, 3, 2, 2, 2, 384, 382, 3, 2, 2, 2, 384, 385, 3, 2, 2, 2, 385, 386, 3, 2, 2, 2, 386, 387, 8, 67, 3, 2, 387, 136, 3, 2, 2, 2, 388, 389, 7, 47, 2, 2, 389, 390, 7, 47, 2, 2, 390, 394, 3, 2, 2, 2, 391, 393, 10, 27, 2, 2, 392, 391, 3, 2, 2, 2, 393, 396, 3, 2, 2, 2, 394, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 398, 3, 2, 2, 2, 396, 394, 3, 2, 2, 2, 397, 399, 7, 12, 2, 2, 398, 397, 3, 2, 2, 2, 398, 399, 3, 2, 2, 2, 399, 400, 3, 2, 2, 2, 400, 401, 8, 68, 3, 2, 401, 138, 3, 2, 2, 2, 402, 403, 7, 42, 2, 2, 403, 404, 7, 44, 2, 2, 404, 405, 3, 2, 2, 2, 405, 406, 8, 69, 4, 2, 406, 140, 3, 2, 2, 2, 407, 408, 5, 139, 69, 2, 408, 409, 5, 141, 70, 2, 409, 410, 5, 143, 71, 2, 410, 417, 3, 2, 2, 2, 411, 413, 11, 2, 2, 2, 412, 411, 3, 2, 2, 2, 413, 414, 3, 2, 2, 2, 414, 415, 3, 2, 2, 2, 414, 412, 3, 2, 2, 2, 415, 417, 3, 2, 2, 2, 416, 407, 3, 2, 2, 2, 416, 412, 3, 2, 2, 2, 417, 418, 3, 2, 2, 2, 418, 419, 8, 70, 3, 2, 419, 142, 3, 2, 2, 2, 420, 421, 7, 44, 2, 2, 421, 422, 7, 43, 2, 2, 422, 423, 3, 2, 2, 2, 423, 424, 8, 71, 5, 2, 424, 144, 3, 2, 2, 2, 425, 427, 5, 47, 23, 2, 426, 425, 3, 2, 2, 2, 427, 430, 3, 2, 2, 2, 428, 426, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 431, 3, 2, 2, 2, 430, 428, 3, 2, 2, 2, 431, 432, 7, 94, 2, 2, 432, 433, 7, 15, 2, 2, 433, 434, 7, 12, 2, 2, 434, 146, 3, 2, 2, 2, 435, 437, 5, 47, 23, 2, 436, 435, 3, 2, 2, 2, 437, 440, 3, 2, 2, 2, 438, 436, 3, 2, 2, 2, 438, 439, 3, 2, 2, 2, 439, 441, 3, 2, 2, 2, 440, 438, 3, 2, 2, 2, 441, 442, 7, 36, 2, 2, 442, 443, 3, 2, 2, 2, 443, 444, 8, 73, 5, 2, 444, 148, 3, 2, 2, 2, 445, 449, 5, 49, 24, 2, 446, 448, 5, 145, 72, 2, 447, 446, 3, 2, 2, 2, 448, 451, 3, 2, 2, 2, 449, 447, 3, 2, 2, 2, 449, 450, 3, 2, 2, 2, 450, 452, 3, 2, 2, 2, 451, 449, 3, 2, 2, 2, 452, 453, 5, 147, 73, 2, 453, 150, 3, 2, 2, 2, 21, 2, 3, 4, 246, 252, 259, 265, 277, 283, 290, 371, 384, 394, 398, 414, 416, 428, 438, 449, 6, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file diff --git a/src/COOL_LEX.py b/src/COOL_LEX.py index b5bb708c..c2fb0dc6 100644 --- a/src/COOL_LEX.py +++ b/src/COOL_LEX.py @@ -8,179 +8,202 @@ def serializedATN(): with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\62") - buf.write("\u0196\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6") - buf.write("\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r") - buf.write("\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22") - buf.write("\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30") - buf.write("\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35") - buf.write("\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\4") - buf.write("%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t,\4-\t") - buf.write("-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63") - buf.write("\4\64\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4") - buf.write(":\t:\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4") - buf.write("C\tC\4D\tD\4E\tE\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3") - buf.write("\3\3\3\3\4\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\6\3\6\3\6") - buf.write("\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3") - buf.write("\t\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\13") - buf.write("\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\16") - buf.write("\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20") - buf.write("\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\22\3\22\3\22") - buf.write("\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\25\3\25") - buf.write("\3\25\3\25\7\25\u00ee\n\25\f\25\16\25\u00f1\13\25\3\25") - buf.write("\3\25\3\26\3\26\3\26\3\26\3\26\3\26\3\26\5\26\u00fc\n") - buf.write("\26\3\27\6\27\u00ff\n\27\r\27\16\27\u0100\3\30\3\30\7") - buf.write("\30\u0105\n\30\f\30\16\30\u0108\13\30\3\31\3\31\7\31\u010c") - buf.write("\n\31\f\31\16\31\u010f\13\31\3\32\3\32\3\32\3\33\3\33") - buf.write("\3\33\3\34\3\34\3\35\3\35\3\36\3\36\3\37\3\37\3 \3 \3") - buf.write("!\3!\3!\3\"\3\"\3#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(") - buf.write("\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3\60\3") - buf.write("\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65\3\66") - buf.write("\3\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<\3<\3=\3=\3") - buf.write(">\3>\3>\5>\u015f\n>\3?\3?\3?\3?\3?\3?\3@\3@\3A\6A\u016a") - buf.write("\nA\rA\16A\u016b\3A\3A\3B\3B\3B\3B\7B\u0174\nB\fB\16B") - buf.write("\u0177\13B\3B\5B\u017a\nB\3B\3B\3C\3C\3C\3C\3C\3C\3D\3") - buf.write("D\3D\3D\3D\6D\u0189\nD\rD\16D\u018a\5D\u018d\nD\3D\3D") - buf.write("\3E\3E\3E\3E\3E\3E\3\u018a\2F\4\3\6\4\b\5\n\6\f\7\16\b") - buf.write("\20\t\22\n\24\13\26\f\30\r\32\16\34\17\36\20 \21\"\22") - buf.write("$\23&\24(\25*\26,\27.\30\60\31\62\32\64\33\66\348\35:") - buf.write("\36<\37> @!B\"D#F$H%J&L\'N(P)R*T+V,X-Z\2\\\2^\2`\2b\2") - buf.write("d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2|\2~\2\u0080\2\u0082") - buf.write(".\u0084/\u0086\60\u0088\61\u008a\62\4\2\3\34\6\2\f\f\17") - buf.write("\17$$^^\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4") - buf.write("\2EEee\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNn") - buf.write("n\4\2PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2") - buf.write("WWww\4\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;C") - buf.write("Hch\5\2\13\f\16\17\"\"\3\2\f\f\2\u018e\2\4\3\2\2\2\2\6") - buf.write("\3\2\2\2\2\b\3\2\2\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16\3\2") - buf.write("\2\2\2\20\3\2\2\2\2\22\3\2\2\2\2\24\3\2\2\2\2\26\3\2\2") - buf.write("\2\2\30\3\2\2\2\2\32\3\2\2\2\2\34\3\2\2\2\2\36\3\2\2\2") - buf.write("\2 \3\2\2\2\2\"\3\2\2\2\2$\3\2\2\2\2&\3\2\2\2\2(\3\2\2") - buf.write("\2\2*\3\2\2\2\2,\3\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2\62") - buf.write("\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\28\3\2\2\2\2:\3\2\2") - buf.write("\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2\2\2\2B\3\2\2\2\2D\3\2") - buf.write("\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3\2\2\2\2L\3\2\2\2\2N\3") - buf.write("\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2\2\2\2V\3\2\2\2\2X") - buf.write("\3\2\2\2\2\u0082\3\2\2\2\2\u0084\3\2\2\2\2\u0086\3\2\2") - buf.write("\2\3\u0088\3\2\2\2\3\u008a\3\2\2\2\4\u008c\3\2\2\2\6\u0092") - buf.write("\3\2\2\2\b\u0097\3\2\2\2\n\u009d\3\2\2\2\f\u00a0\3\2\2") - buf.write("\2\16\u00a3\3\2\2\2\20\u00a6\3\2\2\2\22\u00af\3\2\2\2") - buf.write("\24\u00b6\3\2\2\2\26\u00ba\3\2\2\2\30\u00bf\3\2\2\2\32") - buf.write("\u00c4\3\2\2\2\34\u00c9\3\2\2\2\36\u00cf\3\2\2\2 \u00d4") - buf.write("\3\2\2\2\"\u00d9\3\2\2\2$\u00dd\3\2\2\2&\u00e0\3\2\2\2") - buf.write("(\u00e4\3\2\2\2*\u00e9\3\2\2\2,\u00fb\3\2\2\2.\u00fe\3") - buf.write("\2\2\2\60\u0102\3\2\2\2\62\u0109\3\2\2\2\64\u0110\3\2") - buf.write("\2\2\66\u0113\3\2\2\28\u0116\3\2\2\2:\u0118\3\2\2\2<\u011a") - buf.write("\3\2\2\2>\u011c\3\2\2\2@\u011e\3\2\2\2B\u0120\3\2\2\2") - buf.write("D\u0123\3\2\2\2F\u0125\3\2\2\2H\u0127\3\2\2\2J\u0129\3") - buf.write("\2\2\2L\u012b\3\2\2\2N\u012d\3\2\2\2P\u012f\3\2\2\2R\u0131") - buf.write("\3\2\2\2T\u0133\3\2\2\2V\u0135\3\2\2\2X\u0137\3\2\2\2") - buf.write("Z\u0139\3\2\2\2\\\u013b\3\2\2\2^\u013d\3\2\2\2`\u013f") - buf.write("\3\2\2\2b\u0141\3\2\2\2d\u0143\3\2\2\2f\u0145\3\2\2\2") - buf.write("h\u0147\3\2\2\2j\u0149\3\2\2\2l\u014b\3\2\2\2n\u014d\3") - buf.write("\2\2\2p\u014f\3\2\2\2r\u0151\3\2\2\2t\u0153\3\2\2\2v\u0155") - buf.write("\3\2\2\2x\u0157\3\2\2\2z\u0159\3\2\2\2|\u015b\3\2\2\2") - buf.write("~\u0160\3\2\2\2\u0080\u0166\3\2\2\2\u0082\u0169\3\2\2") - buf.write("\2\u0084\u016f\3\2\2\2\u0086\u017d\3\2\2\2\u0088\u018c") - buf.write("\3\2\2\2\u008a\u0190\3\2\2\2\u008c\u008d\5\\.\2\u008d") - buf.write("\u008e\5h\64\2\u008e\u008f\5Z-\2\u008f\u0090\5r9\2\u0090") - buf.write("\u0091\5r9\2\u0091\5\3\2\2\2\u0092\u0093\5`\60\2\u0093") - buf.write("\u0094\5h\64\2\u0094\u0095\5r9\2\u0095\u0096\5`\60\2\u0096") - buf.write("\7\3\2\2\2\u0097\u0098\7h\2\2\u0098\u0099\5Z-\2\u0099") - buf.write("\u009a\5h\64\2\u009a\u009b\5r9\2\u009b\u009c\5`\60\2\u009c") - buf.write("\t\3\2\2\2\u009d\u009e\5b\61\2\u009e\u009f\5f\63\2\u009f") - buf.write("\13\3\2\2\2\u00a0\u00a1\5f\63\2\u00a1\u00a2\5b\61\2\u00a2") - buf.write("\r\3\2\2\2\u00a3\u00a4\5f\63\2\u00a4\u00a5\5j\65\2\u00a5") - buf.write("\17\3\2\2\2\u00a6\u00a7\5f\63\2\u00a7\u00a8\5j\65\2\u00a8") - buf.write("\u00a9\5d\62\2\u00a9\u00aa\5`\60\2\u00aa\u00ab\5p8\2\u00ab") - buf.write("\u00ac\5f\63\2\u00ac\u00ad\5t:\2\u00ad\u00ae\5r9\2\u00ae") - buf.write("\21\3\2\2\2\u00af\u00b0\5f\63\2\u00b0\u00b1\5r9\2\u00b1") - buf.write("\u00b2\5x<\2\u00b2\u00b3\5l\66\2\u00b3\u00b4\5f\63\2\u00b4") - buf.write("\u00b5\5^/\2\u00b5\23\3\2\2\2\u00b6\u00b7\5h\64\2\u00b7") - buf.write("\u00b8\5`\60\2\u00b8\u00b9\5t:\2\u00b9\25\3\2\2\2\u00ba") - buf.write("\u00bb\5h\64\2\u00bb\u00bc\5l\66\2\u00bc\u00bd\5l\66\2") - buf.write("\u00bd\u00be\5n\67\2\u00be\27\3\2\2\2\u00bf\u00c0\5n\67") - buf.write("\2\u00c0\u00c1\5l\66\2\u00c1\u00c2\5l\66\2\u00c2\u00c3") - buf.write("\5h\64\2\u00c3\31\3\2\2\2\u00c4\u00c5\5t:\2\u00c5\u00c6") - buf.write("\5d\62\2\u00c6\u00c7\5`\60\2\u00c7\u00c8\5j\65\2\u00c8") - buf.write("\33\3\2\2\2\u00c9\u00ca\5z=\2\u00ca\u00cb\5d\62\2\u00cb") - buf.write("\u00cc\5f\63\2\u00cc\u00cd\5h\64\2\u00cd\u00ce\5`\60\2") - buf.write("\u00ce\35\3\2\2\2\u00cf\u00d0\5\\.\2\u00d0\u00d1\5Z-\2") - buf.write("\u00d1\u00d2\5r9\2\u00d2\u00d3\5`\60\2\u00d3\37\3\2\2") - buf.write("\2\u00d4\u00d5\5`\60\2\u00d5\u00d6\5r9\2\u00d6\u00d7\5") - buf.write("Z-\2\u00d7\u00d8\5\\.\2\u00d8!\3\2\2\2\u00d9\u00da\5j") - buf.write("\65\2\u00da\u00db\5`\60\2\u00db\u00dc\5z=\2\u00dc#\3\2") - buf.write("\2\2\u00dd\u00de\5l\66\2\u00de\u00df\5b\61\2\u00df%\3") - buf.write("\2\2\2\u00e0\u00e1\5j\65\2\u00e1\u00e2\5l\66\2\u00e2\u00e3") - buf.write("\5t:\2\u00e3\'\3\2\2\2\u00e4\u00e5\7v\2\2\u00e5\u00e6") - buf.write("\5p8\2\u00e6\u00e7\5v;\2\u00e7\u00e8\5`\60\2\u00e8)\3") - buf.write("\2\2\2\u00e9\u00ef\7$\2\2\u00ea\u00ee\5|>\2\u00eb\u00ee") - buf.write("\5,\26\2\u00ec\u00ee\n\2\2\2\u00ed\u00ea\3\2\2\2\u00ed") - buf.write("\u00eb\3\2\2\2\u00ed\u00ec\3\2\2\2\u00ee\u00f1\3\2\2\2") - buf.write("\u00ef\u00ed\3\2\2\2\u00ef\u00f0\3\2\2\2\u00f0\u00f2\3") - buf.write("\2\2\2\u00f1\u00ef\3\2\2\2\u00f2\u00f3\7$\2\2\u00f3+\3") - buf.write("\2\2\2\u00f4\u00f5\7^\2\2\u00f5\u00f6\7\17\2\2\u00f6\u00fc") - buf.write("\7\f\2\2\u00f7\u00f8\7^\2\2\u00f8\u00fc\7\17\2\2\u00f9") - buf.write("\u00fa\7^\2\2\u00fa\u00fc\7\f\2\2\u00fb\u00f4\3\2\2\2") - buf.write("\u00fb\u00f7\3\2\2\2\u00fb\u00f9\3\2\2\2\u00fc-\3\2\2") - buf.write("\2\u00fd\u00ff\t\3\2\2\u00fe\u00fd\3\2\2\2\u00ff\u0100") - buf.write("\3\2\2\2\u0100\u00fe\3\2\2\2\u0100\u0101\3\2\2\2\u0101") - buf.write("/\3\2\2\2\u0102\u0106\t\4\2\2\u0103\u0105\t\5\2\2\u0104") - buf.write("\u0103\3\2\2\2\u0105\u0108\3\2\2\2\u0106\u0104\3\2\2\2") - buf.write("\u0106\u0107\3\2\2\2\u0107\61\3\2\2\2\u0108\u0106\3\2") - buf.write("\2\2\u0109\u010d\t\6\2\2\u010a\u010c\t\5\2\2\u010b\u010a") - buf.write("\3\2\2\2\u010c\u010f\3\2\2\2\u010d\u010b\3\2\2\2\u010d") - buf.write("\u010e\3\2\2\2\u010e\63\3\2\2\2\u010f\u010d\3\2\2\2\u0110") - buf.write("\u0111\7>\2\2\u0111\u0112\7/\2\2\u0112\65\3\2\2\2\u0113") - buf.write("\u0114\7?\2\2\u0114\u0115\7@\2\2\u0115\67\3\2\2\2\u0116") - buf.write("\u0117\7-\2\2\u01179\3\2\2\2\u0118\u0119\7/\2\2\u0119") - buf.write(";\3\2\2\2\u011a\u011b\7,\2\2\u011b=\3\2\2\2\u011c\u011d") - buf.write("\7\61\2\2\u011d?\3\2\2\2\u011e\u011f\7>\2\2\u011fA\3\2") - buf.write("\2\2\u0120\u0121\7>\2\2\u0121\u0122\7?\2\2\u0122C\3\2") - buf.write("\2\2\u0123\u0124\7?\2\2\u0124E\3\2\2\2\u0125\u0126\7\u0080") - buf.write("\2\2\u0126G\3\2\2\2\u0127\u0128\7*\2\2\u0128I\3\2\2\2") - buf.write("\u0129\u012a\7+\2\2\u012aK\3\2\2\2\u012b\u012c\7}\2\2") - buf.write("\u012cM\3\2\2\2\u012d\u012e\7\177\2\2\u012eO\3\2\2\2\u012f") - buf.write("\u0130\7B\2\2\u0130Q\3\2\2\2\u0131\u0132\7\60\2\2\u0132") - buf.write("S\3\2\2\2\u0133\u0134\7.\2\2\u0134U\3\2\2\2\u0135\u0136") - buf.write("\7<\2\2\u0136W\3\2\2\2\u0137\u0138\7=\2\2\u0138Y\3\2\2") - buf.write("\2\u0139\u013a\t\7\2\2\u013a[\3\2\2\2\u013b\u013c\t\b") - buf.write("\2\2\u013c]\3\2\2\2\u013d\u013e\t\t\2\2\u013e_\3\2\2\2") - buf.write("\u013f\u0140\t\n\2\2\u0140a\3\2\2\2\u0141\u0142\t\13\2") - buf.write("\2\u0142c\3\2\2\2\u0143\u0144\t\f\2\2\u0144e\3\2\2\2\u0145") - buf.write("\u0146\t\r\2\2\u0146g\3\2\2\2\u0147\u0148\t\16\2\2\u0148") - buf.write("i\3\2\2\2\u0149\u014a\t\17\2\2\u014ak\3\2\2\2\u014b\u014c") - buf.write("\t\20\2\2\u014cm\3\2\2\2\u014d\u014e\t\21\2\2\u014eo\3") - buf.write("\2\2\2\u014f\u0150\t\22\2\2\u0150q\3\2\2\2\u0151\u0152") - buf.write("\t\23\2\2\u0152s\3\2\2\2\u0153\u0154\t\24\2\2\u0154u\3") - buf.write("\2\2\2\u0155\u0156\t\25\2\2\u0156w\3\2\2\2\u0157\u0158") - buf.write("\t\26\2\2\u0158y\3\2\2\2\u0159\u015a\t\27\2\2\u015a{\3") - buf.write("\2\2\2\u015b\u015e\7^\2\2\u015c\u015f\t\30\2\2\u015d\u015f") - buf.write("\5~?\2\u015e\u015c\3\2\2\2\u015e\u015d\3\2\2\2\u015f}") - buf.write("\3\2\2\2\u0160\u0161\7w\2\2\u0161\u0162\5\u0080@\2\u0162") - buf.write("\u0163\5\u0080@\2\u0163\u0164\5\u0080@\2\u0164\u0165\5") - buf.write("\u0080@\2\u0165\177\3\2\2\2\u0166\u0167\t\31\2\2\u0167") - buf.write("\u0081\3\2\2\2\u0168\u016a\t\32\2\2\u0169\u0168\3\2\2") - buf.write("\2\u016a\u016b\3\2\2\2\u016b\u0169\3\2\2\2\u016b\u016c") - buf.write("\3\2\2\2\u016c\u016d\3\2\2\2\u016d\u016e\bA\2\2\u016e") - buf.write("\u0083\3\2\2\2\u016f\u0170\7/\2\2\u0170\u0171\7/\2\2\u0171") - buf.write("\u0175\3\2\2\2\u0172\u0174\n\33\2\2\u0173\u0172\3\2\2") - buf.write("\2\u0174\u0177\3\2\2\2\u0175\u0173\3\2\2\2\u0175\u0176") - buf.write("\3\2\2\2\u0176\u0179\3\2\2\2\u0177\u0175\3\2\2\2\u0178") - buf.write("\u017a\7\f\2\2\u0179\u0178\3\2\2\2\u0179\u017a\3\2\2\2") - buf.write("\u017a\u017b\3\2\2\2\u017b\u017c\bB\2\2\u017c\u0085\3") - buf.write("\2\2\2\u017d\u017e\7*\2\2\u017e\u017f\7,\2\2\u017f\u0180") - buf.write("\3\2\2\2\u0180\u0181\bC\2\2\u0181\u0182\bC\3\2\u0182\u0087") - buf.write("\3\2\2\2\u0183\u0184\5\u0086C\2\u0184\u0185\5\u0088D\2") - buf.write("\u0185\u0186\5\u008aE\2\u0186\u018d\3\2\2\2\u0187\u0189") - buf.write("\13\2\2\2\u0188\u0187\3\2\2\2\u0189\u018a\3\2\2\2\u018a") - buf.write("\u018b\3\2\2\2\u018a\u0188\3\2\2\2\u018b\u018d\3\2\2\2") - buf.write("\u018c\u0183\3\2\2\2\u018c\u0188\3\2\2\2\u018d\u018e\3") - buf.write("\2\2\2\u018e\u018f\bD\2\2\u018f\u0089\3\2\2\2\u0190\u0191") - buf.write("\7,\2\2\u0191\u0192\7+\2\2\u0192\u0193\3\2\2\2\u0193\u0194") - buf.write("\bE\2\2\u0194\u0195\bE\4\2\u0195\u008b\3\2\2\2\20\2\3") - buf.write("\u00ed\u00ef\u00fb\u0100\u0106\u010d\u015e\u016b\u0175") - buf.write("\u0179\u018a\u018c\5\b\2\2\7\3\2\6\2\2") + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\66") + buf.write("\u01c6\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6") + buf.write("\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f") + buf.write("\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22") + buf.write("\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27") + buf.write("\4\30\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35") + buf.write("\t\35\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4") + buf.write("$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t") + buf.write(",\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63") + buf.write("\t\63\4\64\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\4") + buf.write("9\t9\4:\t:\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA\4") + buf.write("B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I\tI\4J\tJ\3") + buf.write("\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\4\3\4\3\4") + buf.write("\3\4\3\4\3\4\3\5\3\5\3\5\3\6\3\6\3\6\3\7\3\7\3\7\3\b\3") + buf.write("\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t") + buf.write("\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3\f\3\f") + buf.write("\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3") + buf.write("\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20") + buf.write("\3\20\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\23\3\23\3\23") + buf.write("\3\23\3\24\3\24\3\24\3\24\3\24\3\25\3\25\5\25\u00f7\n") + buf.write("\25\3\26\3\26\7\26\u00fb\n\26\f\26\16\26\u00fe\13\26\3") + buf.write("\26\3\26\3\27\3\27\5\27\u0104\n\27\3\30\3\30\7\30\u0108") + buf.write("\n\30\f\30\16\30\u010b\13\30\3\30\3\30\3\30\3\30\3\30") + buf.write("\3\30\3\31\6\31\u0114\n\31\r\31\16\31\u0115\3\32\3\32") + buf.write("\7\32\u011a\n\32\f\32\16\32\u011d\13\32\3\33\3\33\7\33") + buf.write("\u0121\n\33\f\33\16\33\u0124\13\33\3\34\3\34\3\34\3\35") + buf.write("\3\35\3\35\3\36\3\36\3\37\3\37\3 \3 \3!\3!\3\"\3\"\3#") + buf.write("\3#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(\3)\3)\3*\3*\3+") + buf.write("\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3\60\3\61\3\61\3\62\3") + buf.write("\62\3\63\3\63\3\64\3\64\3\65\3\65\3\66\3\66\3\67\3\67") + buf.write("\38\38\39\39\3:\3:\3;\3;\3<\3<\3=\3=\3>\3>\3?\3?\3@\3") + buf.write("@\3@\5@\u0174\n@\3A\3A\3A\3A\3A\3A\3B\3B\3C\6C\u017f\n") + buf.write("C\rC\16C\u0180\3C\3C\3D\3D\3D\3D\7D\u0189\nD\fD\16D\u018c") + buf.write("\13D\3D\5D\u018f\nD\3D\3D\3E\3E\3E\3E\3E\3F\3F\3F\3F\3") + buf.write("F\6F\u019d\nF\rF\16F\u019e\5F\u01a1\nF\3F\3F\3G\3G\3G") + buf.write("\3G\3G\3H\7H\u01ab\nH\fH\16H\u01ae\13H\3H\3H\3H\3H\3I") + buf.write("\7I\u01b5\nI\fI\16I\u01b8\13I\3I\3I\3I\3I\3J\3J\7J\u01c0") + buf.write("\nJ\fJ\16J\u01c3\13J\3J\3J\3\u019e\2K\5\3\7\4\t\5\13\6") + buf.write("\r\7\17\b\21\t\23\n\25\13\27\f\31\r\33\16\35\17\37\20") + buf.write("!\21#\22%\23\'\24)\25+\26-\27/\2\61\30\63\31\65\32\67") + buf.write("\339\34;\35=\36?\37A C!E\"G#I$K%M&O\'Q(S)U*W+Y,[-]._\2") + buf.write("a\2c\2e\2g\2i\2k\2m\2o\2q\2s\2u\2w\2y\2{\2}\2\177\2\u0081") + buf.write("\2\u0083\2\u0085\2\u0087/\u0089\60\u008b\61\u008d\62\u008f") + buf.write("\63\u0091\64\u0093\65\u0095\66\5\2\3\4\34\5\2\f\f\17\17") + buf.write("$$\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEe") + buf.write("e\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2") + buf.write("PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4") + buf.write("\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2") + buf.write("\13\f\16\17\"\"\3\2\f\f\2\u01be\2\5\3\2\2\2\2\7\3\2\2") + buf.write("\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2") + buf.write("\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31") + buf.write("\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2") + buf.write("\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3") + buf.write("\2\2\2\2-\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2") + buf.write("\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3") + buf.write("\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I") + buf.write("\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2") + buf.write("S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2") + buf.write("\2]\3\2\2\2\2\u0087\3\2\2\2\2\u0089\3\2\2\2\2\u008b\3") + buf.write("\2\2\2\3\u008d\3\2\2\2\3\u008f\3\2\2\2\4\u0091\3\2\2\2") + buf.write("\4\u0093\3\2\2\2\4\u0095\3\2\2\2\5\u0097\3\2\2\2\7\u009d") + buf.write("\3\2\2\2\t\u00a2\3\2\2\2\13\u00a8\3\2\2\2\r\u00ab\3\2") + buf.write("\2\2\17\u00ae\3\2\2\2\21\u00b1\3\2\2\2\23\u00ba\3\2\2") + buf.write("\2\25\u00c1\3\2\2\2\27\u00c5\3\2\2\2\31\u00ca\3\2\2\2") + buf.write("\33\u00cf\3\2\2\2\35\u00d4\3\2\2\2\37\u00da\3\2\2\2!\u00df") + buf.write("\3\2\2\2#\u00e4\3\2\2\2%\u00e8\3\2\2\2\'\u00eb\3\2\2\2") + buf.write(")\u00ef\3\2\2\2+\u00f6\3\2\2\2-\u00f8\3\2\2\2/\u0103\3") + buf.write("\2\2\2\61\u0105\3\2\2\2\63\u0113\3\2\2\2\65\u0117\3\2") + buf.write("\2\2\67\u011e\3\2\2\29\u0125\3\2\2\2;\u0128\3\2\2\2=\u012b") + buf.write("\3\2\2\2?\u012d\3\2\2\2A\u012f\3\2\2\2C\u0131\3\2\2\2") + buf.write("E\u0133\3\2\2\2G\u0135\3\2\2\2I\u0138\3\2\2\2K\u013a\3") + buf.write("\2\2\2M\u013c\3\2\2\2O\u013e\3\2\2\2Q\u0140\3\2\2\2S\u0142") + buf.write("\3\2\2\2U\u0144\3\2\2\2W\u0146\3\2\2\2Y\u0148\3\2\2\2") + buf.write("[\u014a\3\2\2\2]\u014c\3\2\2\2_\u014e\3\2\2\2a\u0150\3") + buf.write("\2\2\2c\u0152\3\2\2\2e\u0154\3\2\2\2g\u0156\3\2\2\2i\u0158") + buf.write("\3\2\2\2k\u015a\3\2\2\2m\u015c\3\2\2\2o\u015e\3\2\2\2") + buf.write("q\u0160\3\2\2\2s\u0162\3\2\2\2u\u0164\3\2\2\2w\u0166\3") + buf.write("\2\2\2y\u0168\3\2\2\2{\u016a\3\2\2\2}\u016c\3\2\2\2\177") + buf.write("\u016e\3\2\2\2\u0081\u0170\3\2\2\2\u0083\u0175\3\2\2\2") + buf.write("\u0085\u017b\3\2\2\2\u0087\u017e\3\2\2\2\u0089\u0184\3") + buf.write("\2\2\2\u008b\u0192\3\2\2\2\u008d\u01a0\3\2\2\2\u008f\u01a4") + buf.write("\3\2\2\2\u0091\u01ac\3\2\2\2\u0093\u01b6\3\2\2\2\u0095") + buf.write("\u01bd\3\2\2\2\u0097\u0098\5a\60\2\u0098\u0099\5m\66\2") + buf.write("\u0099\u009a\5_/\2\u009a\u009b\5w;\2\u009b\u009c\5w;\2") + buf.write("\u009c\6\3\2\2\2\u009d\u009e\5e\62\2\u009e\u009f\5m\66") + buf.write("\2\u009f\u00a0\5w;\2\u00a0\u00a1\5e\62\2\u00a1\b\3\2\2") + buf.write("\2\u00a2\u00a3\7h\2\2\u00a3\u00a4\5_/\2\u00a4\u00a5\5") + buf.write("m\66\2\u00a5\u00a6\5w;\2\u00a6\u00a7\5e\62\2\u00a7\n\3") + buf.write("\2\2\2\u00a8\u00a9\5g\63\2\u00a9\u00aa\5k\65\2\u00aa\f") + buf.write("\3\2\2\2\u00ab\u00ac\5k\65\2\u00ac\u00ad\5g\63\2\u00ad") + buf.write("\16\3\2\2\2\u00ae\u00af\5k\65\2\u00af\u00b0\5o\67\2\u00b0") + buf.write("\20\3\2\2\2\u00b1\u00b2\5k\65\2\u00b2\u00b3\5o\67\2\u00b3") + buf.write("\u00b4\5i\64\2\u00b4\u00b5\5e\62\2\u00b5\u00b6\5u:\2\u00b6") + buf.write("\u00b7\5k\65\2\u00b7\u00b8\5y<\2\u00b8\u00b9\5w;\2\u00b9") + buf.write("\22\3\2\2\2\u00ba\u00bb\5k\65\2\u00bb\u00bc\5w;\2\u00bc") + buf.write("\u00bd\5}>\2\u00bd\u00be\5q8\2\u00be\u00bf\5k\65\2\u00bf") + buf.write("\u00c0\5c\61\2\u00c0\24\3\2\2\2\u00c1\u00c2\5m\66\2\u00c2") + buf.write("\u00c3\5e\62\2\u00c3\u00c4\5y<\2\u00c4\26\3\2\2\2\u00c5") + buf.write("\u00c6\5m\66\2\u00c6\u00c7\5q8\2\u00c7\u00c8\5q8\2\u00c8") + buf.write("\u00c9\5s9\2\u00c9\30\3\2\2\2\u00ca\u00cb\5s9\2\u00cb") + buf.write("\u00cc\5q8\2\u00cc\u00cd\5q8\2\u00cd\u00ce\5m\66\2\u00ce") + buf.write("\32\3\2\2\2\u00cf\u00d0\5y<\2\u00d0\u00d1\5i\64\2\u00d1") + buf.write("\u00d2\5e\62\2\u00d2\u00d3\5o\67\2\u00d3\34\3\2\2\2\u00d4") + buf.write("\u00d5\5\177?\2\u00d5\u00d6\5i\64\2\u00d6\u00d7\5k\65") + buf.write("\2\u00d7\u00d8\5m\66\2\u00d8\u00d9\5e\62\2\u00d9\36\3") + buf.write("\2\2\2\u00da\u00db\5a\60\2\u00db\u00dc\5_/\2\u00dc\u00dd") + buf.write("\5w;\2\u00dd\u00de\5e\62\2\u00de \3\2\2\2\u00df\u00e0") + buf.write("\5e\62\2\u00e0\u00e1\5w;\2\u00e1\u00e2\5_/\2\u00e2\u00e3") + buf.write("\5a\60\2\u00e3\"\3\2\2\2\u00e4\u00e5\5o\67\2\u00e5\u00e6") + buf.write("\5e\62\2\u00e6\u00e7\5\177?\2\u00e7$\3\2\2\2\u00e8\u00e9") + buf.write("\5q8\2\u00e9\u00ea\5g\63\2\u00ea&\3\2\2\2\u00eb\u00ec") + buf.write("\5o\67\2\u00ec\u00ed\5q8\2\u00ed\u00ee\5y<\2\u00ee(\3") + buf.write("\2\2\2\u00ef\u00f0\7v\2\2\u00f0\u00f1\5u:\2\u00f1\u00f2") + buf.write("\5{=\2\u00f2\u00f3\5e\62\2\u00f3*\3\2\2\2\u00f4\u00f7") + buf.write("\5-\26\2\u00f5\u00f7\5\u0095J\2\u00f6\u00f4\3\2\2\2\u00f6") + buf.write("\u00f5\3\2\2\2\u00f7,\3\2\2\2\u00f8\u00fc\7$\2\2\u00f9") + buf.write("\u00fb\5/\27\2\u00fa\u00f9\3\2\2\2\u00fb\u00fe\3\2\2\2") + buf.write("\u00fc\u00fa\3\2\2\2\u00fc\u00fd\3\2\2\2\u00fd\u00ff\3") + buf.write("\2\2\2\u00fe\u00fc\3\2\2\2\u00ff\u0100\7$\2\2\u0100.\3") + buf.write("\2\2\2\u0101\u0104\5\u0081@\2\u0102\u0104\n\2\2\2\u0103") + buf.write("\u0101\3\2\2\2\u0103\u0102\3\2\2\2\u0104\60\3\2\2\2\u0105") + buf.write("\u0109\7$\2\2\u0106\u0108\5/\27\2\u0107\u0106\3\2\2\2") + buf.write("\u0108\u010b\3\2\2\2\u0109\u0107\3\2\2\2\u0109\u010a\3") + buf.write("\2\2\2\u010a\u010c\3\2\2\2\u010b\u0109\3\2\2\2\u010c\u010d") + buf.write("\7^\2\2\u010d\u010e\7\17\2\2\u010e\u010f\7\f\2\2\u010f") + buf.write("\u0110\3\2\2\2\u0110\u0111\b\30\2\2\u0111\62\3\2\2\2\u0112") + buf.write("\u0114\t\3\2\2\u0113\u0112\3\2\2\2\u0114\u0115\3\2\2\2") + buf.write("\u0115\u0113\3\2\2\2\u0115\u0116\3\2\2\2\u0116\64\3\2") + buf.write("\2\2\u0117\u011b\t\4\2\2\u0118\u011a\t\5\2\2\u0119\u0118") + buf.write("\3\2\2\2\u011a\u011d\3\2\2\2\u011b\u0119\3\2\2\2\u011b") + buf.write("\u011c\3\2\2\2\u011c\66\3\2\2\2\u011d\u011b\3\2\2\2\u011e") + buf.write("\u0122\t\6\2\2\u011f\u0121\t\5\2\2\u0120\u011f\3\2\2\2") + buf.write("\u0121\u0124\3\2\2\2\u0122\u0120\3\2\2\2\u0122\u0123\3") + buf.write("\2\2\2\u01238\3\2\2\2\u0124\u0122\3\2\2\2\u0125\u0126") + buf.write("\7>\2\2\u0126\u0127\7/\2\2\u0127:\3\2\2\2\u0128\u0129") + buf.write("\7?\2\2\u0129\u012a\7@\2\2\u012a<\3\2\2\2\u012b\u012c") + buf.write("\7-\2\2\u012c>\3\2\2\2\u012d\u012e\7/\2\2\u012e@\3\2\2") + buf.write("\2\u012f\u0130\7,\2\2\u0130B\3\2\2\2\u0131\u0132\7\61") + buf.write("\2\2\u0132D\3\2\2\2\u0133\u0134\7>\2\2\u0134F\3\2\2\2") + buf.write("\u0135\u0136\7>\2\2\u0136\u0137\7?\2\2\u0137H\3\2\2\2") + buf.write("\u0138\u0139\7?\2\2\u0139J\3\2\2\2\u013a\u013b\7\u0080") + buf.write("\2\2\u013bL\3\2\2\2\u013c\u013d\7*\2\2\u013dN\3\2\2\2") + buf.write("\u013e\u013f\7+\2\2\u013fP\3\2\2\2\u0140\u0141\7}\2\2") + buf.write("\u0141R\3\2\2\2\u0142\u0143\7\177\2\2\u0143T\3\2\2\2\u0144") + buf.write("\u0145\7B\2\2\u0145V\3\2\2\2\u0146\u0147\7\60\2\2\u0147") + buf.write("X\3\2\2\2\u0148\u0149\7.\2\2\u0149Z\3\2\2\2\u014a\u014b") + buf.write("\7<\2\2\u014b\\\3\2\2\2\u014c\u014d\7=\2\2\u014d^\3\2") + buf.write("\2\2\u014e\u014f\t\7\2\2\u014f`\3\2\2\2\u0150\u0151\t") + buf.write("\b\2\2\u0151b\3\2\2\2\u0152\u0153\t\t\2\2\u0153d\3\2\2") + buf.write("\2\u0154\u0155\t\n\2\2\u0155f\3\2\2\2\u0156\u0157\t\13") + buf.write("\2\2\u0157h\3\2\2\2\u0158\u0159\t\f\2\2\u0159j\3\2\2\2") + buf.write("\u015a\u015b\t\r\2\2\u015bl\3\2\2\2\u015c\u015d\t\16\2") + buf.write("\2\u015dn\3\2\2\2\u015e\u015f\t\17\2\2\u015fp\3\2\2\2") + buf.write("\u0160\u0161\t\20\2\2\u0161r\3\2\2\2\u0162\u0163\t\21") + buf.write("\2\2\u0163t\3\2\2\2\u0164\u0165\t\22\2\2\u0165v\3\2\2") + buf.write("\2\u0166\u0167\t\23\2\2\u0167x\3\2\2\2\u0168\u0169\t\24") + buf.write("\2\2\u0169z\3\2\2\2\u016a\u016b\t\25\2\2\u016b|\3\2\2") + buf.write("\2\u016c\u016d\t\26\2\2\u016d~\3\2\2\2\u016e\u016f\t\27") + buf.write("\2\2\u016f\u0080\3\2\2\2\u0170\u0173\7^\2\2\u0171\u0174") + buf.write("\t\30\2\2\u0172\u0174\5\u0083A\2\u0173\u0171\3\2\2\2\u0173") + buf.write("\u0172\3\2\2\2\u0174\u0082\3\2\2\2\u0175\u0176\7w\2\2") + buf.write("\u0176\u0177\5\u0085B\2\u0177\u0178\5\u0085B\2\u0178\u0179") + buf.write("\5\u0085B\2\u0179\u017a\5\u0085B\2\u017a\u0084\3\2\2\2") + buf.write("\u017b\u017c\t\31\2\2\u017c\u0086\3\2\2\2\u017d\u017f") + buf.write("\t\32\2\2\u017e\u017d\3\2\2\2\u017f\u0180\3\2\2\2\u0180") + buf.write("\u017e\3\2\2\2\u0180\u0181\3\2\2\2\u0181\u0182\3\2\2\2") + buf.write("\u0182\u0183\bC\3\2\u0183\u0088\3\2\2\2\u0184\u0185\7") + buf.write("/\2\2\u0185\u0186\7/\2\2\u0186\u018a\3\2\2\2\u0187\u0189") + buf.write("\n\33\2\2\u0188\u0187\3\2\2\2\u0189\u018c\3\2\2\2\u018a") + buf.write("\u0188\3\2\2\2\u018a\u018b\3\2\2\2\u018b\u018e\3\2\2\2") + buf.write("\u018c\u018a\3\2\2\2\u018d\u018f\7\f\2\2\u018e\u018d\3") + buf.write("\2\2\2\u018e\u018f\3\2\2\2\u018f\u0190\3\2\2\2\u0190\u0191") + buf.write("\bD\3\2\u0191\u008a\3\2\2\2\u0192\u0193\7*\2\2\u0193\u0194") + buf.write("\7,\2\2\u0194\u0195\3\2\2\2\u0195\u0196\bE\4\2\u0196\u008c") + buf.write("\3\2\2\2\u0197\u0198\5\u008bE\2\u0198\u0199\5\u008dF\2") + buf.write("\u0199\u019a\5\u008fG\2\u019a\u01a1\3\2\2\2\u019b\u019d") + buf.write("\13\2\2\2\u019c\u019b\3\2\2\2\u019d\u019e\3\2\2\2\u019e") + buf.write("\u019f\3\2\2\2\u019e\u019c\3\2\2\2\u019f\u01a1\3\2\2\2") + buf.write("\u01a0\u0197\3\2\2\2\u01a0\u019c\3\2\2\2\u01a1\u01a2\3") + buf.write("\2\2\2\u01a2\u01a3\bF\3\2\u01a3\u008e\3\2\2\2\u01a4\u01a5") + buf.write("\7,\2\2\u01a5\u01a6\7+\2\2\u01a6\u01a7\3\2\2\2\u01a7\u01a8") + buf.write("\bG\5\2\u01a8\u0090\3\2\2\2\u01a9\u01ab\5/\27\2\u01aa") + buf.write("\u01a9\3\2\2\2\u01ab\u01ae\3\2\2\2\u01ac\u01aa\3\2\2\2") + buf.write("\u01ac\u01ad\3\2\2\2\u01ad\u01af\3\2\2\2\u01ae\u01ac\3") + buf.write("\2\2\2\u01af\u01b0\7^\2\2\u01b0\u01b1\7\17\2\2\u01b1\u01b2") + buf.write("\7\f\2\2\u01b2\u0092\3\2\2\2\u01b3\u01b5\5/\27\2\u01b4") + buf.write("\u01b3\3\2\2\2\u01b5\u01b8\3\2\2\2\u01b6\u01b4\3\2\2\2") + buf.write("\u01b6\u01b7\3\2\2\2\u01b7\u01b9\3\2\2\2\u01b8\u01b6\3") + buf.write("\2\2\2\u01b9\u01ba\7$\2\2\u01ba\u01bb\3\2\2\2\u01bb\u01bc") + buf.write("\bI\5\2\u01bc\u0094\3\2\2\2\u01bd\u01c1\5\61\30\2\u01be") + buf.write("\u01c0\5\u0091H\2\u01bf\u01be\3\2\2\2\u01c0\u01c3\3\2") + buf.write("\2\2\u01c1\u01bf\3\2\2\2\u01c1\u01c2\3\2\2\2\u01c2\u01c4") + buf.write("\3\2\2\2\u01c3\u01c1\3\2\2\2\u01c4\u01c5\5\u0093I\2\u01c5") + buf.write("\u0096\3\2\2\2\25\2\3\4\u00f6\u00fc\u0103\u0109\u0115") + buf.write("\u011b\u0122\u0173\u0180\u018a\u018e\u019e\u01a0\u01ac") + buf.write("\u01b6\u01c1\6\7\4\2\b\2\2\7\3\2\6\2\2") return buf.getvalue() @@ -191,6 +214,7 @@ class COOL_LEX(Lexer): decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] MULTILINE_COMMENT = 1 + MULTILINE_STR = 2 CLASS = 1 ELSE = 2 @@ -212,38 +236,42 @@ class COOL_LEX(Lexer): NOT = 18 TRUE = 19 STRING = 20 - BREAK_STRING = 21 - INT = 22 - TYPEID = 23 - OBJECTID = 24 - ASSIGNMENT = 25 - CASE_ARROW = 26 - ADD = 27 - MINUS = 28 - MULTIPLY = 29 - DIVISION = 30 - LESS_THAN = 31 - LESS_EQUAL = 32 - EQUAL = 33 - INTEGER_NEGATIVE = 34 - OPEN_ROUND = 35 - CLOSE_ROUND = 36 - OPEN_CURLY = 37 - CLOSE_CURLY = 38 - AT = 39 - DOT = 40 - COMMA = 41 - COLON = 42 - SEMICOLON = 43 - WHITESPACE = 44 - ONE_LINE_COMMENT = 45 - OPEN_COMMENT = 46 - COMMENT = 47 - CLOSE_COMMENT = 48 + STRING_SIMPLE = 21 + STRING_FIRSTLINE = 22 + INT = 23 + TYPEID = 24 + OBJECTID = 25 + ASSIGNMENT = 26 + CASE_ARROW = 27 + ADD = 28 + MINUS = 29 + MULTIPLY = 30 + DIVISION = 31 + LESS_THAN = 32 + LESS_EQUAL = 33 + EQUAL = 34 + INTEGER_NEGATIVE = 35 + OPEN_ROUND = 36 + CLOSE_ROUND = 37 + OPEN_CURLY = 38 + CLOSE_CURLY = 39 + AT = 40 + DOT = 41 + COMMA = 42 + COLON = 43 + SEMICOLON = 44 + WHITESPACE = 45 + ONE_LINE_COMMENT = 46 + OPEN_COMMENT = 47 + COMMENT = 48 + CLOSE_COMMENT = 49 + STRING_INNERLINE = 50 + STRING_LASTLINE = 51 + STRING_MULTILINE = 52 channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] - modeNames = [ "DEFAULT_MODE", "MULTILINE_COMMENT" ] + modeNames = [ "DEFAULT_MODE", "MULTILINE_COMMENT", "MULTILINE_STR" ] literalNames = [ "", "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", "'<='", "'='", @@ -253,24 +281,27 @@ class COOL_LEX(Lexer): symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", - "OF", "NOT", "TRUE", "STRING", "BREAK_STRING", "INT", "TYPEID", - "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", - "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", - "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", "CLOSE_CURLY", "AT", - "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", "ONE_LINE_COMMENT", - "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT" ] + "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", "STRING_FIRSTLINE", + "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", + "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", + "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", + "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", + "ONE_LINE_COMMENT", "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT", + "STRING_INNERLINE", "STRING_LASTLINE", "STRING_MULTILINE" ] ruleNames = [ "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", - "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", "BREAK_STRING", - "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", - "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", - "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", - "OPEN_CURLY", "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", - "SEMICOLON", "A", "C", "D", "E", "F", "H", "I", "L", "N", - "O", "P", "R", "S", "T", "U", "V", "W", "ESC", "UNICODE", - "HEX", "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", - "COMMENT", "CLOSE_COMMENT" ] + "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", + "STRING_CONTENT", "STRING_FIRSTLINE", "INT", "TYPEID", + "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", + "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", + "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", + "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", "SEMICOLON", + "A", "C", "D", "E", "F", "H", "I", "L", "N", "O", "P", + "R", "S", "T", "U", "V", "W", "ESC", "UNICODE", "HEX", + "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", "COMMENT", + "CLOSE_COMMENT", "STRING_INNERLINE", "STRING_LASTLINE", + "STRING_MULTILINE" ] grammarFileName = "COOL_LEX.g4" diff --git a/src/COOL_LEX.tokens b/src/COOL_LEX.tokens index bbdda836..de4efcf0 100644 --- a/src/COOL_LEX.tokens +++ b/src/COOL_LEX.tokens @@ -18,52 +18,56 @@ OF=17 NOT=18 TRUE=19 STRING=20 -BREAK_STRING=21 -INT=22 -TYPEID=23 -OBJECTID=24 -ASSIGNMENT=25 -CASE_ARROW=26 -ADD=27 -MINUS=28 -MULTIPLY=29 -DIVISION=30 -LESS_THAN=31 -LESS_EQUAL=32 -EQUAL=33 -INTEGER_NEGATIVE=34 -OPEN_ROUND=35 -CLOSE_ROUND=36 -OPEN_CURLY=37 -CLOSE_CURLY=38 -AT=39 -DOT=40 -COMMA=41 -COLON=42 -SEMICOLON=43 -WHITESPACE=44 -ONE_LINE_COMMENT=45 -OPEN_COMMENT=46 -COMMENT=47 -CLOSE_COMMENT=48 -'<-'=25 -'=>'=26 -'+'=27 -'-'=28 -'*'=29 -'/'=30 -'<'=31 -'<='=32 -'='=33 -'~'=34 -'('=35 -')'=36 -'{'=37 -'}'=38 -'@'=39 -'.'=40 -','=41 -':'=42 -';'=43 -'(*'=46 -'*)'=48 +STRING_SIMPLE=21 +STRING_FIRSTLINE=22 +INT=23 +TYPEID=24 +OBJECTID=25 +ASSIGNMENT=26 +CASE_ARROW=27 +ADD=28 +MINUS=29 +MULTIPLY=30 +DIVISION=31 +LESS_THAN=32 +LESS_EQUAL=33 +EQUAL=34 +INTEGER_NEGATIVE=35 +OPEN_ROUND=36 +CLOSE_ROUND=37 +OPEN_CURLY=38 +CLOSE_CURLY=39 +AT=40 +DOT=41 +COMMA=42 +COLON=43 +SEMICOLON=44 +WHITESPACE=45 +ONE_LINE_COMMENT=46 +OPEN_COMMENT=47 +COMMENT=48 +CLOSE_COMMENT=49 +STRING_INNERLINE=50 +STRING_LASTLINE=51 +STRING_MULTILINE=52 +'<-'=26 +'=>'=27 +'+'=28 +'-'=29 +'*'=30 +'/'=31 +'<'=32 +'<='=33 +'='=34 +'~'=35 +'('=36 +')'=37 +'{'=38 +'}'=39 +'@'=40 +'.'=41 +','=42 +':'=43 +';'=44 +'(*'=47 +'*)'=49 diff --git a/src/coolc.sh b/src/coolc.sh index 2b13ab2e..bfea5d60 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,8 +4,8 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "COOLCompiler 1.0.1" -echo "Copyright (c) 2019: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" +echo "COOLCompiler 1.0.2" +echo "Copyright (C) 2019-2020: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" # Llamar al compilador #echo "Compiling $INPUT_FILE into $OUTPUT_FILE" diff --git a/tests/parser/program1_error.txt b/tests/parser/program1_error.txt index de00ac46..d7474383 100644 --- a/tests/parser/program1_error.txt +++ b/tests/parser/program1_error.txt @@ -1 +1 @@ -(0, 0) - SyntacticError: ERROR at or near EOF \ No newline at end of file +(1, 36) - SyntacticError: ERROR at or near EOF \ No newline at end of file From 288d4205f85737f8f51b45546a549a445b7341c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 16 Mar 2020 10:52:10 -0400 Subject: [PATCH 11/77] Se arreglo el lexer para detectar caracter nulo --- src/COOL.interp | 8 +- src/COOL.py | 177 +++++++------ src/COOL.tokens | 107 ++++---- src/COOLLexer.py | 6 +- src/COOL_LEX.interp | 12 +- src/COOL_LEX.py | 504 ++++++++++++++++++------------------ src/COOL_LEX.tokens | 107 ++++---- tests/lexer/test1_error.txt | 6 +- 8 files changed, 485 insertions(+), 442 deletions(-) diff --git a/src/COOL.interp b/src/COOL.interp index 740232fd..0a51d34e 100644 --- a/src/COOL.interp +++ b/src/COOL.interp @@ -25,6 +25,7 @@ null null null null +null '<-' '=>' '+' @@ -52,6 +53,8 @@ null null null null +null +null token symbolic names: null @@ -76,6 +79,7 @@ NOT TRUE STRING STRING_SIMPLE +STRING_SIMPLE_START STRING_FIRSTLINE INT TYPEID @@ -107,6 +111,8 @@ CLOSE_COMMENT STRING_INNERLINE STRING_LASTLINE STRING_MULTILINE +STRING_SIMPLE_CONTENT +STRING_SIMPLE_STOP rule names: program @@ -118,4 +124,4 @@ expression atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 54, 219, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 5, 7, 86, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 107, 10, 7, 13, 7, 14, 7, 108, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 119, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 127, 10, 7, 7, 7, 129, 10, 7, 12, 7, 14, 7, 132, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 146, 10, 7, 13, 7, 14, 7, 147, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 172, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 198, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 206, 10, 7, 12, 7, 14, 7, 209, 11, 7, 5, 7, 211, 10, 7, 3, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 253, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 171, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 46, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 26, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 26, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 40, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 46, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 41, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 27, 2, 2, 40, 51, 7, 38, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 44, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 39, 2, 2, 55, 56, 7, 45, 2, 2, 56, 57, 7, 26, 2, 2, 57, 58, 7, 40, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 41, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 27, 2, 2, 62, 63, 7, 45, 2, 2, 63, 66, 7, 26, 2, 2, 64, 65, 7, 28, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 27, 2, 2, 71, 72, 7, 45, 2, 2, 72, 73, 7, 26, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 27, 2, 2, 76, 85, 7, 38, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 44, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 85, 86, 3, 2, 2, 2, 86, 87, 3, 2, 2, 2, 87, 172, 7, 39, 2, 2, 88, 89, 7, 7, 2, 2, 89, 90, 5, 12, 7, 2, 90, 91, 7, 14, 2, 2, 91, 92, 5, 12, 7, 2, 92, 93, 7, 4, 2, 2, 93, 94, 5, 12, 7, 2, 94, 95, 7, 6, 2, 2, 95, 172, 3, 2, 2, 2, 96, 97, 7, 15, 2, 2, 97, 98, 5, 12, 7, 2, 98, 99, 7, 12, 2, 2, 99, 100, 5, 12, 7, 2, 100, 101, 7, 13, 2, 2, 101, 172, 3, 2, 2, 2, 102, 106, 7, 40, 2, 2, 103, 104, 5, 12, 7, 2, 104, 105, 7, 46, 2, 2, 105, 107, 3, 2, 2, 2, 106, 103, 3, 2, 2, 2, 107, 108, 3, 2, 2, 2, 108, 106, 3, 2, 2, 2, 108, 109, 3, 2, 2, 2, 109, 110, 3, 2, 2, 2, 110, 111, 7, 41, 2, 2, 111, 172, 3, 2, 2, 2, 112, 113, 7, 11, 2, 2, 113, 114, 7, 27, 2, 2, 114, 115, 7, 45, 2, 2, 115, 118, 7, 26, 2, 2, 116, 117, 7, 28, 2, 2, 117, 119, 5, 12, 7, 2, 118, 116, 3, 2, 2, 2, 118, 119, 3, 2, 2, 2, 119, 130, 3, 2, 2, 2, 120, 121, 7, 44, 2, 2, 121, 122, 7, 27, 2, 2, 122, 123, 7, 45, 2, 2, 123, 126, 7, 26, 2, 2, 124, 125, 7, 28, 2, 2, 125, 127, 5, 12, 7, 2, 126, 124, 3, 2, 2, 2, 126, 127, 3, 2, 2, 2, 127, 129, 3, 2, 2, 2, 128, 120, 3, 2, 2, 2, 129, 132, 3, 2, 2, 2, 130, 128, 3, 2, 2, 2, 130, 131, 3, 2, 2, 2, 131, 133, 3, 2, 2, 2, 132, 130, 3, 2, 2, 2, 133, 134, 7, 8, 2, 2, 134, 172, 5, 12, 7, 22, 135, 136, 7, 16, 2, 2, 136, 137, 5, 12, 7, 2, 137, 145, 7, 19, 2, 2, 138, 139, 7, 27, 2, 2, 139, 140, 7, 45, 2, 2, 140, 141, 7, 26, 2, 2, 141, 142, 7, 29, 2, 2, 142, 143, 5, 12, 7, 2, 143, 144, 7, 46, 2, 2, 144, 146, 3, 2, 2, 2, 145, 138, 3, 2, 2, 2, 146, 147, 3, 2, 2, 2, 147, 145, 3, 2, 2, 2, 147, 148, 3, 2, 2, 2, 148, 149, 3, 2, 2, 2, 149, 150, 7, 17, 2, 2, 150, 172, 3, 2, 2, 2, 151, 152, 7, 18, 2, 2, 152, 172, 7, 26, 2, 2, 153, 154, 7, 37, 2, 2, 154, 172, 5, 12, 7, 19, 155, 156, 7, 10, 2, 2, 156, 172, 5, 12, 7, 18, 157, 158, 7, 20, 2, 2, 158, 172, 5, 12, 7, 10, 159, 160, 7, 38, 2, 2, 160, 161, 5, 12, 7, 2, 161, 162, 7, 39, 2, 2, 162, 172, 3, 2, 2, 2, 163, 172, 7, 27, 2, 2, 164, 172, 7, 25, 2, 2, 165, 172, 7, 22, 2, 2, 166, 172, 7, 21, 2, 2, 167, 172, 7, 5, 2, 2, 168, 169, 7, 27, 2, 2, 169, 170, 7, 28, 2, 2, 170, 172, 5, 12, 7, 3, 171, 74, 3, 2, 2, 2, 171, 88, 3, 2, 2, 2, 171, 96, 3, 2, 2, 2, 171, 102, 3, 2, 2, 2, 171, 112, 3, 2, 2, 2, 171, 135, 3, 2, 2, 2, 171, 151, 3, 2, 2, 2, 171, 153, 3, 2, 2, 2, 171, 155, 3, 2, 2, 2, 171, 157, 3, 2, 2, 2, 171, 159, 3, 2, 2, 2, 171, 163, 3, 2, 2, 2, 171, 164, 3, 2, 2, 2, 171, 165, 3, 2, 2, 2, 171, 166, 3, 2, 2, 2, 171, 167, 3, 2, 2, 2, 171, 168, 3, 2, 2, 2, 172, 215, 3, 2, 2, 2, 173, 174, 12, 17, 2, 2, 174, 175, 7, 32, 2, 2, 175, 214, 5, 12, 7, 18, 176, 177, 12, 16, 2, 2, 177, 178, 7, 33, 2, 2, 178, 214, 5, 12, 7, 17, 179, 180, 12, 15, 2, 2, 180, 181, 7, 30, 2, 2, 181, 214, 5, 12, 7, 16, 182, 183, 12, 14, 2, 2, 183, 184, 7, 31, 2, 2, 184, 214, 5, 12, 7, 15, 185, 186, 12, 13, 2, 2, 186, 187, 7, 34, 2, 2, 187, 214, 5, 12, 7, 14, 188, 189, 12, 12, 2, 2, 189, 190, 7, 35, 2, 2, 190, 214, 5, 12, 7, 13, 191, 192, 12, 11, 2, 2, 192, 193, 7, 36, 2, 2, 193, 214, 5, 12, 7, 12, 194, 197, 12, 27, 2, 2, 195, 196, 7, 42, 2, 2, 196, 198, 7, 26, 2, 2, 197, 195, 3, 2, 2, 2, 197, 198, 3, 2, 2, 2, 198, 199, 3, 2, 2, 2, 199, 200, 7, 43, 2, 2, 200, 201, 7, 27, 2, 2, 201, 210, 7, 38, 2, 2, 202, 207, 5, 12, 7, 2, 203, 204, 7, 44, 2, 2, 204, 206, 5, 12, 7, 2, 205, 203, 3, 2, 2, 2, 206, 209, 3, 2, 2, 2, 207, 205, 3, 2, 2, 2, 207, 208, 3, 2, 2, 2, 208, 211, 3, 2, 2, 2, 209, 207, 3, 2, 2, 2, 210, 202, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 212, 3, 2, 2, 2, 212, 214, 7, 39, 2, 2, 213, 173, 3, 2, 2, 2, 213, 176, 3, 2, 2, 2, 213, 179, 3, 2, 2, 2, 213, 182, 3, 2, 2, 2, 213, 185, 3, 2, 2, 2, 213, 188, 3, 2, 2, 2, 213, 191, 3, 2, 2, 2, 213, 194, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 13, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 85, 108, 118, 126, 130, 147, 171, 197, 207, 210, 213, 215] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 57, 219, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 5, 7, 86, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 107, 10, 7, 13, 7, 14, 7, 108, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 119, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 127, 10, 7, 7, 7, 129, 10, 7, 12, 7, 14, 7, 132, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 146, 10, 7, 13, 7, 14, 7, 147, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 172, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 198, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 206, 10, 7, 12, 7, 14, 7, 209, 11, 7, 5, 7, 211, 10, 7, 3, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 253, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 171, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 47, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 27, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 27, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 41, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 47, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 42, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 28, 2, 2, 40, 51, 7, 39, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 45, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 40, 2, 2, 55, 56, 7, 46, 2, 2, 56, 57, 7, 27, 2, 2, 57, 58, 7, 41, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 42, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 28, 2, 2, 62, 63, 7, 46, 2, 2, 63, 66, 7, 27, 2, 2, 64, 65, 7, 29, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 28, 2, 2, 71, 72, 7, 46, 2, 2, 72, 73, 7, 27, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 28, 2, 2, 76, 85, 7, 39, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 45, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 85, 86, 3, 2, 2, 2, 86, 87, 3, 2, 2, 2, 87, 172, 7, 40, 2, 2, 88, 89, 7, 7, 2, 2, 89, 90, 5, 12, 7, 2, 90, 91, 7, 14, 2, 2, 91, 92, 5, 12, 7, 2, 92, 93, 7, 4, 2, 2, 93, 94, 5, 12, 7, 2, 94, 95, 7, 6, 2, 2, 95, 172, 3, 2, 2, 2, 96, 97, 7, 15, 2, 2, 97, 98, 5, 12, 7, 2, 98, 99, 7, 12, 2, 2, 99, 100, 5, 12, 7, 2, 100, 101, 7, 13, 2, 2, 101, 172, 3, 2, 2, 2, 102, 106, 7, 41, 2, 2, 103, 104, 5, 12, 7, 2, 104, 105, 7, 47, 2, 2, 105, 107, 3, 2, 2, 2, 106, 103, 3, 2, 2, 2, 107, 108, 3, 2, 2, 2, 108, 106, 3, 2, 2, 2, 108, 109, 3, 2, 2, 2, 109, 110, 3, 2, 2, 2, 110, 111, 7, 42, 2, 2, 111, 172, 3, 2, 2, 2, 112, 113, 7, 11, 2, 2, 113, 114, 7, 28, 2, 2, 114, 115, 7, 46, 2, 2, 115, 118, 7, 27, 2, 2, 116, 117, 7, 29, 2, 2, 117, 119, 5, 12, 7, 2, 118, 116, 3, 2, 2, 2, 118, 119, 3, 2, 2, 2, 119, 130, 3, 2, 2, 2, 120, 121, 7, 45, 2, 2, 121, 122, 7, 28, 2, 2, 122, 123, 7, 46, 2, 2, 123, 126, 7, 27, 2, 2, 124, 125, 7, 29, 2, 2, 125, 127, 5, 12, 7, 2, 126, 124, 3, 2, 2, 2, 126, 127, 3, 2, 2, 2, 127, 129, 3, 2, 2, 2, 128, 120, 3, 2, 2, 2, 129, 132, 3, 2, 2, 2, 130, 128, 3, 2, 2, 2, 130, 131, 3, 2, 2, 2, 131, 133, 3, 2, 2, 2, 132, 130, 3, 2, 2, 2, 133, 134, 7, 8, 2, 2, 134, 172, 5, 12, 7, 22, 135, 136, 7, 16, 2, 2, 136, 137, 5, 12, 7, 2, 137, 145, 7, 19, 2, 2, 138, 139, 7, 28, 2, 2, 139, 140, 7, 46, 2, 2, 140, 141, 7, 27, 2, 2, 141, 142, 7, 30, 2, 2, 142, 143, 5, 12, 7, 2, 143, 144, 7, 47, 2, 2, 144, 146, 3, 2, 2, 2, 145, 138, 3, 2, 2, 2, 146, 147, 3, 2, 2, 2, 147, 145, 3, 2, 2, 2, 147, 148, 3, 2, 2, 2, 148, 149, 3, 2, 2, 2, 149, 150, 7, 17, 2, 2, 150, 172, 3, 2, 2, 2, 151, 152, 7, 18, 2, 2, 152, 172, 7, 27, 2, 2, 153, 154, 7, 38, 2, 2, 154, 172, 5, 12, 7, 19, 155, 156, 7, 10, 2, 2, 156, 172, 5, 12, 7, 18, 157, 158, 7, 20, 2, 2, 158, 172, 5, 12, 7, 10, 159, 160, 7, 39, 2, 2, 160, 161, 5, 12, 7, 2, 161, 162, 7, 40, 2, 2, 162, 172, 3, 2, 2, 2, 163, 172, 7, 28, 2, 2, 164, 172, 7, 26, 2, 2, 165, 172, 7, 22, 2, 2, 166, 172, 7, 21, 2, 2, 167, 172, 7, 5, 2, 2, 168, 169, 7, 28, 2, 2, 169, 170, 7, 29, 2, 2, 170, 172, 5, 12, 7, 3, 171, 74, 3, 2, 2, 2, 171, 88, 3, 2, 2, 2, 171, 96, 3, 2, 2, 2, 171, 102, 3, 2, 2, 2, 171, 112, 3, 2, 2, 2, 171, 135, 3, 2, 2, 2, 171, 151, 3, 2, 2, 2, 171, 153, 3, 2, 2, 2, 171, 155, 3, 2, 2, 2, 171, 157, 3, 2, 2, 2, 171, 159, 3, 2, 2, 2, 171, 163, 3, 2, 2, 2, 171, 164, 3, 2, 2, 2, 171, 165, 3, 2, 2, 2, 171, 166, 3, 2, 2, 2, 171, 167, 3, 2, 2, 2, 171, 168, 3, 2, 2, 2, 172, 215, 3, 2, 2, 2, 173, 174, 12, 17, 2, 2, 174, 175, 7, 33, 2, 2, 175, 214, 5, 12, 7, 18, 176, 177, 12, 16, 2, 2, 177, 178, 7, 34, 2, 2, 178, 214, 5, 12, 7, 17, 179, 180, 12, 15, 2, 2, 180, 181, 7, 31, 2, 2, 181, 214, 5, 12, 7, 16, 182, 183, 12, 14, 2, 2, 183, 184, 7, 32, 2, 2, 184, 214, 5, 12, 7, 15, 185, 186, 12, 13, 2, 2, 186, 187, 7, 35, 2, 2, 187, 214, 5, 12, 7, 14, 188, 189, 12, 12, 2, 2, 189, 190, 7, 36, 2, 2, 190, 214, 5, 12, 7, 13, 191, 192, 12, 11, 2, 2, 192, 193, 7, 37, 2, 2, 193, 214, 5, 12, 7, 12, 194, 197, 12, 27, 2, 2, 195, 196, 7, 43, 2, 2, 196, 198, 7, 27, 2, 2, 197, 195, 3, 2, 2, 2, 197, 198, 3, 2, 2, 2, 198, 199, 3, 2, 2, 2, 199, 200, 7, 44, 2, 2, 200, 201, 7, 28, 2, 2, 201, 210, 7, 39, 2, 2, 202, 207, 5, 12, 7, 2, 203, 204, 7, 45, 2, 2, 204, 206, 5, 12, 7, 2, 205, 203, 3, 2, 2, 2, 206, 209, 3, 2, 2, 2, 207, 205, 3, 2, 2, 2, 207, 208, 3, 2, 2, 2, 208, 211, 3, 2, 2, 2, 209, 207, 3, 2, 2, 2, 210, 202, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 212, 3, 2, 2, 2, 212, 214, 7, 40, 2, 2, 213, 173, 3, 2, 2, 2, 213, 176, 3, 2, 2, 2, 213, 179, 3, 2, 2, 2, 213, 182, 3, 2, 2, 2, 213, 185, 3, 2, 2, 2, 213, 188, 3, 2, 2, 2, 213, 191, 3, 2, 2, 2, 213, 194, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 13, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 85, 108, 118, 126, 130, 147, 171, 197, 207, 210, 213, 215] \ No newline at end of file diff --git a/src/COOL.py b/src/COOL.py index a342382b..1e1ab864 100644 --- a/src/COOL.py +++ b/src/COOL.py @@ -8,7 +8,7 @@ def serializedATN(): with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\66") + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\39") buf.write("\u00db\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") buf.write("\3\2\3\2\3\2\3\3\3\3\3\3\5\3\25\n\3\3\4\3\4\3\4\3\4\5") buf.write("\4\33\n\4\3\4\3\4\3\4\3\4\7\4!\n\4\f\4\16\4$\13\4\3\4") @@ -30,71 +30,71 @@ def serializedATN(): buf.write("\16\7\u00d9\13\7\3\7\2\3\f\b\2\4\6\b\n\f\2\2\2\u00fd\2") buf.write("\16\3\2\2\2\4\21\3\2\2\2\6\26\3\2\2\2\bD\3\2\2\2\nF\3") buf.write("\2\2\2\f\u00ab\3\2\2\2\16\17\5\4\3\2\17\20\7\2\2\3\20") - buf.write("\3\3\2\2\2\21\22\5\6\4\2\22\24\7.\2\2\23\25\5\4\3\2\24") + buf.write("\3\3\2\2\2\21\22\5\6\4\2\22\24\7/\2\2\23\25\5\4\3\2\24") buf.write("\23\3\2\2\2\24\25\3\2\2\2\25\5\3\2\2\2\26\27\7\3\2\2\27") - buf.write("\32\7\32\2\2\30\31\7\t\2\2\31\33\7\32\2\2\32\30\3\2\2") - buf.write("\2\32\33\3\2\2\2\33\34\3\2\2\2\34\"\7(\2\2\35\36\5\b\5") - buf.write("\2\36\37\7.\2\2\37!\3\2\2\2 \35\3\2\2\2!$\3\2\2\2\" \3") - buf.write("\2\2\2\"#\3\2\2\2#%\3\2\2\2$\"\3\2\2\2%&\7)\2\2&\7\3\2") - buf.write("\2\2\'(\7\33\2\2(\63\7&\2\2).\5\n\6\2*+\7,\2\2+-\5\n\6") - buf.write("\2,*\3\2\2\2-\60\3\2\2\2.,\3\2\2\2./\3\2\2\2/\62\3\2\2") - buf.write("\2\60.\3\2\2\2\61)\3\2\2\2\62\65\3\2\2\2\63\61\3\2\2\2") - buf.write("\63\64\3\2\2\2\64\66\3\2\2\2\65\63\3\2\2\2\66\67\7\'\2") - buf.write("\2\678\7-\2\289\7\32\2\29:\7(\2\2:;\5\f\7\2;<\7)\2\2<") - buf.write("E\3\2\2\2=>\7\33\2\2>?\7-\2\2?B\7\32\2\2@A\7\34\2\2AC") - buf.write("\5\f\7\2B@\3\2\2\2BC\3\2\2\2CE\3\2\2\2D\'\3\2\2\2D=\3") - buf.write("\2\2\2E\t\3\2\2\2FG\7\33\2\2GH\7-\2\2HI\7\32\2\2I\13\3") - buf.write("\2\2\2JK\b\7\1\2KL\7\33\2\2LU\7&\2\2MR\5\f\7\2NO\7,\2") + buf.write("\32\7\33\2\2\30\31\7\t\2\2\31\33\7\33\2\2\32\30\3\2\2") + buf.write("\2\32\33\3\2\2\2\33\34\3\2\2\2\34\"\7)\2\2\35\36\5\b\5") + buf.write("\2\36\37\7/\2\2\37!\3\2\2\2 \35\3\2\2\2!$\3\2\2\2\" \3") + buf.write("\2\2\2\"#\3\2\2\2#%\3\2\2\2$\"\3\2\2\2%&\7*\2\2&\7\3\2") + buf.write("\2\2\'(\7\34\2\2(\63\7\'\2\2).\5\n\6\2*+\7-\2\2+-\5\n") + buf.write("\6\2,*\3\2\2\2-\60\3\2\2\2.,\3\2\2\2./\3\2\2\2/\62\3\2") + buf.write("\2\2\60.\3\2\2\2\61)\3\2\2\2\62\65\3\2\2\2\63\61\3\2\2") + buf.write("\2\63\64\3\2\2\2\64\66\3\2\2\2\65\63\3\2\2\2\66\67\7(") + buf.write("\2\2\678\7.\2\289\7\33\2\29:\7)\2\2:;\5\f\7\2;<\7*\2\2") + buf.write("\7\34\2\2>?\7.\2\2?B\7\33\2\2@A\7\35\2\2A") + buf.write("C\5\f\7\2B@\3\2\2\2BC\3\2\2\2CE\3\2\2\2D\'\3\2\2\2D=\3") + buf.write("\2\2\2E\t\3\2\2\2FG\7\34\2\2GH\7.\2\2HI\7\33\2\2I\13\3") + buf.write("\2\2\2JK\b\7\1\2KL\7\34\2\2LU\7\'\2\2MR\5\f\7\2NO\7-\2") buf.write("\2OQ\5\f\7\2PN\3\2\2\2QT\3\2\2\2RP\3\2\2\2RS\3\2\2\2S") buf.write("V\3\2\2\2TR\3\2\2\2UM\3\2\2\2UV\3\2\2\2VW\3\2\2\2W\u00ac") - buf.write("\7\'\2\2XY\7\7\2\2YZ\5\f\7\2Z[\7\16\2\2[\\\5\f\7\2\\]") - buf.write("\7\4\2\2]^\5\f\7\2^_\7\6\2\2_\u00ac\3\2\2\2`a\7\17\2\2") - buf.write("ab\5\f\7\2bc\7\f\2\2cd\5\f\7\2de\7\r\2\2e\u00ac\3\2\2") - buf.write("\2fj\7(\2\2gh\5\f\7\2hi\7.\2\2ik\3\2\2\2jg\3\2\2\2kl\3") - buf.write("\2\2\2lj\3\2\2\2lm\3\2\2\2mn\3\2\2\2no\7)\2\2o\u00ac\3") - buf.write("\2\2\2pq\7\13\2\2qr\7\33\2\2rs\7-\2\2sv\7\32\2\2tu\7\34") + buf.write("\7(\2\2XY\7\7\2\2YZ\5\f\7\2Z[\7\16\2\2[\\\5\f\7\2\\]\7") + buf.write("\4\2\2]^\5\f\7\2^_\7\6\2\2_\u00ac\3\2\2\2`a\7\17\2\2a") + buf.write("b\5\f\7\2bc\7\f\2\2cd\5\f\7\2de\7\r\2\2e\u00ac\3\2\2\2") + buf.write("fj\7)\2\2gh\5\f\7\2hi\7/\2\2ik\3\2\2\2jg\3\2\2\2kl\3\2") + buf.write("\2\2lj\3\2\2\2lm\3\2\2\2mn\3\2\2\2no\7*\2\2o\u00ac\3\2") + buf.write("\2\2pq\7\13\2\2qr\7\34\2\2rs\7.\2\2sv\7\33\2\2tu\7\35") buf.write("\2\2uw\5\f\7\2vt\3\2\2\2vw\3\2\2\2w\u0082\3\2\2\2xy\7") - buf.write(",\2\2yz\7\33\2\2z{\7-\2\2{~\7\32\2\2|}\7\34\2\2}\177\5") + buf.write("-\2\2yz\7\34\2\2z{\7.\2\2{~\7\33\2\2|}\7\35\2\2}\177\5") buf.write("\f\7\2~|\3\2\2\2~\177\3\2\2\2\177\u0081\3\2\2\2\u0080") buf.write("x\3\2\2\2\u0081\u0084\3\2\2\2\u0082\u0080\3\2\2\2\u0082") buf.write("\u0083\3\2\2\2\u0083\u0085\3\2\2\2\u0084\u0082\3\2\2\2") buf.write("\u0085\u0086\7\b\2\2\u0086\u00ac\5\f\7\26\u0087\u0088") buf.write("\7\20\2\2\u0088\u0089\5\f\7\2\u0089\u0091\7\23\2\2\u008a") - buf.write("\u008b\7\33\2\2\u008b\u008c\7-\2\2\u008c\u008d\7\32\2") - buf.write("\2\u008d\u008e\7\35\2\2\u008e\u008f\5\f\7\2\u008f\u0090") - buf.write("\7.\2\2\u0090\u0092\3\2\2\2\u0091\u008a\3\2\2\2\u0092") + buf.write("\u008b\7\34\2\2\u008b\u008c\7.\2\2\u008c\u008d\7\33\2") + buf.write("\2\u008d\u008e\7\36\2\2\u008e\u008f\5\f\7\2\u008f\u0090") + buf.write("\7/\2\2\u0090\u0092\3\2\2\2\u0091\u008a\3\2\2\2\u0092") buf.write("\u0093\3\2\2\2\u0093\u0091\3\2\2\2\u0093\u0094\3\2\2\2") buf.write("\u0094\u0095\3\2\2\2\u0095\u0096\7\21\2\2\u0096\u00ac") - buf.write("\3\2\2\2\u0097\u0098\7\22\2\2\u0098\u00ac\7\32\2\2\u0099") - buf.write("\u009a\7%\2\2\u009a\u00ac\5\f\7\23\u009b\u009c\7\n\2\2") + buf.write("\3\2\2\2\u0097\u0098\7\22\2\2\u0098\u00ac\7\33\2\2\u0099") + buf.write("\u009a\7&\2\2\u009a\u00ac\5\f\7\23\u009b\u009c\7\n\2\2") buf.write("\u009c\u00ac\5\f\7\22\u009d\u009e\7\24\2\2\u009e\u00ac") - buf.write("\5\f\7\n\u009f\u00a0\7&\2\2\u00a0\u00a1\5\f\7\2\u00a1") - buf.write("\u00a2\7\'\2\2\u00a2\u00ac\3\2\2\2\u00a3\u00ac\7\33\2") - buf.write("\2\u00a4\u00ac\7\31\2\2\u00a5\u00ac\7\26\2\2\u00a6\u00ac") - buf.write("\7\25\2\2\u00a7\u00ac\7\5\2\2\u00a8\u00a9\7\33\2\2\u00a9") - buf.write("\u00aa\7\34\2\2\u00aa\u00ac\5\f\7\3\u00abJ\3\2\2\2\u00ab") + buf.write("\5\f\7\n\u009f\u00a0\7\'\2\2\u00a0\u00a1\5\f\7\2\u00a1") + buf.write("\u00a2\7(\2\2\u00a2\u00ac\3\2\2\2\u00a3\u00ac\7\34\2\2") + buf.write("\u00a4\u00ac\7\32\2\2\u00a5\u00ac\7\26\2\2\u00a6\u00ac") + buf.write("\7\25\2\2\u00a7\u00ac\7\5\2\2\u00a8\u00a9\7\34\2\2\u00a9") + buf.write("\u00aa\7\35\2\2\u00aa\u00ac\5\f\7\3\u00abJ\3\2\2\2\u00ab") buf.write("X\3\2\2\2\u00ab`\3\2\2\2\u00abf\3\2\2\2\u00abp\3\2\2\2") buf.write("\u00ab\u0087\3\2\2\2\u00ab\u0097\3\2\2\2\u00ab\u0099\3") buf.write("\2\2\2\u00ab\u009b\3\2\2\2\u00ab\u009d\3\2\2\2\u00ab\u009f") buf.write("\3\2\2\2\u00ab\u00a3\3\2\2\2\u00ab\u00a4\3\2\2\2\u00ab") buf.write("\u00a5\3\2\2\2\u00ab\u00a6\3\2\2\2\u00ab\u00a7\3\2\2\2") buf.write("\u00ab\u00a8\3\2\2\2\u00ac\u00d7\3\2\2\2\u00ad\u00ae\f") - buf.write("\21\2\2\u00ae\u00af\7 \2\2\u00af\u00d6\5\f\7\22\u00b0") - buf.write("\u00b1\f\20\2\2\u00b1\u00b2\7!\2\2\u00b2\u00d6\5\f\7\21") - buf.write("\u00b3\u00b4\f\17\2\2\u00b4\u00b5\7\36\2\2\u00b5\u00d6") - buf.write("\5\f\7\20\u00b6\u00b7\f\16\2\2\u00b7\u00b8\7\37\2\2\u00b8") - buf.write("\u00d6\5\f\7\17\u00b9\u00ba\f\r\2\2\u00ba\u00bb\7\"\2") - buf.write("\2\u00bb\u00d6\5\f\7\16\u00bc\u00bd\f\f\2\2\u00bd\u00be") - buf.write("\7#\2\2\u00be\u00d6\5\f\7\r\u00bf\u00c0\f\13\2\2\u00c0") - buf.write("\u00c1\7$\2\2\u00c1\u00d6\5\f\7\f\u00c2\u00c5\f\33\2\2") - buf.write("\u00c3\u00c4\7*\2\2\u00c4\u00c6\7\32\2\2\u00c5\u00c3\3") + buf.write("\21\2\2\u00ae\u00af\7!\2\2\u00af\u00d6\5\f\7\22\u00b0") + buf.write("\u00b1\f\20\2\2\u00b1\u00b2\7\"\2\2\u00b2\u00d6\5\f\7") + buf.write("\21\u00b3\u00b4\f\17\2\2\u00b4\u00b5\7\37\2\2\u00b5\u00d6") + buf.write("\5\f\7\20\u00b6\u00b7\f\16\2\2\u00b7\u00b8\7 \2\2\u00b8") + buf.write("\u00d6\5\f\7\17\u00b9\u00ba\f\r\2\2\u00ba\u00bb\7#\2\2") + buf.write("\u00bb\u00d6\5\f\7\16\u00bc\u00bd\f\f\2\2\u00bd\u00be") + buf.write("\7$\2\2\u00be\u00d6\5\f\7\r\u00bf\u00c0\f\13\2\2\u00c0") + buf.write("\u00c1\7%\2\2\u00c1\u00d6\5\f\7\f\u00c2\u00c5\f\33\2\2") + buf.write("\u00c3\u00c4\7+\2\2\u00c4\u00c6\7\33\2\2\u00c5\u00c3\3") buf.write("\2\2\2\u00c5\u00c6\3\2\2\2\u00c6\u00c7\3\2\2\2\u00c7\u00c8") - buf.write("\7+\2\2\u00c8\u00c9\7\33\2\2\u00c9\u00d2\7&\2\2\u00ca") - buf.write("\u00cf\5\f\7\2\u00cb\u00cc\7,\2\2\u00cc\u00ce\5\f\7\2") + buf.write("\7,\2\2\u00c8\u00c9\7\34\2\2\u00c9\u00d2\7\'\2\2\u00ca") + buf.write("\u00cf\5\f\7\2\u00cb\u00cc\7-\2\2\u00cc\u00ce\5\f\7\2") buf.write("\u00cd\u00cb\3\2\2\2\u00ce\u00d1\3\2\2\2\u00cf\u00cd\3") buf.write("\2\2\2\u00cf\u00d0\3\2\2\2\u00d0\u00d3\3\2\2\2\u00d1\u00cf") buf.write("\3\2\2\2\u00d2\u00ca\3\2\2\2\u00d2\u00d3\3\2\2\2\u00d3") - buf.write("\u00d4\3\2\2\2\u00d4\u00d6\7\'\2\2\u00d5\u00ad\3\2\2\2") + buf.write("\u00d4\3\2\2\2\u00d4\u00d6\7(\2\2\u00d5\u00ad\3\2\2\2") buf.write("\u00d5\u00b0\3\2\2\2\u00d5\u00b3\3\2\2\2\u00d5\u00b6\3") buf.write("\2\2\2\u00d5\u00b9\3\2\2\2\u00d5\u00bc\3\2\2\2\u00d5\u00bf") buf.write("\3\2\2\2\u00d5\u00c2\3\2\2\2\u00d6\u00d9\3\2\2\2\u00d7") @@ -120,22 +120,24 @@ class COOL ( Parser ): "", "", "", "", "", "", "", "", "", "", "", "", - "", "", "'<-'", "'=>'", "'+'", "'-'", - "'*'", "'/'", "'<'", "'<='", "'='", "'~'", "'('", "')'", - "'{'", "'}'", "'@'", "'.'", "','", "':'", "';'", "", - "", "'(*'", "", "'*)'" ] + "", "", "", "'<-'", "'=>'", + "'+'", "'-'", "'*'", "'/'", "'<'", "'<='", "'='", "'~'", + "'('", "')'", "'{'", "'}'", "'@'", "'.'", "','", "':'", + "';'", "", "", "'(*'", "", + "'*)'" ] symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", - "TRUE", "STRING", "STRING_SIMPLE", "STRING_FIRSTLINE", - "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", - "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", - "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", - "CLOSE_ROUND", "OPEN_CURLY", "CLOSE_CURLY", "AT", - "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", + "TRUE", "STRING", "STRING_SIMPLE", "STRING_SIMPLE_START", + "STRING_FIRSTLINE", "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", + "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", + "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", + "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", "CLOSE_CURLY", + "AT", "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT", - "STRING_INNERLINE", "STRING_LASTLINE", "STRING_MULTILINE" ] + "STRING_INNERLINE", "STRING_LASTLINE", "STRING_MULTILINE", + "STRING_SIMPLE_CONTENT", "STRING_SIMPLE_STOP" ] RULE_program = 0 RULE_programBlocks = 1 @@ -169,37 +171,40 @@ class COOL ( Parser ): TRUE=19 STRING=20 STRING_SIMPLE=21 - STRING_FIRSTLINE=22 - INT=23 - TYPEID=24 - OBJECTID=25 - ASSIGNMENT=26 - CASE_ARROW=27 - ADD=28 - MINUS=29 - MULTIPLY=30 - DIVISION=31 - LESS_THAN=32 - LESS_EQUAL=33 - EQUAL=34 - INTEGER_NEGATIVE=35 - OPEN_ROUND=36 - CLOSE_ROUND=37 - OPEN_CURLY=38 - CLOSE_CURLY=39 - AT=40 - DOT=41 - COMMA=42 - COLON=43 - SEMICOLON=44 - WHITESPACE=45 - ONE_LINE_COMMENT=46 - OPEN_COMMENT=47 - COMMENT=48 - CLOSE_COMMENT=49 - STRING_INNERLINE=50 - STRING_LASTLINE=51 - STRING_MULTILINE=52 + STRING_SIMPLE_START=22 + STRING_FIRSTLINE=23 + INT=24 + TYPEID=25 + OBJECTID=26 + ASSIGNMENT=27 + CASE_ARROW=28 + ADD=29 + MINUS=30 + MULTIPLY=31 + DIVISION=32 + LESS_THAN=33 + LESS_EQUAL=34 + EQUAL=35 + INTEGER_NEGATIVE=36 + OPEN_ROUND=37 + CLOSE_ROUND=38 + OPEN_CURLY=39 + CLOSE_CURLY=40 + AT=41 + DOT=42 + COMMA=43 + COLON=44 + SEMICOLON=45 + WHITESPACE=46 + ONE_LINE_COMMENT=47 + OPEN_COMMENT=48 + COMMENT=49 + CLOSE_COMMENT=50 + STRING_INNERLINE=51 + STRING_LASTLINE=52 + STRING_MULTILINE=53 + STRING_SIMPLE_CONTENT=54 + STRING_SIMPLE_STOP=55 def __init__(self, input:TokenStream, output:TextIO = sys.stdout): super().__init__(input, output) diff --git a/src/COOL.tokens b/src/COOL.tokens index de4efcf0..c7eacfe4 100644 --- a/src/COOL.tokens +++ b/src/COOL.tokens @@ -19,55 +19,58 @@ NOT=18 TRUE=19 STRING=20 STRING_SIMPLE=21 -STRING_FIRSTLINE=22 -INT=23 -TYPEID=24 -OBJECTID=25 -ASSIGNMENT=26 -CASE_ARROW=27 -ADD=28 -MINUS=29 -MULTIPLY=30 -DIVISION=31 -LESS_THAN=32 -LESS_EQUAL=33 -EQUAL=34 -INTEGER_NEGATIVE=35 -OPEN_ROUND=36 -CLOSE_ROUND=37 -OPEN_CURLY=38 -CLOSE_CURLY=39 -AT=40 -DOT=41 -COMMA=42 -COLON=43 -SEMICOLON=44 -WHITESPACE=45 -ONE_LINE_COMMENT=46 -OPEN_COMMENT=47 -COMMENT=48 -CLOSE_COMMENT=49 -STRING_INNERLINE=50 -STRING_LASTLINE=51 -STRING_MULTILINE=52 -'<-'=26 -'=>'=27 -'+'=28 -'-'=29 -'*'=30 -'/'=31 -'<'=32 -'<='=33 -'='=34 -'~'=35 -'('=36 -')'=37 -'{'=38 -'}'=39 -'@'=40 -'.'=41 -','=42 -':'=43 -';'=44 -'(*'=47 -'*)'=49 +STRING_SIMPLE_START=22 +STRING_FIRSTLINE=23 +INT=24 +TYPEID=25 +OBJECTID=26 +ASSIGNMENT=27 +CASE_ARROW=28 +ADD=29 +MINUS=30 +MULTIPLY=31 +DIVISION=32 +LESS_THAN=33 +LESS_EQUAL=34 +EQUAL=35 +INTEGER_NEGATIVE=36 +OPEN_ROUND=37 +CLOSE_ROUND=38 +OPEN_CURLY=39 +CLOSE_CURLY=40 +AT=41 +DOT=42 +COMMA=43 +COLON=44 +SEMICOLON=45 +WHITESPACE=46 +ONE_LINE_COMMENT=47 +OPEN_COMMENT=48 +COMMENT=49 +CLOSE_COMMENT=50 +STRING_INNERLINE=51 +STRING_LASTLINE=52 +STRING_MULTILINE=53 +STRING_SIMPLE_CONTENT=54 +STRING_SIMPLE_STOP=55 +'<-'=27 +'=>'=28 +'+'=29 +'-'=30 +'*'=31 +'/'=32 +'<'=33 +'<='=34 +'='=35 +'~'=36 +'('=37 +')'=38 +'{'=39 +'}'=40 +'@'=41 +'.'=42 +','=43 +':'=44 +';'=45 +'(*'=48 +'*)'=50 diff --git a/src/COOLLexer.py b/src/COOLLexer.py index 8456f1b6..62b3502f 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -22,8 +22,10 @@ def notifyListeners(self, e:LexerNoViableAltException): start = self._tokenStartCharIndex stop = self._input.index text = self._input.getText(start, stop) - if self._currentToken.type in [COOL_LEX.STRING, COOL_LEX.STRING_FIRSTLINE, COOL_LEX.STRING_INNERLINE] or text[0] == '"': - if self.inputStream.size == self.inputStream.index: + if self._currentToken.type in [COOL_LEX.STRING, COOL_LEX.STRING_FIRSTLINE, COOL_LEX.STRING_INNERLINE, COOL_LEX.STRING_SIMPLE_START, COOL_LEX.STRING_SIMPLE_CONTENT ] or text[0] == '"': + if self._input.data[start] == 0: + msg = "String contains null character" + elif self.inputStream.size == self.inputStream.index: msg = "EOF in string constant" else: msg = "Unterminated string constant" diff --git a/src/COOL_LEX.interp b/src/COOL_LEX.interp index 4d6e25e8..b7975eb6 100644 --- a/src/COOL_LEX.interp +++ b/src/COOL_LEX.interp @@ -25,6 +25,7 @@ null null null null +null '<-' '=>' '+' @@ -52,6 +53,8 @@ null null null null +null +null token symbolic names: null @@ -76,6 +79,7 @@ NOT TRUE STRING STRING_SIMPLE +STRING_SIMPLE_START STRING_FIRSTLINE INT TYPEID @@ -107,6 +111,8 @@ CLOSE_COMMENT STRING_INNERLINE STRING_LASTLINE STRING_MULTILINE +STRING_SIMPLE_CONTENT +STRING_SIMPLE_STOP rule names: CLASS @@ -130,6 +136,7 @@ NOT TRUE STRING STRING_SIMPLE +STRING_SIMPLE_START STRING_CONTENT STRING_FIRSTLINE INT @@ -182,6 +189,8 @@ CLOSE_COMMENT STRING_INNERLINE STRING_LASTLINE STRING_MULTILINE +STRING_SIMPLE_CONTENT +STRING_SIMPLE_STOP channel names: DEFAULT_TOKEN_CHANNEL @@ -191,6 +200,7 @@ mode names: DEFAULT_MODE MULTILINE_COMMENT MULTILINE_STR +SIMPLE_STR atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 54, 454, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 247, 10, 21, 3, 22, 3, 22, 7, 22, 251, 10, 22, 12, 22, 14, 22, 254, 11, 22, 3, 22, 3, 22, 3, 23, 3, 23, 5, 23, 260, 10, 23, 3, 24, 3, 24, 7, 24, 264, 10, 24, 12, 24, 14, 24, 267, 11, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 6, 25, 276, 10, 25, 13, 25, 14, 25, 277, 3, 26, 3, 26, 7, 26, 282, 10, 26, 12, 26, 14, 26, 285, 11, 26, 3, 27, 3, 27, 7, 27, 289, 10, 27, 12, 27, 14, 27, 292, 11, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 64, 5, 64, 372, 10, 64, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 66, 3, 66, 3, 67, 6, 67, 383, 10, 67, 13, 67, 14, 67, 384, 3, 67, 3, 67, 3, 68, 3, 68, 3, 68, 3, 68, 7, 68, 393, 10, 68, 12, 68, 14, 68, 396, 11, 68, 3, 68, 5, 68, 399, 10, 68, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 6, 70, 413, 10, 70, 13, 70, 14, 70, 414, 5, 70, 417, 10, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 72, 7, 72, 427, 10, 72, 12, 72, 14, 72, 430, 11, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 437, 10, 73, 12, 73, 14, 73, 440, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 3, 74, 7, 74, 448, 10, 74, 12, 74, 14, 74, 451, 11, 74, 3, 74, 3, 74, 3, 414, 2, 75, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 2, 49, 24, 51, 25, 53, 26, 55, 27, 57, 28, 59, 29, 61, 30, 63, 31, 65, 32, 67, 33, 69, 34, 71, 35, 73, 36, 75, 37, 77, 38, 79, 39, 81, 40, 83, 41, 85, 42, 87, 43, 89, 44, 91, 45, 93, 46, 95, 2, 97, 2, 99, 2, 101, 2, 103, 2, 105, 2, 107, 2, 109, 2, 111, 2, 113, 2, 115, 2, 117, 2, 119, 2, 121, 2, 123, 2, 125, 2, 127, 2, 129, 2, 131, 2, 133, 2, 135, 47, 137, 48, 139, 49, 141, 50, 143, 51, 145, 52, 147, 53, 149, 54, 5, 2, 3, 4, 28, 5, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 446, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 87, 3, 2, 2, 2, 2, 89, 3, 2, 2, 2, 2, 91, 3, 2, 2, 2, 2, 93, 3, 2, 2, 2, 2, 135, 3, 2, 2, 2, 2, 137, 3, 2, 2, 2, 2, 139, 3, 2, 2, 2, 3, 141, 3, 2, 2, 2, 3, 143, 3, 2, 2, 2, 4, 145, 3, 2, 2, 2, 4, 147, 3, 2, 2, 2, 4, 149, 3, 2, 2, 2, 5, 151, 3, 2, 2, 2, 7, 157, 3, 2, 2, 2, 9, 162, 3, 2, 2, 2, 11, 168, 3, 2, 2, 2, 13, 171, 3, 2, 2, 2, 15, 174, 3, 2, 2, 2, 17, 177, 3, 2, 2, 2, 19, 186, 3, 2, 2, 2, 21, 193, 3, 2, 2, 2, 23, 197, 3, 2, 2, 2, 25, 202, 3, 2, 2, 2, 27, 207, 3, 2, 2, 2, 29, 212, 3, 2, 2, 2, 31, 218, 3, 2, 2, 2, 33, 223, 3, 2, 2, 2, 35, 228, 3, 2, 2, 2, 37, 232, 3, 2, 2, 2, 39, 235, 3, 2, 2, 2, 41, 239, 3, 2, 2, 2, 43, 246, 3, 2, 2, 2, 45, 248, 3, 2, 2, 2, 47, 259, 3, 2, 2, 2, 49, 261, 3, 2, 2, 2, 51, 275, 3, 2, 2, 2, 53, 279, 3, 2, 2, 2, 55, 286, 3, 2, 2, 2, 57, 293, 3, 2, 2, 2, 59, 296, 3, 2, 2, 2, 61, 299, 3, 2, 2, 2, 63, 301, 3, 2, 2, 2, 65, 303, 3, 2, 2, 2, 67, 305, 3, 2, 2, 2, 69, 307, 3, 2, 2, 2, 71, 309, 3, 2, 2, 2, 73, 312, 3, 2, 2, 2, 75, 314, 3, 2, 2, 2, 77, 316, 3, 2, 2, 2, 79, 318, 3, 2, 2, 2, 81, 320, 3, 2, 2, 2, 83, 322, 3, 2, 2, 2, 85, 324, 3, 2, 2, 2, 87, 326, 3, 2, 2, 2, 89, 328, 3, 2, 2, 2, 91, 330, 3, 2, 2, 2, 93, 332, 3, 2, 2, 2, 95, 334, 3, 2, 2, 2, 97, 336, 3, 2, 2, 2, 99, 338, 3, 2, 2, 2, 101, 340, 3, 2, 2, 2, 103, 342, 3, 2, 2, 2, 105, 344, 3, 2, 2, 2, 107, 346, 3, 2, 2, 2, 109, 348, 3, 2, 2, 2, 111, 350, 3, 2, 2, 2, 113, 352, 3, 2, 2, 2, 115, 354, 3, 2, 2, 2, 117, 356, 3, 2, 2, 2, 119, 358, 3, 2, 2, 2, 121, 360, 3, 2, 2, 2, 123, 362, 3, 2, 2, 2, 125, 364, 3, 2, 2, 2, 127, 366, 3, 2, 2, 2, 129, 368, 3, 2, 2, 2, 131, 373, 3, 2, 2, 2, 133, 379, 3, 2, 2, 2, 135, 382, 3, 2, 2, 2, 137, 388, 3, 2, 2, 2, 139, 402, 3, 2, 2, 2, 141, 416, 3, 2, 2, 2, 143, 420, 3, 2, 2, 2, 145, 428, 3, 2, 2, 2, 147, 438, 3, 2, 2, 2, 149, 445, 3, 2, 2, 2, 151, 152, 5, 97, 48, 2, 152, 153, 5, 109, 54, 2, 153, 154, 5, 95, 47, 2, 154, 155, 5, 119, 59, 2, 155, 156, 5, 119, 59, 2, 156, 6, 3, 2, 2, 2, 157, 158, 5, 101, 50, 2, 158, 159, 5, 109, 54, 2, 159, 160, 5, 119, 59, 2, 160, 161, 5, 101, 50, 2, 161, 8, 3, 2, 2, 2, 162, 163, 7, 104, 2, 2, 163, 164, 5, 95, 47, 2, 164, 165, 5, 109, 54, 2, 165, 166, 5, 119, 59, 2, 166, 167, 5, 101, 50, 2, 167, 10, 3, 2, 2, 2, 168, 169, 5, 103, 51, 2, 169, 170, 5, 107, 53, 2, 170, 12, 3, 2, 2, 2, 171, 172, 5, 107, 53, 2, 172, 173, 5, 103, 51, 2, 173, 14, 3, 2, 2, 2, 174, 175, 5, 107, 53, 2, 175, 176, 5, 111, 55, 2, 176, 16, 3, 2, 2, 2, 177, 178, 5, 107, 53, 2, 178, 179, 5, 111, 55, 2, 179, 180, 5, 105, 52, 2, 180, 181, 5, 101, 50, 2, 181, 182, 5, 117, 58, 2, 182, 183, 5, 107, 53, 2, 183, 184, 5, 121, 60, 2, 184, 185, 5, 119, 59, 2, 185, 18, 3, 2, 2, 2, 186, 187, 5, 107, 53, 2, 187, 188, 5, 119, 59, 2, 188, 189, 5, 125, 62, 2, 189, 190, 5, 113, 56, 2, 190, 191, 5, 107, 53, 2, 191, 192, 5, 99, 49, 2, 192, 20, 3, 2, 2, 2, 193, 194, 5, 109, 54, 2, 194, 195, 5, 101, 50, 2, 195, 196, 5, 121, 60, 2, 196, 22, 3, 2, 2, 2, 197, 198, 5, 109, 54, 2, 198, 199, 5, 113, 56, 2, 199, 200, 5, 113, 56, 2, 200, 201, 5, 115, 57, 2, 201, 24, 3, 2, 2, 2, 202, 203, 5, 115, 57, 2, 203, 204, 5, 113, 56, 2, 204, 205, 5, 113, 56, 2, 205, 206, 5, 109, 54, 2, 206, 26, 3, 2, 2, 2, 207, 208, 5, 121, 60, 2, 208, 209, 5, 105, 52, 2, 209, 210, 5, 101, 50, 2, 210, 211, 5, 111, 55, 2, 211, 28, 3, 2, 2, 2, 212, 213, 5, 127, 63, 2, 213, 214, 5, 105, 52, 2, 214, 215, 5, 107, 53, 2, 215, 216, 5, 109, 54, 2, 216, 217, 5, 101, 50, 2, 217, 30, 3, 2, 2, 2, 218, 219, 5, 97, 48, 2, 219, 220, 5, 95, 47, 2, 220, 221, 5, 119, 59, 2, 221, 222, 5, 101, 50, 2, 222, 32, 3, 2, 2, 2, 223, 224, 5, 101, 50, 2, 224, 225, 5, 119, 59, 2, 225, 226, 5, 95, 47, 2, 226, 227, 5, 97, 48, 2, 227, 34, 3, 2, 2, 2, 228, 229, 5, 111, 55, 2, 229, 230, 5, 101, 50, 2, 230, 231, 5, 127, 63, 2, 231, 36, 3, 2, 2, 2, 232, 233, 5, 113, 56, 2, 233, 234, 5, 103, 51, 2, 234, 38, 3, 2, 2, 2, 235, 236, 5, 111, 55, 2, 236, 237, 5, 113, 56, 2, 237, 238, 5, 121, 60, 2, 238, 40, 3, 2, 2, 2, 239, 240, 7, 118, 2, 2, 240, 241, 5, 117, 58, 2, 241, 242, 5, 123, 61, 2, 242, 243, 5, 101, 50, 2, 243, 42, 3, 2, 2, 2, 244, 247, 5, 45, 22, 2, 245, 247, 5, 149, 74, 2, 246, 244, 3, 2, 2, 2, 246, 245, 3, 2, 2, 2, 247, 44, 3, 2, 2, 2, 248, 252, 7, 36, 2, 2, 249, 251, 5, 47, 23, 2, 250, 249, 3, 2, 2, 2, 251, 254, 3, 2, 2, 2, 252, 250, 3, 2, 2, 2, 252, 253, 3, 2, 2, 2, 253, 255, 3, 2, 2, 2, 254, 252, 3, 2, 2, 2, 255, 256, 7, 36, 2, 2, 256, 46, 3, 2, 2, 2, 257, 260, 5, 129, 64, 2, 258, 260, 10, 2, 2, 2, 259, 257, 3, 2, 2, 2, 259, 258, 3, 2, 2, 2, 260, 48, 3, 2, 2, 2, 261, 265, 7, 36, 2, 2, 262, 264, 5, 47, 23, 2, 263, 262, 3, 2, 2, 2, 264, 267, 3, 2, 2, 2, 265, 263, 3, 2, 2, 2, 265, 266, 3, 2, 2, 2, 266, 268, 3, 2, 2, 2, 267, 265, 3, 2, 2, 2, 268, 269, 7, 94, 2, 2, 269, 270, 7, 15, 2, 2, 270, 271, 7, 12, 2, 2, 271, 272, 3, 2, 2, 2, 272, 273, 8, 24, 2, 2, 273, 50, 3, 2, 2, 2, 274, 276, 9, 3, 2, 2, 275, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 275, 3, 2, 2, 2, 277, 278, 3, 2, 2, 2, 278, 52, 3, 2, 2, 2, 279, 283, 9, 4, 2, 2, 280, 282, 9, 5, 2, 2, 281, 280, 3, 2, 2, 2, 282, 285, 3, 2, 2, 2, 283, 281, 3, 2, 2, 2, 283, 284, 3, 2, 2, 2, 284, 54, 3, 2, 2, 2, 285, 283, 3, 2, 2, 2, 286, 290, 9, 6, 2, 2, 287, 289, 9, 5, 2, 2, 288, 287, 3, 2, 2, 2, 289, 292, 3, 2, 2, 2, 290, 288, 3, 2, 2, 2, 290, 291, 3, 2, 2, 2, 291, 56, 3, 2, 2, 2, 292, 290, 3, 2, 2, 2, 293, 294, 7, 62, 2, 2, 294, 295, 7, 47, 2, 2, 295, 58, 3, 2, 2, 2, 296, 297, 7, 63, 2, 2, 297, 298, 7, 64, 2, 2, 298, 60, 3, 2, 2, 2, 299, 300, 7, 45, 2, 2, 300, 62, 3, 2, 2, 2, 301, 302, 7, 47, 2, 2, 302, 64, 3, 2, 2, 2, 303, 304, 7, 44, 2, 2, 304, 66, 3, 2, 2, 2, 305, 306, 7, 49, 2, 2, 306, 68, 3, 2, 2, 2, 307, 308, 7, 62, 2, 2, 308, 70, 3, 2, 2, 2, 309, 310, 7, 62, 2, 2, 310, 311, 7, 63, 2, 2, 311, 72, 3, 2, 2, 2, 312, 313, 7, 63, 2, 2, 313, 74, 3, 2, 2, 2, 314, 315, 7, 128, 2, 2, 315, 76, 3, 2, 2, 2, 316, 317, 7, 42, 2, 2, 317, 78, 3, 2, 2, 2, 318, 319, 7, 43, 2, 2, 319, 80, 3, 2, 2, 2, 320, 321, 7, 125, 2, 2, 321, 82, 3, 2, 2, 2, 322, 323, 7, 127, 2, 2, 323, 84, 3, 2, 2, 2, 324, 325, 7, 66, 2, 2, 325, 86, 3, 2, 2, 2, 326, 327, 7, 48, 2, 2, 327, 88, 3, 2, 2, 2, 328, 329, 7, 46, 2, 2, 329, 90, 3, 2, 2, 2, 330, 331, 7, 60, 2, 2, 331, 92, 3, 2, 2, 2, 332, 333, 7, 61, 2, 2, 333, 94, 3, 2, 2, 2, 334, 335, 9, 7, 2, 2, 335, 96, 3, 2, 2, 2, 336, 337, 9, 8, 2, 2, 337, 98, 3, 2, 2, 2, 338, 339, 9, 9, 2, 2, 339, 100, 3, 2, 2, 2, 340, 341, 9, 10, 2, 2, 341, 102, 3, 2, 2, 2, 342, 343, 9, 11, 2, 2, 343, 104, 3, 2, 2, 2, 344, 345, 9, 12, 2, 2, 345, 106, 3, 2, 2, 2, 346, 347, 9, 13, 2, 2, 347, 108, 3, 2, 2, 2, 348, 349, 9, 14, 2, 2, 349, 110, 3, 2, 2, 2, 350, 351, 9, 15, 2, 2, 351, 112, 3, 2, 2, 2, 352, 353, 9, 16, 2, 2, 353, 114, 3, 2, 2, 2, 354, 355, 9, 17, 2, 2, 355, 116, 3, 2, 2, 2, 356, 357, 9, 18, 2, 2, 357, 118, 3, 2, 2, 2, 358, 359, 9, 19, 2, 2, 359, 120, 3, 2, 2, 2, 360, 361, 9, 20, 2, 2, 361, 122, 3, 2, 2, 2, 362, 363, 9, 21, 2, 2, 363, 124, 3, 2, 2, 2, 364, 365, 9, 22, 2, 2, 365, 126, 3, 2, 2, 2, 366, 367, 9, 23, 2, 2, 367, 128, 3, 2, 2, 2, 368, 371, 7, 94, 2, 2, 369, 372, 9, 24, 2, 2, 370, 372, 5, 131, 65, 2, 371, 369, 3, 2, 2, 2, 371, 370, 3, 2, 2, 2, 372, 130, 3, 2, 2, 2, 373, 374, 7, 119, 2, 2, 374, 375, 5, 133, 66, 2, 375, 376, 5, 133, 66, 2, 376, 377, 5, 133, 66, 2, 377, 378, 5, 133, 66, 2, 378, 132, 3, 2, 2, 2, 379, 380, 9, 25, 2, 2, 380, 134, 3, 2, 2, 2, 381, 383, 9, 26, 2, 2, 382, 381, 3, 2, 2, 2, 383, 384, 3, 2, 2, 2, 384, 382, 3, 2, 2, 2, 384, 385, 3, 2, 2, 2, 385, 386, 3, 2, 2, 2, 386, 387, 8, 67, 3, 2, 387, 136, 3, 2, 2, 2, 388, 389, 7, 47, 2, 2, 389, 390, 7, 47, 2, 2, 390, 394, 3, 2, 2, 2, 391, 393, 10, 27, 2, 2, 392, 391, 3, 2, 2, 2, 393, 396, 3, 2, 2, 2, 394, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 398, 3, 2, 2, 2, 396, 394, 3, 2, 2, 2, 397, 399, 7, 12, 2, 2, 398, 397, 3, 2, 2, 2, 398, 399, 3, 2, 2, 2, 399, 400, 3, 2, 2, 2, 400, 401, 8, 68, 3, 2, 401, 138, 3, 2, 2, 2, 402, 403, 7, 42, 2, 2, 403, 404, 7, 44, 2, 2, 404, 405, 3, 2, 2, 2, 405, 406, 8, 69, 4, 2, 406, 140, 3, 2, 2, 2, 407, 408, 5, 139, 69, 2, 408, 409, 5, 141, 70, 2, 409, 410, 5, 143, 71, 2, 410, 417, 3, 2, 2, 2, 411, 413, 11, 2, 2, 2, 412, 411, 3, 2, 2, 2, 413, 414, 3, 2, 2, 2, 414, 415, 3, 2, 2, 2, 414, 412, 3, 2, 2, 2, 415, 417, 3, 2, 2, 2, 416, 407, 3, 2, 2, 2, 416, 412, 3, 2, 2, 2, 417, 418, 3, 2, 2, 2, 418, 419, 8, 70, 3, 2, 419, 142, 3, 2, 2, 2, 420, 421, 7, 44, 2, 2, 421, 422, 7, 43, 2, 2, 422, 423, 3, 2, 2, 2, 423, 424, 8, 71, 5, 2, 424, 144, 3, 2, 2, 2, 425, 427, 5, 47, 23, 2, 426, 425, 3, 2, 2, 2, 427, 430, 3, 2, 2, 2, 428, 426, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 431, 3, 2, 2, 2, 430, 428, 3, 2, 2, 2, 431, 432, 7, 94, 2, 2, 432, 433, 7, 15, 2, 2, 433, 434, 7, 12, 2, 2, 434, 146, 3, 2, 2, 2, 435, 437, 5, 47, 23, 2, 436, 435, 3, 2, 2, 2, 437, 440, 3, 2, 2, 2, 438, 436, 3, 2, 2, 2, 438, 439, 3, 2, 2, 2, 439, 441, 3, 2, 2, 2, 440, 438, 3, 2, 2, 2, 441, 442, 7, 36, 2, 2, 442, 443, 3, 2, 2, 2, 443, 444, 8, 73, 5, 2, 444, 148, 3, 2, 2, 2, 445, 449, 5, 49, 24, 2, 446, 448, 5, 145, 72, 2, 447, 446, 3, 2, 2, 2, 448, 451, 3, 2, 2, 2, 449, 447, 3, 2, 2, 2, 449, 450, 3, 2, 2, 2, 450, 452, 3, 2, 2, 2, 451, 449, 3, 2, 2, 2, 452, 453, 5, 147, 73, 2, 453, 150, 3, 2, 2, 2, 21, 2, 3, 4, 246, 252, 259, 265, 277, 283, 290, 371, 384, 394, 398, 414, 416, 428, 438, 449, 6, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 57, 471, 8, 1, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 254, 10, 21, 3, 22, 3, 22, 7, 22, 258, 10, 22, 12, 22, 14, 22, 261, 11, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 5, 24, 271, 10, 24, 3, 25, 3, 25, 7, 25, 275, 10, 25, 12, 25, 14, 25, 278, 11, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 6, 26, 287, 10, 26, 13, 26, 14, 26, 288, 3, 27, 3, 27, 7, 27, 293, 10, 27, 12, 27, 14, 27, 296, 11, 27, 3, 28, 3, 28, 7, 28, 300, 10, 28, 12, 28, 14, 28, 303, 11, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 5, 65, 383, 10, 65, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 6, 68, 394, 10, 68, 13, 68, 14, 68, 395, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 7, 69, 404, 10, 69, 12, 69, 14, 69, 407, 11, 69, 3, 69, 5, 69, 410, 10, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 424, 10, 71, 13, 71, 14, 71, 425, 5, 71, 428, 10, 71, 3, 71, 3, 71, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 438, 10, 73, 12, 73, 14, 73, 441, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 7, 74, 448, 10, 74, 12, 74, 14, 74, 451, 11, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 75, 3, 75, 7, 75, 459, 10, 75, 12, 75, 14, 75, 462, 11, 75, 3, 75, 3, 75, 3, 76, 3, 76, 3, 77, 3, 77, 3, 77, 3, 77, 3, 425, 2, 78, 6, 3, 8, 4, 10, 5, 12, 6, 14, 7, 16, 8, 18, 9, 20, 10, 22, 11, 24, 12, 26, 13, 28, 14, 30, 15, 32, 16, 34, 17, 36, 18, 38, 19, 40, 20, 42, 21, 44, 22, 46, 23, 48, 24, 50, 2, 52, 25, 54, 26, 56, 27, 58, 28, 60, 29, 62, 30, 64, 31, 66, 32, 68, 33, 70, 34, 72, 35, 74, 36, 76, 37, 78, 38, 80, 39, 82, 40, 84, 41, 86, 42, 88, 43, 90, 44, 92, 45, 94, 46, 96, 47, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 2, 132, 2, 134, 2, 136, 2, 138, 48, 140, 49, 142, 50, 144, 51, 146, 52, 148, 53, 150, 54, 152, 55, 154, 56, 156, 57, 6, 2, 3, 4, 5, 28, 6, 2, 2, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 462, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 90, 3, 2, 2, 2, 2, 92, 3, 2, 2, 2, 2, 94, 3, 2, 2, 2, 2, 96, 3, 2, 2, 2, 2, 138, 3, 2, 2, 2, 2, 140, 3, 2, 2, 2, 2, 142, 3, 2, 2, 2, 3, 144, 3, 2, 2, 2, 3, 146, 3, 2, 2, 2, 4, 148, 3, 2, 2, 2, 4, 150, 3, 2, 2, 2, 4, 152, 3, 2, 2, 2, 5, 154, 3, 2, 2, 2, 5, 156, 3, 2, 2, 2, 6, 158, 3, 2, 2, 2, 8, 164, 3, 2, 2, 2, 10, 169, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 178, 3, 2, 2, 2, 16, 181, 3, 2, 2, 2, 18, 184, 3, 2, 2, 2, 20, 193, 3, 2, 2, 2, 22, 200, 3, 2, 2, 2, 24, 204, 3, 2, 2, 2, 26, 209, 3, 2, 2, 2, 28, 214, 3, 2, 2, 2, 30, 219, 3, 2, 2, 2, 32, 225, 3, 2, 2, 2, 34, 230, 3, 2, 2, 2, 36, 235, 3, 2, 2, 2, 38, 239, 3, 2, 2, 2, 40, 242, 3, 2, 2, 2, 42, 246, 3, 2, 2, 2, 44, 253, 3, 2, 2, 2, 46, 255, 3, 2, 2, 2, 48, 264, 3, 2, 2, 2, 50, 270, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 286, 3, 2, 2, 2, 56, 290, 3, 2, 2, 2, 58, 297, 3, 2, 2, 2, 60, 304, 3, 2, 2, 2, 62, 307, 3, 2, 2, 2, 64, 310, 3, 2, 2, 2, 66, 312, 3, 2, 2, 2, 68, 314, 3, 2, 2, 2, 70, 316, 3, 2, 2, 2, 72, 318, 3, 2, 2, 2, 74, 320, 3, 2, 2, 2, 76, 323, 3, 2, 2, 2, 78, 325, 3, 2, 2, 2, 80, 327, 3, 2, 2, 2, 82, 329, 3, 2, 2, 2, 84, 331, 3, 2, 2, 2, 86, 333, 3, 2, 2, 2, 88, 335, 3, 2, 2, 2, 90, 337, 3, 2, 2, 2, 92, 339, 3, 2, 2, 2, 94, 341, 3, 2, 2, 2, 96, 343, 3, 2, 2, 2, 98, 345, 3, 2, 2, 2, 100, 347, 3, 2, 2, 2, 102, 349, 3, 2, 2, 2, 104, 351, 3, 2, 2, 2, 106, 353, 3, 2, 2, 2, 108, 355, 3, 2, 2, 2, 110, 357, 3, 2, 2, 2, 112, 359, 3, 2, 2, 2, 114, 361, 3, 2, 2, 2, 116, 363, 3, 2, 2, 2, 118, 365, 3, 2, 2, 2, 120, 367, 3, 2, 2, 2, 122, 369, 3, 2, 2, 2, 124, 371, 3, 2, 2, 2, 126, 373, 3, 2, 2, 2, 128, 375, 3, 2, 2, 2, 130, 377, 3, 2, 2, 2, 132, 379, 3, 2, 2, 2, 134, 384, 3, 2, 2, 2, 136, 390, 3, 2, 2, 2, 138, 393, 3, 2, 2, 2, 140, 399, 3, 2, 2, 2, 142, 413, 3, 2, 2, 2, 144, 427, 3, 2, 2, 2, 146, 431, 3, 2, 2, 2, 148, 439, 3, 2, 2, 2, 150, 449, 3, 2, 2, 2, 152, 456, 3, 2, 2, 2, 154, 465, 3, 2, 2, 2, 156, 467, 3, 2, 2, 2, 158, 159, 5, 100, 49, 2, 159, 160, 5, 112, 55, 2, 160, 161, 5, 98, 48, 2, 161, 162, 5, 122, 60, 2, 162, 163, 5, 122, 60, 2, 163, 7, 3, 2, 2, 2, 164, 165, 5, 104, 51, 2, 165, 166, 5, 112, 55, 2, 166, 167, 5, 122, 60, 2, 167, 168, 5, 104, 51, 2, 168, 9, 3, 2, 2, 2, 169, 170, 7, 104, 2, 2, 170, 171, 5, 98, 48, 2, 171, 172, 5, 112, 55, 2, 172, 173, 5, 122, 60, 2, 173, 174, 5, 104, 51, 2, 174, 11, 3, 2, 2, 2, 175, 176, 5, 106, 52, 2, 176, 177, 5, 110, 54, 2, 177, 13, 3, 2, 2, 2, 178, 179, 5, 110, 54, 2, 179, 180, 5, 106, 52, 2, 180, 15, 3, 2, 2, 2, 181, 182, 5, 110, 54, 2, 182, 183, 5, 114, 56, 2, 183, 17, 3, 2, 2, 2, 184, 185, 5, 110, 54, 2, 185, 186, 5, 114, 56, 2, 186, 187, 5, 108, 53, 2, 187, 188, 5, 104, 51, 2, 188, 189, 5, 120, 59, 2, 189, 190, 5, 110, 54, 2, 190, 191, 5, 124, 61, 2, 191, 192, 5, 122, 60, 2, 192, 19, 3, 2, 2, 2, 193, 194, 5, 110, 54, 2, 194, 195, 5, 122, 60, 2, 195, 196, 5, 128, 63, 2, 196, 197, 5, 116, 57, 2, 197, 198, 5, 110, 54, 2, 198, 199, 5, 102, 50, 2, 199, 21, 3, 2, 2, 2, 200, 201, 5, 112, 55, 2, 201, 202, 5, 104, 51, 2, 202, 203, 5, 124, 61, 2, 203, 23, 3, 2, 2, 2, 204, 205, 5, 112, 55, 2, 205, 206, 5, 116, 57, 2, 206, 207, 5, 116, 57, 2, 207, 208, 5, 118, 58, 2, 208, 25, 3, 2, 2, 2, 209, 210, 5, 118, 58, 2, 210, 211, 5, 116, 57, 2, 211, 212, 5, 116, 57, 2, 212, 213, 5, 112, 55, 2, 213, 27, 3, 2, 2, 2, 214, 215, 5, 124, 61, 2, 215, 216, 5, 108, 53, 2, 216, 217, 5, 104, 51, 2, 217, 218, 5, 114, 56, 2, 218, 29, 3, 2, 2, 2, 219, 220, 5, 130, 64, 2, 220, 221, 5, 108, 53, 2, 221, 222, 5, 110, 54, 2, 222, 223, 5, 112, 55, 2, 223, 224, 5, 104, 51, 2, 224, 31, 3, 2, 2, 2, 225, 226, 5, 100, 49, 2, 226, 227, 5, 98, 48, 2, 227, 228, 5, 122, 60, 2, 228, 229, 5, 104, 51, 2, 229, 33, 3, 2, 2, 2, 230, 231, 5, 104, 51, 2, 231, 232, 5, 122, 60, 2, 232, 233, 5, 98, 48, 2, 233, 234, 5, 100, 49, 2, 234, 35, 3, 2, 2, 2, 235, 236, 5, 114, 56, 2, 236, 237, 5, 104, 51, 2, 237, 238, 5, 130, 64, 2, 238, 37, 3, 2, 2, 2, 239, 240, 5, 116, 57, 2, 240, 241, 5, 106, 52, 2, 241, 39, 3, 2, 2, 2, 242, 243, 5, 114, 56, 2, 243, 244, 5, 116, 57, 2, 244, 245, 5, 124, 61, 2, 245, 41, 3, 2, 2, 2, 246, 247, 7, 118, 2, 2, 247, 248, 5, 120, 59, 2, 248, 249, 5, 126, 62, 2, 249, 250, 5, 104, 51, 2, 250, 43, 3, 2, 2, 2, 251, 254, 5, 46, 22, 2, 252, 254, 5, 152, 75, 2, 253, 251, 3, 2, 2, 2, 253, 252, 3, 2, 2, 2, 254, 45, 3, 2, 2, 2, 255, 259, 5, 48, 23, 2, 256, 258, 5, 154, 76, 2, 257, 256, 3, 2, 2, 2, 258, 261, 3, 2, 2, 2, 259, 257, 3, 2, 2, 2, 259, 260, 3, 2, 2, 2, 260, 262, 3, 2, 2, 2, 261, 259, 3, 2, 2, 2, 262, 263, 5, 156, 77, 2, 263, 47, 3, 2, 2, 2, 264, 265, 7, 36, 2, 2, 265, 266, 3, 2, 2, 2, 266, 267, 8, 23, 2, 2, 267, 49, 3, 2, 2, 2, 268, 271, 5, 132, 65, 2, 269, 271, 10, 2, 2, 2, 270, 268, 3, 2, 2, 2, 270, 269, 3, 2, 2, 2, 271, 51, 3, 2, 2, 2, 272, 276, 7, 36, 2, 2, 273, 275, 5, 50, 24, 2, 274, 273, 3, 2, 2, 2, 275, 278, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 279, 3, 2, 2, 2, 278, 276, 3, 2, 2, 2, 279, 280, 7, 94, 2, 2, 280, 281, 7, 15, 2, 2, 281, 282, 7, 12, 2, 2, 282, 283, 3, 2, 2, 2, 283, 284, 8, 25, 3, 2, 284, 53, 3, 2, 2, 2, 285, 287, 9, 3, 2, 2, 286, 285, 3, 2, 2, 2, 287, 288, 3, 2, 2, 2, 288, 286, 3, 2, 2, 2, 288, 289, 3, 2, 2, 2, 289, 55, 3, 2, 2, 2, 290, 294, 9, 4, 2, 2, 291, 293, 9, 5, 2, 2, 292, 291, 3, 2, 2, 2, 293, 296, 3, 2, 2, 2, 294, 292, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 57, 3, 2, 2, 2, 296, 294, 3, 2, 2, 2, 297, 301, 9, 6, 2, 2, 298, 300, 9, 5, 2, 2, 299, 298, 3, 2, 2, 2, 300, 303, 3, 2, 2, 2, 301, 299, 3, 2, 2, 2, 301, 302, 3, 2, 2, 2, 302, 59, 3, 2, 2, 2, 303, 301, 3, 2, 2, 2, 304, 305, 7, 62, 2, 2, 305, 306, 7, 47, 2, 2, 306, 61, 3, 2, 2, 2, 307, 308, 7, 63, 2, 2, 308, 309, 7, 64, 2, 2, 309, 63, 3, 2, 2, 2, 310, 311, 7, 45, 2, 2, 311, 65, 3, 2, 2, 2, 312, 313, 7, 47, 2, 2, 313, 67, 3, 2, 2, 2, 314, 315, 7, 44, 2, 2, 315, 69, 3, 2, 2, 2, 316, 317, 7, 49, 2, 2, 317, 71, 3, 2, 2, 2, 318, 319, 7, 62, 2, 2, 319, 73, 3, 2, 2, 2, 320, 321, 7, 62, 2, 2, 321, 322, 7, 63, 2, 2, 322, 75, 3, 2, 2, 2, 323, 324, 7, 63, 2, 2, 324, 77, 3, 2, 2, 2, 325, 326, 7, 128, 2, 2, 326, 79, 3, 2, 2, 2, 327, 328, 7, 42, 2, 2, 328, 81, 3, 2, 2, 2, 329, 330, 7, 43, 2, 2, 330, 83, 3, 2, 2, 2, 331, 332, 7, 125, 2, 2, 332, 85, 3, 2, 2, 2, 333, 334, 7, 127, 2, 2, 334, 87, 3, 2, 2, 2, 335, 336, 7, 66, 2, 2, 336, 89, 3, 2, 2, 2, 337, 338, 7, 48, 2, 2, 338, 91, 3, 2, 2, 2, 339, 340, 7, 46, 2, 2, 340, 93, 3, 2, 2, 2, 341, 342, 7, 60, 2, 2, 342, 95, 3, 2, 2, 2, 343, 344, 7, 61, 2, 2, 344, 97, 3, 2, 2, 2, 345, 346, 9, 7, 2, 2, 346, 99, 3, 2, 2, 2, 347, 348, 9, 8, 2, 2, 348, 101, 3, 2, 2, 2, 349, 350, 9, 9, 2, 2, 350, 103, 3, 2, 2, 2, 351, 352, 9, 10, 2, 2, 352, 105, 3, 2, 2, 2, 353, 354, 9, 11, 2, 2, 354, 107, 3, 2, 2, 2, 355, 356, 9, 12, 2, 2, 356, 109, 3, 2, 2, 2, 357, 358, 9, 13, 2, 2, 358, 111, 3, 2, 2, 2, 359, 360, 9, 14, 2, 2, 360, 113, 3, 2, 2, 2, 361, 362, 9, 15, 2, 2, 362, 115, 3, 2, 2, 2, 363, 364, 9, 16, 2, 2, 364, 117, 3, 2, 2, 2, 365, 366, 9, 17, 2, 2, 366, 119, 3, 2, 2, 2, 367, 368, 9, 18, 2, 2, 368, 121, 3, 2, 2, 2, 369, 370, 9, 19, 2, 2, 370, 123, 3, 2, 2, 2, 371, 372, 9, 20, 2, 2, 372, 125, 3, 2, 2, 2, 373, 374, 9, 21, 2, 2, 374, 127, 3, 2, 2, 2, 375, 376, 9, 22, 2, 2, 376, 129, 3, 2, 2, 2, 377, 378, 9, 23, 2, 2, 378, 131, 3, 2, 2, 2, 379, 382, 7, 94, 2, 2, 380, 383, 9, 24, 2, 2, 381, 383, 5, 134, 66, 2, 382, 380, 3, 2, 2, 2, 382, 381, 3, 2, 2, 2, 383, 133, 3, 2, 2, 2, 384, 385, 7, 119, 2, 2, 385, 386, 5, 136, 67, 2, 386, 387, 5, 136, 67, 2, 387, 388, 5, 136, 67, 2, 388, 389, 5, 136, 67, 2, 389, 135, 3, 2, 2, 2, 390, 391, 9, 25, 2, 2, 391, 137, 3, 2, 2, 2, 392, 394, 9, 26, 2, 2, 393, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 393, 3, 2, 2, 2, 395, 396, 3, 2, 2, 2, 396, 397, 3, 2, 2, 2, 397, 398, 8, 68, 4, 2, 398, 139, 3, 2, 2, 2, 399, 400, 7, 47, 2, 2, 400, 401, 7, 47, 2, 2, 401, 405, 3, 2, 2, 2, 402, 404, 10, 27, 2, 2, 403, 402, 3, 2, 2, 2, 404, 407, 3, 2, 2, 2, 405, 403, 3, 2, 2, 2, 405, 406, 3, 2, 2, 2, 406, 409, 3, 2, 2, 2, 407, 405, 3, 2, 2, 2, 408, 410, 7, 12, 2, 2, 409, 408, 3, 2, 2, 2, 409, 410, 3, 2, 2, 2, 410, 411, 3, 2, 2, 2, 411, 412, 8, 69, 4, 2, 412, 141, 3, 2, 2, 2, 413, 414, 7, 42, 2, 2, 414, 415, 7, 44, 2, 2, 415, 416, 3, 2, 2, 2, 416, 417, 8, 70, 5, 2, 417, 143, 3, 2, 2, 2, 418, 419, 5, 142, 70, 2, 419, 420, 5, 144, 71, 2, 420, 421, 5, 146, 72, 2, 421, 428, 3, 2, 2, 2, 422, 424, 11, 2, 2, 2, 423, 422, 3, 2, 2, 2, 424, 425, 3, 2, 2, 2, 425, 426, 3, 2, 2, 2, 425, 423, 3, 2, 2, 2, 426, 428, 3, 2, 2, 2, 427, 418, 3, 2, 2, 2, 427, 423, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 430, 8, 71, 4, 2, 430, 145, 3, 2, 2, 2, 431, 432, 7, 44, 2, 2, 432, 433, 7, 43, 2, 2, 433, 434, 3, 2, 2, 2, 434, 435, 8, 72, 6, 2, 435, 147, 3, 2, 2, 2, 436, 438, 5, 50, 24, 2, 437, 436, 3, 2, 2, 2, 438, 441, 3, 2, 2, 2, 439, 437, 3, 2, 2, 2, 439, 440, 3, 2, 2, 2, 440, 442, 3, 2, 2, 2, 441, 439, 3, 2, 2, 2, 442, 443, 7, 94, 2, 2, 443, 444, 7, 15, 2, 2, 444, 445, 7, 12, 2, 2, 445, 149, 3, 2, 2, 2, 446, 448, 5, 50, 24, 2, 447, 446, 3, 2, 2, 2, 448, 451, 3, 2, 2, 2, 449, 447, 3, 2, 2, 2, 449, 450, 3, 2, 2, 2, 450, 452, 3, 2, 2, 2, 451, 449, 3, 2, 2, 2, 452, 453, 7, 36, 2, 2, 453, 454, 3, 2, 2, 2, 454, 455, 8, 74, 6, 2, 455, 151, 3, 2, 2, 2, 456, 460, 5, 52, 25, 2, 457, 459, 5, 148, 73, 2, 458, 457, 3, 2, 2, 2, 459, 462, 3, 2, 2, 2, 460, 458, 3, 2, 2, 2, 460, 461, 3, 2, 2, 2, 461, 463, 3, 2, 2, 2, 462, 460, 3, 2, 2, 2, 463, 464, 5, 150, 74, 2, 464, 153, 3, 2, 2, 2, 465, 466, 5, 50, 24, 2, 466, 155, 3, 2, 2, 2, 467, 468, 7, 36, 2, 2, 468, 469, 3, 2, 2, 2, 469, 470, 8, 77, 6, 2, 470, 157, 3, 2, 2, 2, 22, 2, 3, 4, 5, 253, 259, 270, 276, 288, 294, 301, 382, 395, 405, 409, 425, 427, 439, 449, 460, 7, 7, 5, 2, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file diff --git a/src/COOL_LEX.py b/src/COOL_LEX.py index c2fb0dc6..02c42de2 100644 --- a/src/COOL_LEX.py +++ b/src/COOL_LEX.py @@ -8,202 +8,210 @@ def serializedATN(): with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\66") - buf.write("\u01c6\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6") - buf.write("\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f") - buf.write("\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22") - buf.write("\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27") - buf.write("\4\30\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35") - buf.write("\t\35\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4") - buf.write("$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t") - buf.write(",\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63") - buf.write("\t\63\4\64\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\4") - buf.write("9\t9\4:\t:\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA\4") - buf.write("B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I\tI\4J\tJ\3") - buf.write("\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\4\3\4\3\4") - buf.write("\3\4\3\4\3\4\3\5\3\5\3\5\3\6\3\6\3\6\3\7\3\7\3\7\3\b\3") - buf.write("\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t") - buf.write("\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3\f\3\f") - buf.write("\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3") - buf.write("\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20") - buf.write("\3\20\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\23\3\23\3\23") - buf.write("\3\23\3\24\3\24\3\24\3\24\3\24\3\25\3\25\5\25\u00f7\n") - buf.write("\25\3\26\3\26\7\26\u00fb\n\26\f\26\16\26\u00fe\13\26\3") - buf.write("\26\3\26\3\27\3\27\5\27\u0104\n\27\3\30\3\30\7\30\u0108") - buf.write("\n\30\f\30\16\30\u010b\13\30\3\30\3\30\3\30\3\30\3\30") - buf.write("\3\30\3\31\6\31\u0114\n\31\r\31\16\31\u0115\3\32\3\32") - buf.write("\7\32\u011a\n\32\f\32\16\32\u011d\13\32\3\33\3\33\7\33") - buf.write("\u0121\n\33\f\33\16\33\u0124\13\33\3\34\3\34\3\34\3\35") - buf.write("\3\35\3\35\3\36\3\36\3\37\3\37\3 \3 \3!\3!\3\"\3\"\3#") - buf.write("\3#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(\3)\3)\3*\3*\3+") - buf.write("\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3\60\3\61\3\61\3\62\3") - buf.write("\62\3\63\3\63\3\64\3\64\3\65\3\65\3\66\3\66\3\67\3\67") - buf.write("\38\38\39\39\3:\3:\3;\3;\3<\3<\3=\3=\3>\3>\3?\3?\3@\3") - buf.write("@\3@\5@\u0174\n@\3A\3A\3A\3A\3A\3A\3B\3B\3C\6C\u017f\n") - buf.write("C\rC\16C\u0180\3C\3C\3D\3D\3D\3D\7D\u0189\nD\fD\16D\u018c") - buf.write("\13D\3D\5D\u018f\nD\3D\3D\3E\3E\3E\3E\3E\3F\3F\3F\3F\3") - buf.write("F\6F\u019d\nF\rF\16F\u019e\5F\u01a1\nF\3F\3F\3G\3G\3G") - buf.write("\3G\3G\3H\7H\u01ab\nH\fH\16H\u01ae\13H\3H\3H\3H\3H\3I") - buf.write("\7I\u01b5\nI\fI\16I\u01b8\13I\3I\3I\3I\3I\3J\3J\7J\u01c0") - buf.write("\nJ\fJ\16J\u01c3\13J\3J\3J\3\u019e\2K\5\3\7\4\t\5\13\6") - buf.write("\r\7\17\b\21\t\23\n\25\13\27\f\31\r\33\16\35\17\37\20") - buf.write("!\21#\22%\23\'\24)\25+\26-\27/\2\61\30\63\31\65\32\67") - buf.write("\339\34;\35=\36?\37A C!E\"G#I$K%M&O\'Q(S)U*W+Y,[-]._\2") - buf.write("a\2c\2e\2g\2i\2k\2m\2o\2q\2s\2u\2w\2y\2{\2}\2\177\2\u0081") - buf.write("\2\u0083\2\u0085\2\u0087/\u0089\60\u008b\61\u008d\62\u008f") - buf.write("\63\u0091\64\u0093\65\u0095\66\5\2\3\4\34\5\2\f\f\17\17") - buf.write("$$\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEe") - buf.write("e\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2") - buf.write("PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4") - buf.write("\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2") - buf.write("\13\f\16\17\"\"\3\2\f\f\2\u01be\2\5\3\2\2\2\2\7\3\2\2") - buf.write("\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2") - buf.write("\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31") - buf.write("\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2") - buf.write("\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3") - buf.write("\2\2\2\2-\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2") - buf.write("\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3") - buf.write("\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I") - buf.write("\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2") - buf.write("S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2") - buf.write("\2]\3\2\2\2\2\u0087\3\2\2\2\2\u0089\3\2\2\2\2\u008b\3") - buf.write("\2\2\2\3\u008d\3\2\2\2\3\u008f\3\2\2\2\4\u0091\3\2\2\2") - buf.write("\4\u0093\3\2\2\2\4\u0095\3\2\2\2\5\u0097\3\2\2\2\7\u009d") - buf.write("\3\2\2\2\t\u00a2\3\2\2\2\13\u00a8\3\2\2\2\r\u00ab\3\2") - buf.write("\2\2\17\u00ae\3\2\2\2\21\u00b1\3\2\2\2\23\u00ba\3\2\2") - buf.write("\2\25\u00c1\3\2\2\2\27\u00c5\3\2\2\2\31\u00ca\3\2\2\2") - buf.write("\33\u00cf\3\2\2\2\35\u00d4\3\2\2\2\37\u00da\3\2\2\2!\u00df") - buf.write("\3\2\2\2#\u00e4\3\2\2\2%\u00e8\3\2\2\2\'\u00eb\3\2\2\2") - buf.write(")\u00ef\3\2\2\2+\u00f6\3\2\2\2-\u00f8\3\2\2\2/\u0103\3") - buf.write("\2\2\2\61\u0105\3\2\2\2\63\u0113\3\2\2\2\65\u0117\3\2") - buf.write("\2\2\67\u011e\3\2\2\29\u0125\3\2\2\2;\u0128\3\2\2\2=\u012b") - buf.write("\3\2\2\2?\u012d\3\2\2\2A\u012f\3\2\2\2C\u0131\3\2\2\2") - buf.write("E\u0133\3\2\2\2G\u0135\3\2\2\2I\u0138\3\2\2\2K\u013a\3") - buf.write("\2\2\2M\u013c\3\2\2\2O\u013e\3\2\2\2Q\u0140\3\2\2\2S\u0142") - buf.write("\3\2\2\2U\u0144\3\2\2\2W\u0146\3\2\2\2Y\u0148\3\2\2\2") - buf.write("[\u014a\3\2\2\2]\u014c\3\2\2\2_\u014e\3\2\2\2a\u0150\3") - buf.write("\2\2\2c\u0152\3\2\2\2e\u0154\3\2\2\2g\u0156\3\2\2\2i\u0158") - buf.write("\3\2\2\2k\u015a\3\2\2\2m\u015c\3\2\2\2o\u015e\3\2\2\2") - buf.write("q\u0160\3\2\2\2s\u0162\3\2\2\2u\u0164\3\2\2\2w\u0166\3") - buf.write("\2\2\2y\u0168\3\2\2\2{\u016a\3\2\2\2}\u016c\3\2\2\2\177") - buf.write("\u016e\3\2\2\2\u0081\u0170\3\2\2\2\u0083\u0175\3\2\2\2") - buf.write("\u0085\u017b\3\2\2\2\u0087\u017e\3\2\2\2\u0089\u0184\3") - buf.write("\2\2\2\u008b\u0192\3\2\2\2\u008d\u01a0\3\2\2\2\u008f\u01a4") - buf.write("\3\2\2\2\u0091\u01ac\3\2\2\2\u0093\u01b6\3\2\2\2\u0095") - buf.write("\u01bd\3\2\2\2\u0097\u0098\5a\60\2\u0098\u0099\5m\66\2") - buf.write("\u0099\u009a\5_/\2\u009a\u009b\5w;\2\u009b\u009c\5w;\2") - buf.write("\u009c\6\3\2\2\2\u009d\u009e\5e\62\2\u009e\u009f\5m\66") - buf.write("\2\u009f\u00a0\5w;\2\u00a0\u00a1\5e\62\2\u00a1\b\3\2\2") - buf.write("\2\u00a2\u00a3\7h\2\2\u00a3\u00a4\5_/\2\u00a4\u00a5\5") - buf.write("m\66\2\u00a5\u00a6\5w;\2\u00a6\u00a7\5e\62\2\u00a7\n\3") - buf.write("\2\2\2\u00a8\u00a9\5g\63\2\u00a9\u00aa\5k\65\2\u00aa\f") - buf.write("\3\2\2\2\u00ab\u00ac\5k\65\2\u00ac\u00ad\5g\63\2\u00ad") - buf.write("\16\3\2\2\2\u00ae\u00af\5k\65\2\u00af\u00b0\5o\67\2\u00b0") - buf.write("\20\3\2\2\2\u00b1\u00b2\5k\65\2\u00b2\u00b3\5o\67\2\u00b3") - buf.write("\u00b4\5i\64\2\u00b4\u00b5\5e\62\2\u00b5\u00b6\5u:\2\u00b6") - buf.write("\u00b7\5k\65\2\u00b7\u00b8\5y<\2\u00b8\u00b9\5w;\2\u00b9") - buf.write("\22\3\2\2\2\u00ba\u00bb\5k\65\2\u00bb\u00bc\5w;\2\u00bc") - buf.write("\u00bd\5}>\2\u00bd\u00be\5q8\2\u00be\u00bf\5k\65\2\u00bf") - buf.write("\u00c0\5c\61\2\u00c0\24\3\2\2\2\u00c1\u00c2\5m\66\2\u00c2") - buf.write("\u00c3\5e\62\2\u00c3\u00c4\5y<\2\u00c4\26\3\2\2\2\u00c5") - buf.write("\u00c6\5m\66\2\u00c6\u00c7\5q8\2\u00c7\u00c8\5q8\2\u00c8") - buf.write("\u00c9\5s9\2\u00c9\30\3\2\2\2\u00ca\u00cb\5s9\2\u00cb") - buf.write("\u00cc\5q8\2\u00cc\u00cd\5q8\2\u00cd\u00ce\5m\66\2\u00ce") - buf.write("\32\3\2\2\2\u00cf\u00d0\5y<\2\u00d0\u00d1\5i\64\2\u00d1") - buf.write("\u00d2\5e\62\2\u00d2\u00d3\5o\67\2\u00d3\34\3\2\2\2\u00d4") - buf.write("\u00d5\5\177?\2\u00d5\u00d6\5i\64\2\u00d6\u00d7\5k\65") - buf.write("\2\u00d7\u00d8\5m\66\2\u00d8\u00d9\5e\62\2\u00d9\36\3") - buf.write("\2\2\2\u00da\u00db\5a\60\2\u00db\u00dc\5_/\2\u00dc\u00dd") - buf.write("\5w;\2\u00dd\u00de\5e\62\2\u00de \3\2\2\2\u00df\u00e0") - buf.write("\5e\62\2\u00e0\u00e1\5w;\2\u00e1\u00e2\5_/\2\u00e2\u00e3") - buf.write("\5a\60\2\u00e3\"\3\2\2\2\u00e4\u00e5\5o\67\2\u00e5\u00e6") - buf.write("\5e\62\2\u00e6\u00e7\5\177?\2\u00e7$\3\2\2\2\u00e8\u00e9") - buf.write("\5q8\2\u00e9\u00ea\5g\63\2\u00ea&\3\2\2\2\u00eb\u00ec") - buf.write("\5o\67\2\u00ec\u00ed\5q8\2\u00ed\u00ee\5y<\2\u00ee(\3") - buf.write("\2\2\2\u00ef\u00f0\7v\2\2\u00f0\u00f1\5u:\2\u00f1\u00f2") - buf.write("\5{=\2\u00f2\u00f3\5e\62\2\u00f3*\3\2\2\2\u00f4\u00f7") - buf.write("\5-\26\2\u00f5\u00f7\5\u0095J\2\u00f6\u00f4\3\2\2\2\u00f6") - buf.write("\u00f5\3\2\2\2\u00f7,\3\2\2\2\u00f8\u00fc\7$\2\2\u00f9") - buf.write("\u00fb\5/\27\2\u00fa\u00f9\3\2\2\2\u00fb\u00fe\3\2\2\2") - buf.write("\u00fc\u00fa\3\2\2\2\u00fc\u00fd\3\2\2\2\u00fd\u00ff\3") - buf.write("\2\2\2\u00fe\u00fc\3\2\2\2\u00ff\u0100\7$\2\2\u0100.\3") - buf.write("\2\2\2\u0101\u0104\5\u0081@\2\u0102\u0104\n\2\2\2\u0103") - buf.write("\u0101\3\2\2\2\u0103\u0102\3\2\2\2\u0104\60\3\2\2\2\u0105") - buf.write("\u0109\7$\2\2\u0106\u0108\5/\27\2\u0107\u0106\3\2\2\2") - buf.write("\u0108\u010b\3\2\2\2\u0109\u0107\3\2\2\2\u0109\u010a\3") - buf.write("\2\2\2\u010a\u010c\3\2\2\2\u010b\u0109\3\2\2\2\u010c\u010d") - buf.write("\7^\2\2\u010d\u010e\7\17\2\2\u010e\u010f\7\f\2\2\u010f") - buf.write("\u0110\3\2\2\2\u0110\u0111\b\30\2\2\u0111\62\3\2\2\2\u0112") - buf.write("\u0114\t\3\2\2\u0113\u0112\3\2\2\2\u0114\u0115\3\2\2\2") - buf.write("\u0115\u0113\3\2\2\2\u0115\u0116\3\2\2\2\u0116\64\3\2") - buf.write("\2\2\u0117\u011b\t\4\2\2\u0118\u011a\t\5\2\2\u0119\u0118") - buf.write("\3\2\2\2\u011a\u011d\3\2\2\2\u011b\u0119\3\2\2\2\u011b") - buf.write("\u011c\3\2\2\2\u011c\66\3\2\2\2\u011d\u011b\3\2\2\2\u011e") - buf.write("\u0122\t\6\2\2\u011f\u0121\t\5\2\2\u0120\u011f\3\2\2\2") - buf.write("\u0121\u0124\3\2\2\2\u0122\u0120\3\2\2\2\u0122\u0123\3") - buf.write("\2\2\2\u01238\3\2\2\2\u0124\u0122\3\2\2\2\u0125\u0126") - buf.write("\7>\2\2\u0126\u0127\7/\2\2\u0127:\3\2\2\2\u0128\u0129") - buf.write("\7?\2\2\u0129\u012a\7@\2\2\u012a<\3\2\2\2\u012b\u012c") - buf.write("\7-\2\2\u012c>\3\2\2\2\u012d\u012e\7/\2\2\u012e@\3\2\2") - buf.write("\2\u012f\u0130\7,\2\2\u0130B\3\2\2\2\u0131\u0132\7\61") - buf.write("\2\2\u0132D\3\2\2\2\u0133\u0134\7>\2\2\u0134F\3\2\2\2") - buf.write("\u0135\u0136\7>\2\2\u0136\u0137\7?\2\2\u0137H\3\2\2\2") - buf.write("\u0138\u0139\7?\2\2\u0139J\3\2\2\2\u013a\u013b\7\u0080") - buf.write("\2\2\u013bL\3\2\2\2\u013c\u013d\7*\2\2\u013dN\3\2\2\2") - buf.write("\u013e\u013f\7+\2\2\u013fP\3\2\2\2\u0140\u0141\7}\2\2") - buf.write("\u0141R\3\2\2\2\u0142\u0143\7\177\2\2\u0143T\3\2\2\2\u0144") - buf.write("\u0145\7B\2\2\u0145V\3\2\2\2\u0146\u0147\7\60\2\2\u0147") - buf.write("X\3\2\2\2\u0148\u0149\7.\2\2\u0149Z\3\2\2\2\u014a\u014b") - buf.write("\7<\2\2\u014b\\\3\2\2\2\u014c\u014d\7=\2\2\u014d^\3\2") - buf.write("\2\2\u014e\u014f\t\7\2\2\u014f`\3\2\2\2\u0150\u0151\t") - buf.write("\b\2\2\u0151b\3\2\2\2\u0152\u0153\t\t\2\2\u0153d\3\2\2") - buf.write("\2\u0154\u0155\t\n\2\2\u0155f\3\2\2\2\u0156\u0157\t\13") - buf.write("\2\2\u0157h\3\2\2\2\u0158\u0159\t\f\2\2\u0159j\3\2\2\2") - buf.write("\u015a\u015b\t\r\2\2\u015bl\3\2\2\2\u015c\u015d\t\16\2") - buf.write("\2\u015dn\3\2\2\2\u015e\u015f\t\17\2\2\u015fp\3\2\2\2") - buf.write("\u0160\u0161\t\20\2\2\u0161r\3\2\2\2\u0162\u0163\t\21") - buf.write("\2\2\u0163t\3\2\2\2\u0164\u0165\t\22\2\2\u0165v\3\2\2") - buf.write("\2\u0166\u0167\t\23\2\2\u0167x\3\2\2\2\u0168\u0169\t\24") - buf.write("\2\2\u0169z\3\2\2\2\u016a\u016b\t\25\2\2\u016b|\3\2\2") - buf.write("\2\u016c\u016d\t\26\2\2\u016d~\3\2\2\2\u016e\u016f\t\27") - buf.write("\2\2\u016f\u0080\3\2\2\2\u0170\u0173\7^\2\2\u0171\u0174") - buf.write("\t\30\2\2\u0172\u0174\5\u0083A\2\u0173\u0171\3\2\2\2\u0173") - buf.write("\u0172\3\2\2\2\u0174\u0082\3\2\2\2\u0175\u0176\7w\2\2") - buf.write("\u0176\u0177\5\u0085B\2\u0177\u0178\5\u0085B\2\u0178\u0179") - buf.write("\5\u0085B\2\u0179\u017a\5\u0085B\2\u017a\u0084\3\2\2\2") - buf.write("\u017b\u017c\t\31\2\2\u017c\u0086\3\2\2\2\u017d\u017f") - buf.write("\t\32\2\2\u017e\u017d\3\2\2\2\u017f\u0180\3\2\2\2\u0180") - buf.write("\u017e\3\2\2\2\u0180\u0181\3\2\2\2\u0181\u0182\3\2\2\2") - buf.write("\u0182\u0183\bC\3\2\u0183\u0088\3\2\2\2\u0184\u0185\7") - buf.write("/\2\2\u0185\u0186\7/\2\2\u0186\u018a\3\2\2\2\u0187\u0189") - buf.write("\n\33\2\2\u0188\u0187\3\2\2\2\u0189\u018c\3\2\2\2\u018a") - buf.write("\u0188\3\2\2\2\u018a\u018b\3\2\2\2\u018b\u018e\3\2\2\2") - buf.write("\u018c\u018a\3\2\2\2\u018d\u018f\7\f\2\2\u018e\u018d\3") - buf.write("\2\2\2\u018e\u018f\3\2\2\2\u018f\u0190\3\2\2\2\u0190\u0191") - buf.write("\bD\3\2\u0191\u008a\3\2\2\2\u0192\u0193\7*\2\2\u0193\u0194") - buf.write("\7,\2\2\u0194\u0195\3\2\2\2\u0195\u0196\bE\4\2\u0196\u008c") - buf.write("\3\2\2\2\u0197\u0198\5\u008bE\2\u0198\u0199\5\u008dF\2") - buf.write("\u0199\u019a\5\u008fG\2\u019a\u01a1\3\2\2\2\u019b\u019d") - buf.write("\13\2\2\2\u019c\u019b\3\2\2\2\u019d\u019e\3\2\2\2\u019e") - buf.write("\u019f\3\2\2\2\u019e\u019c\3\2\2\2\u019f\u01a1\3\2\2\2") - buf.write("\u01a0\u0197\3\2\2\2\u01a0\u019c\3\2\2\2\u01a1\u01a2\3") - buf.write("\2\2\2\u01a2\u01a3\bF\3\2\u01a3\u008e\3\2\2\2\u01a4\u01a5") - buf.write("\7,\2\2\u01a5\u01a6\7+\2\2\u01a6\u01a7\3\2\2\2\u01a7\u01a8") - buf.write("\bG\5\2\u01a8\u0090\3\2\2\2\u01a9\u01ab\5/\27\2\u01aa") - buf.write("\u01a9\3\2\2\2\u01ab\u01ae\3\2\2\2\u01ac\u01aa\3\2\2\2") - buf.write("\u01ac\u01ad\3\2\2\2\u01ad\u01af\3\2\2\2\u01ae\u01ac\3") - buf.write("\2\2\2\u01af\u01b0\7^\2\2\u01b0\u01b1\7\17\2\2\u01b1\u01b2") - buf.write("\7\f\2\2\u01b2\u0092\3\2\2\2\u01b3\u01b5\5/\27\2\u01b4") - buf.write("\u01b3\3\2\2\2\u01b5\u01b8\3\2\2\2\u01b6\u01b4\3\2\2\2") - buf.write("\u01b6\u01b7\3\2\2\2\u01b7\u01b9\3\2\2\2\u01b8\u01b6\3") - buf.write("\2\2\2\u01b9\u01ba\7$\2\2\u01ba\u01bb\3\2\2\2\u01bb\u01bc") - buf.write("\bI\5\2\u01bc\u0094\3\2\2\2\u01bd\u01c1\5\61\30\2\u01be") - buf.write("\u01c0\5\u0091H\2\u01bf\u01be\3\2\2\2\u01c0\u01c3\3\2") - buf.write("\2\2\u01c1\u01bf\3\2\2\2\u01c1\u01c2\3\2\2\2\u01c2\u01c4") - buf.write("\3\2\2\2\u01c3\u01c1\3\2\2\2\u01c4\u01c5\5\u0093I\2\u01c5") - buf.write("\u0096\3\2\2\2\25\2\3\4\u00f6\u00fc\u0103\u0109\u0115") - buf.write("\u011b\u0122\u0173\u0180\u018a\u018e\u019e\u01a0\u01ac") - buf.write("\u01b6\u01c1\6\7\4\2\b\2\2\7\3\2\6\2\2") + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\29") + buf.write("\u01d7\b\1\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5") + buf.write("\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f") + buf.write("\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4") + buf.write("\22\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27") + buf.write("\t\27\4\30\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34") + buf.write("\4\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#") + buf.write("\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+") + buf.write("\4,\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62") + buf.write("\4\63\t\63\4\64\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48") + buf.write("\t8\49\t9\4:\t:\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4") + buf.write("A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I\tI\4") + buf.write("J\tJ\4K\tK\4L\tL\4M\tM\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3") + buf.write("\3\3\3\3\3\3\3\4\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\6\3") + buf.write("\6\3\6\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b") + buf.write("\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\13\3\13") + buf.write("\3\13\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3") + buf.write("\r\3\16\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3") + buf.write("\17\3\20\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\22") + buf.write("\3\22\3\22\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24") + buf.write("\3\25\3\25\5\25\u00fe\n\25\3\26\3\26\7\26\u0102\n\26\f") + buf.write("\26\16\26\u0105\13\26\3\26\3\26\3\27\3\27\3\27\3\27\3") + buf.write("\30\3\30\5\30\u010f\n\30\3\31\3\31\7\31\u0113\n\31\f\31") + buf.write("\16\31\u0116\13\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32") + buf.write("\6\32\u011f\n\32\r\32\16\32\u0120\3\33\3\33\7\33\u0125") + buf.write("\n\33\f\33\16\33\u0128\13\33\3\34\3\34\7\34\u012c\n\34") + buf.write("\f\34\16\34\u012f\13\34\3\35\3\35\3\35\3\36\3\36\3\36") + buf.write("\3\37\3\37\3 \3 \3!\3!\3\"\3\"\3#\3#\3$\3$\3$\3%\3%\3") + buf.write("&\3&\3\'\3\'\3(\3(\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3") + buf.write(".\3/\3/\3\60\3\60\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3") + buf.write("\64\3\65\3\65\3\66\3\66\3\67\3\67\38\38\39\39\3:\3:\3") + buf.write(";\3;\3<\3<\3=\3=\3>\3>\3?\3?\3@\3@\3A\3A\3A\5A\u017f\n") + buf.write("A\3B\3B\3B\3B\3B\3B\3C\3C\3D\6D\u018a\nD\rD\16D\u018b") + buf.write("\3D\3D\3E\3E\3E\3E\7E\u0194\nE\fE\16E\u0197\13E\3E\5E") + buf.write("\u019a\nE\3E\3E\3F\3F\3F\3F\3F\3G\3G\3G\3G\3G\6G\u01a8") + buf.write("\nG\rG\16G\u01a9\5G\u01ac\nG\3G\3G\3H\3H\3H\3H\3H\3I\7") + buf.write("I\u01b6\nI\fI\16I\u01b9\13I\3I\3I\3I\3I\3J\7J\u01c0\n") + buf.write("J\fJ\16J\u01c3\13J\3J\3J\3J\3J\3K\3K\7K\u01cb\nK\fK\16") + buf.write("K\u01ce\13K\3K\3K\3L\3L\3M\3M\3M\3M\3\u01a9\2N\6\3\b\4") + buf.write("\n\5\f\6\16\7\20\b\22\t\24\n\26\13\30\f\32\r\34\16\36") + buf.write("\17 \20\"\21$\22&\23(\24*\25,\26.\27\60\30\62\2\64\31") + buf.write("\66\328\33:\34<\35>\36@\37B D!F\"H#J$L%N&P\'R(T)V*X+Z") + buf.write(",\\-^.`/b\2d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2|\2~\2") + buf.write("\u0080\2\u0082\2\u0084\2\u0086\2\u0088\2\u008a\60\u008c") + buf.write("\61\u008e\62\u0090\63\u0092\64\u0094\65\u0096\66\u0098") + buf.write("\67\u009a8\u009c9\6\2\3\4\5\34\6\2\2\2\f\f\17\17$$\3\2") + buf.write("\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEee\4\2F") + buf.write("Fff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2PPpp\4") + buf.write("\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4\2XXx") + buf.write("x\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2\13\f") + buf.write("\16\17\"\"\3\2\f\f\2\u01ce\2\6\3\2\2\2\2\b\3\2\2\2\2\n") + buf.write("\3\2\2\2\2\f\3\2\2\2\2\16\3\2\2\2\2\20\3\2\2\2\2\22\3") + buf.write("\2\2\2\2\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32\3\2") + buf.write("\2\2\2\34\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2\2\2") + buf.write("\2$\3\2\2\2\2&\3\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3\2\2") + buf.write("\2\2.\3\2\2\2\2\60\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\2") + buf.write("8\3\2\2\2\2:\3\2\2\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2\2\2") + buf.write("\2B\3\2\2\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3\2\2") + buf.write("\2\2L\3\2\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2") + buf.write("\2\2\2V\3\2\2\2\2X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2\2^\3") + buf.write("\2\2\2\2`\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2\2\u008e") + buf.write("\3\2\2\2\3\u0090\3\2\2\2\3\u0092\3\2\2\2\4\u0094\3\2\2") + buf.write("\2\4\u0096\3\2\2\2\4\u0098\3\2\2\2\5\u009a\3\2\2\2\5\u009c") + buf.write("\3\2\2\2\6\u009e\3\2\2\2\b\u00a4\3\2\2\2\n\u00a9\3\2\2") + buf.write("\2\f\u00af\3\2\2\2\16\u00b2\3\2\2\2\20\u00b5\3\2\2\2\22") + buf.write("\u00b8\3\2\2\2\24\u00c1\3\2\2\2\26\u00c8\3\2\2\2\30\u00cc") + buf.write("\3\2\2\2\32\u00d1\3\2\2\2\34\u00d6\3\2\2\2\36\u00db\3") + buf.write("\2\2\2 \u00e1\3\2\2\2\"\u00e6\3\2\2\2$\u00eb\3\2\2\2&") + buf.write("\u00ef\3\2\2\2(\u00f2\3\2\2\2*\u00f6\3\2\2\2,\u00fd\3") + buf.write("\2\2\2.\u00ff\3\2\2\2\60\u0108\3\2\2\2\62\u010e\3\2\2") + buf.write("\2\64\u0110\3\2\2\2\66\u011e\3\2\2\28\u0122\3\2\2\2:\u0129") + buf.write("\3\2\2\2<\u0130\3\2\2\2>\u0133\3\2\2\2@\u0136\3\2\2\2") + buf.write("B\u0138\3\2\2\2D\u013a\3\2\2\2F\u013c\3\2\2\2H\u013e\3") + buf.write("\2\2\2J\u0140\3\2\2\2L\u0143\3\2\2\2N\u0145\3\2\2\2P\u0147") + buf.write("\3\2\2\2R\u0149\3\2\2\2T\u014b\3\2\2\2V\u014d\3\2\2\2") + buf.write("X\u014f\3\2\2\2Z\u0151\3\2\2\2\\\u0153\3\2\2\2^\u0155") + buf.write("\3\2\2\2`\u0157\3\2\2\2b\u0159\3\2\2\2d\u015b\3\2\2\2") + buf.write("f\u015d\3\2\2\2h\u015f\3\2\2\2j\u0161\3\2\2\2l\u0163\3") + buf.write("\2\2\2n\u0165\3\2\2\2p\u0167\3\2\2\2r\u0169\3\2\2\2t\u016b") + buf.write("\3\2\2\2v\u016d\3\2\2\2x\u016f\3\2\2\2z\u0171\3\2\2\2") + buf.write("|\u0173\3\2\2\2~\u0175\3\2\2\2\u0080\u0177\3\2\2\2\u0082") + buf.write("\u0179\3\2\2\2\u0084\u017b\3\2\2\2\u0086\u0180\3\2\2\2") + buf.write("\u0088\u0186\3\2\2\2\u008a\u0189\3\2\2\2\u008c\u018f\3") + buf.write("\2\2\2\u008e\u019d\3\2\2\2\u0090\u01ab\3\2\2\2\u0092\u01af") + buf.write("\3\2\2\2\u0094\u01b7\3\2\2\2\u0096\u01c1\3\2\2\2\u0098") + buf.write("\u01c8\3\2\2\2\u009a\u01d1\3\2\2\2\u009c\u01d3\3\2\2\2") + buf.write("\u009e\u009f\5d\61\2\u009f\u00a0\5p\67\2\u00a0\u00a1\5") + buf.write("b\60\2\u00a1\u00a2\5z<\2\u00a2\u00a3\5z<\2\u00a3\7\3\2") + buf.write("\2\2\u00a4\u00a5\5h\63\2\u00a5\u00a6\5p\67\2\u00a6\u00a7") + buf.write("\5z<\2\u00a7\u00a8\5h\63\2\u00a8\t\3\2\2\2\u00a9\u00aa") + buf.write("\7h\2\2\u00aa\u00ab\5b\60\2\u00ab\u00ac\5p\67\2\u00ac") + buf.write("\u00ad\5z<\2\u00ad\u00ae\5h\63\2\u00ae\13\3\2\2\2\u00af") + buf.write("\u00b0\5j\64\2\u00b0\u00b1\5n\66\2\u00b1\r\3\2\2\2\u00b2") + buf.write("\u00b3\5n\66\2\u00b3\u00b4\5j\64\2\u00b4\17\3\2\2\2\u00b5") + buf.write("\u00b6\5n\66\2\u00b6\u00b7\5r8\2\u00b7\21\3\2\2\2\u00b8") + buf.write("\u00b9\5n\66\2\u00b9\u00ba\5r8\2\u00ba\u00bb\5l\65\2\u00bb") + buf.write("\u00bc\5h\63\2\u00bc\u00bd\5x;\2\u00bd\u00be\5n\66\2\u00be") + buf.write("\u00bf\5|=\2\u00bf\u00c0\5z<\2\u00c0\23\3\2\2\2\u00c1") + buf.write("\u00c2\5n\66\2\u00c2\u00c3\5z<\2\u00c3\u00c4\5\u0080?") + buf.write("\2\u00c4\u00c5\5t9\2\u00c5\u00c6\5n\66\2\u00c6\u00c7\5") + buf.write("f\62\2\u00c7\25\3\2\2\2\u00c8\u00c9\5p\67\2\u00c9\u00ca") + buf.write("\5h\63\2\u00ca\u00cb\5|=\2\u00cb\27\3\2\2\2\u00cc\u00cd") + buf.write("\5p\67\2\u00cd\u00ce\5t9\2\u00ce\u00cf\5t9\2\u00cf\u00d0") + buf.write("\5v:\2\u00d0\31\3\2\2\2\u00d1\u00d2\5v:\2\u00d2\u00d3") + buf.write("\5t9\2\u00d3\u00d4\5t9\2\u00d4\u00d5\5p\67\2\u00d5\33") + buf.write("\3\2\2\2\u00d6\u00d7\5|=\2\u00d7\u00d8\5l\65\2\u00d8\u00d9") + buf.write("\5h\63\2\u00d9\u00da\5r8\2\u00da\35\3\2\2\2\u00db\u00dc") + buf.write("\5\u0082@\2\u00dc\u00dd\5l\65\2\u00dd\u00de\5n\66\2\u00de") + buf.write("\u00df\5p\67\2\u00df\u00e0\5h\63\2\u00e0\37\3\2\2\2\u00e1") + buf.write("\u00e2\5d\61\2\u00e2\u00e3\5b\60\2\u00e3\u00e4\5z<\2\u00e4") + buf.write("\u00e5\5h\63\2\u00e5!\3\2\2\2\u00e6\u00e7\5h\63\2\u00e7") + buf.write("\u00e8\5z<\2\u00e8\u00e9\5b\60\2\u00e9\u00ea\5d\61\2\u00ea") + buf.write("#\3\2\2\2\u00eb\u00ec\5r8\2\u00ec\u00ed\5h\63\2\u00ed") + buf.write("\u00ee\5\u0082@\2\u00ee%\3\2\2\2\u00ef\u00f0\5t9\2\u00f0") + buf.write("\u00f1\5j\64\2\u00f1\'\3\2\2\2\u00f2\u00f3\5r8\2\u00f3") + buf.write("\u00f4\5t9\2\u00f4\u00f5\5|=\2\u00f5)\3\2\2\2\u00f6\u00f7") + buf.write("\7v\2\2\u00f7\u00f8\5x;\2\u00f8\u00f9\5~>\2\u00f9\u00fa") + buf.write("\5h\63\2\u00fa+\3\2\2\2\u00fb\u00fe\5.\26\2\u00fc\u00fe") + buf.write("\5\u0098K\2\u00fd\u00fb\3\2\2\2\u00fd\u00fc\3\2\2\2\u00fe") + buf.write("-\3\2\2\2\u00ff\u0103\5\60\27\2\u0100\u0102\5\u009aL\2") + buf.write("\u0101\u0100\3\2\2\2\u0102\u0105\3\2\2\2\u0103\u0101\3") + buf.write("\2\2\2\u0103\u0104\3\2\2\2\u0104\u0106\3\2\2\2\u0105\u0103") + buf.write("\3\2\2\2\u0106\u0107\5\u009cM\2\u0107/\3\2\2\2\u0108\u0109") + buf.write("\7$\2\2\u0109\u010a\3\2\2\2\u010a\u010b\b\27\2\2\u010b") + buf.write("\61\3\2\2\2\u010c\u010f\5\u0084A\2\u010d\u010f\n\2\2\2") + buf.write("\u010e\u010c\3\2\2\2\u010e\u010d\3\2\2\2\u010f\63\3\2") + buf.write("\2\2\u0110\u0114\7$\2\2\u0111\u0113\5\62\30\2\u0112\u0111") + buf.write("\3\2\2\2\u0113\u0116\3\2\2\2\u0114\u0112\3\2\2\2\u0114") + buf.write("\u0115\3\2\2\2\u0115\u0117\3\2\2\2\u0116\u0114\3\2\2\2") + buf.write("\u0117\u0118\7^\2\2\u0118\u0119\7\17\2\2\u0119\u011a\7") + buf.write("\f\2\2\u011a\u011b\3\2\2\2\u011b\u011c\b\31\3\2\u011c") + buf.write("\65\3\2\2\2\u011d\u011f\t\3\2\2\u011e\u011d\3\2\2\2\u011f") + buf.write("\u0120\3\2\2\2\u0120\u011e\3\2\2\2\u0120\u0121\3\2\2\2") + buf.write("\u0121\67\3\2\2\2\u0122\u0126\t\4\2\2\u0123\u0125\t\5") + buf.write("\2\2\u0124\u0123\3\2\2\2\u0125\u0128\3\2\2\2\u0126\u0124") + buf.write("\3\2\2\2\u0126\u0127\3\2\2\2\u01279\3\2\2\2\u0128\u0126") + buf.write("\3\2\2\2\u0129\u012d\t\6\2\2\u012a\u012c\t\5\2\2\u012b") + buf.write("\u012a\3\2\2\2\u012c\u012f\3\2\2\2\u012d\u012b\3\2\2\2") + buf.write("\u012d\u012e\3\2\2\2\u012e;\3\2\2\2\u012f\u012d\3\2\2") + buf.write("\2\u0130\u0131\7>\2\2\u0131\u0132\7/\2\2\u0132=\3\2\2") + buf.write("\2\u0133\u0134\7?\2\2\u0134\u0135\7@\2\2\u0135?\3\2\2") + buf.write("\2\u0136\u0137\7-\2\2\u0137A\3\2\2\2\u0138\u0139\7/\2") + buf.write("\2\u0139C\3\2\2\2\u013a\u013b\7,\2\2\u013bE\3\2\2\2\u013c") + buf.write("\u013d\7\61\2\2\u013dG\3\2\2\2\u013e\u013f\7>\2\2\u013f") + buf.write("I\3\2\2\2\u0140\u0141\7>\2\2\u0141\u0142\7?\2\2\u0142") + buf.write("K\3\2\2\2\u0143\u0144\7?\2\2\u0144M\3\2\2\2\u0145\u0146") + buf.write("\7\u0080\2\2\u0146O\3\2\2\2\u0147\u0148\7*\2\2\u0148Q") + buf.write("\3\2\2\2\u0149\u014a\7+\2\2\u014aS\3\2\2\2\u014b\u014c") + buf.write("\7}\2\2\u014cU\3\2\2\2\u014d\u014e\7\177\2\2\u014eW\3") + buf.write("\2\2\2\u014f\u0150\7B\2\2\u0150Y\3\2\2\2\u0151\u0152\7") + buf.write("\60\2\2\u0152[\3\2\2\2\u0153\u0154\7.\2\2\u0154]\3\2\2") + buf.write("\2\u0155\u0156\7<\2\2\u0156_\3\2\2\2\u0157\u0158\7=\2") + buf.write("\2\u0158a\3\2\2\2\u0159\u015a\t\7\2\2\u015ac\3\2\2\2\u015b") + buf.write("\u015c\t\b\2\2\u015ce\3\2\2\2\u015d\u015e\t\t\2\2\u015e") + buf.write("g\3\2\2\2\u015f\u0160\t\n\2\2\u0160i\3\2\2\2\u0161\u0162") + buf.write("\t\13\2\2\u0162k\3\2\2\2\u0163\u0164\t\f\2\2\u0164m\3") + buf.write("\2\2\2\u0165\u0166\t\r\2\2\u0166o\3\2\2\2\u0167\u0168") + buf.write("\t\16\2\2\u0168q\3\2\2\2\u0169\u016a\t\17\2\2\u016as\3") + buf.write("\2\2\2\u016b\u016c\t\20\2\2\u016cu\3\2\2\2\u016d\u016e") + buf.write("\t\21\2\2\u016ew\3\2\2\2\u016f\u0170\t\22\2\2\u0170y\3") + buf.write("\2\2\2\u0171\u0172\t\23\2\2\u0172{\3\2\2\2\u0173\u0174") + buf.write("\t\24\2\2\u0174}\3\2\2\2\u0175\u0176\t\25\2\2\u0176\177") + buf.write("\3\2\2\2\u0177\u0178\t\26\2\2\u0178\u0081\3\2\2\2\u0179") + buf.write("\u017a\t\27\2\2\u017a\u0083\3\2\2\2\u017b\u017e\7^\2\2") + buf.write("\u017c\u017f\t\30\2\2\u017d\u017f\5\u0086B\2\u017e\u017c") + buf.write("\3\2\2\2\u017e\u017d\3\2\2\2\u017f\u0085\3\2\2\2\u0180") + buf.write("\u0181\7w\2\2\u0181\u0182\5\u0088C\2\u0182\u0183\5\u0088") + buf.write("C\2\u0183\u0184\5\u0088C\2\u0184\u0185\5\u0088C\2\u0185") + buf.write("\u0087\3\2\2\2\u0186\u0187\t\31\2\2\u0187\u0089\3\2\2") + buf.write("\2\u0188\u018a\t\32\2\2\u0189\u0188\3\2\2\2\u018a\u018b") + buf.write("\3\2\2\2\u018b\u0189\3\2\2\2\u018b\u018c\3\2\2\2\u018c") + buf.write("\u018d\3\2\2\2\u018d\u018e\bD\4\2\u018e\u008b\3\2\2\2") + buf.write("\u018f\u0190\7/\2\2\u0190\u0191\7/\2\2\u0191\u0195\3\2") + buf.write("\2\2\u0192\u0194\n\33\2\2\u0193\u0192\3\2\2\2\u0194\u0197") + buf.write("\3\2\2\2\u0195\u0193\3\2\2\2\u0195\u0196\3\2\2\2\u0196") + buf.write("\u0199\3\2\2\2\u0197\u0195\3\2\2\2\u0198\u019a\7\f\2\2") + buf.write("\u0199\u0198\3\2\2\2\u0199\u019a\3\2\2\2\u019a\u019b\3") + buf.write("\2\2\2\u019b\u019c\bE\4\2\u019c\u008d\3\2\2\2\u019d\u019e") + buf.write("\7*\2\2\u019e\u019f\7,\2\2\u019f\u01a0\3\2\2\2\u01a0\u01a1") + buf.write("\bF\5\2\u01a1\u008f\3\2\2\2\u01a2\u01a3\5\u008eF\2\u01a3") + buf.write("\u01a4\5\u0090G\2\u01a4\u01a5\5\u0092H\2\u01a5\u01ac\3") + buf.write("\2\2\2\u01a6\u01a8\13\2\2\2\u01a7\u01a6\3\2\2\2\u01a8") + buf.write("\u01a9\3\2\2\2\u01a9\u01aa\3\2\2\2\u01a9\u01a7\3\2\2\2") + buf.write("\u01aa\u01ac\3\2\2\2\u01ab\u01a2\3\2\2\2\u01ab\u01a7\3") + buf.write("\2\2\2\u01ac\u01ad\3\2\2\2\u01ad\u01ae\bG\4\2\u01ae\u0091") + buf.write("\3\2\2\2\u01af\u01b0\7,\2\2\u01b0\u01b1\7+\2\2\u01b1\u01b2") + buf.write("\3\2\2\2\u01b2\u01b3\bH\6\2\u01b3\u0093\3\2\2\2\u01b4") + buf.write("\u01b6\5\62\30\2\u01b5\u01b4\3\2\2\2\u01b6\u01b9\3\2\2") + buf.write("\2\u01b7\u01b5\3\2\2\2\u01b7\u01b8\3\2\2\2\u01b8\u01ba") + buf.write("\3\2\2\2\u01b9\u01b7\3\2\2\2\u01ba\u01bb\7^\2\2\u01bb") + buf.write("\u01bc\7\17\2\2\u01bc\u01bd\7\f\2\2\u01bd\u0095\3\2\2") + buf.write("\2\u01be\u01c0\5\62\30\2\u01bf\u01be\3\2\2\2\u01c0\u01c3") + buf.write("\3\2\2\2\u01c1\u01bf\3\2\2\2\u01c1\u01c2\3\2\2\2\u01c2") + buf.write("\u01c4\3\2\2\2\u01c3\u01c1\3\2\2\2\u01c4\u01c5\7$\2\2") + buf.write("\u01c5\u01c6\3\2\2\2\u01c6\u01c7\bJ\6\2\u01c7\u0097\3") + buf.write("\2\2\2\u01c8\u01cc\5\64\31\2\u01c9\u01cb\5\u0094I\2\u01ca") + buf.write("\u01c9\3\2\2\2\u01cb\u01ce\3\2\2\2\u01cc\u01ca\3\2\2\2") + buf.write("\u01cc\u01cd\3\2\2\2\u01cd\u01cf\3\2\2\2\u01ce\u01cc\3") + buf.write("\2\2\2\u01cf\u01d0\5\u0096J\2\u01d0\u0099\3\2\2\2\u01d1") + buf.write("\u01d2\5\62\30\2\u01d2\u009b\3\2\2\2\u01d3\u01d4\7$\2") + buf.write("\2\u01d4\u01d5\3\2\2\2\u01d5\u01d6\bM\6\2\u01d6\u009d") + buf.write("\3\2\2\2\26\2\3\4\5\u00fd\u0103\u010e\u0114\u0120\u0126") + buf.write("\u012d\u017e\u018b\u0195\u0199\u01a9\u01ab\u01b7\u01c1") + buf.write("\u01cc\7\7\5\2\7\4\2\b\2\2\7\3\2\6\2\2") return buf.getvalue() @@ -215,6 +223,7 @@ class COOL_LEX(Lexer): MULTILINE_COMMENT = 1 MULTILINE_STR = 2 + SIMPLE_STR = 3 CLASS = 1 ELSE = 2 @@ -237,41 +246,45 @@ class COOL_LEX(Lexer): TRUE = 19 STRING = 20 STRING_SIMPLE = 21 - STRING_FIRSTLINE = 22 - INT = 23 - TYPEID = 24 - OBJECTID = 25 - ASSIGNMENT = 26 - CASE_ARROW = 27 - ADD = 28 - MINUS = 29 - MULTIPLY = 30 - DIVISION = 31 - LESS_THAN = 32 - LESS_EQUAL = 33 - EQUAL = 34 - INTEGER_NEGATIVE = 35 - OPEN_ROUND = 36 - CLOSE_ROUND = 37 - OPEN_CURLY = 38 - CLOSE_CURLY = 39 - AT = 40 - DOT = 41 - COMMA = 42 - COLON = 43 - SEMICOLON = 44 - WHITESPACE = 45 - ONE_LINE_COMMENT = 46 - OPEN_COMMENT = 47 - COMMENT = 48 - CLOSE_COMMENT = 49 - STRING_INNERLINE = 50 - STRING_LASTLINE = 51 - STRING_MULTILINE = 52 + STRING_SIMPLE_START = 22 + STRING_FIRSTLINE = 23 + INT = 24 + TYPEID = 25 + OBJECTID = 26 + ASSIGNMENT = 27 + CASE_ARROW = 28 + ADD = 29 + MINUS = 30 + MULTIPLY = 31 + DIVISION = 32 + LESS_THAN = 33 + LESS_EQUAL = 34 + EQUAL = 35 + INTEGER_NEGATIVE = 36 + OPEN_ROUND = 37 + CLOSE_ROUND = 38 + OPEN_CURLY = 39 + CLOSE_CURLY = 40 + AT = 41 + DOT = 42 + COMMA = 43 + COLON = 44 + SEMICOLON = 45 + WHITESPACE = 46 + ONE_LINE_COMMENT = 47 + OPEN_COMMENT = 48 + COMMENT = 49 + CLOSE_COMMENT = 50 + STRING_INNERLINE = 51 + STRING_LASTLINE = 52 + STRING_MULTILINE = 53 + STRING_SIMPLE_CONTENT = 54 + STRING_SIMPLE_STOP = 55 channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] - modeNames = [ "DEFAULT_MODE", "MULTILINE_COMMENT", "MULTILINE_STR" ] + modeNames = [ "DEFAULT_MODE", "MULTILINE_COMMENT", "MULTILINE_STR", + "SIMPLE_STR" ] literalNames = [ "", "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", "'<='", "'='", @@ -281,27 +294,28 @@ class COOL_LEX(Lexer): symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", - "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", "STRING_FIRSTLINE", - "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", - "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", - "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", - "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", - "ONE_LINE_COMMENT", "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT", - "STRING_INNERLINE", "STRING_LASTLINE", "STRING_MULTILINE" ] + "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", "STRING_SIMPLE_START", + "STRING_FIRSTLINE", "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", + "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", + "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", + "OPEN_CURLY", "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", + "SEMICOLON", "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", + "COMMENT", "CLOSE_COMMENT", "STRING_INNERLINE", "STRING_LASTLINE", + "STRING_MULTILINE", "STRING_SIMPLE_CONTENT", "STRING_SIMPLE_STOP" ] ruleNames = [ "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", - "STRING_CONTENT", "STRING_FIRSTLINE", "INT", "TYPEID", - "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", - "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", - "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", - "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", "SEMICOLON", - "A", "C", "D", "E", "F", "H", "I", "L", "N", "O", "P", - "R", "S", "T", "U", "V", "W", "ESC", "UNICODE", "HEX", - "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", "COMMENT", - "CLOSE_COMMENT", "STRING_INNERLINE", "STRING_LASTLINE", - "STRING_MULTILINE" ] + "STRING_SIMPLE_START", "STRING_CONTENT", "STRING_FIRSTLINE", + "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", + "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", + "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", + "OPEN_CURLY", "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", + "SEMICOLON", "A", "C", "D", "E", "F", "H", "I", "L", "N", + "O", "P", "R", "S", "T", "U", "V", "W", "ESC", "UNICODE", + "HEX", "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", + "COMMENT", "CLOSE_COMMENT", "STRING_INNERLINE", "STRING_LASTLINE", + "STRING_MULTILINE", "STRING_SIMPLE_CONTENT", "STRING_SIMPLE_STOP" ] grammarFileName = "COOL_LEX.g4" diff --git a/src/COOL_LEX.tokens b/src/COOL_LEX.tokens index de4efcf0..c7eacfe4 100644 --- a/src/COOL_LEX.tokens +++ b/src/COOL_LEX.tokens @@ -19,55 +19,58 @@ NOT=18 TRUE=19 STRING=20 STRING_SIMPLE=21 -STRING_FIRSTLINE=22 -INT=23 -TYPEID=24 -OBJECTID=25 -ASSIGNMENT=26 -CASE_ARROW=27 -ADD=28 -MINUS=29 -MULTIPLY=30 -DIVISION=31 -LESS_THAN=32 -LESS_EQUAL=33 -EQUAL=34 -INTEGER_NEGATIVE=35 -OPEN_ROUND=36 -CLOSE_ROUND=37 -OPEN_CURLY=38 -CLOSE_CURLY=39 -AT=40 -DOT=41 -COMMA=42 -COLON=43 -SEMICOLON=44 -WHITESPACE=45 -ONE_LINE_COMMENT=46 -OPEN_COMMENT=47 -COMMENT=48 -CLOSE_COMMENT=49 -STRING_INNERLINE=50 -STRING_LASTLINE=51 -STRING_MULTILINE=52 -'<-'=26 -'=>'=27 -'+'=28 -'-'=29 -'*'=30 -'/'=31 -'<'=32 -'<='=33 -'='=34 -'~'=35 -'('=36 -')'=37 -'{'=38 -'}'=39 -'@'=40 -'.'=41 -','=42 -':'=43 -';'=44 -'(*'=47 -'*)'=49 +STRING_SIMPLE_START=22 +STRING_FIRSTLINE=23 +INT=24 +TYPEID=25 +OBJECTID=26 +ASSIGNMENT=27 +CASE_ARROW=28 +ADD=29 +MINUS=30 +MULTIPLY=31 +DIVISION=32 +LESS_THAN=33 +LESS_EQUAL=34 +EQUAL=35 +INTEGER_NEGATIVE=36 +OPEN_ROUND=37 +CLOSE_ROUND=38 +OPEN_CURLY=39 +CLOSE_CURLY=40 +AT=41 +DOT=42 +COMMA=43 +COLON=44 +SEMICOLON=45 +WHITESPACE=46 +ONE_LINE_COMMENT=47 +OPEN_COMMENT=48 +COMMENT=49 +CLOSE_COMMENT=50 +STRING_INNERLINE=51 +STRING_LASTLINE=52 +STRING_MULTILINE=53 +STRING_SIMPLE_CONTENT=54 +STRING_SIMPLE_STOP=55 +'<-'=27 +'=>'=28 +'+'=29 +'-'=30 +'*'=31 +'/'=32 +'<'=33 +'<='=34 +'='=35 +'~'=36 +'('=37 +')'=38 +'{'=39 +'}'=40 +'@'=41 +'.'=42 +','=43 +':'=44 +';'=45 +'(*'=48 +'*)'=50 diff --git a/tests/lexer/test1_error.txt b/tests/lexer/test1_error.txt index 5145209d..05df8e6c 100644 --- a/tests/lexer/test1_error.txt +++ b/tests/lexer/test1_error.txt @@ -1,3 +1,3 @@ -(3, 4) - LexicographicError: Unterminated string constant -(4, 2) - LexicographicError: Unterminated string constant -(7, 4) - LexicographicError: Unterminated string constant \ No newline at end of file +(2, 27) - LexicographicError: Unterminated string constant +(3, 27) - LexicographicError: Unterminated string constant +(6, 51) - LexicographicError: Unterminated string constant \ No newline at end of file From 440f719f06d4dc1be2c6662a664192164cee077d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 16 Mar 2020 12:55:06 -0400 Subject: [PATCH 12/77] =?UTF-8?q?Se=20arregl=C3=B3=20un=20bug=20del=20lexe?= =?UTF-8?q?r=20relativo=20a=20las=20cadenas=20simples=20no=20terminadas=20?= =?UTF-8?q?correctamente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + grammar/COOL.g4 | 57 +++++++ grammar/COOL_LEX.g4 | 320 +++++++++++++++++++++++++++++++++++++ src/COOL.interp | 2 +- src/COOL.py | 6 +- src/COOL.tokens | 4 +- src/COOLLexer.py | 2 + src/COOL_LEX.interp | 6 +- src/COOL_LEX.py | 382 ++++++++++++++++++++++---------------------- src/COOL_LEX.tokens | 4 +- 10 files changed, 583 insertions(+), 201 deletions(-) create mode 100644 grammar/COOL.g4 create mode 100644 grammar/COOL_LEX.g4 diff --git a/.gitignore b/.gitignore index 4acafde1..ebfe77c1 100644 --- a/.gitignore +++ b/.gitignore @@ -408,3 +408,4 @@ dmypy.json # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) +/.idea diff --git a/grammar/COOL.g4 b/grammar/COOL.g4 new file mode 100644 index 00000000..76a2f58f --- /dev/null +++ b/grammar/COOL.g4 @@ -0,0 +1,57 @@ +parser grammar COOL; + +options { + tokenVocab=COOL_LEX; +} + +program + : programBlocks EOF + ; + +programBlocks + : classDefine SEMICOLON programBlocks? # classes + ; + +classDefine + : CLASS TYPEID (INHERITS TYPEID)? OPEN_CURLY (feature SEMICOLON)* CLOSE_CURLY + ; + +feature + : OBJECTID OPEN_ROUND (formal (COMMA formal)*)* CLOSE_ROUND COLON TYPEID OPEN_CURLY expression CLOSE_CURLY # method + | OBJECTID COLON TYPEID (ASSIGNMENT expression)? # property + ; + +formal + : OBJECTID COLON TYPEID + ; +/* method argument */ + + +expression + : expression (AT TYPEID)? DOT OBJECTID OPEN_ROUND (expression (COMMA expression)*)? CLOSE_ROUND # methodCall + | OBJECTID OPEN_ROUND (expression (COMMA expression)*)? CLOSE_ROUND # ownMethodCall + | IF expression THEN expression ELSE expression FI # if + | WHILE expression LOOP expression POOL # while + | OPEN_CURLY (expression SEMICOLON)+ CLOSE_CURLY # block + | LET OBJECTID COLON TYPEID (ASSIGNMENT expression)? (COMMA OBJECTID COLON TYPEID (ASSIGNMENT expression)?)* IN expression # letIn + | CASE expression OF (OBJECTID COLON TYPEID CASE_ARROW expression SEMICOLON)+ ESAC # case + | NEW TYPEID # new + | INTEGER_NEGATIVE expression # negative + | ISVOID expression # isvoid + | expression MULTIPLY expression # multiply + | expression DIVISION expression # division + | expression ADD expression # add + | expression MINUS expression # minus + | expression LESS_THAN expression # lessThan + | expression LESS_EQUAL expression # lessEqual + | expression EQUAL expression # equal + | NOT expression # boolNot + | OPEN_ROUND expression CLOSE_ROUND # parentheses + | OBJECTID # id + | INT # int + | STRING # string + | TRUE # true + | FALSE # false + | OBJECTID ASSIGNMENT expression # assignment + ; + // key words diff --git a/grammar/COOL_LEX.g4 b/grammar/COOL_LEX.g4 new file mode 100644 index 00000000..ae23319b --- /dev/null +++ b/grammar/COOL_LEX.g4 @@ -0,0 +1,320 @@ +lexer grammar COOL_LEX; + +CLASS + : C L A S S + ; + +ELSE + : E L S E + ; + +FALSE + : 'f' A L S E + ; + +FI + : F I + ; + +IF + : I F + ; + +IN + : I N + ; + +INHERITS + : I N H E R I T S + ; + +ISVOID + : I S V O I D + ; + +LET + : L E T + ; + +LOOP + : L O O P + ; + +POOL + : P O O L + ; + +THEN + : T H E N + ; + +WHILE + : W H I L E + ; + +CASE + : C A S E + ; + +ESAC + : E S A C + ; + +NEW + : N E W + ; + +OF + : O F + ; + +NOT + : N O T + ; + +TRUE + : 't' R U E + ; + // primitives + +STRING + : STRING_SIMPLE + | STRING_MULTILINE + ; + +STRING_SIMPLE_START : + '"' -> pushMode(SIMPLE_STR) + ; + +STRING_SIMPLE + : STRING_SIMPLE_START STRING_SIMPLE_CONTENT STRING_SIMPLE_STOP + | STRING_SIMPLE_START STRING_SIMPLE_STOP + ; + +fragment +STRING_CONTENT + : ESC | ~["\r\n\u0000] + ; + +STRING_FIRSTLINE + : '"' STRING_CONTENT* '\\\r\n' -> pushMode(MULTILINE_STR) + ; + +INT + : [0-9]+ + ; + +TYPEID + : [A-Z] [_0-9A-Za-z]* + ; + +OBJECTID + : [a-z] [_0-9A-Za-z]* + ; + +ASSIGNMENT + : '<-' + ; + +CASE_ARROW + : '=>' + ; + +ADD + : '+' + ; + +MINUS + : '-' + ; + +MULTIPLY + : '*' + ; + +DIVISION + : '/' + ; + +LESS_THAN + : '<' + ; + +LESS_EQUAL + : '<=' + ; + +EQUAL + : '=' + ; + +INTEGER_NEGATIVE + : '~' + ; + +OPEN_ROUND + : '(' + ; + +CLOSE_ROUND + : ')' + ; + +OPEN_CURLY + : '{' + ; + +CLOSE_CURLY + : '}' + ; + +AT + : '@' + ; + +DOT + : '.' + ; + +COMMA + : ',' + ; + +COLON + : ':' + ; + +SEMICOLON + : ';' + ; + +fragment A + : [aA] + ; + +fragment C + : [cC] + ; + +fragment D + : [dD] + ; + +fragment E + : [eE] + ; + +fragment F + : [fF] + ; + +fragment H + : [hH] + ; + +fragment I + : [iI] + ; + +fragment L + : [lL] + ; + +fragment N + : [nN] + ; + +fragment O + : [oO] + ; + +fragment P + : [pP] + ; + +fragment R + : [rR] + ; + +fragment S + : [sS] + ; + +fragment T + : [tT] + ; + +fragment U + : [uU] + ; + +fragment V + : [vV] + ; + +fragment W + : [wW] + ; + +fragment ESC + : '\\' (["\\/bfnrt] | UNICODE) + ; + +fragment UNICODE + : 'u' HEX HEX HEX HEX + ; + +fragment HEX + : [0-9a-fA-F] + ; + + // skip spaces, tabs, newlines, note that \v is not suppoted in antlr + +WHITESPACE + : [ \t\r\n\f]+ -> skip + ; + + // comments + +ONE_LINE_COMMENT + : '--' (~ '\n')* '\n'? -> skip + ; + +OPEN_COMMENT + : '(*' -> pushMode(MULTILINE_COMMENT) + ; + +mode MULTILINE_COMMENT; + +COMMENT + : ((OPEN_COMMENT COMMENT CLOSE_COMMENT) | (.)+? ) -> skip + ; + +CLOSE_COMMENT + : '*)' -> popMode + ; + +mode MULTILINE_STR; + +STRING_INNERLINE + : STRING_CONTENT* '\\\r\n' + ; + +STRING_LASTLINE + : STRING_CONTENT* '"' -> popMode + ; + +STRING_MULTILINE + : STRING_FIRSTLINE STRING_INNERLINE* STRING_LASTLINE + ; + +mode SIMPLE_STR; + +STRING_SIMPLE_CONTENT + : STRING_CONTENT+ + ; + +STRING_SIMPLE_STOP : + '"' -> popMode + ; + diff --git a/src/COOL.interp b/src/COOL.interp index 0a51d34e..656b83cd 100644 --- a/src/COOL.interp +++ b/src/COOL.interp @@ -78,8 +78,8 @@ OF NOT TRUE STRING -STRING_SIMPLE STRING_SIMPLE_START +STRING_SIMPLE STRING_FIRSTLINE INT TYPEID diff --git a/src/COOL.py b/src/COOL.py index 1e1ab864..98bb717d 100644 --- a/src/COOL.py +++ b/src/COOL.py @@ -129,7 +129,7 @@ class COOL ( Parser ): symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", - "TRUE", "STRING", "STRING_SIMPLE", "STRING_SIMPLE_START", + "TRUE", "STRING", "STRING_SIMPLE_START", "STRING_SIMPLE", "STRING_FIRSTLINE", "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", @@ -170,8 +170,8 @@ class COOL ( Parser ): NOT=18 TRUE=19 STRING=20 - STRING_SIMPLE=21 - STRING_SIMPLE_START=22 + STRING_SIMPLE_START=21 + STRING_SIMPLE=22 STRING_FIRSTLINE=23 INT=24 TYPEID=25 diff --git a/src/COOL.tokens b/src/COOL.tokens index c7eacfe4..b0899aa4 100644 --- a/src/COOL.tokens +++ b/src/COOL.tokens @@ -18,8 +18,8 @@ OF=17 NOT=18 TRUE=19 STRING=20 -STRING_SIMPLE=21 -STRING_SIMPLE_START=22 +STRING_SIMPLE_START=21 +STRING_SIMPLE=22 STRING_FIRSTLINE=23 INT=24 TYPEID=25 diff --git a/src/COOLLexer.py b/src/COOLLexer.py index 62b3502f..fda56cf1 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -27,6 +27,8 @@ def notifyListeners(self, e:LexerNoViableAltException): msg = "String contains null character" elif self.inputStream.size == self.inputStream.index: msg = "EOF in string constant" + elif text in ['\r', '\n', '\0'] and self._input.getText(start-1, start-1) in ['\r', '\n', '\0']: + return; else: msg = "Unterminated string constant" else: diff --git a/src/COOL_LEX.interp b/src/COOL_LEX.interp index b7975eb6..d1000fee 100644 --- a/src/COOL_LEX.interp +++ b/src/COOL_LEX.interp @@ -78,8 +78,8 @@ OF NOT TRUE STRING -STRING_SIMPLE STRING_SIMPLE_START +STRING_SIMPLE STRING_FIRSTLINE INT TYPEID @@ -135,8 +135,8 @@ OF NOT TRUE STRING -STRING_SIMPLE STRING_SIMPLE_START +STRING_SIMPLE STRING_CONTENT STRING_FIRSTLINE INT @@ -203,4 +203,4 @@ MULTILINE_STR SIMPLE_STR atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 57, 471, 8, 1, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 254, 10, 21, 3, 22, 3, 22, 7, 22, 258, 10, 22, 12, 22, 14, 22, 261, 11, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 5, 24, 271, 10, 24, 3, 25, 3, 25, 7, 25, 275, 10, 25, 12, 25, 14, 25, 278, 11, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 6, 26, 287, 10, 26, 13, 26, 14, 26, 288, 3, 27, 3, 27, 7, 27, 293, 10, 27, 12, 27, 14, 27, 296, 11, 27, 3, 28, 3, 28, 7, 28, 300, 10, 28, 12, 28, 14, 28, 303, 11, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 5, 65, 383, 10, 65, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 6, 68, 394, 10, 68, 13, 68, 14, 68, 395, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 7, 69, 404, 10, 69, 12, 69, 14, 69, 407, 11, 69, 3, 69, 5, 69, 410, 10, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 424, 10, 71, 13, 71, 14, 71, 425, 5, 71, 428, 10, 71, 3, 71, 3, 71, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 438, 10, 73, 12, 73, 14, 73, 441, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 7, 74, 448, 10, 74, 12, 74, 14, 74, 451, 11, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 75, 3, 75, 7, 75, 459, 10, 75, 12, 75, 14, 75, 462, 11, 75, 3, 75, 3, 75, 3, 76, 3, 76, 3, 77, 3, 77, 3, 77, 3, 77, 3, 425, 2, 78, 6, 3, 8, 4, 10, 5, 12, 6, 14, 7, 16, 8, 18, 9, 20, 10, 22, 11, 24, 12, 26, 13, 28, 14, 30, 15, 32, 16, 34, 17, 36, 18, 38, 19, 40, 20, 42, 21, 44, 22, 46, 23, 48, 24, 50, 2, 52, 25, 54, 26, 56, 27, 58, 28, 60, 29, 62, 30, 64, 31, 66, 32, 68, 33, 70, 34, 72, 35, 74, 36, 76, 37, 78, 38, 80, 39, 82, 40, 84, 41, 86, 42, 88, 43, 90, 44, 92, 45, 94, 46, 96, 47, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 2, 132, 2, 134, 2, 136, 2, 138, 48, 140, 49, 142, 50, 144, 51, 146, 52, 148, 53, 150, 54, 152, 55, 154, 56, 156, 57, 6, 2, 3, 4, 5, 28, 6, 2, 2, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 462, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 90, 3, 2, 2, 2, 2, 92, 3, 2, 2, 2, 2, 94, 3, 2, 2, 2, 2, 96, 3, 2, 2, 2, 2, 138, 3, 2, 2, 2, 2, 140, 3, 2, 2, 2, 2, 142, 3, 2, 2, 2, 3, 144, 3, 2, 2, 2, 3, 146, 3, 2, 2, 2, 4, 148, 3, 2, 2, 2, 4, 150, 3, 2, 2, 2, 4, 152, 3, 2, 2, 2, 5, 154, 3, 2, 2, 2, 5, 156, 3, 2, 2, 2, 6, 158, 3, 2, 2, 2, 8, 164, 3, 2, 2, 2, 10, 169, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 178, 3, 2, 2, 2, 16, 181, 3, 2, 2, 2, 18, 184, 3, 2, 2, 2, 20, 193, 3, 2, 2, 2, 22, 200, 3, 2, 2, 2, 24, 204, 3, 2, 2, 2, 26, 209, 3, 2, 2, 2, 28, 214, 3, 2, 2, 2, 30, 219, 3, 2, 2, 2, 32, 225, 3, 2, 2, 2, 34, 230, 3, 2, 2, 2, 36, 235, 3, 2, 2, 2, 38, 239, 3, 2, 2, 2, 40, 242, 3, 2, 2, 2, 42, 246, 3, 2, 2, 2, 44, 253, 3, 2, 2, 2, 46, 255, 3, 2, 2, 2, 48, 264, 3, 2, 2, 2, 50, 270, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 286, 3, 2, 2, 2, 56, 290, 3, 2, 2, 2, 58, 297, 3, 2, 2, 2, 60, 304, 3, 2, 2, 2, 62, 307, 3, 2, 2, 2, 64, 310, 3, 2, 2, 2, 66, 312, 3, 2, 2, 2, 68, 314, 3, 2, 2, 2, 70, 316, 3, 2, 2, 2, 72, 318, 3, 2, 2, 2, 74, 320, 3, 2, 2, 2, 76, 323, 3, 2, 2, 2, 78, 325, 3, 2, 2, 2, 80, 327, 3, 2, 2, 2, 82, 329, 3, 2, 2, 2, 84, 331, 3, 2, 2, 2, 86, 333, 3, 2, 2, 2, 88, 335, 3, 2, 2, 2, 90, 337, 3, 2, 2, 2, 92, 339, 3, 2, 2, 2, 94, 341, 3, 2, 2, 2, 96, 343, 3, 2, 2, 2, 98, 345, 3, 2, 2, 2, 100, 347, 3, 2, 2, 2, 102, 349, 3, 2, 2, 2, 104, 351, 3, 2, 2, 2, 106, 353, 3, 2, 2, 2, 108, 355, 3, 2, 2, 2, 110, 357, 3, 2, 2, 2, 112, 359, 3, 2, 2, 2, 114, 361, 3, 2, 2, 2, 116, 363, 3, 2, 2, 2, 118, 365, 3, 2, 2, 2, 120, 367, 3, 2, 2, 2, 122, 369, 3, 2, 2, 2, 124, 371, 3, 2, 2, 2, 126, 373, 3, 2, 2, 2, 128, 375, 3, 2, 2, 2, 130, 377, 3, 2, 2, 2, 132, 379, 3, 2, 2, 2, 134, 384, 3, 2, 2, 2, 136, 390, 3, 2, 2, 2, 138, 393, 3, 2, 2, 2, 140, 399, 3, 2, 2, 2, 142, 413, 3, 2, 2, 2, 144, 427, 3, 2, 2, 2, 146, 431, 3, 2, 2, 2, 148, 439, 3, 2, 2, 2, 150, 449, 3, 2, 2, 2, 152, 456, 3, 2, 2, 2, 154, 465, 3, 2, 2, 2, 156, 467, 3, 2, 2, 2, 158, 159, 5, 100, 49, 2, 159, 160, 5, 112, 55, 2, 160, 161, 5, 98, 48, 2, 161, 162, 5, 122, 60, 2, 162, 163, 5, 122, 60, 2, 163, 7, 3, 2, 2, 2, 164, 165, 5, 104, 51, 2, 165, 166, 5, 112, 55, 2, 166, 167, 5, 122, 60, 2, 167, 168, 5, 104, 51, 2, 168, 9, 3, 2, 2, 2, 169, 170, 7, 104, 2, 2, 170, 171, 5, 98, 48, 2, 171, 172, 5, 112, 55, 2, 172, 173, 5, 122, 60, 2, 173, 174, 5, 104, 51, 2, 174, 11, 3, 2, 2, 2, 175, 176, 5, 106, 52, 2, 176, 177, 5, 110, 54, 2, 177, 13, 3, 2, 2, 2, 178, 179, 5, 110, 54, 2, 179, 180, 5, 106, 52, 2, 180, 15, 3, 2, 2, 2, 181, 182, 5, 110, 54, 2, 182, 183, 5, 114, 56, 2, 183, 17, 3, 2, 2, 2, 184, 185, 5, 110, 54, 2, 185, 186, 5, 114, 56, 2, 186, 187, 5, 108, 53, 2, 187, 188, 5, 104, 51, 2, 188, 189, 5, 120, 59, 2, 189, 190, 5, 110, 54, 2, 190, 191, 5, 124, 61, 2, 191, 192, 5, 122, 60, 2, 192, 19, 3, 2, 2, 2, 193, 194, 5, 110, 54, 2, 194, 195, 5, 122, 60, 2, 195, 196, 5, 128, 63, 2, 196, 197, 5, 116, 57, 2, 197, 198, 5, 110, 54, 2, 198, 199, 5, 102, 50, 2, 199, 21, 3, 2, 2, 2, 200, 201, 5, 112, 55, 2, 201, 202, 5, 104, 51, 2, 202, 203, 5, 124, 61, 2, 203, 23, 3, 2, 2, 2, 204, 205, 5, 112, 55, 2, 205, 206, 5, 116, 57, 2, 206, 207, 5, 116, 57, 2, 207, 208, 5, 118, 58, 2, 208, 25, 3, 2, 2, 2, 209, 210, 5, 118, 58, 2, 210, 211, 5, 116, 57, 2, 211, 212, 5, 116, 57, 2, 212, 213, 5, 112, 55, 2, 213, 27, 3, 2, 2, 2, 214, 215, 5, 124, 61, 2, 215, 216, 5, 108, 53, 2, 216, 217, 5, 104, 51, 2, 217, 218, 5, 114, 56, 2, 218, 29, 3, 2, 2, 2, 219, 220, 5, 130, 64, 2, 220, 221, 5, 108, 53, 2, 221, 222, 5, 110, 54, 2, 222, 223, 5, 112, 55, 2, 223, 224, 5, 104, 51, 2, 224, 31, 3, 2, 2, 2, 225, 226, 5, 100, 49, 2, 226, 227, 5, 98, 48, 2, 227, 228, 5, 122, 60, 2, 228, 229, 5, 104, 51, 2, 229, 33, 3, 2, 2, 2, 230, 231, 5, 104, 51, 2, 231, 232, 5, 122, 60, 2, 232, 233, 5, 98, 48, 2, 233, 234, 5, 100, 49, 2, 234, 35, 3, 2, 2, 2, 235, 236, 5, 114, 56, 2, 236, 237, 5, 104, 51, 2, 237, 238, 5, 130, 64, 2, 238, 37, 3, 2, 2, 2, 239, 240, 5, 116, 57, 2, 240, 241, 5, 106, 52, 2, 241, 39, 3, 2, 2, 2, 242, 243, 5, 114, 56, 2, 243, 244, 5, 116, 57, 2, 244, 245, 5, 124, 61, 2, 245, 41, 3, 2, 2, 2, 246, 247, 7, 118, 2, 2, 247, 248, 5, 120, 59, 2, 248, 249, 5, 126, 62, 2, 249, 250, 5, 104, 51, 2, 250, 43, 3, 2, 2, 2, 251, 254, 5, 46, 22, 2, 252, 254, 5, 152, 75, 2, 253, 251, 3, 2, 2, 2, 253, 252, 3, 2, 2, 2, 254, 45, 3, 2, 2, 2, 255, 259, 5, 48, 23, 2, 256, 258, 5, 154, 76, 2, 257, 256, 3, 2, 2, 2, 258, 261, 3, 2, 2, 2, 259, 257, 3, 2, 2, 2, 259, 260, 3, 2, 2, 2, 260, 262, 3, 2, 2, 2, 261, 259, 3, 2, 2, 2, 262, 263, 5, 156, 77, 2, 263, 47, 3, 2, 2, 2, 264, 265, 7, 36, 2, 2, 265, 266, 3, 2, 2, 2, 266, 267, 8, 23, 2, 2, 267, 49, 3, 2, 2, 2, 268, 271, 5, 132, 65, 2, 269, 271, 10, 2, 2, 2, 270, 268, 3, 2, 2, 2, 270, 269, 3, 2, 2, 2, 271, 51, 3, 2, 2, 2, 272, 276, 7, 36, 2, 2, 273, 275, 5, 50, 24, 2, 274, 273, 3, 2, 2, 2, 275, 278, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 279, 3, 2, 2, 2, 278, 276, 3, 2, 2, 2, 279, 280, 7, 94, 2, 2, 280, 281, 7, 15, 2, 2, 281, 282, 7, 12, 2, 2, 282, 283, 3, 2, 2, 2, 283, 284, 8, 25, 3, 2, 284, 53, 3, 2, 2, 2, 285, 287, 9, 3, 2, 2, 286, 285, 3, 2, 2, 2, 287, 288, 3, 2, 2, 2, 288, 286, 3, 2, 2, 2, 288, 289, 3, 2, 2, 2, 289, 55, 3, 2, 2, 2, 290, 294, 9, 4, 2, 2, 291, 293, 9, 5, 2, 2, 292, 291, 3, 2, 2, 2, 293, 296, 3, 2, 2, 2, 294, 292, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 57, 3, 2, 2, 2, 296, 294, 3, 2, 2, 2, 297, 301, 9, 6, 2, 2, 298, 300, 9, 5, 2, 2, 299, 298, 3, 2, 2, 2, 300, 303, 3, 2, 2, 2, 301, 299, 3, 2, 2, 2, 301, 302, 3, 2, 2, 2, 302, 59, 3, 2, 2, 2, 303, 301, 3, 2, 2, 2, 304, 305, 7, 62, 2, 2, 305, 306, 7, 47, 2, 2, 306, 61, 3, 2, 2, 2, 307, 308, 7, 63, 2, 2, 308, 309, 7, 64, 2, 2, 309, 63, 3, 2, 2, 2, 310, 311, 7, 45, 2, 2, 311, 65, 3, 2, 2, 2, 312, 313, 7, 47, 2, 2, 313, 67, 3, 2, 2, 2, 314, 315, 7, 44, 2, 2, 315, 69, 3, 2, 2, 2, 316, 317, 7, 49, 2, 2, 317, 71, 3, 2, 2, 2, 318, 319, 7, 62, 2, 2, 319, 73, 3, 2, 2, 2, 320, 321, 7, 62, 2, 2, 321, 322, 7, 63, 2, 2, 322, 75, 3, 2, 2, 2, 323, 324, 7, 63, 2, 2, 324, 77, 3, 2, 2, 2, 325, 326, 7, 128, 2, 2, 326, 79, 3, 2, 2, 2, 327, 328, 7, 42, 2, 2, 328, 81, 3, 2, 2, 2, 329, 330, 7, 43, 2, 2, 330, 83, 3, 2, 2, 2, 331, 332, 7, 125, 2, 2, 332, 85, 3, 2, 2, 2, 333, 334, 7, 127, 2, 2, 334, 87, 3, 2, 2, 2, 335, 336, 7, 66, 2, 2, 336, 89, 3, 2, 2, 2, 337, 338, 7, 48, 2, 2, 338, 91, 3, 2, 2, 2, 339, 340, 7, 46, 2, 2, 340, 93, 3, 2, 2, 2, 341, 342, 7, 60, 2, 2, 342, 95, 3, 2, 2, 2, 343, 344, 7, 61, 2, 2, 344, 97, 3, 2, 2, 2, 345, 346, 9, 7, 2, 2, 346, 99, 3, 2, 2, 2, 347, 348, 9, 8, 2, 2, 348, 101, 3, 2, 2, 2, 349, 350, 9, 9, 2, 2, 350, 103, 3, 2, 2, 2, 351, 352, 9, 10, 2, 2, 352, 105, 3, 2, 2, 2, 353, 354, 9, 11, 2, 2, 354, 107, 3, 2, 2, 2, 355, 356, 9, 12, 2, 2, 356, 109, 3, 2, 2, 2, 357, 358, 9, 13, 2, 2, 358, 111, 3, 2, 2, 2, 359, 360, 9, 14, 2, 2, 360, 113, 3, 2, 2, 2, 361, 362, 9, 15, 2, 2, 362, 115, 3, 2, 2, 2, 363, 364, 9, 16, 2, 2, 364, 117, 3, 2, 2, 2, 365, 366, 9, 17, 2, 2, 366, 119, 3, 2, 2, 2, 367, 368, 9, 18, 2, 2, 368, 121, 3, 2, 2, 2, 369, 370, 9, 19, 2, 2, 370, 123, 3, 2, 2, 2, 371, 372, 9, 20, 2, 2, 372, 125, 3, 2, 2, 2, 373, 374, 9, 21, 2, 2, 374, 127, 3, 2, 2, 2, 375, 376, 9, 22, 2, 2, 376, 129, 3, 2, 2, 2, 377, 378, 9, 23, 2, 2, 378, 131, 3, 2, 2, 2, 379, 382, 7, 94, 2, 2, 380, 383, 9, 24, 2, 2, 381, 383, 5, 134, 66, 2, 382, 380, 3, 2, 2, 2, 382, 381, 3, 2, 2, 2, 383, 133, 3, 2, 2, 2, 384, 385, 7, 119, 2, 2, 385, 386, 5, 136, 67, 2, 386, 387, 5, 136, 67, 2, 387, 388, 5, 136, 67, 2, 388, 389, 5, 136, 67, 2, 389, 135, 3, 2, 2, 2, 390, 391, 9, 25, 2, 2, 391, 137, 3, 2, 2, 2, 392, 394, 9, 26, 2, 2, 393, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 393, 3, 2, 2, 2, 395, 396, 3, 2, 2, 2, 396, 397, 3, 2, 2, 2, 397, 398, 8, 68, 4, 2, 398, 139, 3, 2, 2, 2, 399, 400, 7, 47, 2, 2, 400, 401, 7, 47, 2, 2, 401, 405, 3, 2, 2, 2, 402, 404, 10, 27, 2, 2, 403, 402, 3, 2, 2, 2, 404, 407, 3, 2, 2, 2, 405, 403, 3, 2, 2, 2, 405, 406, 3, 2, 2, 2, 406, 409, 3, 2, 2, 2, 407, 405, 3, 2, 2, 2, 408, 410, 7, 12, 2, 2, 409, 408, 3, 2, 2, 2, 409, 410, 3, 2, 2, 2, 410, 411, 3, 2, 2, 2, 411, 412, 8, 69, 4, 2, 412, 141, 3, 2, 2, 2, 413, 414, 7, 42, 2, 2, 414, 415, 7, 44, 2, 2, 415, 416, 3, 2, 2, 2, 416, 417, 8, 70, 5, 2, 417, 143, 3, 2, 2, 2, 418, 419, 5, 142, 70, 2, 419, 420, 5, 144, 71, 2, 420, 421, 5, 146, 72, 2, 421, 428, 3, 2, 2, 2, 422, 424, 11, 2, 2, 2, 423, 422, 3, 2, 2, 2, 424, 425, 3, 2, 2, 2, 425, 426, 3, 2, 2, 2, 425, 423, 3, 2, 2, 2, 426, 428, 3, 2, 2, 2, 427, 418, 3, 2, 2, 2, 427, 423, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 430, 8, 71, 4, 2, 430, 145, 3, 2, 2, 2, 431, 432, 7, 44, 2, 2, 432, 433, 7, 43, 2, 2, 433, 434, 3, 2, 2, 2, 434, 435, 8, 72, 6, 2, 435, 147, 3, 2, 2, 2, 436, 438, 5, 50, 24, 2, 437, 436, 3, 2, 2, 2, 438, 441, 3, 2, 2, 2, 439, 437, 3, 2, 2, 2, 439, 440, 3, 2, 2, 2, 440, 442, 3, 2, 2, 2, 441, 439, 3, 2, 2, 2, 442, 443, 7, 94, 2, 2, 443, 444, 7, 15, 2, 2, 444, 445, 7, 12, 2, 2, 445, 149, 3, 2, 2, 2, 446, 448, 5, 50, 24, 2, 447, 446, 3, 2, 2, 2, 448, 451, 3, 2, 2, 2, 449, 447, 3, 2, 2, 2, 449, 450, 3, 2, 2, 2, 450, 452, 3, 2, 2, 2, 451, 449, 3, 2, 2, 2, 452, 453, 7, 36, 2, 2, 453, 454, 3, 2, 2, 2, 454, 455, 8, 74, 6, 2, 455, 151, 3, 2, 2, 2, 456, 460, 5, 52, 25, 2, 457, 459, 5, 148, 73, 2, 458, 457, 3, 2, 2, 2, 459, 462, 3, 2, 2, 2, 460, 458, 3, 2, 2, 2, 460, 461, 3, 2, 2, 2, 461, 463, 3, 2, 2, 2, 462, 460, 3, 2, 2, 2, 463, 464, 5, 150, 74, 2, 464, 153, 3, 2, 2, 2, 465, 466, 5, 50, 24, 2, 466, 155, 3, 2, 2, 2, 467, 468, 7, 36, 2, 2, 468, 469, 3, 2, 2, 2, 469, 470, 8, 77, 6, 2, 470, 157, 3, 2, 2, 2, 22, 2, 3, 4, 5, 253, 259, 270, 276, 288, 294, 301, 382, 395, 405, 409, 425, 427, 439, 449, 460, 7, 7, 5, 2, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 57, 474, 8, 1, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 254, 10, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 5, 23, 267, 10, 23, 3, 24, 3, 24, 5, 24, 271, 10, 24, 3, 25, 3, 25, 7, 25, 275, 10, 25, 12, 25, 14, 25, 278, 11, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 6, 26, 287, 10, 26, 13, 26, 14, 26, 288, 3, 27, 3, 27, 7, 27, 293, 10, 27, 12, 27, 14, 27, 296, 11, 27, 3, 28, 3, 28, 7, 28, 300, 10, 28, 12, 28, 14, 28, 303, 11, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 5, 65, 383, 10, 65, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 6, 68, 394, 10, 68, 13, 68, 14, 68, 395, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 7, 69, 404, 10, 69, 12, 69, 14, 69, 407, 11, 69, 3, 69, 5, 69, 410, 10, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 424, 10, 71, 13, 71, 14, 71, 425, 5, 71, 428, 10, 71, 3, 71, 3, 71, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 438, 10, 73, 12, 73, 14, 73, 441, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 7, 74, 448, 10, 74, 12, 74, 14, 74, 451, 11, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 75, 3, 75, 7, 75, 459, 10, 75, 12, 75, 14, 75, 462, 11, 75, 3, 75, 3, 75, 3, 76, 6, 76, 467, 10, 76, 13, 76, 14, 76, 468, 3, 77, 3, 77, 3, 77, 3, 77, 3, 425, 2, 78, 6, 3, 8, 4, 10, 5, 12, 6, 14, 7, 16, 8, 18, 9, 20, 10, 22, 11, 24, 12, 26, 13, 28, 14, 30, 15, 32, 16, 34, 17, 36, 18, 38, 19, 40, 20, 42, 21, 44, 22, 46, 23, 48, 24, 50, 2, 52, 25, 54, 26, 56, 27, 58, 28, 60, 29, 62, 30, 64, 31, 66, 32, 68, 33, 70, 34, 72, 35, 74, 36, 76, 37, 78, 38, 80, 39, 82, 40, 84, 41, 86, 42, 88, 43, 90, 44, 92, 45, 94, 46, 96, 47, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 2, 132, 2, 134, 2, 136, 2, 138, 48, 140, 49, 142, 50, 144, 51, 146, 52, 148, 53, 150, 54, 152, 55, 154, 56, 156, 57, 6, 2, 3, 4, 5, 28, 6, 2, 2, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 466, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 90, 3, 2, 2, 2, 2, 92, 3, 2, 2, 2, 2, 94, 3, 2, 2, 2, 2, 96, 3, 2, 2, 2, 2, 138, 3, 2, 2, 2, 2, 140, 3, 2, 2, 2, 2, 142, 3, 2, 2, 2, 3, 144, 3, 2, 2, 2, 3, 146, 3, 2, 2, 2, 4, 148, 3, 2, 2, 2, 4, 150, 3, 2, 2, 2, 4, 152, 3, 2, 2, 2, 5, 154, 3, 2, 2, 2, 5, 156, 3, 2, 2, 2, 6, 158, 3, 2, 2, 2, 8, 164, 3, 2, 2, 2, 10, 169, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 178, 3, 2, 2, 2, 16, 181, 3, 2, 2, 2, 18, 184, 3, 2, 2, 2, 20, 193, 3, 2, 2, 2, 22, 200, 3, 2, 2, 2, 24, 204, 3, 2, 2, 2, 26, 209, 3, 2, 2, 2, 28, 214, 3, 2, 2, 2, 30, 219, 3, 2, 2, 2, 32, 225, 3, 2, 2, 2, 34, 230, 3, 2, 2, 2, 36, 235, 3, 2, 2, 2, 38, 239, 3, 2, 2, 2, 40, 242, 3, 2, 2, 2, 42, 246, 3, 2, 2, 2, 44, 253, 3, 2, 2, 2, 46, 255, 3, 2, 2, 2, 48, 266, 3, 2, 2, 2, 50, 270, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 286, 3, 2, 2, 2, 56, 290, 3, 2, 2, 2, 58, 297, 3, 2, 2, 2, 60, 304, 3, 2, 2, 2, 62, 307, 3, 2, 2, 2, 64, 310, 3, 2, 2, 2, 66, 312, 3, 2, 2, 2, 68, 314, 3, 2, 2, 2, 70, 316, 3, 2, 2, 2, 72, 318, 3, 2, 2, 2, 74, 320, 3, 2, 2, 2, 76, 323, 3, 2, 2, 2, 78, 325, 3, 2, 2, 2, 80, 327, 3, 2, 2, 2, 82, 329, 3, 2, 2, 2, 84, 331, 3, 2, 2, 2, 86, 333, 3, 2, 2, 2, 88, 335, 3, 2, 2, 2, 90, 337, 3, 2, 2, 2, 92, 339, 3, 2, 2, 2, 94, 341, 3, 2, 2, 2, 96, 343, 3, 2, 2, 2, 98, 345, 3, 2, 2, 2, 100, 347, 3, 2, 2, 2, 102, 349, 3, 2, 2, 2, 104, 351, 3, 2, 2, 2, 106, 353, 3, 2, 2, 2, 108, 355, 3, 2, 2, 2, 110, 357, 3, 2, 2, 2, 112, 359, 3, 2, 2, 2, 114, 361, 3, 2, 2, 2, 116, 363, 3, 2, 2, 2, 118, 365, 3, 2, 2, 2, 120, 367, 3, 2, 2, 2, 122, 369, 3, 2, 2, 2, 124, 371, 3, 2, 2, 2, 126, 373, 3, 2, 2, 2, 128, 375, 3, 2, 2, 2, 130, 377, 3, 2, 2, 2, 132, 379, 3, 2, 2, 2, 134, 384, 3, 2, 2, 2, 136, 390, 3, 2, 2, 2, 138, 393, 3, 2, 2, 2, 140, 399, 3, 2, 2, 2, 142, 413, 3, 2, 2, 2, 144, 427, 3, 2, 2, 2, 146, 431, 3, 2, 2, 2, 148, 439, 3, 2, 2, 2, 150, 449, 3, 2, 2, 2, 152, 456, 3, 2, 2, 2, 154, 466, 3, 2, 2, 2, 156, 470, 3, 2, 2, 2, 158, 159, 5, 100, 49, 2, 159, 160, 5, 112, 55, 2, 160, 161, 5, 98, 48, 2, 161, 162, 5, 122, 60, 2, 162, 163, 5, 122, 60, 2, 163, 7, 3, 2, 2, 2, 164, 165, 5, 104, 51, 2, 165, 166, 5, 112, 55, 2, 166, 167, 5, 122, 60, 2, 167, 168, 5, 104, 51, 2, 168, 9, 3, 2, 2, 2, 169, 170, 7, 104, 2, 2, 170, 171, 5, 98, 48, 2, 171, 172, 5, 112, 55, 2, 172, 173, 5, 122, 60, 2, 173, 174, 5, 104, 51, 2, 174, 11, 3, 2, 2, 2, 175, 176, 5, 106, 52, 2, 176, 177, 5, 110, 54, 2, 177, 13, 3, 2, 2, 2, 178, 179, 5, 110, 54, 2, 179, 180, 5, 106, 52, 2, 180, 15, 3, 2, 2, 2, 181, 182, 5, 110, 54, 2, 182, 183, 5, 114, 56, 2, 183, 17, 3, 2, 2, 2, 184, 185, 5, 110, 54, 2, 185, 186, 5, 114, 56, 2, 186, 187, 5, 108, 53, 2, 187, 188, 5, 104, 51, 2, 188, 189, 5, 120, 59, 2, 189, 190, 5, 110, 54, 2, 190, 191, 5, 124, 61, 2, 191, 192, 5, 122, 60, 2, 192, 19, 3, 2, 2, 2, 193, 194, 5, 110, 54, 2, 194, 195, 5, 122, 60, 2, 195, 196, 5, 128, 63, 2, 196, 197, 5, 116, 57, 2, 197, 198, 5, 110, 54, 2, 198, 199, 5, 102, 50, 2, 199, 21, 3, 2, 2, 2, 200, 201, 5, 112, 55, 2, 201, 202, 5, 104, 51, 2, 202, 203, 5, 124, 61, 2, 203, 23, 3, 2, 2, 2, 204, 205, 5, 112, 55, 2, 205, 206, 5, 116, 57, 2, 206, 207, 5, 116, 57, 2, 207, 208, 5, 118, 58, 2, 208, 25, 3, 2, 2, 2, 209, 210, 5, 118, 58, 2, 210, 211, 5, 116, 57, 2, 211, 212, 5, 116, 57, 2, 212, 213, 5, 112, 55, 2, 213, 27, 3, 2, 2, 2, 214, 215, 5, 124, 61, 2, 215, 216, 5, 108, 53, 2, 216, 217, 5, 104, 51, 2, 217, 218, 5, 114, 56, 2, 218, 29, 3, 2, 2, 2, 219, 220, 5, 130, 64, 2, 220, 221, 5, 108, 53, 2, 221, 222, 5, 110, 54, 2, 222, 223, 5, 112, 55, 2, 223, 224, 5, 104, 51, 2, 224, 31, 3, 2, 2, 2, 225, 226, 5, 100, 49, 2, 226, 227, 5, 98, 48, 2, 227, 228, 5, 122, 60, 2, 228, 229, 5, 104, 51, 2, 229, 33, 3, 2, 2, 2, 230, 231, 5, 104, 51, 2, 231, 232, 5, 122, 60, 2, 232, 233, 5, 98, 48, 2, 233, 234, 5, 100, 49, 2, 234, 35, 3, 2, 2, 2, 235, 236, 5, 114, 56, 2, 236, 237, 5, 104, 51, 2, 237, 238, 5, 130, 64, 2, 238, 37, 3, 2, 2, 2, 239, 240, 5, 116, 57, 2, 240, 241, 5, 106, 52, 2, 241, 39, 3, 2, 2, 2, 242, 243, 5, 114, 56, 2, 243, 244, 5, 116, 57, 2, 244, 245, 5, 124, 61, 2, 245, 41, 3, 2, 2, 2, 246, 247, 7, 118, 2, 2, 247, 248, 5, 120, 59, 2, 248, 249, 5, 126, 62, 2, 249, 250, 5, 104, 51, 2, 250, 43, 3, 2, 2, 2, 251, 254, 5, 48, 23, 2, 252, 254, 5, 152, 75, 2, 253, 251, 3, 2, 2, 2, 253, 252, 3, 2, 2, 2, 254, 45, 3, 2, 2, 2, 255, 256, 7, 36, 2, 2, 256, 257, 3, 2, 2, 2, 257, 258, 8, 22, 2, 2, 258, 47, 3, 2, 2, 2, 259, 260, 5, 46, 22, 2, 260, 261, 5, 154, 76, 2, 261, 262, 5, 156, 77, 2, 262, 267, 3, 2, 2, 2, 263, 264, 5, 46, 22, 2, 264, 265, 5, 156, 77, 2, 265, 267, 3, 2, 2, 2, 266, 259, 3, 2, 2, 2, 266, 263, 3, 2, 2, 2, 267, 49, 3, 2, 2, 2, 268, 271, 5, 132, 65, 2, 269, 271, 10, 2, 2, 2, 270, 268, 3, 2, 2, 2, 270, 269, 3, 2, 2, 2, 271, 51, 3, 2, 2, 2, 272, 276, 7, 36, 2, 2, 273, 275, 5, 50, 24, 2, 274, 273, 3, 2, 2, 2, 275, 278, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 279, 3, 2, 2, 2, 278, 276, 3, 2, 2, 2, 279, 280, 7, 94, 2, 2, 280, 281, 7, 15, 2, 2, 281, 282, 7, 12, 2, 2, 282, 283, 3, 2, 2, 2, 283, 284, 8, 25, 3, 2, 284, 53, 3, 2, 2, 2, 285, 287, 9, 3, 2, 2, 286, 285, 3, 2, 2, 2, 287, 288, 3, 2, 2, 2, 288, 286, 3, 2, 2, 2, 288, 289, 3, 2, 2, 2, 289, 55, 3, 2, 2, 2, 290, 294, 9, 4, 2, 2, 291, 293, 9, 5, 2, 2, 292, 291, 3, 2, 2, 2, 293, 296, 3, 2, 2, 2, 294, 292, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 57, 3, 2, 2, 2, 296, 294, 3, 2, 2, 2, 297, 301, 9, 6, 2, 2, 298, 300, 9, 5, 2, 2, 299, 298, 3, 2, 2, 2, 300, 303, 3, 2, 2, 2, 301, 299, 3, 2, 2, 2, 301, 302, 3, 2, 2, 2, 302, 59, 3, 2, 2, 2, 303, 301, 3, 2, 2, 2, 304, 305, 7, 62, 2, 2, 305, 306, 7, 47, 2, 2, 306, 61, 3, 2, 2, 2, 307, 308, 7, 63, 2, 2, 308, 309, 7, 64, 2, 2, 309, 63, 3, 2, 2, 2, 310, 311, 7, 45, 2, 2, 311, 65, 3, 2, 2, 2, 312, 313, 7, 47, 2, 2, 313, 67, 3, 2, 2, 2, 314, 315, 7, 44, 2, 2, 315, 69, 3, 2, 2, 2, 316, 317, 7, 49, 2, 2, 317, 71, 3, 2, 2, 2, 318, 319, 7, 62, 2, 2, 319, 73, 3, 2, 2, 2, 320, 321, 7, 62, 2, 2, 321, 322, 7, 63, 2, 2, 322, 75, 3, 2, 2, 2, 323, 324, 7, 63, 2, 2, 324, 77, 3, 2, 2, 2, 325, 326, 7, 128, 2, 2, 326, 79, 3, 2, 2, 2, 327, 328, 7, 42, 2, 2, 328, 81, 3, 2, 2, 2, 329, 330, 7, 43, 2, 2, 330, 83, 3, 2, 2, 2, 331, 332, 7, 125, 2, 2, 332, 85, 3, 2, 2, 2, 333, 334, 7, 127, 2, 2, 334, 87, 3, 2, 2, 2, 335, 336, 7, 66, 2, 2, 336, 89, 3, 2, 2, 2, 337, 338, 7, 48, 2, 2, 338, 91, 3, 2, 2, 2, 339, 340, 7, 46, 2, 2, 340, 93, 3, 2, 2, 2, 341, 342, 7, 60, 2, 2, 342, 95, 3, 2, 2, 2, 343, 344, 7, 61, 2, 2, 344, 97, 3, 2, 2, 2, 345, 346, 9, 7, 2, 2, 346, 99, 3, 2, 2, 2, 347, 348, 9, 8, 2, 2, 348, 101, 3, 2, 2, 2, 349, 350, 9, 9, 2, 2, 350, 103, 3, 2, 2, 2, 351, 352, 9, 10, 2, 2, 352, 105, 3, 2, 2, 2, 353, 354, 9, 11, 2, 2, 354, 107, 3, 2, 2, 2, 355, 356, 9, 12, 2, 2, 356, 109, 3, 2, 2, 2, 357, 358, 9, 13, 2, 2, 358, 111, 3, 2, 2, 2, 359, 360, 9, 14, 2, 2, 360, 113, 3, 2, 2, 2, 361, 362, 9, 15, 2, 2, 362, 115, 3, 2, 2, 2, 363, 364, 9, 16, 2, 2, 364, 117, 3, 2, 2, 2, 365, 366, 9, 17, 2, 2, 366, 119, 3, 2, 2, 2, 367, 368, 9, 18, 2, 2, 368, 121, 3, 2, 2, 2, 369, 370, 9, 19, 2, 2, 370, 123, 3, 2, 2, 2, 371, 372, 9, 20, 2, 2, 372, 125, 3, 2, 2, 2, 373, 374, 9, 21, 2, 2, 374, 127, 3, 2, 2, 2, 375, 376, 9, 22, 2, 2, 376, 129, 3, 2, 2, 2, 377, 378, 9, 23, 2, 2, 378, 131, 3, 2, 2, 2, 379, 382, 7, 94, 2, 2, 380, 383, 9, 24, 2, 2, 381, 383, 5, 134, 66, 2, 382, 380, 3, 2, 2, 2, 382, 381, 3, 2, 2, 2, 383, 133, 3, 2, 2, 2, 384, 385, 7, 119, 2, 2, 385, 386, 5, 136, 67, 2, 386, 387, 5, 136, 67, 2, 387, 388, 5, 136, 67, 2, 388, 389, 5, 136, 67, 2, 389, 135, 3, 2, 2, 2, 390, 391, 9, 25, 2, 2, 391, 137, 3, 2, 2, 2, 392, 394, 9, 26, 2, 2, 393, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 393, 3, 2, 2, 2, 395, 396, 3, 2, 2, 2, 396, 397, 3, 2, 2, 2, 397, 398, 8, 68, 4, 2, 398, 139, 3, 2, 2, 2, 399, 400, 7, 47, 2, 2, 400, 401, 7, 47, 2, 2, 401, 405, 3, 2, 2, 2, 402, 404, 10, 27, 2, 2, 403, 402, 3, 2, 2, 2, 404, 407, 3, 2, 2, 2, 405, 403, 3, 2, 2, 2, 405, 406, 3, 2, 2, 2, 406, 409, 3, 2, 2, 2, 407, 405, 3, 2, 2, 2, 408, 410, 7, 12, 2, 2, 409, 408, 3, 2, 2, 2, 409, 410, 3, 2, 2, 2, 410, 411, 3, 2, 2, 2, 411, 412, 8, 69, 4, 2, 412, 141, 3, 2, 2, 2, 413, 414, 7, 42, 2, 2, 414, 415, 7, 44, 2, 2, 415, 416, 3, 2, 2, 2, 416, 417, 8, 70, 5, 2, 417, 143, 3, 2, 2, 2, 418, 419, 5, 142, 70, 2, 419, 420, 5, 144, 71, 2, 420, 421, 5, 146, 72, 2, 421, 428, 3, 2, 2, 2, 422, 424, 11, 2, 2, 2, 423, 422, 3, 2, 2, 2, 424, 425, 3, 2, 2, 2, 425, 426, 3, 2, 2, 2, 425, 423, 3, 2, 2, 2, 426, 428, 3, 2, 2, 2, 427, 418, 3, 2, 2, 2, 427, 423, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 430, 8, 71, 4, 2, 430, 145, 3, 2, 2, 2, 431, 432, 7, 44, 2, 2, 432, 433, 7, 43, 2, 2, 433, 434, 3, 2, 2, 2, 434, 435, 8, 72, 6, 2, 435, 147, 3, 2, 2, 2, 436, 438, 5, 50, 24, 2, 437, 436, 3, 2, 2, 2, 438, 441, 3, 2, 2, 2, 439, 437, 3, 2, 2, 2, 439, 440, 3, 2, 2, 2, 440, 442, 3, 2, 2, 2, 441, 439, 3, 2, 2, 2, 442, 443, 7, 94, 2, 2, 443, 444, 7, 15, 2, 2, 444, 445, 7, 12, 2, 2, 445, 149, 3, 2, 2, 2, 446, 448, 5, 50, 24, 2, 447, 446, 3, 2, 2, 2, 448, 451, 3, 2, 2, 2, 449, 447, 3, 2, 2, 2, 449, 450, 3, 2, 2, 2, 450, 452, 3, 2, 2, 2, 451, 449, 3, 2, 2, 2, 452, 453, 7, 36, 2, 2, 453, 454, 3, 2, 2, 2, 454, 455, 8, 74, 6, 2, 455, 151, 3, 2, 2, 2, 456, 460, 5, 52, 25, 2, 457, 459, 5, 148, 73, 2, 458, 457, 3, 2, 2, 2, 459, 462, 3, 2, 2, 2, 460, 458, 3, 2, 2, 2, 460, 461, 3, 2, 2, 2, 461, 463, 3, 2, 2, 2, 462, 460, 3, 2, 2, 2, 463, 464, 5, 150, 74, 2, 464, 153, 3, 2, 2, 2, 465, 467, 5, 50, 24, 2, 466, 465, 3, 2, 2, 2, 467, 468, 3, 2, 2, 2, 468, 466, 3, 2, 2, 2, 468, 469, 3, 2, 2, 2, 469, 155, 3, 2, 2, 2, 470, 471, 7, 36, 2, 2, 471, 472, 3, 2, 2, 2, 472, 473, 8, 77, 6, 2, 473, 157, 3, 2, 2, 2, 23, 2, 3, 4, 5, 253, 266, 270, 276, 288, 294, 301, 382, 395, 405, 409, 425, 427, 439, 449, 460, 468, 7, 7, 5, 2, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file diff --git a/src/COOL_LEX.py b/src/COOL_LEX.py index 02c42de2..74921491 100644 --- a/src/COOL_LEX.py +++ b/src/COOL_LEX.py @@ -9,7 +9,7 @@ def serializedATN(): with StringIO() as buf: buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\29") - buf.write("\u01d7\b\1\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5") + buf.write("\u01da\b\1\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5") buf.write("\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f") buf.write("\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4") buf.write("\22\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27") @@ -28,190 +28,192 @@ def serializedATN(): buf.write("\r\3\16\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3") buf.write("\17\3\20\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\22") buf.write("\3\22\3\22\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24") - buf.write("\3\25\3\25\5\25\u00fe\n\25\3\26\3\26\7\26\u0102\n\26\f") - buf.write("\26\16\26\u0105\13\26\3\26\3\26\3\27\3\27\3\27\3\27\3") - buf.write("\30\3\30\5\30\u010f\n\30\3\31\3\31\7\31\u0113\n\31\f\31") - buf.write("\16\31\u0116\13\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32") - buf.write("\6\32\u011f\n\32\r\32\16\32\u0120\3\33\3\33\7\33\u0125") - buf.write("\n\33\f\33\16\33\u0128\13\33\3\34\3\34\7\34\u012c\n\34") - buf.write("\f\34\16\34\u012f\13\34\3\35\3\35\3\35\3\36\3\36\3\36") - buf.write("\3\37\3\37\3 \3 \3!\3!\3\"\3\"\3#\3#\3$\3$\3$\3%\3%\3") - buf.write("&\3&\3\'\3\'\3(\3(\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3") - buf.write(".\3/\3/\3\60\3\60\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3") - buf.write("\64\3\65\3\65\3\66\3\66\3\67\3\67\38\38\39\39\3:\3:\3") - buf.write(";\3;\3<\3<\3=\3=\3>\3>\3?\3?\3@\3@\3A\3A\3A\5A\u017f\n") - buf.write("A\3B\3B\3B\3B\3B\3B\3C\3C\3D\6D\u018a\nD\rD\16D\u018b") - buf.write("\3D\3D\3E\3E\3E\3E\7E\u0194\nE\fE\16E\u0197\13E\3E\5E") - buf.write("\u019a\nE\3E\3E\3F\3F\3F\3F\3F\3G\3G\3G\3G\3G\6G\u01a8") - buf.write("\nG\rG\16G\u01a9\5G\u01ac\nG\3G\3G\3H\3H\3H\3H\3H\3I\7") - buf.write("I\u01b6\nI\fI\16I\u01b9\13I\3I\3I\3I\3I\3J\7J\u01c0\n") - buf.write("J\fJ\16J\u01c3\13J\3J\3J\3J\3J\3K\3K\7K\u01cb\nK\fK\16") - buf.write("K\u01ce\13K\3K\3K\3L\3L\3M\3M\3M\3M\3\u01a9\2N\6\3\b\4") - buf.write("\n\5\f\6\16\7\20\b\22\t\24\n\26\13\30\f\32\r\34\16\36") - buf.write("\17 \20\"\21$\22&\23(\24*\25,\26.\27\60\30\62\2\64\31") - buf.write("\66\328\33:\34<\35>\36@\37B D!F\"H#J$L%N&P\'R(T)V*X+Z") - buf.write(",\\-^.`/b\2d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2|\2~\2") - buf.write("\u0080\2\u0082\2\u0084\2\u0086\2\u0088\2\u008a\60\u008c") - buf.write("\61\u008e\62\u0090\63\u0092\64\u0094\65\u0096\66\u0098") - buf.write("\67\u009a8\u009c9\6\2\3\4\5\34\6\2\2\2\f\f\17\17$$\3\2") - buf.write("\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEee\4\2F") - buf.write("Fff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2PPpp\4") - buf.write("\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4\2XXx") - buf.write("x\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2\13\f") - buf.write("\16\17\"\"\3\2\f\f\2\u01ce\2\6\3\2\2\2\2\b\3\2\2\2\2\n") - buf.write("\3\2\2\2\2\f\3\2\2\2\2\16\3\2\2\2\2\20\3\2\2\2\2\22\3") - buf.write("\2\2\2\2\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32\3\2") - buf.write("\2\2\2\34\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2\2\2") - buf.write("\2$\3\2\2\2\2&\3\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3\2\2") - buf.write("\2\2.\3\2\2\2\2\60\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\2") - buf.write("8\3\2\2\2\2:\3\2\2\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2\2\2") - buf.write("\2B\3\2\2\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3\2\2") - buf.write("\2\2L\3\2\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2") - buf.write("\2\2\2V\3\2\2\2\2X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2\2^\3") - buf.write("\2\2\2\2`\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2\2\u008e") - buf.write("\3\2\2\2\3\u0090\3\2\2\2\3\u0092\3\2\2\2\4\u0094\3\2\2") - buf.write("\2\4\u0096\3\2\2\2\4\u0098\3\2\2\2\5\u009a\3\2\2\2\5\u009c") - buf.write("\3\2\2\2\6\u009e\3\2\2\2\b\u00a4\3\2\2\2\n\u00a9\3\2\2") - buf.write("\2\f\u00af\3\2\2\2\16\u00b2\3\2\2\2\20\u00b5\3\2\2\2\22") - buf.write("\u00b8\3\2\2\2\24\u00c1\3\2\2\2\26\u00c8\3\2\2\2\30\u00cc") - buf.write("\3\2\2\2\32\u00d1\3\2\2\2\34\u00d6\3\2\2\2\36\u00db\3") - buf.write("\2\2\2 \u00e1\3\2\2\2\"\u00e6\3\2\2\2$\u00eb\3\2\2\2&") - buf.write("\u00ef\3\2\2\2(\u00f2\3\2\2\2*\u00f6\3\2\2\2,\u00fd\3") - buf.write("\2\2\2.\u00ff\3\2\2\2\60\u0108\3\2\2\2\62\u010e\3\2\2") - buf.write("\2\64\u0110\3\2\2\2\66\u011e\3\2\2\28\u0122\3\2\2\2:\u0129") - buf.write("\3\2\2\2<\u0130\3\2\2\2>\u0133\3\2\2\2@\u0136\3\2\2\2") - buf.write("B\u0138\3\2\2\2D\u013a\3\2\2\2F\u013c\3\2\2\2H\u013e\3") - buf.write("\2\2\2J\u0140\3\2\2\2L\u0143\3\2\2\2N\u0145\3\2\2\2P\u0147") - buf.write("\3\2\2\2R\u0149\3\2\2\2T\u014b\3\2\2\2V\u014d\3\2\2\2") - buf.write("X\u014f\3\2\2\2Z\u0151\3\2\2\2\\\u0153\3\2\2\2^\u0155") - buf.write("\3\2\2\2`\u0157\3\2\2\2b\u0159\3\2\2\2d\u015b\3\2\2\2") - buf.write("f\u015d\3\2\2\2h\u015f\3\2\2\2j\u0161\3\2\2\2l\u0163\3") - buf.write("\2\2\2n\u0165\3\2\2\2p\u0167\3\2\2\2r\u0169\3\2\2\2t\u016b") - buf.write("\3\2\2\2v\u016d\3\2\2\2x\u016f\3\2\2\2z\u0171\3\2\2\2") - buf.write("|\u0173\3\2\2\2~\u0175\3\2\2\2\u0080\u0177\3\2\2\2\u0082") - buf.write("\u0179\3\2\2\2\u0084\u017b\3\2\2\2\u0086\u0180\3\2\2\2") - buf.write("\u0088\u0186\3\2\2\2\u008a\u0189\3\2\2\2\u008c\u018f\3") - buf.write("\2\2\2\u008e\u019d\3\2\2\2\u0090\u01ab\3\2\2\2\u0092\u01af") - buf.write("\3\2\2\2\u0094\u01b7\3\2\2\2\u0096\u01c1\3\2\2\2\u0098") - buf.write("\u01c8\3\2\2\2\u009a\u01d1\3\2\2\2\u009c\u01d3\3\2\2\2") - buf.write("\u009e\u009f\5d\61\2\u009f\u00a0\5p\67\2\u00a0\u00a1\5") - buf.write("b\60\2\u00a1\u00a2\5z<\2\u00a2\u00a3\5z<\2\u00a3\7\3\2") - buf.write("\2\2\u00a4\u00a5\5h\63\2\u00a5\u00a6\5p\67\2\u00a6\u00a7") - buf.write("\5z<\2\u00a7\u00a8\5h\63\2\u00a8\t\3\2\2\2\u00a9\u00aa") - buf.write("\7h\2\2\u00aa\u00ab\5b\60\2\u00ab\u00ac\5p\67\2\u00ac") - buf.write("\u00ad\5z<\2\u00ad\u00ae\5h\63\2\u00ae\13\3\2\2\2\u00af") - buf.write("\u00b0\5j\64\2\u00b0\u00b1\5n\66\2\u00b1\r\3\2\2\2\u00b2") - buf.write("\u00b3\5n\66\2\u00b3\u00b4\5j\64\2\u00b4\17\3\2\2\2\u00b5") - buf.write("\u00b6\5n\66\2\u00b6\u00b7\5r8\2\u00b7\21\3\2\2\2\u00b8") - buf.write("\u00b9\5n\66\2\u00b9\u00ba\5r8\2\u00ba\u00bb\5l\65\2\u00bb") - buf.write("\u00bc\5h\63\2\u00bc\u00bd\5x;\2\u00bd\u00be\5n\66\2\u00be") - buf.write("\u00bf\5|=\2\u00bf\u00c0\5z<\2\u00c0\23\3\2\2\2\u00c1") - buf.write("\u00c2\5n\66\2\u00c2\u00c3\5z<\2\u00c3\u00c4\5\u0080?") - buf.write("\2\u00c4\u00c5\5t9\2\u00c5\u00c6\5n\66\2\u00c6\u00c7\5") - buf.write("f\62\2\u00c7\25\3\2\2\2\u00c8\u00c9\5p\67\2\u00c9\u00ca") - buf.write("\5h\63\2\u00ca\u00cb\5|=\2\u00cb\27\3\2\2\2\u00cc\u00cd") - buf.write("\5p\67\2\u00cd\u00ce\5t9\2\u00ce\u00cf\5t9\2\u00cf\u00d0") - buf.write("\5v:\2\u00d0\31\3\2\2\2\u00d1\u00d2\5v:\2\u00d2\u00d3") - buf.write("\5t9\2\u00d3\u00d4\5t9\2\u00d4\u00d5\5p\67\2\u00d5\33") - buf.write("\3\2\2\2\u00d6\u00d7\5|=\2\u00d7\u00d8\5l\65\2\u00d8\u00d9") - buf.write("\5h\63\2\u00d9\u00da\5r8\2\u00da\35\3\2\2\2\u00db\u00dc") - buf.write("\5\u0082@\2\u00dc\u00dd\5l\65\2\u00dd\u00de\5n\66\2\u00de") - buf.write("\u00df\5p\67\2\u00df\u00e0\5h\63\2\u00e0\37\3\2\2\2\u00e1") - buf.write("\u00e2\5d\61\2\u00e2\u00e3\5b\60\2\u00e3\u00e4\5z<\2\u00e4") - buf.write("\u00e5\5h\63\2\u00e5!\3\2\2\2\u00e6\u00e7\5h\63\2\u00e7") - buf.write("\u00e8\5z<\2\u00e8\u00e9\5b\60\2\u00e9\u00ea\5d\61\2\u00ea") - buf.write("#\3\2\2\2\u00eb\u00ec\5r8\2\u00ec\u00ed\5h\63\2\u00ed") - buf.write("\u00ee\5\u0082@\2\u00ee%\3\2\2\2\u00ef\u00f0\5t9\2\u00f0") - buf.write("\u00f1\5j\64\2\u00f1\'\3\2\2\2\u00f2\u00f3\5r8\2\u00f3") - buf.write("\u00f4\5t9\2\u00f4\u00f5\5|=\2\u00f5)\3\2\2\2\u00f6\u00f7") - buf.write("\7v\2\2\u00f7\u00f8\5x;\2\u00f8\u00f9\5~>\2\u00f9\u00fa") - buf.write("\5h\63\2\u00fa+\3\2\2\2\u00fb\u00fe\5.\26\2\u00fc\u00fe") - buf.write("\5\u0098K\2\u00fd\u00fb\3\2\2\2\u00fd\u00fc\3\2\2\2\u00fe") - buf.write("-\3\2\2\2\u00ff\u0103\5\60\27\2\u0100\u0102\5\u009aL\2") - buf.write("\u0101\u0100\3\2\2\2\u0102\u0105\3\2\2\2\u0103\u0101\3") - buf.write("\2\2\2\u0103\u0104\3\2\2\2\u0104\u0106\3\2\2\2\u0105\u0103") - buf.write("\3\2\2\2\u0106\u0107\5\u009cM\2\u0107/\3\2\2\2\u0108\u0109") - buf.write("\7$\2\2\u0109\u010a\3\2\2\2\u010a\u010b\b\27\2\2\u010b") - buf.write("\61\3\2\2\2\u010c\u010f\5\u0084A\2\u010d\u010f\n\2\2\2") - buf.write("\u010e\u010c\3\2\2\2\u010e\u010d\3\2\2\2\u010f\63\3\2") - buf.write("\2\2\u0110\u0114\7$\2\2\u0111\u0113\5\62\30\2\u0112\u0111") - buf.write("\3\2\2\2\u0113\u0116\3\2\2\2\u0114\u0112\3\2\2\2\u0114") - buf.write("\u0115\3\2\2\2\u0115\u0117\3\2\2\2\u0116\u0114\3\2\2\2") - buf.write("\u0117\u0118\7^\2\2\u0118\u0119\7\17\2\2\u0119\u011a\7") - buf.write("\f\2\2\u011a\u011b\3\2\2\2\u011b\u011c\b\31\3\2\u011c") - buf.write("\65\3\2\2\2\u011d\u011f\t\3\2\2\u011e\u011d\3\2\2\2\u011f") - buf.write("\u0120\3\2\2\2\u0120\u011e\3\2\2\2\u0120\u0121\3\2\2\2") - buf.write("\u0121\67\3\2\2\2\u0122\u0126\t\4\2\2\u0123\u0125\t\5") - buf.write("\2\2\u0124\u0123\3\2\2\2\u0125\u0128\3\2\2\2\u0126\u0124") - buf.write("\3\2\2\2\u0126\u0127\3\2\2\2\u01279\3\2\2\2\u0128\u0126") - buf.write("\3\2\2\2\u0129\u012d\t\6\2\2\u012a\u012c\t\5\2\2\u012b") - buf.write("\u012a\3\2\2\2\u012c\u012f\3\2\2\2\u012d\u012b\3\2\2\2") - buf.write("\u012d\u012e\3\2\2\2\u012e;\3\2\2\2\u012f\u012d\3\2\2") - buf.write("\2\u0130\u0131\7>\2\2\u0131\u0132\7/\2\2\u0132=\3\2\2") - buf.write("\2\u0133\u0134\7?\2\2\u0134\u0135\7@\2\2\u0135?\3\2\2") - buf.write("\2\u0136\u0137\7-\2\2\u0137A\3\2\2\2\u0138\u0139\7/\2") - buf.write("\2\u0139C\3\2\2\2\u013a\u013b\7,\2\2\u013bE\3\2\2\2\u013c") - buf.write("\u013d\7\61\2\2\u013dG\3\2\2\2\u013e\u013f\7>\2\2\u013f") - buf.write("I\3\2\2\2\u0140\u0141\7>\2\2\u0141\u0142\7?\2\2\u0142") - buf.write("K\3\2\2\2\u0143\u0144\7?\2\2\u0144M\3\2\2\2\u0145\u0146") - buf.write("\7\u0080\2\2\u0146O\3\2\2\2\u0147\u0148\7*\2\2\u0148Q") - buf.write("\3\2\2\2\u0149\u014a\7+\2\2\u014aS\3\2\2\2\u014b\u014c") - buf.write("\7}\2\2\u014cU\3\2\2\2\u014d\u014e\7\177\2\2\u014eW\3") - buf.write("\2\2\2\u014f\u0150\7B\2\2\u0150Y\3\2\2\2\u0151\u0152\7") - buf.write("\60\2\2\u0152[\3\2\2\2\u0153\u0154\7.\2\2\u0154]\3\2\2") - buf.write("\2\u0155\u0156\7<\2\2\u0156_\3\2\2\2\u0157\u0158\7=\2") - buf.write("\2\u0158a\3\2\2\2\u0159\u015a\t\7\2\2\u015ac\3\2\2\2\u015b") - buf.write("\u015c\t\b\2\2\u015ce\3\2\2\2\u015d\u015e\t\t\2\2\u015e") - buf.write("g\3\2\2\2\u015f\u0160\t\n\2\2\u0160i\3\2\2\2\u0161\u0162") - buf.write("\t\13\2\2\u0162k\3\2\2\2\u0163\u0164\t\f\2\2\u0164m\3") - buf.write("\2\2\2\u0165\u0166\t\r\2\2\u0166o\3\2\2\2\u0167\u0168") - buf.write("\t\16\2\2\u0168q\3\2\2\2\u0169\u016a\t\17\2\2\u016as\3") - buf.write("\2\2\2\u016b\u016c\t\20\2\2\u016cu\3\2\2\2\u016d\u016e") - buf.write("\t\21\2\2\u016ew\3\2\2\2\u016f\u0170\t\22\2\2\u0170y\3") - buf.write("\2\2\2\u0171\u0172\t\23\2\2\u0172{\3\2\2\2\u0173\u0174") - buf.write("\t\24\2\2\u0174}\3\2\2\2\u0175\u0176\t\25\2\2\u0176\177") - buf.write("\3\2\2\2\u0177\u0178\t\26\2\2\u0178\u0081\3\2\2\2\u0179") - buf.write("\u017a\t\27\2\2\u017a\u0083\3\2\2\2\u017b\u017e\7^\2\2") - buf.write("\u017c\u017f\t\30\2\2\u017d\u017f\5\u0086B\2\u017e\u017c") - buf.write("\3\2\2\2\u017e\u017d\3\2\2\2\u017f\u0085\3\2\2\2\u0180") - buf.write("\u0181\7w\2\2\u0181\u0182\5\u0088C\2\u0182\u0183\5\u0088") - buf.write("C\2\u0183\u0184\5\u0088C\2\u0184\u0185\5\u0088C\2\u0185") - buf.write("\u0087\3\2\2\2\u0186\u0187\t\31\2\2\u0187\u0089\3\2\2") - buf.write("\2\u0188\u018a\t\32\2\2\u0189\u0188\3\2\2\2\u018a\u018b") - buf.write("\3\2\2\2\u018b\u0189\3\2\2\2\u018b\u018c\3\2\2\2\u018c") - buf.write("\u018d\3\2\2\2\u018d\u018e\bD\4\2\u018e\u008b\3\2\2\2") - buf.write("\u018f\u0190\7/\2\2\u0190\u0191\7/\2\2\u0191\u0195\3\2") - buf.write("\2\2\u0192\u0194\n\33\2\2\u0193\u0192\3\2\2\2\u0194\u0197") - buf.write("\3\2\2\2\u0195\u0193\3\2\2\2\u0195\u0196\3\2\2\2\u0196") - buf.write("\u0199\3\2\2\2\u0197\u0195\3\2\2\2\u0198\u019a\7\f\2\2") - buf.write("\u0199\u0198\3\2\2\2\u0199\u019a\3\2\2\2\u019a\u019b\3") - buf.write("\2\2\2\u019b\u019c\bE\4\2\u019c\u008d\3\2\2\2\u019d\u019e") - buf.write("\7*\2\2\u019e\u019f\7,\2\2\u019f\u01a0\3\2\2\2\u01a0\u01a1") - buf.write("\bF\5\2\u01a1\u008f\3\2\2\2\u01a2\u01a3\5\u008eF\2\u01a3") - buf.write("\u01a4\5\u0090G\2\u01a4\u01a5\5\u0092H\2\u01a5\u01ac\3") - buf.write("\2\2\2\u01a6\u01a8\13\2\2\2\u01a7\u01a6\3\2\2\2\u01a8") - buf.write("\u01a9\3\2\2\2\u01a9\u01aa\3\2\2\2\u01a9\u01a7\3\2\2\2") - buf.write("\u01aa\u01ac\3\2\2\2\u01ab\u01a2\3\2\2\2\u01ab\u01a7\3") - buf.write("\2\2\2\u01ac\u01ad\3\2\2\2\u01ad\u01ae\bG\4\2\u01ae\u0091") - buf.write("\3\2\2\2\u01af\u01b0\7,\2\2\u01b0\u01b1\7+\2\2\u01b1\u01b2") - buf.write("\3\2\2\2\u01b2\u01b3\bH\6\2\u01b3\u0093\3\2\2\2\u01b4") - buf.write("\u01b6\5\62\30\2\u01b5\u01b4\3\2\2\2\u01b6\u01b9\3\2\2") - buf.write("\2\u01b7\u01b5\3\2\2\2\u01b7\u01b8\3\2\2\2\u01b8\u01ba") - buf.write("\3\2\2\2\u01b9\u01b7\3\2\2\2\u01ba\u01bb\7^\2\2\u01bb") - buf.write("\u01bc\7\17\2\2\u01bc\u01bd\7\f\2\2\u01bd\u0095\3\2\2") - buf.write("\2\u01be\u01c0\5\62\30\2\u01bf\u01be\3\2\2\2\u01c0\u01c3") - buf.write("\3\2\2\2\u01c1\u01bf\3\2\2\2\u01c1\u01c2\3\2\2\2\u01c2") - buf.write("\u01c4\3\2\2\2\u01c3\u01c1\3\2\2\2\u01c4\u01c5\7$\2\2") - buf.write("\u01c5\u01c6\3\2\2\2\u01c6\u01c7\bJ\6\2\u01c7\u0097\3") - buf.write("\2\2\2\u01c8\u01cc\5\64\31\2\u01c9\u01cb\5\u0094I\2\u01ca") - buf.write("\u01c9\3\2\2\2\u01cb\u01ce\3\2\2\2\u01cc\u01ca\3\2\2\2") - buf.write("\u01cc\u01cd\3\2\2\2\u01cd\u01cf\3\2\2\2\u01ce\u01cc\3") - buf.write("\2\2\2\u01cf\u01d0\5\u0096J\2\u01d0\u0099\3\2\2\2\u01d1") - buf.write("\u01d2\5\62\30\2\u01d2\u009b\3\2\2\2\u01d3\u01d4\7$\2") - buf.write("\2\u01d4\u01d5\3\2\2\2\u01d5\u01d6\bM\6\2\u01d6\u009d") - buf.write("\3\2\2\2\26\2\3\4\5\u00fd\u0103\u010e\u0114\u0120\u0126") - buf.write("\u012d\u017e\u018b\u0195\u0199\u01a9\u01ab\u01b7\u01c1") - buf.write("\u01cc\7\7\5\2\7\4\2\b\2\2\7\3\2\6\2\2") + buf.write("\3\25\3\25\5\25\u00fe\n\25\3\26\3\26\3\26\3\26\3\27\3") + buf.write("\27\3\27\3\27\3\27\3\27\3\27\5\27\u010b\n\27\3\30\3\30") + buf.write("\5\30\u010f\n\30\3\31\3\31\7\31\u0113\n\31\f\31\16\31") + buf.write("\u0116\13\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32\6\32\u011f") + buf.write("\n\32\r\32\16\32\u0120\3\33\3\33\7\33\u0125\n\33\f\33") + buf.write("\16\33\u0128\13\33\3\34\3\34\7\34\u012c\n\34\f\34\16\34") + buf.write("\u012f\13\34\3\35\3\35\3\35\3\36\3\36\3\36\3\37\3\37\3") + buf.write(" \3 \3!\3!\3\"\3\"\3#\3#\3$\3$\3$\3%\3%\3&\3&\3\'\3\'") + buf.write("\3(\3(\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60") + buf.write("\3\60\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65") + buf.write("\3\66\3\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<\3<\3=") + buf.write("\3=\3>\3>\3?\3?\3@\3@\3A\3A\3A\5A\u017f\nA\3B\3B\3B\3") + buf.write("B\3B\3B\3C\3C\3D\6D\u018a\nD\rD\16D\u018b\3D\3D\3E\3E") + buf.write("\3E\3E\7E\u0194\nE\fE\16E\u0197\13E\3E\5E\u019a\nE\3E") + buf.write("\3E\3F\3F\3F\3F\3F\3G\3G\3G\3G\3G\6G\u01a8\nG\rG\16G\u01a9") + buf.write("\5G\u01ac\nG\3G\3G\3H\3H\3H\3H\3H\3I\7I\u01b6\nI\fI\16") + buf.write("I\u01b9\13I\3I\3I\3I\3I\3J\7J\u01c0\nJ\fJ\16J\u01c3\13") + buf.write("J\3J\3J\3J\3J\3K\3K\7K\u01cb\nK\fK\16K\u01ce\13K\3K\3") + buf.write("K\3L\6L\u01d3\nL\rL\16L\u01d4\3M\3M\3M\3M\3\u01a9\2N\6") + buf.write("\3\b\4\n\5\f\6\16\7\20\b\22\t\24\n\26\13\30\f\32\r\34") + buf.write("\16\36\17 \20\"\21$\22&\23(\24*\25,\26.\27\60\30\62\2") + buf.write("\64\31\66\328\33:\34<\35>\36@\37B D!F\"H#J$L%N&P\'R(T") + buf.write(")V*X+Z,\\-^.`/b\2d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2") + buf.write("|\2~\2\u0080\2\u0082\2\u0084\2\u0086\2\u0088\2\u008a\60") + buf.write("\u008c\61\u008e\62\u0090\63\u0092\64\u0094\65\u0096\66") + buf.write("\u0098\67\u009a8\u009c9\6\2\3\4\5\34\6\2\2\2\f\f\17\17") + buf.write("$$\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEe") + buf.write("e\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2") + buf.write("PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4") + buf.write("\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2") + buf.write("\13\f\16\17\"\"\3\2\f\f\2\u01d2\2\6\3\2\2\2\2\b\3\2\2") + buf.write("\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16\3\2\2\2\2\20\3\2\2\2\2") + buf.write("\22\3\2\2\2\2\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32") + buf.write("\3\2\2\2\2\34\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2") + buf.write("\2\2\2$\3\2\2\2\2&\3\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3") + buf.write("\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2") + buf.write("\2\28\3\2\2\2\2:\3\2\2\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2") + buf.write("\2\2\2B\3\2\2\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3") + buf.write("\2\2\2\2L\3\2\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T") + buf.write("\3\2\2\2\2V\3\2\2\2\2X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2") + buf.write("\2^\3\2\2\2\2`\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2") + buf.write("\2\u008e\3\2\2\2\3\u0090\3\2\2\2\3\u0092\3\2\2\2\4\u0094") + buf.write("\3\2\2\2\4\u0096\3\2\2\2\4\u0098\3\2\2\2\5\u009a\3\2\2") + buf.write("\2\5\u009c\3\2\2\2\6\u009e\3\2\2\2\b\u00a4\3\2\2\2\n\u00a9") + buf.write("\3\2\2\2\f\u00af\3\2\2\2\16\u00b2\3\2\2\2\20\u00b5\3\2") + buf.write("\2\2\22\u00b8\3\2\2\2\24\u00c1\3\2\2\2\26\u00c8\3\2\2") + buf.write("\2\30\u00cc\3\2\2\2\32\u00d1\3\2\2\2\34\u00d6\3\2\2\2") + buf.write("\36\u00db\3\2\2\2 \u00e1\3\2\2\2\"\u00e6\3\2\2\2$\u00eb") + buf.write("\3\2\2\2&\u00ef\3\2\2\2(\u00f2\3\2\2\2*\u00f6\3\2\2\2") + buf.write(",\u00fd\3\2\2\2.\u00ff\3\2\2\2\60\u010a\3\2\2\2\62\u010e") + buf.write("\3\2\2\2\64\u0110\3\2\2\2\66\u011e\3\2\2\28\u0122\3\2") + buf.write("\2\2:\u0129\3\2\2\2<\u0130\3\2\2\2>\u0133\3\2\2\2@\u0136") + buf.write("\3\2\2\2B\u0138\3\2\2\2D\u013a\3\2\2\2F\u013c\3\2\2\2") + buf.write("H\u013e\3\2\2\2J\u0140\3\2\2\2L\u0143\3\2\2\2N\u0145\3") + buf.write("\2\2\2P\u0147\3\2\2\2R\u0149\3\2\2\2T\u014b\3\2\2\2V\u014d") + buf.write("\3\2\2\2X\u014f\3\2\2\2Z\u0151\3\2\2\2\\\u0153\3\2\2\2") + buf.write("^\u0155\3\2\2\2`\u0157\3\2\2\2b\u0159\3\2\2\2d\u015b\3") + buf.write("\2\2\2f\u015d\3\2\2\2h\u015f\3\2\2\2j\u0161\3\2\2\2l\u0163") + buf.write("\3\2\2\2n\u0165\3\2\2\2p\u0167\3\2\2\2r\u0169\3\2\2\2") + buf.write("t\u016b\3\2\2\2v\u016d\3\2\2\2x\u016f\3\2\2\2z\u0171\3") + buf.write("\2\2\2|\u0173\3\2\2\2~\u0175\3\2\2\2\u0080\u0177\3\2\2") + buf.write("\2\u0082\u0179\3\2\2\2\u0084\u017b\3\2\2\2\u0086\u0180") + buf.write("\3\2\2\2\u0088\u0186\3\2\2\2\u008a\u0189\3\2\2\2\u008c") + buf.write("\u018f\3\2\2\2\u008e\u019d\3\2\2\2\u0090\u01ab\3\2\2\2") + buf.write("\u0092\u01af\3\2\2\2\u0094\u01b7\3\2\2\2\u0096\u01c1\3") + buf.write("\2\2\2\u0098\u01c8\3\2\2\2\u009a\u01d2\3\2\2\2\u009c\u01d6") + buf.write("\3\2\2\2\u009e\u009f\5d\61\2\u009f\u00a0\5p\67\2\u00a0") + buf.write("\u00a1\5b\60\2\u00a1\u00a2\5z<\2\u00a2\u00a3\5z<\2\u00a3") + buf.write("\7\3\2\2\2\u00a4\u00a5\5h\63\2\u00a5\u00a6\5p\67\2\u00a6") + buf.write("\u00a7\5z<\2\u00a7\u00a8\5h\63\2\u00a8\t\3\2\2\2\u00a9") + buf.write("\u00aa\7h\2\2\u00aa\u00ab\5b\60\2\u00ab\u00ac\5p\67\2") + buf.write("\u00ac\u00ad\5z<\2\u00ad\u00ae\5h\63\2\u00ae\13\3\2\2") + buf.write("\2\u00af\u00b0\5j\64\2\u00b0\u00b1\5n\66\2\u00b1\r\3\2") + buf.write("\2\2\u00b2\u00b3\5n\66\2\u00b3\u00b4\5j\64\2\u00b4\17") + buf.write("\3\2\2\2\u00b5\u00b6\5n\66\2\u00b6\u00b7\5r8\2\u00b7\21") + buf.write("\3\2\2\2\u00b8\u00b9\5n\66\2\u00b9\u00ba\5r8\2\u00ba\u00bb") + buf.write("\5l\65\2\u00bb\u00bc\5h\63\2\u00bc\u00bd\5x;\2\u00bd\u00be") + buf.write("\5n\66\2\u00be\u00bf\5|=\2\u00bf\u00c0\5z<\2\u00c0\23") + buf.write("\3\2\2\2\u00c1\u00c2\5n\66\2\u00c2\u00c3\5z<\2\u00c3\u00c4") + buf.write("\5\u0080?\2\u00c4\u00c5\5t9\2\u00c5\u00c6\5n\66\2\u00c6") + buf.write("\u00c7\5f\62\2\u00c7\25\3\2\2\2\u00c8\u00c9\5p\67\2\u00c9") + buf.write("\u00ca\5h\63\2\u00ca\u00cb\5|=\2\u00cb\27\3\2\2\2\u00cc") + buf.write("\u00cd\5p\67\2\u00cd\u00ce\5t9\2\u00ce\u00cf\5t9\2\u00cf") + buf.write("\u00d0\5v:\2\u00d0\31\3\2\2\2\u00d1\u00d2\5v:\2\u00d2") + buf.write("\u00d3\5t9\2\u00d3\u00d4\5t9\2\u00d4\u00d5\5p\67\2\u00d5") + buf.write("\33\3\2\2\2\u00d6\u00d7\5|=\2\u00d7\u00d8\5l\65\2\u00d8") + buf.write("\u00d9\5h\63\2\u00d9\u00da\5r8\2\u00da\35\3\2\2\2\u00db") + buf.write("\u00dc\5\u0082@\2\u00dc\u00dd\5l\65\2\u00dd\u00de\5n\66") + buf.write("\2\u00de\u00df\5p\67\2\u00df\u00e0\5h\63\2\u00e0\37\3") + buf.write("\2\2\2\u00e1\u00e2\5d\61\2\u00e2\u00e3\5b\60\2\u00e3\u00e4") + buf.write("\5z<\2\u00e4\u00e5\5h\63\2\u00e5!\3\2\2\2\u00e6\u00e7") + buf.write("\5h\63\2\u00e7\u00e8\5z<\2\u00e8\u00e9\5b\60\2\u00e9\u00ea") + buf.write("\5d\61\2\u00ea#\3\2\2\2\u00eb\u00ec\5r8\2\u00ec\u00ed") + buf.write("\5h\63\2\u00ed\u00ee\5\u0082@\2\u00ee%\3\2\2\2\u00ef\u00f0") + buf.write("\5t9\2\u00f0\u00f1\5j\64\2\u00f1\'\3\2\2\2\u00f2\u00f3") + buf.write("\5r8\2\u00f3\u00f4\5t9\2\u00f4\u00f5\5|=\2\u00f5)\3\2") + buf.write("\2\2\u00f6\u00f7\7v\2\2\u00f7\u00f8\5x;\2\u00f8\u00f9") + buf.write("\5~>\2\u00f9\u00fa\5h\63\2\u00fa+\3\2\2\2\u00fb\u00fe") + buf.write("\5\60\27\2\u00fc\u00fe\5\u0098K\2\u00fd\u00fb\3\2\2\2") + buf.write("\u00fd\u00fc\3\2\2\2\u00fe-\3\2\2\2\u00ff\u0100\7$\2\2") + buf.write("\u0100\u0101\3\2\2\2\u0101\u0102\b\26\2\2\u0102/\3\2\2") + buf.write("\2\u0103\u0104\5.\26\2\u0104\u0105\5\u009aL\2\u0105\u0106") + buf.write("\5\u009cM\2\u0106\u010b\3\2\2\2\u0107\u0108\5.\26\2\u0108") + buf.write("\u0109\5\u009cM\2\u0109\u010b\3\2\2\2\u010a\u0103\3\2") + buf.write("\2\2\u010a\u0107\3\2\2\2\u010b\61\3\2\2\2\u010c\u010f") + buf.write("\5\u0084A\2\u010d\u010f\n\2\2\2\u010e\u010c\3\2\2\2\u010e") + buf.write("\u010d\3\2\2\2\u010f\63\3\2\2\2\u0110\u0114\7$\2\2\u0111") + buf.write("\u0113\5\62\30\2\u0112\u0111\3\2\2\2\u0113\u0116\3\2\2") + buf.write("\2\u0114\u0112\3\2\2\2\u0114\u0115\3\2\2\2\u0115\u0117") + buf.write("\3\2\2\2\u0116\u0114\3\2\2\2\u0117\u0118\7^\2\2\u0118") + buf.write("\u0119\7\17\2\2\u0119\u011a\7\f\2\2\u011a\u011b\3\2\2") + buf.write("\2\u011b\u011c\b\31\3\2\u011c\65\3\2\2\2\u011d\u011f\t") + buf.write("\3\2\2\u011e\u011d\3\2\2\2\u011f\u0120\3\2\2\2\u0120\u011e") + buf.write("\3\2\2\2\u0120\u0121\3\2\2\2\u0121\67\3\2\2\2\u0122\u0126") + buf.write("\t\4\2\2\u0123\u0125\t\5\2\2\u0124\u0123\3\2\2\2\u0125") + buf.write("\u0128\3\2\2\2\u0126\u0124\3\2\2\2\u0126\u0127\3\2\2\2") + buf.write("\u01279\3\2\2\2\u0128\u0126\3\2\2\2\u0129\u012d\t\6\2") + buf.write("\2\u012a\u012c\t\5\2\2\u012b\u012a\3\2\2\2\u012c\u012f") + buf.write("\3\2\2\2\u012d\u012b\3\2\2\2\u012d\u012e\3\2\2\2\u012e") + buf.write(";\3\2\2\2\u012f\u012d\3\2\2\2\u0130\u0131\7>\2\2\u0131") + buf.write("\u0132\7/\2\2\u0132=\3\2\2\2\u0133\u0134\7?\2\2\u0134") + buf.write("\u0135\7@\2\2\u0135?\3\2\2\2\u0136\u0137\7-\2\2\u0137") + buf.write("A\3\2\2\2\u0138\u0139\7/\2\2\u0139C\3\2\2\2\u013a\u013b") + buf.write("\7,\2\2\u013bE\3\2\2\2\u013c\u013d\7\61\2\2\u013dG\3\2") + buf.write("\2\2\u013e\u013f\7>\2\2\u013fI\3\2\2\2\u0140\u0141\7>") + buf.write("\2\2\u0141\u0142\7?\2\2\u0142K\3\2\2\2\u0143\u0144\7?") + buf.write("\2\2\u0144M\3\2\2\2\u0145\u0146\7\u0080\2\2\u0146O\3\2") + buf.write("\2\2\u0147\u0148\7*\2\2\u0148Q\3\2\2\2\u0149\u014a\7+") + buf.write("\2\2\u014aS\3\2\2\2\u014b\u014c\7}\2\2\u014cU\3\2\2\2") + buf.write("\u014d\u014e\7\177\2\2\u014eW\3\2\2\2\u014f\u0150\7B\2") + buf.write("\2\u0150Y\3\2\2\2\u0151\u0152\7\60\2\2\u0152[\3\2\2\2") + buf.write("\u0153\u0154\7.\2\2\u0154]\3\2\2\2\u0155\u0156\7<\2\2") + buf.write("\u0156_\3\2\2\2\u0157\u0158\7=\2\2\u0158a\3\2\2\2\u0159") + buf.write("\u015a\t\7\2\2\u015ac\3\2\2\2\u015b\u015c\t\b\2\2\u015c") + buf.write("e\3\2\2\2\u015d\u015e\t\t\2\2\u015eg\3\2\2\2\u015f\u0160") + buf.write("\t\n\2\2\u0160i\3\2\2\2\u0161\u0162\t\13\2\2\u0162k\3") + buf.write("\2\2\2\u0163\u0164\t\f\2\2\u0164m\3\2\2\2\u0165\u0166") + buf.write("\t\r\2\2\u0166o\3\2\2\2\u0167\u0168\t\16\2\2\u0168q\3") + buf.write("\2\2\2\u0169\u016a\t\17\2\2\u016as\3\2\2\2\u016b\u016c") + buf.write("\t\20\2\2\u016cu\3\2\2\2\u016d\u016e\t\21\2\2\u016ew\3") + buf.write("\2\2\2\u016f\u0170\t\22\2\2\u0170y\3\2\2\2\u0171\u0172") + buf.write("\t\23\2\2\u0172{\3\2\2\2\u0173\u0174\t\24\2\2\u0174}\3") + buf.write("\2\2\2\u0175\u0176\t\25\2\2\u0176\177\3\2\2\2\u0177\u0178") + buf.write("\t\26\2\2\u0178\u0081\3\2\2\2\u0179\u017a\t\27\2\2\u017a") + buf.write("\u0083\3\2\2\2\u017b\u017e\7^\2\2\u017c\u017f\t\30\2\2") + buf.write("\u017d\u017f\5\u0086B\2\u017e\u017c\3\2\2\2\u017e\u017d") + buf.write("\3\2\2\2\u017f\u0085\3\2\2\2\u0180\u0181\7w\2\2\u0181") + buf.write("\u0182\5\u0088C\2\u0182\u0183\5\u0088C\2\u0183\u0184\5") + buf.write("\u0088C\2\u0184\u0185\5\u0088C\2\u0185\u0087\3\2\2\2\u0186") + buf.write("\u0187\t\31\2\2\u0187\u0089\3\2\2\2\u0188\u018a\t\32\2") + buf.write("\2\u0189\u0188\3\2\2\2\u018a\u018b\3\2\2\2\u018b\u0189") + buf.write("\3\2\2\2\u018b\u018c\3\2\2\2\u018c\u018d\3\2\2\2\u018d") + buf.write("\u018e\bD\4\2\u018e\u008b\3\2\2\2\u018f\u0190\7/\2\2\u0190") + buf.write("\u0191\7/\2\2\u0191\u0195\3\2\2\2\u0192\u0194\n\33\2\2") + buf.write("\u0193\u0192\3\2\2\2\u0194\u0197\3\2\2\2\u0195\u0193\3") + buf.write("\2\2\2\u0195\u0196\3\2\2\2\u0196\u0199\3\2\2\2\u0197\u0195") + buf.write("\3\2\2\2\u0198\u019a\7\f\2\2\u0199\u0198\3\2\2\2\u0199") + buf.write("\u019a\3\2\2\2\u019a\u019b\3\2\2\2\u019b\u019c\bE\4\2") + buf.write("\u019c\u008d\3\2\2\2\u019d\u019e\7*\2\2\u019e\u019f\7") + buf.write(",\2\2\u019f\u01a0\3\2\2\2\u01a0\u01a1\bF\5\2\u01a1\u008f") + buf.write("\3\2\2\2\u01a2\u01a3\5\u008eF\2\u01a3\u01a4\5\u0090G\2") + buf.write("\u01a4\u01a5\5\u0092H\2\u01a5\u01ac\3\2\2\2\u01a6\u01a8") + buf.write("\13\2\2\2\u01a7\u01a6\3\2\2\2\u01a8\u01a9\3\2\2\2\u01a9") + buf.write("\u01aa\3\2\2\2\u01a9\u01a7\3\2\2\2\u01aa\u01ac\3\2\2\2") + buf.write("\u01ab\u01a2\3\2\2\2\u01ab\u01a7\3\2\2\2\u01ac\u01ad\3") + buf.write("\2\2\2\u01ad\u01ae\bG\4\2\u01ae\u0091\3\2\2\2\u01af\u01b0") + buf.write("\7,\2\2\u01b0\u01b1\7+\2\2\u01b1\u01b2\3\2\2\2\u01b2\u01b3") + buf.write("\bH\6\2\u01b3\u0093\3\2\2\2\u01b4\u01b6\5\62\30\2\u01b5") + buf.write("\u01b4\3\2\2\2\u01b6\u01b9\3\2\2\2\u01b7\u01b5\3\2\2\2") + buf.write("\u01b7\u01b8\3\2\2\2\u01b8\u01ba\3\2\2\2\u01b9\u01b7\3") + buf.write("\2\2\2\u01ba\u01bb\7^\2\2\u01bb\u01bc\7\17\2\2\u01bc\u01bd") + buf.write("\7\f\2\2\u01bd\u0095\3\2\2\2\u01be\u01c0\5\62\30\2\u01bf") + buf.write("\u01be\3\2\2\2\u01c0\u01c3\3\2\2\2\u01c1\u01bf\3\2\2\2") + buf.write("\u01c1\u01c2\3\2\2\2\u01c2\u01c4\3\2\2\2\u01c3\u01c1\3") + buf.write("\2\2\2\u01c4\u01c5\7$\2\2\u01c5\u01c6\3\2\2\2\u01c6\u01c7") + buf.write("\bJ\6\2\u01c7\u0097\3\2\2\2\u01c8\u01cc\5\64\31\2\u01c9") + buf.write("\u01cb\5\u0094I\2\u01ca\u01c9\3\2\2\2\u01cb\u01ce\3\2") + buf.write("\2\2\u01cc\u01ca\3\2\2\2\u01cc\u01cd\3\2\2\2\u01cd\u01cf") + buf.write("\3\2\2\2\u01ce\u01cc\3\2\2\2\u01cf\u01d0\5\u0096J\2\u01d0") + buf.write("\u0099\3\2\2\2\u01d1\u01d3\5\62\30\2\u01d2\u01d1\3\2\2") + buf.write("\2\u01d3\u01d4\3\2\2\2\u01d4\u01d2\3\2\2\2\u01d4\u01d5") + buf.write("\3\2\2\2\u01d5\u009b\3\2\2\2\u01d6\u01d7\7$\2\2\u01d7") + buf.write("\u01d8\3\2\2\2\u01d8\u01d9\bM\6\2\u01d9\u009d\3\2\2\2") + buf.write("\27\2\3\4\5\u00fd\u010a\u010e\u0114\u0120\u0126\u012d") + buf.write("\u017e\u018b\u0195\u0199\u01a9\u01ab\u01b7\u01c1\u01cc") + buf.write("\u01d4\7\7\5\2\7\4\2\b\2\2\7\3\2\6\2\2") return buf.getvalue() @@ -245,8 +247,8 @@ class COOL_LEX(Lexer): NOT = 18 TRUE = 19 STRING = 20 - STRING_SIMPLE = 21 - STRING_SIMPLE_START = 22 + STRING_SIMPLE_START = 21 + STRING_SIMPLE = 22 STRING_FIRSTLINE = 23 INT = 24 TYPEID = 25 @@ -294,7 +296,7 @@ class COOL_LEX(Lexer): symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", - "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", "STRING_SIMPLE_START", + "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE_START", "STRING_SIMPLE", "STRING_FIRSTLINE", "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", @@ -305,8 +307,8 @@ class COOL_LEX(Lexer): ruleNames = [ "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", - "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", - "STRING_SIMPLE_START", "STRING_CONTENT", "STRING_FIRSTLINE", + "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE_START", + "STRING_SIMPLE", "STRING_CONTENT", "STRING_FIRSTLINE", "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", diff --git a/src/COOL_LEX.tokens b/src/COOL_LEX.tokens index c7eacfe4..b0899aa4 100644 --- a/src/COOL_LEX.tokens +++ b/src/COOL_LEX.tokens @@ -18,8 +18,8 @@ OF=17 NOT=18 TRUE=19 STRING=20 -STRING_SIMPLE=21 -STRING_SIMPLE_START=22 +STRING_SIMPLE_START=21 +STRING_SIMPLE=22 STRING_FIRSTLINE=23 INT=24 TYPEID=25 From dc91b15bd972afb8d20ca1c8fd720a287c1c585e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 16 Mar 2020 18:54:20 -0400 Subject: [PATCH 13/77] Se arreglo un bug de las cadenas simples --- src/COOLLexer.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/COOLLexer.py b/src/COOLLexer.py index fda56cf1..65fe0f15 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -30,6 +30,7 @@ def notifyListeners(self, e:LexerNoViableAltException): elif text in ['\r', '\n', '\0'] and self._input.getText(start-1, start-1) in ['\r', '\n', '\0']: return; else: + self.popMode() msg = "Unterminated string constant" else: msg = "'" + self.getErrorDisplay(text) + "'" @@ -52,15 +53,25 @@ def nextToken(self): continue elif self._currentToken.type == COOL_LEX.STRING_INNERLINE: continue + elif self._currentToken.type == COOL_LEX.STRING_SIMPLE_START: + continue + elif self._currentToken.type == COOL_LEX.STRING_SIMPLE_CONTENT: + continue else: break if self._currentToken.type == Token.EOF: - if lastToken != None and lastToken.type == COOL_LEX.OPEN_COMMENT: - self._hasErrors = True - listener = self.getErrorListenerDispatch() - listener.syntaxError(self, self._currentToken, self._currentToken.line, self._currentToken.column, - "EOF in comment", None) + if lastToken != None: + if lastToken.type == COOL_LEX.OPEN_COMMENT: + self._hasErrors = True + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, self._currentToken, self._currentToken.line, self._currentToken.column, + "EOF in comment", None) + elif lastToken.type == COOL_LEX.STRING_SIMPLE_START: + self._hasErrors = True + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, self._currentToken, self._currentToken.line, self._currentToken.column, + "EOF in string constant", None) return self._currentToken; def reset(self): From c6f277591c426aa58d087f67aeb7b70281c348a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 16 Mar 2020 19:24:18 -0400 Subject: [PATCH 14/77] Se arreglo otro bug --- src/COOLLexer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/COOLLexer.py b/src/COOLLexer.py index 65fe0f15..4df6933e 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -22,7 +22,7 @@ def notifyListeners(self, e:LexerNoViableAltException): start = self._tokenStartCharIndex stop = self._input.index text = self._input.getText(start, stop) - if self._currentToken.type in [COOL_LEX.STRING, COOL_LEX.STRING_FIRSTLINE, COOL_LEX.STRING_INNERLINE, COOL_LEX.STRING_SIMPLE_START, COOL_LEX.STRING_SIMPLE_CONTENT ] or text[0] == '"': + if self._currentToken.type in [COOL_LEX.STRING_FIRSTLINE, COOL_LEX.STRING_INNERLINE, COOL_LEX.STRING_SIMPLE_START, COOL_LEX.STRING_SIMPLE_CONTENT ] or text[0] == '"': if self._input.data[start] == 0: msg = "String contains null character" elif self.inputStream.size == self.inputStream.index: @@ -67,7 +67,7 @@ def nextToken(self): listener = self.getErrorListenerDispatch() listener.syntaxError(self, self._currentToken, self._currentToken.line, self._currentToken.column, "EOF in comment", None) - elif lastToken.type == COOL_LEX.STRING_SIMPLE_START: + elif lastToken.type in [COOL_LEX.STRING_SIMPLE_START, COOL_LEX.STRING_SIMPLE_CONTENT]: self._hasErrors = True listener = self.getErrorListenerDispatch() listener.syntaxError(self, self._currentToken, self._currentToken.line, self._currentToken.column, From 6e08c090a097e2031098e8e24f724cb854a39464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 16 Mar 2020 19:38:21 -0400 Subject: [PATCH 15/77] =?UTF-8?q?Se=20arregl=C3=B3=20el=20mensaje=20de=20e?= =?UTF-8?q?rror=20del=20lexer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/COOLLexer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/COOLLexer.py b/src/COOLLexer.py index 4df6933e..40b9885b 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -33,7 +33,7 @@ def notifyListeners(self, e:LexerNoViableAltException): self.popMode() msg = "Unterminated string constant" else: - msg = "'" + self.getErrorDisplay(text) + "'" + msg = "ERROR \"" + self.getErrorDisplay(text) + "\"" if self._token == None: line = self.line col= self.column From a618a37794f9551119673f95dc09148e17368558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 16 Mar 2020 20:01:37 -0400 Subject: [PATCH 16/77] =?UTF-8?q?Se=20arregl=C3=B3=20un=20bug=20relacionad?= =?UTF-8?q?o=20con=20la=20diferencia=20en=20el=20EOL=20entre=20Windows=20/?= =?UTF-8?q?=20Linux?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grammar/COOL_LEX.g4 | 4 +- src/COOL_LEX.interp | 2 +- src/COOL_LEX.py | 372 ++++++++++++++++++++++---------------------- 3 files changed, 191 insertions(+), 187 deletions(-) diff --git a/grammar/COOL_LEX.g4 b/grammar/COOL_LEX.g4 index ae23319b..eca3a6ed 100644 --- a/grammar/COOL_LEX.g4 +++ b/grammar/COOL_LEX.g4 @@ -97,7 +97,7 @@ STRING_CONTENT ; STRING_FIRSTLINE - : '"' STRING_CONTENT* '\\\r\n' -> pushMode(MULTILINE_STR) + : '"' STRING_CONTENT* ('\\\r\n' | '\\\n') -> pushMode(MULTILINE_STR) ; INT @@ -297,7 +297,7 @@ CLOSE_COMMENT mode MULTILINE_STR; STRING_INNERLINE - : STRING_CONTENT* '\\\r\n' + : STRING_CONTENT* ('\\\r\n' | '\\\n') ; STRING_LASTLINE diff --git a/src/COOL_LEX.interp b/src/COOL_LEX.interp index d1000fee..4bf1cb28 100644 --- a/src/COOL_LEX.interp +++ b/src/COOL_LEX.interp @@ -203,4 +203,4 @@ MULTILINE_STR SIMPLE_STR atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 57, 474, 8, 1, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 254, 10, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 5, 23, 267, 10, 23, 3, 24, 3, 24, 5, 24, 271, 10, 24, 3, 25, 3, 25, 7, 25, 275, 10, 25, 12, 25, 14, 25, 278, 11, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 6, 26, 287, 10, 26, 13, 26, 14, 26, 288, 3, 27, 3, 27, 7, 27, 293, 10, 27, 12, 27, 14, 27, 296, 11, 27, 3, 28, 3, 28, 7, 28, 300, 10, 28, 12, 28, 14, 28, 303, 11, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 5, 65, 383, 10, 65, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 6, 68, 394, 10, 68, 13, 68, 14, 68, 395, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 7, 69, 404, 10, 69, 12, 69, 14, 69, 407, 11, 69, 3, 69, 5, 69, 410, 10, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 424, 10, 71, 13, 71, 14, 71, 425, 5, 71, 428, 10, 71, 3, 71, 3, 71, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 438, 10, 73, 12, 73, 14, 73, 441, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 7, 74, 448, 10, 74, 12, 74, 14, 74, 451, 11, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 75, 3, 75, 7, 75, 459, 10, 75, 12, 75, 14, 75, 462, 11, 75, 3, 75, 3, 75, 3, 76, 6, 76, 467, 10, 76, 13, 76, 14, 76, 468, 3, 77, 3, 77, 3, 77, 3, 77, 3, 425, 2, 78, 6, 3, 8, 4, 10, 5, 12, 6, 14, 7, 16, 8, 18, 9, 20, 10, 22, 11, 24, 12, 26, 13, 28, 14, 30, 15, 32, 16, 34, 17, 36, 18, 38, 19, 40, 20, 42, 21, 44, 22, 46, 23, 48, 24, 50, 2, 52, 25, 54, 26, 56, 27, 58, 28, 60, 29, 62, 30, 64, 31, 66, 32, 68, 33, 70, 34, 72, 35, 74, 36, 76, 37, 78, 38, 80, 39, 82, 40, 84, 41, 86, 42, 88, 43, 90, 44, 92, 45, 94, 46, 96, 47, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 2, 132, 2, 134, 2, 136, 2, 138, 48, 140, 49, 142, 50, 144, 51, 146, 52, 148, 53, 150, 54, 152, 55, 154, 56, 156, 57, 6, 2, 3, 4, 5, 28, 6, 2, 2, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 466, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 90, 3, 2, 2, 2, 2, 92, 3, 2, 2, 2, 2, 94, 3, 2, 2, 2, 2, 96, 3, 2, 2, 2, 2, 138, 3, 2, 2, 2, 2, 140, 3, 2, 2, 2, 2, 142, 3, 2, 2, 2, 3, 144, 3, 2, 2, 2, 3, 146, 3, 2, 2, 2, 4, 148, 3, 2, 2, 2, 4, 150, 3, 2, 2, 2, 4, 152, 3, 2, 2, 2, 5, 154, 3, 2, 2, 2, 5, 156, 3, 2, 2, 2, 6, 158, 3, 2, 2, 2, 8, 164, 3, 2, 2, 2, 10, 169, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 178, 3, 2, 2, 2, 16, 181, 3, 2, 2, 2, 18, 184, 3, 2, 2, 2, 20, 193, 3, 2, 2, 2, 22, 200, 3, 2, 2, 2, 24, 204, 3, 2, 2, 2, 26, 209, 3, 2, 2, 2, 28, 214, 3, 2, 2, 2, 30, 219, 3, 2, 2, 2, 32, 225, 3, 2, 2, 2, 34, 230, 3, 2, 2, 2, 36, 235, 3, 2, 2, 2, 38, 239, 3, 2, 2, 2, 40, 242, 3, 2, 2, 2, 42, 246, 3, 2, 2, 2, 44, 253, 3, 2, 2, 2, 46, 255, 3, 2, 2, 2, 48, 266, 3, 2, 2, 2, 50, 270, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 286, 3, 2, 2, 2, 56, 290, 3, 2, 2, 2, 58, 297, 3, 2, 2, 2, 60, 304, 3, 2, 2, 2, 62, 307, 3, 2, 2, 2, 64, 310, 3, 2, 2, 2, 66, 312, 3, 2, 2, 2, 68, 314, 3, 2, 2, 2, 70, 316, 3, 2, 2, 2, 72, 318, 3, 2, 2, 2, 74, 320, 3, 2, 2, 2, 76, 323, 3, 2, 2, 2, 78, 325, 3, 2, 2, 2, 80, 327, 3, 2, 2, 2, 82, 329, 3, 2, 2, 2, 84, 331, 3, 2, 2, 2, 86, 333, 3, 2, 2, 2, 88, 335, 3, 2, 2, 2, 90, 337, 3, 2, 2, 2, 92, 339, 3, 2, 2, 2, 94, 341, 3, 2, 2, 2, 96, 343, 3, 2, 2, 2, 98, 345, 3, 2, 2, 2, 100, 347, 3, 2, 2, 2, 102, 349, 3, 2, 2, 2, 104, 351, 3, 2, 2, 2, 106, 353, 3, 2, 2, 2, 108, 355, 3, 2, 2, 2, 110, 357, 3, 2, 2, 2, 112, 359, 3, 2, 2, 2, 114, 361, 3, 2, 2, 2, 116, 363, 3, 2, 2, 2, 118, 365, 3, 2, 2, 2, 120, 367, 3, 2, 2, 2, 122, 369, 3, 2, 2, 2, 124, 371, 3, 2, 2, 2, 126, 373, 3, 2, 2, 2, 128, 375, 3, 2, 2, 2, 130, 377, 3, 2, 2, 2, 132, 379, 3, 2, 2, 2, 134, 384, 3, 2, 2, 2, 136, 390, 3, 2, 2, 2, 138, 393, 3, 2, 2, 2, 140, 399, 3, 2, 2, 2, 142, 413, 3, 2, 2, 2, 144, 427, 3, 2, 2, 2, 146, 431, 3, 2, 2, 2, 148, 439, 3, 2, 2, 2, 150, 449, 3, 2, 2, 2, 152, 456, 3, 2, 2, 2, 154, 466, 3, 2, 2, 2, 156, 470, 3, 2, 2, 2, 158, 159, 5, 100, 49, 2, 159, 160, 5, 112, 55, 2, 160, 161, 5, 98, 48, 2, 161, 162, 5, 122, 60, 2, 162, 163, 5, 122, 60, 2, 163, 7, 3, 2, 2, 2, 164, 165, 5, 104, 51, 2, 165, 166, 5, 112, 55, 2, 166, 167, 5, 122, 60, 2, 167, 168, 5, 104, 51, 2, 168, 9, 3, 2, 2, 2, 169, 170, 7, 104, 2, 2, 170, 171, 5, 98, 48, 2, 171, 172, 5, 112, 55, 2, 172, 173, 5, 122, 60, 2, 173, 174, 5, 104, 51, 2, 174, 11, 3, 2, 2, 2, 175, 176, 5, 106, 52, 2, 176, 177, 5, 110, 54, 2, 177, 13, 3, 2, 2, 2, 178, 179, 5, 110, 54, 2, 179, 180, 5, 106, 52, 2, 180, 15, 3, 2, 2, 2, 181, 182, 5, 110, 54, 2, 182, 183, 5, 114, 56, 2, 183, 17, 3, 2, 2, 2, 184, 185, 5, 110, 54, 2, 185, 186, 5, 114, 56, 2, 186, 187, 5, 108, 53, 2, 187, 188, 5, 104, 51, 2, 188, 189, 5, 120, 59, 2, 189, 190, 5, 110, 54, 2, 190, 191, 5, 124, 61, 2, 191, 192, 5, 122, 60, 2, 192, 19, 3, 2, 2, 2, 193, 194, 5, 110, 54, 2, 194, 195, 5, 122, 60, 2, 195, 196, 5, 128, 63, 2, 196, 197, 5, 116, 57, 2, 197, 198, 5, 110, 54, 2, 198, 199, 5, 102, 50, 2, 199, 21, 3, 2, 2, 2, 200, 201, 5, 112, 55, 2, 201, 202, 5, 104, 51, 2, 202, 203, 5, 124, 61, 2, 203, 23, 3, 2, 2, 2, 204, 205, 5, 112, 55, 2, 205, 206, 5, 116, 57, 2, 206, 207, 5, 116, 57, 2, 207, 208, 5, 118, 58, 2, 208, 25, 3, 2, 2, 2, 209, 210, 5, 118, 58, 2, 210, 211, 5, 116, 57, 2, 211, 212, 5, 116, 57, 2, 212, 213, 5, 112, 55, 2, 213, 27, 3, 2, 2, 2, 214, 215, 5, 124, 61, 2, 215, 216, 5, 108, 53, 2, 216, 217, 5, 104, 51, 2, 217, 218, 5, 114, 56, 2, 218, 29, 3, 2, 2, 2, 219, 220, 5, 130, 64, 2, 220, 221, 5, 108, 53, 2, 221, 222, 5, 110, 54, 2, 222, 223, 5, 112, 55, 2, 223, 224, 5, 104, 51, 2, 224, 31, 3, 2, 2, 2, 225, 226, 5, 100, 49, 2, 226, 227, 5, 98, 48, 2, 227, 228, 5, 122, 60, 2, 228, 229, 5, 104, 51, 2, 229, 33, 3, 2, 2, 2, 230, 231, 5, 104, 51, 2, 231, 232, 5, 122, 60, 2, 232, 233, 5, 98, 48, 2, 233, 234, 5, 100, 49, 2, 234, 35, 3, 2, 2, 2, 235, 236, 5, 114, 56, 2, 236, 237, 5, 104, 51, 2, 237, 238, 5, 130, 64, 2, 238, 37, 3, 2, 2, 2, 239, 240, 5, 116, 57, 2, 240, 241, 5, 106, 52, 2, 241, 39, 3, 2, 2, 2, 242, 243, 5, 114, 56, 2, 243, 244, 5, 116, 57, 2, 244, 245, 5, 124, 61, 2, 245, 41, 3, 2, 2, 2, 246, 247, 7, 118, 2, 2, 247, 248, 5, 120, 59, 2, 248, 249, 5, 126, 62, 2, 249, 250, 5, 104, 51, 2, 250, 43, 3, 2, 2, 2, 251, 254, 5, 48, 23, 2, 252, 254, 5, 152, 75, 2, 253, 251, 3, 2, 2, 2, 253, 252, 3, 2, 2, 2, 254, 45, 3, 2, 2, 2, 255, 256, 7, 36, 2, 2, 256, 257, 3, 2, 2, 2, 257, 258, 8, 22, 2, 2, 258, 47, 3, 2, 2, 2, 259, 260, 5, 46, 22, 2, 260, 261, 5, 154, 76, 2, 261, 262, 5, 156, 77, 2, 262, 267, 3, 2, 2, 2, 263, 264, 5, 46, 22, 2, 264, 265, 5, 156, 77, 2, 265, 267, 3, 2, 2, 2, 266, 259, 3, 2, 2, 2, 266, 263, 3, 2, 2, 2, 267, 49, 3, 2, 2, 2, 268, 271, 5, 132, 65, 2, 269, 271, 10, 2, 2, 2, 270, 268, 3, 2, 2, 2, 270, 269, 3, 2, 2, 2, 271, 51, 3, 2, 2, 2, 272, 276, 7, 36, 2, 2, 273, 275, 5, 50, 24, 2, 274, 273, 3, 2, 2, 2, 275, 278, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 279, 3, 2, 2, 2, 278, 276, 3, 2, 2, 2, 279, 280, 7, 94, 2, 2, 280, 281, 7, 15, 2, 2, 281, 282, 7, 12, 2, 2, 282, 283, 3, 2, 2, 2, 283, 284, 8, 25, 3, 2, 284, 53, 3, 2, 2, 2, 285, 287, 9, 3, 2, 2, 286, 285, 3, 2, 2, 2, 287, 288, 3, 2, 2, 2, 288, 286, 3, 2, 2, 2, 288, 289, 3, 2, 2, 2, 289, 55, 3, 2, 2, 2, 290, 294, 9, 4, 2, 2, 291, 293, 9, 5, 2, 2, 292, 291, 3, 2, 2, 2, 293, 296, 3, 2, 2, 2, 294, 292, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 57, 3, 2, 2, 2, 296, 294, 3, 2, 2, 2, 297, 301, 9, 6, 2, 2, 298, 300, 9, 5, 2, 2, 299, 298, 3, 2, 2, 2, 300, 303, 3, 2, 2, 2, 301, 299, 3, 2, 2, 2, 301, 302, 3, 2, 2, 2, 302, 59, 3, 2, 2, 2, 303, 301, 3, 2, 2, 2, 304, 305, 7, 62, 2, 2, 305, 306, 7, 47, 2, 2, 306, 61, 3, 2, 2, 2, 307, 308, 7, 63, 2, 2, 308, 309, 7, 64, 2, 2, 309, 63, 3, 2, 2, 2, 310, 311, 7, 45, 2, 2, 311, 65, 3, 2, 2, 2, 312, 313, 7, 47, 2, 2, 313, 67, 3, 2, 2, 2, 314, 315, 7, 44, 2, 2, 315, 69, 3, 2, 2, 2, 316, 317, 7, 49, 2, 2, 317, 71, 3, 2, 2, 2, 318, 319, 7, 62, 2, 2, 319, 73, 3, 2, 2, 2, 320, 321, 7, 62, 2, 2, 321, 322, 7, 63, 2, 2, 322, 75, 3, 2, 2, 2, 323, 324, 7, 63, 2, 2, 324, 77, 3, 2, 2, 2, 325, 326, 7, 128, 2, 2, 326, 79, 3, 2, 2, 2, 327, 328, 7, 42, 2, 2, 328, 81, 3, 2, 2, 2, 329, 330, 7, 43, 2, 2, 330, 83, 3, 2, 2, 2, 331, 332, 7, 125, 2, 2, 332, 85, 3, 2, 2, 2, 333, 334, 7, 127, 2, 2, 334, 87, 3, 2, 2, 2, 335, 336, 7, 66, 2, 2, 336, 89, 3, 2, 2, 2, 337, 338, 7, 48, 2, 2, 338, 91, 3, 2, 2, 2, 339, 340, 7, 46, 2, 2, 340, 93, 3, 2, 2, 2, 341, 342, 7, 60, 2, 2, 342, 95, 3, 2, 2, 2, 343, 344, 7, 61, 2, 2, 344, 97, 3, 2, 2, 2, 345, 346, 9, 7, 2, 2, 346, 99, 3, 2, 2, 2, 347, 348, 9, 8, 2, 2, 348, 101, 3, 2, 2, 2, 349, 350, 9, 9, 2, 2, 350, 103, 3, 2, 2, 2, 351, 352, 9, 10, 2, 2, 352, 105, 3, 2, 2, 2, 353, 354, 9, 11, 2, 2, 354, 107, 3, 2, 2, 2, 355, 356, 9, 12, 2, 2, 356, 109, 3, 2, 2, 2, 357, 358, 9, 13, 2, 2, 358, 111, 3, 2, 2, 2, 359, 360, 9, 14, 2, 2, 360, 113, 3, 2, 2, 2, 361, 362, 9, 15, 2, 2, 362, 115, 3, 2, 2, 2, 363, 364, 9, 16, 2, 2, 364, 117, 3, 2, 2, 2, 365, 366, 9, 17, 2, 2, 366, 119, 3, 2, 2, 2, 367, 368, 9, 18, 2, 2, 368, 121, 3, 2, 2, 2, 369, 370, 9, 19, 2, 2, 370, 123, 3, 2, 2, 2, 371, 372, 9, 20, 2, 2, 372, 125, 3, 2, 2, 2, 373, 374, 9, 21, 2, 2, 374, 127, 3, 2, 2, 2, 375, 376, 9, 22, 2, 2, 376, 129, 3, 2, 2, 2, 377, 378, 9, 23, 2, 2, 378, 131, 3, 2, 2, 2, 379, 382, 7, 94, 2, 2, 380, 383, 9, 24, 2, 2, 381, 383, 5, 134, 66, 2, 382, 380, 3, 2, 2, 2, 382, 381, 3, 2, 2, 2, 383, 133, 3, 2, 2, 2, 384, 385, 7, 119, 2, 2, 385, 386, 5, 136, 67, 2, 386, 387, 5, 136, 67, 2, 387, 388, 5, 136, 67, 2, 388, 389, 5, 136, 67, 2, 389, 135, 3, 2, 2, 2, 390, 391, 9, 25, 2, 2, 391, 137, 3, 2, 2, 2, 392, 394, 9, 26, 2, 2, 393, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 393, 3, 2, 2, 2, 395, 396, 3, 2, 2, 2, 396, 397, 3, 2, 2, 2, 397, 398, 8, 68, 4, 2, 398, 139, 3, 2, 2, 2, 399, 400, 7, 47, 2, 2, 400, 401, 7, 47, 2, 2, 401, 405, 3, 2, 2, 2, 402, 404, 10, 27, 2, 2, 403, 402, 3, 2, 2, 2, 404, 407, 3, 2, 2, 2, 405, 403, 3, 2, 2, 2, 405, 406, 3, 2, 2, 2, 406, 409, 3, 2, 2, 2, 407, 405, 3, 2, 2, 2, 408, 410, 7, 12, 2, 2, 409, 408, 3, 2, 2, 2, 409, 410, 3, 2, 2, 2, 410, 411, 3, 2, 2, 2, 411, 412, 8, 69, 4, 2, 412, 141, 3, 2, 2, 2, 413, 414, 7, 42, 2, 2, 414, 415, 7, 44, 2, 2, 415, 416, 3, 2, 2, 2, 416, 417, 8, 70, 5, 2, 417, 143, 3, 2, 2, 2, 418, 419, 5, 142, 70, 2, 419, 420, 5, 144, 71, 2, 420, 421, 5, 146, 72, 2, 421, 428, 3, 2, 2, 2, 422, 424, 11, 2, 2, 2, 423, 422, 3, 2, 2, 2, 424, 425, 3, 2, 2, 2, 425, 426, 3, 2, 2, 2, 425, 423, 3, 2, 2, 2, 426, 428, 3, 2, 2, 2, 427, 418, 3, 2, 2, 2, 427, 423, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 430, 8, 71, 4, 2, 430, 145, 3, 2, 2, 2, 431, 432, 7, 44, 2, 2, 432, 433, 7, 43, 2, 2, 433, 434, 3, 2, 2, 2, 434, 435, 8, 72, 6, 2, 435, 147, 3, 2, 2, 2, 436, 438, 5, 50, 24, 2, 437, 436, 3, 2, 2, 2, 438, 441, 3, 2, 2, 2, 439, 437, 3, 2, 2, 2, 439, 440, 3, 2, 2, 2, 440, 442, 3, 2, 2, 2, 441, 439, 3, 2, 2, 2, 442, 443, 7, 94, 2, 2, 443, 444, 7, 15, 2, 2, 444, 445, 7, 12, 2, 2, 445, 149, 3, 2, 2, 2, 446, 448, 5, 50, 24, 2, 447, 446, 3, 2, 2, 2, 448, 451, 3, 2, 2, 2, 449, 447, 3, 2, 2, 2, 449, 450, 3, 2, 2, 2, 450, 452, 3, 2, 2, 2, 451, 449, 3, 2, 2, 2, 452, 453, 7, 36, 2, 2, 453, 454, 3, 2, 2, 2, 454, 455, 8, 74, 6, 2, 455, 151, 3, 2, 2, 2, 456, 460, 5, 52, 25, 2, 457, 459, 5, 148, 73, 2, 458, 457, 3, 2, 2, 2, 459, 462, 3, 2, 2, 2, 460, 458, 3, 2, 2, 2, 460, 461, 3, 2, 2, 2, 461, 463, 3, 2, 2, 2, 462, 460, 3, 2, 2, 2, 463, 464, 5, 150, 74, 2, 464, 153, 3, 2, 2, 2, 465, 467, 5, 50, 24, 2, 466, 465, 3, 2, 2, 2, 467, 468, 3, 2, 2, 2, 468, 466, 3, 2, 2, 2, 468, 469, 3, 2, 2, 2, 469, 155, 3, 2, 2, 2, 470, 471, 7, 36, 2, 2, 471, 472, 3, 2, 2, 2, 472, 473, 8, 77, 6, 2, 473, 157, 3, 2, 2, 2, 23, 2, 3, 4, 5, 253, 266, 270, 276, 288, 294, 301, 382, 395, 405, 409, 425, 427, 439, 449, 460, 468, 7, 7, 5, 2, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 57, 480, 8, 1, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 254, 10, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 5, 23, 267, 10, 23, 3, 24, 3, 24, 5, 24, 271, 10, 24, 3, 25, 3, 25, 7, 25, 275, 10, 25, 12, 25, 14, 25, 278, 11, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 5, 25, 285, 10, 25, 3, 25, 3, 25, 3, 26, 6, 26, 290, 10, 26, 13, 26, 14, 26, 291, 3, 27, 3, 27, 7, 27, 296, 10, 27, 12, 27, 14, 27, 299, 11, 27, 3, 28, 3, 28, 7, 28, 303, 10, 28, 12, 28, 14, 28, 306, 11, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 5, 65, 386, 10, 65, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 6, 68, 397, 10, 68, 13, 68, 14, 68, 398, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 7, 69, 407, 10, 69, 12, 69, 14, 69, 410, 11, 69, 3, 69, 5, 69, 413, 10, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 427, 10, 71, 13, 71, 14, 71, 428, 5, 71, 431, 10, 71, 3, 71, 3, 71, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 441, 10, 73, 12, 73, 14, 73, 444, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 73, 5, 73, 451, 10, 73, 3, 74, 7, 74, 454, 10, 74, 12, 74, 14, 74, 457, 11, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 75, 3, 75, 7, 75, 465, 10, 75, 12, 75, 14, 75, 468, 11, 75, 3, 75, 3, 75, 3, 76, 6, 76, 473, 10, 76, 13, 76, 14, 76, 474, 3, 77, 3, 77, 3, 77, 3, 77, 3, 428, 2, 78, 6, 3, 8, 4, 10, 5, 12, 6, 14, 7, 16, 8, 18, 9, 20, 10, 22, 11, 24, 12, 26, 13, 28, 14, 30, 15, 32, 16, 34, 17, 36, 18, 38, 19, 40, 20, 42, 21, 44, 22, 46, 23, 48, 24, 50, 2, 52, 25, 54, 26, 56, 27, 58, 28, 60, 29, 62, 30, 64, 31, 66, 32, 68, 33, 70, 34, 72, 35, 74, 36, 76, 37, 78, 38, 80, 39, 82, 40, 84, 41, 86, 42, 88, 43, 90, 44, 92, 45, 94, 46, 96, 47, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 2, 132, 2, 134, 2, 136, 2, 138, 48, 140, 49, 142, 50, 144, 51, 146, 52, 148, 53, 150, 54, 152, 55, 154, 56, 156, 57, 6, 2, 3, 4, 5, 28, 6, 2, 2, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 474, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 90, 3, 2, 2, 2, 2, 92, 3, 2, 2, 2, 2, 94, 3, 2, 2, 2, 2, 96, 3, 2, 2, 2, 2, 138, 3, 2, 2, 2, 2, 140, 3, 2, 2, 2, 2, 142, 3, 2, 2, 2, 3, 144, 3, 2, 2, 2, 3, 146, 3, 2, 2, 2, 4, 148, 3, 2, 2, 2, 4, 150, 3, 2, 2, 2, 4, 152, 3, 2, 2, 2, 5, 154, 3, 2, 2, 2, 5, 156, 3, 2, 2, 2, 6, 158, 3, 2, 2, 2, 8, 164, 3, 2, 2, 2, 10, 169, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 178, 3, 2, 2, 2, 16, 181, 3, 2, 2, 2, 18, 184, 3, 2, 2, 2, 20, 193, 3, 2, 2, 2, 22, 200, 3, 2, 2, 2, 24, 204, 3, 2, 2, 2, 26, 209, 3, 2, 2, 2, 28, 214, 3, 2, 2, 2, 30, 219, 3, 2, 2, 2, 32, 225, 3, 2, 2, 2, 34, 230, 3, 2, 2, 2, 36, 235, 3, 2, 2, 2, 38, 239, 3, 2, 2, 2, 40, 242, 3, 2, 2, 2, 42, 246, 3, 2, 2, 2, 44, 253, 3, 2, 2, 2, 46, 255, 3, 2, 2, 2, 48, 266, 3, 2, 2, 2, 50, 270, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 289, 3, 2, 2, 2, 56, 293, 3, 2, 2, 2, 58, 300, 3, 2, 2, 2, 60, 307, 3, 2, 2, 2, 62, 310, 3, 2, 2, 2, 64, 313, 3, 2, 2, 2, 66, 315, 3, 2, 2, 2, 68, 317, 3, 2, 2, 2, 70, 319, 3, 2, 2, 2, 72, 321, 3, 2, 2, 2, 74, 323, 3, 2, 2, 2, 76, 326, 3, 2, 2, 2, 78, 328, 3, 2, 2, 2, 80, 330, 3, 2, 2, 2, 82, 332, 3, 2, 2, 2, 84, 334, 3, 2, 2, 2, 86, 336, 3, 2, 2, 2, 88, 338, 3, 2, 2, 2, 90, 340, 3, 2, 2, 2, 92, 342, 3, 2, 2, 2, 94, 344, 3, 2, 2, 2, 96, 346, 3, 2, 2, 2, 98, 348, 3, 2, 2, 2, 100, 350, 3, 2, 2, 2, 102, 352, 3, 2, 2, 2, 104, 354, 3, 2, 2, 2, 106, 356, 3, 2, 2, 2, 108, 358, 3, 2, 2, 2, 110, 360, 3, 2, 2, 2, 112, 362, 3, 2, 2, 2, 114, 364, 3, 2, 2, 2, 116, 366, 3, 2, 2, 2, 118, 368, 3, 2, 2, 2, 120, 370, 3, 2, 2, 2, 122, 372, 3, 2, 2, 2, 124, 374, 3, 2, 2, 2, 126, 376, 3, 2, 2, 2, 128, 378, 3, 2, 2, 2, 130, 380, 3, 2, 2, 2, 132, 382, 3, 2, 2, 2, 134, 387, 3, 2, 2, 2, 136, 393, 3, 2, 2, 2, 138, 396, 3, 2, 2, 2, 140, 402, 3, 2, 2, 2, 142, 416, 3, 2, 2, 2, 144, 430, 3, 2, 2, 2, 146, 434, 3, 2, 2, 2, 148, 442, 3, 2, 2, 2, 150, 455, 3, 2, 2, 2, 152, 462, 3, 2, 2, 2, 154, 472, 3, 2, 2, 2, 156, 476, 3, 2, 2, 2, 158, 159, 5, 100, 49, 2, 159, 160, 5, 112, 55, 2, 160, 161, 5, 98, 48, 2, 161, 162, 5, 122, 60, 2, 162, 163, 5, 122, 60, 2, 163, 7, 3, 2, 2, 2, 164, 165, 5, 104, 51, 2, 165, 166, 5, 112, 55, 2, 166, 167, 5, 122, 60, 2, 167, 168, 5, 104, 51, 2, 168, 9, 3, 2, 2, 2, 169, 170, 7, 104, 2, 2, 170, 171, 5, 98, 48, 2, 171, 172, 5, 112, 55, 2, 172, 173, 5, 122, 60, 2, 173, 174, 5, 104, 51, 2, 174, 11, 3, 2, 2, 2, 175, 176, 5, 106, 52, 2, 176, 177, 5, 110, 54, 2, 177, 13, 3, 2, 2, 2, 178, 179, 5, 110, 54, 2, 179, 180, 5, 106, 52, 2, 180, 15, 3, 2, 2, 2, 181, 182, 5, 110, 54, 2, 182, 183, 5, 114, 56, 2, 183, 17, 3, 2, 2, 2, 184, 185, 5, 110, 54, 2, 185, 186, 5, 114, 56, 2, 186, 187, 5, 108, 53, 2, 187, 188, 5, 104, 51, 2, 188, 189, 5, 120, 59, 2, 189, 190, 5, 110, 54, 2, 190, 191, 5, 124, 61, 2, 191, 192, 5, 122, 60, 2, 192, 19, 3, 2, 2, 2, 193, 194, 5, 110, 54, 2, 194, 195, 5, 122, 60, 2, 195, 196, 5, 128, 63, 2, 196, 197, 5, 116, 57, 2, 197, 198, 5, 110, 54, 2, 198, 199, 5, 102, 50, 2, 199, 21, 3, 2, 2, 2, 200, 201, 5, 112, 55, 2, 201, 202, 5, 104, 51, 2, 202, 203, 5, 124, 61, 2, 203, 23, 3, 2, 2, 2, 204, 205, 5, 112, 55, 2, 205, 206, 5, 116, 57, 2, 206, 207, 5, 116, 57, 2, 207, 208, 5, 118, 58, 2, 208, 25, 3, 2, 2, 2, 209, 210, 5, 118, 58, 2, 210, 211, 5, 116, 57, 2, 211, 212, 5, 116, 57, 2, 212, 213, 5, 112, 55, 2, 213, 27, 3, 2, 2, 2, 214, 215, 5, 124, 61, 2, 215, 216, 5, 108, 53, 2, 216, 217, 5, 104, 51, 2, 217, 218, 5, 114, 56, 2, 218, 29, 3, 2, 2, 2, 219, 220, 5, 130, 64, 2, 220, 221, 5, 108, 53, 2, 221, 222, 5, 110, 54, 2, 222, 223, 5, 112, 55, 2, 223, 224, 5, 104, 51, 2, 224, 31, 3, 2, 2, 2, 225, 226, 5, 100, 49, 2, 226, 227, 5, 98, 48, 2, 227, 228, 5, 122, 60, 2, 228, 229, 5, 104, 51, 2, 229, 33, 3, 2, 2, 2, 230, 231, 5, 104, 51, 2, 231, 232, 5, 122, 60, 2, 232, 233, 5, 98, 48, 2, 233, 234, 5, 100, 49, 2, 234, 35, 3, 2, 2, 2, 235, 236, 5, 114, 56, 2, 236, 237, 5, 104, 51, 2, 237, 238, 5, 130, 64, 2, 238, 37, 3, 2, 2, 2, 239, 240, 5, 116, 57, 2, 240, 241, 5, 106, 52, 2, 241, 39, 3, 2, 2, 2, 242, 243, 5, 114, 56, 2, 243, 244, 5, 116, 57, 2, 244, 245, 5, 124, 61, 2, 245, 41, 3, 2, 2, 2, 246, 247, 7, 118, 2, 2, 247, 248, 5, 120, 59, 2, 248, 249, 5, 126, 62, 2, 249, 250, 5, 104, 51, 2, 250, 43, 3, 2, 2, 2, 251, 254, 5, 48, 23, 2, 252, 254, 5, 152, 75, 2, 253, 251, 3, 2, 2, 2, 253, 252, 3, 2, 2, 2, 254, 45, 3, 2, 2, 2, 255, 256, 7, 36, 2, 2, 256, 257, 3, 2, 2, 2, 257, 258, 8, 22, 2, 2, 258, 47, 3, 2, 2, 2, 259, 260, 5, 46, 22, 2, 260, 261, 5, 154, 76, 2, 261, 262, 5, 156, 77, 2, 262, 267, 3, 2, 2, 2, 263, 264, 5, 46, 22, 2, 264, 265, 5, 156, 77, 2, 265, 267, 3, 2, 2, 2, 266, 259, 3, 2, 2, 2, 266, 263, 3, 2, 2, 2, 267, 49, 3, 2, 2, 2, 268, 271, 5, 132, 65, 2, 269, 271, 10, 2, 2, 2, 270, 268, 3, 2, 2, 2, 270, 269, 3, 2, 2, 2, 271, 51, 3, 2, 2, 2, 272, 276, 7, 36, 2, 2, 273, 275, 5, 50, 24, 2, 274, 273, 3, 2, 2, 2, 275, 278, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 284, 3, 2, 2, 2, 278, 276, 3, 2, 2, 2, 279, 280, 7, 94, 2, 2, 280, 281, 7, 15, 2, 2, 281, 285, 7, 12, 2, 2, 282, 283, 7, 94, 2, 2, 283, 285, 7, 12, 2, 2, 284, 279, 3, 2, 2, 2, 284, 282, 3, 2, 2, 2, 285, 286, 3, 2, 2, 2, 286, 287, 8, 25, 3, 2, 287, 53, 3, 2, 2, 2, 288, 290, 9, 3, 2, 2, 289, 288, 3, 2, 2, 2, 290, 291, 3, 2, 2, 2, 291, 289, 3, 2, 2, 2, 291, 292, 3, 2, 2, 2, 292, 55, 3, 2, 2, 2, 293, 297, 9, 4, 2, 2, 294, 296, 9, 5, 2, 2, 295, 294, 3, 2, 2, 2, 296, 299, 3, 2, 2, 2, 297, 295, 3, 2, 2, 2, 297, 298, 3, 2, 2, 2, 298, 57, 3, 2, 2, 2, 299, 297, 3, 2, 2, 2, 300, 304, 9, 6, 2, 2, 301, 303, 9, 5, 2, 2, 302, 301, 3, 2, 2, 2, 303, 306, 3, 2, 2, 2, 304, 302, 3, 2, 2, 2, 304, 305, 3, 2, 2, 2, 305, 59, 3, 2, 2, 2, 306, 304, 3, 2, 2, 2, 307, 308, 7, 62, 2, 2, 308, 309, 7, 47, 2, 2, 309, 61, 3, 2, 2, 2, 310, 311, 7, 63, 2, 2, 311, 312, 7, 64, 2, 2, 312, 63, 3, 2, 2, 2, 313, 314, 7, 45, 2, 2, 314, 65, 3, 2, 2, 2, 315, 316, 7, 47, 2, 2, 316, 67, 3, 2, 2, 2, 317, 318, 7, 44, 2, 2, 318, 69, 3, 2, 2, 2, 319, 320, 7, 49, 2, 2, 320, 71, 3, 2, 2, 2, 321, 322, 7, 62, 2, 2, 322, 73, 3, 2, 2, 2, 323, 324, 7, 62, 2, 2, 324, 325, 7, 63, 2, 2, 325, 75, 3, 2, 2, 2, 326, 327, 7, 63, 2, 2, 327, 77, 3, 2, 2, 2, 328, 329, 7, 128, 2, 2, 329, 79, 3, 2, 2, 2, 330, 331, 7, 42, 2, 2, 331, 81, 3, 2, 2, 2, 332, 333, 7, 43, 2, 2, 333, 83, 3, 2, 2, 2, 334, 335, 7, 125, 2, 2, 335, 85, 3, 2, 2, 2, 336, 337, 7, 127, 2, 2, 337, 87, 3, 2, 2, 2, 338, 339, 7, 66, 2, 2, 339, 89, 3, 2, 2, 2, 340, 341, 7, 48, 2, 2, 341, 91, 3, 2, 2, 2, 342, 343, 7, 46, 2, 2, 343, 93, 3, 2, 2, 2, 344, 345, 7, 60, 2, 2, 345, 95, 3, 2, 2, 2, 346, 347, 7, 61, 2, 2, 347, 97, 3, 2, 2, 2, 348, 349, 9, 7, 2, 2, 349, 99, 3, 2, 2, 2, 350, 351, 9, 8, 2, 2, 351, 101, 3, 2, 2, 2, 352, 353, 9, 9, 2, 2, 353, 103, 3, 2, 2, 2, 354, 355, 9, 10, 2, 2, 355, 105, 3, 2, 2, 2, 356, 357, 9, 11, 2, 2, 357, 107, 3, 2, 2, 2, 358, 359, 9, 12, 2, 2, 359, 109, 3, 2, 2, 2, 360, 361, 9, 13, 2, 2, 361, 111, 3, 2, 2, 2, 362, 363, 9, 14, 2, 2, 363, 113, 3, 2, 2, 2, 364, 365, 9, 15, 2, 2, 365, 115, 3, 2, 2, 2, 366, 367, 9, 16, 2, 2, 367, 117, 3, 2, 2, 2, 368, 369, 9, 17, 2, 2, 369, 119, 3, 2, 2, 2, 370, 371, 9, 18, 2, 2, 371, 121, 3, 2, 2, 2, 372, 373, 9, 19, 2, 2, 373, 123, 3, 2, 2, 2, 374, 375, 9, 20, 2, 2, 375, 125, 3, 2, 2, 2, 376, 377, 9, 21, 2, 2, 377, 127, 3, 2, 2, 2, 378, 379, 9, 22, 2, 2, 379, 129, 3, 2, 2, 2, 380, 381, 9, 23, 2, 2, 381, 131, 3, 2, 2, 2, 382, 385, 7, 94, 2, 2, 383, 386, 9, 24, 2, 2, 384, 386, 5, 134, 66, 2, 385, 383, 3, 2, 2, 2, 385, 384, 3, 2, 2, 2, 386, 133, 3, 2, 2, 2, 387, 388, 7, 119, 2, 2, 388, 389, 5, 136, 67, 2, 389, 390, 5, 136, 67, 2, 390, 391, 5, 136, 67, 2, 391, 392, 5, 136, 67, 2, 392, 135, 3, 2, 2, 2, 393, 394, 9, 25, 2, 2, 394, 137, 3, 2, 2, 2, 395, 397, 9, 26, 2, 2, 396, 395, 3, 2, 2, 2, 397, 398, 3, 2, 2, 2, 398, 396, 3, 2, 2, 2, 398, 399, 3, 2, 2, 2, 399, 400, 3, 2, 2, 2, 400, 401, 8, 68, 4, 2, 401, 139, 3, 2, 2, 2, 402, 403, 7, 47, 2, 2, 403, 404, 7, 47, 2, 2, 404, 408, 3, 2, 2, 2, 405, 407, 10, 27, 2, 2, 406, 405, 3, 2, 2, 2, 407, 410, 3, 2, 2, 2, 408, 406, 3, 2, 2, 2, 408, 409, 3, 2, 2, 2, 409, 412, 3, 2, 2, 2, 410, 408, 3, 2, 2, 2, 411, 413, 7, 12, 2, 2, 412, 411, 3, 2, 2, 2, 412, 413, 3, 2, 2, 2, 413, 414, 3, 2, 2, 2, 414, 415, 8, 69, 4, 2, 415, 141, 3, 2, 2, 2, 416, 417, 7, 42, 2, 2, 417, 418, 7, 44, 2, 2, 418, 419, 3, 2, 2, 2, 419, 420, 8, 70, 5, 2, 420, 143, 3, 2, 2, 2, 421, 422, 5, 142, 70, 2, 422, 423, 5, 144, 71, 2, 423, 424, 5, 146, 72, 2, 424, 431, 3, 2, 2, 2, 425, 427, 11, 2, 2, 2, 426, 425, 3, 2, 2, 2, 427, 428, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 428, 426, 3, 2, 2, 2, 429, 431, 3, 2, 2, 2, 430, 421, 3, 2, 2, 2, 430, 426, 3, 2, 2, 2, 431, 432, 3, 2, 2, 2, 432, 433, 8, 71, 4, 2, 433, 145, 3, 2, 2, 2, 434, 435, 7, 44, 2, 2, 435, 436, 7, 43, 2, 2, 436, 437, 3, 2, 2, 2, 437, 438, 8, 72, 6, 2, 438, 147, 3, 2, 2, 2, 439, 441, 5, 50, 24, 2, 440, 439, 3, 2, 2, 2, 441, 444, 3, 2, 2, 2, 442, 440, 3, 2, 2, 2, 442, 443, 3, 2, 2, 2, 443, 450, 3, 2, 2, 2, 444, 442, 3, 2, 2, 2, 445, 446, 7, 94, 2, 2, 446, 447, 7, 15, 2, 2, 447, 451, 7, 12, 2, 2, 448, 449, 7, 94, 2, 2, 449, 451, 7, 12, 2, 2, 450, 445, 3, 2, 2, 2, 450, 448, 3, 2, 2, 2, 451, 149, 3, 2, 2, 2, 452, 454, 5, 50, 24, 2, 453, 452, 3, 2, 2, 2, 454, 457, 3, 2, 2, 2, 455, 453, 3, 2, 2, 2, 455, 456, 3, 2, 2, 2, 456, 458, 3, 2, 2, 2, 457, 455, 3, 2, 2, 2, 458, 459, 7, 36, 2, 2, 459, 460, 3, 2, 2, 2, 460, 461, 8, 74, 6, 2, 461, 151, 3, 2, 2, 2, 462, 466, 5, 52, 25, 2, 463, 465, 5, 148, 73, 2, 464, 463, 3, 2, 2, 2, 465, 468, 3, 2, 2, 2, 466, 464, 3, 2, 2, 2, 466, 467, 3, 2, 2, 2, 467, 469, 3, 2, 2, 2, 468, 466, 3, 2, 2, 2, 469, 470, 5, 150, 74, 2, 470, 153, 3, 2, 2, 2, 471, 473, 5, 50, 24, 2, 472, 471, 3, 2, 2, 2, 473, 474, 3, 2, 2, 2, 474, 472, 3, 2, 2, 2, 474, 475, 3, 2, 2, 2, 475, 155, 3, 2, 2, 2, 476, 477, 7, 36, 2, 2, 477, 478, 3, 2, 2, 2, 478, 479, 8, 77, 6, 2, 479, 157, 3, 2, 2, 2, 25, 2, 3, 4, 5, 253, 266, 270, 276, 284, 291, 297, 304, 385, 398, 408, 412, 428, 430, 442, 450, 455, 466, 474, 7, 7, 5, 2, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file diff --git a/src/COOL_LEX.py b/src/COOL_LEX.py index 74921491..9514ec13 100644 --- a/src/COOL_LEX.py +++ b/src/COOL_LEX.py @@ -9,7 +9,7 @@ def serializedATN(): with StringIO() as buf: buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\29") - buf.write("\u01da\b\1\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5") + buf.write("\u01e0\b\1\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5") buf.write("\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f") buf.write("\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4") buf.write("\22\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27") @@ -31,189 +31,193 @@ def serializedATN(): buf.write("\3\25\3\25\5\25\u00fe\n\25\3\26\3\26\3\26\3\26\3\27\3") buf.write("\27\3\27\3\27\3\27\3\27\3\27\5\27\u010b\n\27\3\30\3\30") buf.write("\5\30\u010f\n\30\3\31\3\31\7\31\u0113\n\31\f\31\16\31") - buf.write("\u0116\13\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32\6\32\u011f") - buf.write("\n\32\r\32\16\32\u0120\3\33\3\33\7\33\u0125\n\33\f\33") - buf.write("\16\33\u0128\13\33\3\34\3\34\7\34\u012c\n\34\f\34\16\34") - buf.write("\u012f\13\34\3\35\3\35\3\35\3\36\3\36\3\36\3\37\3\37\3") - buf.write(" \3 \3!\3!\3\"\3\"\3#\3#\3$\3$\3$\3%\3%\3&\3&\3\'\3\'") - buf.write("\3(\3(\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60") - buf.write("\3\60\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65") - buf.write("\3\66\3\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<\3<\3=") - buf.write("\3=\3>\3>\3?\3?\3@\3@\3A\3A\3A\5A\u017f\nA\3B\3B\3B\3") - buf.write("B\3B\3B\3C\3C\3D\6D\u018a\nD\rD\16D\u018b\3D\3D\3E\3E") - buf.write("\3E\3E\7E\u0194\nE\fE\16E\u0197\13E\3E\5E\u019a\nE\3E") - buf.write("\3E\3F\3F\3F\3F\3F\3G\3G\3G\3G\3G\6G\u01a8\nG\rG\16G\u01a9") - buf.write("\5G\u01ac\nG\3G\3G\3H\3H\3H\3H\3H\3I\7I\u01b6\nI\fI\16") - buf.write("I\u01b9\13I\3I\3I\3I\3I\3J\7J\u01c0\nJ\fJ\16J\u01c3\13") - buf.write("J\3J\3J\3J\3J\3K\3K\7K\u01cb\nK\fK\16K\u01ce\13K\3K\3") - buf.write("K\3L\6L\u01d3\nL\rL\16L\u01d4\3M\3M\3M\3M\3\u01a9\2N\6") - buf.write("\3\b\4\n\5\f\6\16\7\20\b\22\t\24\n\26\13\30\f\32\r\34") - buf.write("\16\36\17 \20\"\21$\22&\23(\24*\25,\26.\27\60\30\62\2") - buf.write("\64\31\66\328\33:\34<\35>\36@\37B D!F\"H#J$L%N&P\'R(T") - buf.write(")V*X+Z,\\-^.`/b\2d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2") - buf.write("|\2~\2\u0080\2\u0082\2\u0084\2\u0086\2\u0088\2\u008a\60") - buf.write("\u008c\61\u008e\62\u0090\63\u0092\64\u0094\65\u0096\66") - buf.write("\u0098\67\u009a8\u009c9\6\2\3\4\5\34\6\2\2\2\f\f\17\17") - buf.write("$$\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEe") - buf.write("e\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2") - buf.write("PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4") - buf.write("\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2") - buf.write("\13\f\16\17\"\"\3\2\f\f\2\u01d2\2\6\3\2\2\2\2\b\3\2\2") - buf.write("\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16\3\2\2\2\2\20\3\2\2\2\2") - buf.write("\22\3\2\2\2\2\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32") - buf.write("\3\2\2\2\2\34\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2") - buf.write("\2\2\2$\3\2\2\2\2&\3\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3") - buf.write("\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2") - buf.write("\2\28\3\2\2\2\2:\3\2\2\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2") - buf.write("\2\2\2B\3\2\2\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3") - buf.write("\2\2\2\2L\3\2\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T") - buf.write("\3\2\2\2\2V\3\2\2\2\2X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2") - buf.write("\2^\3\2\2\2\2`\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2") - buf.write("\2\u008e\3\2\2\2\3\u0090\3\2\2\2\3\u0092\3\2\2\2\4\u0094") - buf.write("\3\2\2\2\4\u0096\3\2\2\2\4\u0098\3\2\2\2\5\u009a\3\2\2") - buf.write("\2\5\u009c\3\2\2\2\6\u009e\3\2\2\2\b\u00a4\3\2\2\2\n\u00a9") - buf.write("\3\2\2\2\f\u00af\3\2\2\2\16\u00b2\3\2\2\2\20\u00b5\3\2") - buf.write("\2\2\22\u00b8\3\2\2\2\24\u00c1\3\2\2\2\26\u00c8\3\2\2") - buf.write("\2\30\u00cc\3\2\2\2\32\u00d1\3\2\2\2\34\u00d6\3\2\2\2") - buf.write("\36\u00db\3\2\2\2 \u00e1\3\2\2\2\"\u00e6\3\2\2\2$\u00eb") - buf.write("\3\2\2\2&\u00ef\3\2\2\2(\u00f2\3\2\2\2*\u00f6\3\2\2\2") - buf.write(",\u00fd\3\2\2\2.\u00ff\3\2\2\2\60\u010a\3\2\2\2\62\u010e") - buf.write("\3\2\2\2\64\u0110\3\2\2\2\66\u011e\3\2\2\28\u0122\3\2") - buf.write("\2\2:\u0129\3\2\2\2<\u0130\3\2\2\2>\u0133\3\2\2\2@\u0136") - buf.write("\3\2\2\2B\u0138\3\2\2\2D\u013a\3\2\2\2F\u013c\3\2\2\2") - buf.write("H\u013e\3\2\2\2J\u0140\3\2\2\2L\u0143\3\2\2\2N\u0145\3") - buf.write("\2\2\2P\u0147\3\2\2\2R\u0149\3\2\2\2T\u014b\3\2\2\2V\u014d") - buf.write("\3\2\2\2X\u014f\3\2\2\2Z\u0151\3\2\2\2\\\u0153\3\2\2\2") - buf.write("^\u0155\3\2\2\2`\u0157\3\2\2\2b\u0159\3\2\2\2d\u015b\3") - buf.write("\2\2\2f\u015d\3\2\2\2h\u015f\3\2\2\2j\u0161\3\2\2\2l\u0163") - buf.write("\3\2\2\2n\u0165\3\2\2\2p\u0167\3\2\2\2r\u0169\3\2\2\2") - buf.write("t\u016b\3\2\2\2v\u016d\3\2\2\2x\u016f\3\2\2\2z\u0171\3") - buf.write("\2\2\2|\u0173\3\2\2\2~\u0175\3\2\2\2\u0080\u0177\3\2\2") - buf.write("\2\u0082\u0179\3\2\2\2\u0084\u017b\3\2\2\2\u0086\u0180") - buf.write("\3\2\2\2\u0088\u0186\3\2\2\2\u008a\u0189\3\2\2\2\u008c") - buf.write("\u018f\3\2\2\2\u008e\u019d\3\2\2\2\u0090\u01ab\3\2\2\2") - buf.write("\u0092\u01af\3\2\2\2\u0094\u01b7\3\2\2\2\u0096\u01c1\3") - buf.write("\2\2\2\u0098\u01c8\3\2\2\2\u009a\u01d2\3\2\2\2\u009c\u01d6") - buf.write("\3\2\2\2\u009e\u009f\5d\61\2\u009f\u00a0\5p\67\2\u00a0") - buf.write("\u00a1\5b\60\2\u00a1\u00a2\5z<\2\u00a2\u00a3\5z<\2\u00a3") - buf.write("\7\3\2\2\2\u00a4\u00a5\5h\63\2\u00a5\u00a6\5p\67\2\u00a6") - buf.write("\u00a7\5z<\2\u00a7\u00a8\5h\63\2\u00a8\t\3\2\2\2\u00a9") - buf.write("\u00aa\7h\2\2\u00aa\u00ab\5b\60\2\u00ab\u00ac\5p\67\2") - buf.write("\u00ac\u00ad\5z<\2\u00ad\u00ae\5h\63\2\u00ae\13\3\2\2") - buf.write("\2\u00af\u00b0\5j\64\2\u00b0\u00b1\5n\66\2\u00b1\r\3\2") - buf.write("\2\2\u00b2\u00b3\5n\66\2\u00b3\u00b4\5j\64\2\u00b4\17") - buf.write("\3\2\2\2\u00b5\u00b6\5n\66\2\u00b6\u00b7\5r8\2\u00b7\21") - buf.write("\3\2\2\2\u00b8\u00b9\5n\66\2\u00b9\u00ba\5r8\2\u00ba\u00bb") - buf.write("\5l\65\2\u00bb\u00bc\5h\63\2\u00bc\u00bd\5x;\2\u00bd\u00be") - buf.write("\5n\66\2\u00be\u00bf\5|=\2\u00bf\u00c0\5z<\2\u00c0\23") - buf.write("\3\2\2\2\u00c1\u00c2\5n\66\2\u00c2\u00c3\5z<\2\u00c3\u00c4") - buf.write("\5\u0080?\2\u00c4\u00c5\5t9\2\u00c5\u00c6\5n\66\2\u00c6") - buf.write("\u00c7\5f\62\2\u00c7\25\3\2\2\2\u00c8\u00c9\5p\67\2\u00c9") - buf.write("\u00ca\5h\63\2\u00ca\u00cb\5|=\2\u00cb\27\3\2\2\2\u00cc") - buf.write("\u00cd\5p\67\2\u00cd\u00ce\5t9\2\u00ce\u00cf\5t9\2\u00cf") - buf.write("\u00d0\5v:\2\u00d0\31\3\2\2\2\u00d1\u00d2\5v:\2\u00d2") - buf.write("\u00d3\5t9\2\u00d3\u00d4\5t9\2\u00d4\u00d5\5p\67\2\u00d5") - buf.write("\33\3\2\2\2\u00d6\u00d7\5|=\2\u00d7\u00d8\5l\65\2\u00d8") - buf.write("\u00d9\5h\63\2\u00d9\u00da\5r8\2\u00da\35\3\2\2\2\u00db") - buf.write("\u00dc\5\u0082@\2\u00dc\u00dd\5l\65\2\u00dd\u00de\5n\66") - buf.write("\2\u00de\u00df\5p\67\2\u00df\u00e0\5h\63\2\u00e0\37\3") - buf.write("\2\2\2\u00e1\u00e2\5d\61\2\u00e2\u00e3\5b\60\2\u00e3\u00e4") - buf.write("\5z<\2\u00e4\u00e5\5h\63\2\u00e5!\3\2\2\2\u00e6\u00e7") - buf.write("\5h\63\2\u00e7\u00e8\5z<\2\u00e8\u00e9\5b\60\2\u00e9\u00ea") - buf.write("\5d\61\2\u00ea#\3\2\2\2\u00eb\u00ec\5r8\2\u00ec\u00ed") - buf.write("\5h\63\2\u00ed\u00ee\5\u0082@\2\u00ee%\3\2\2\2\u00ef\u00f0") - buf.write("\5t9\2\u00f0\u00f1\5j\64\2\u00f1\'\3\2\2\2\u00f2\u00f3") - buf.write("\5r8\2\u00f3\u00f4\5t9\2\u00f4\u00f5\5|=\2\u00f5)\3\2") - buf.write("\2\2\u00f6\u00f7\7v\2\2\u00f7\u00f8\5x;\2\u00f8\u00f9") - buf.write("\5~>\2\u00f9\u00fa\5h\63\2\u00fa+\3\2\2\2\u00fb\u00fe") - buf.write("\5\60\27\2\u00fc\u00fe\5\u0098K\2\u00fd\u00fb\3\2\2\2") - buf.write("\u00fd\u00fc\3\2\2\2\u00fe-\3\2\2\2\u00ff\u0100\7$\2\2") - buf.write("\u0100\u0101\3\2\2\2\u0101\u0102\b\26\2\2\u0102/\3\2\2") - buf.write("\2\u0103\u0104\5.\26\2\u0104\u0105\5\u009aL\2\u0105\u0106") - buf.write("\5\u009cM\2\u0106\u010b\3\2\2\2\u0107\u0108\5.\26\2\u0108") - buf.write("\u0109\5\u009cM\2\u0109\u010b\3\2\2\2\u010a\u0103\3\2") - buf.write("\2\2\u010a\u0107\3\2\2\2\u010b\61\3\2\2\2\u010c\u010f") - buf.write("\5\u0084A\2\u010d\u010f\n\2\2\2\u010e\u010c\3\2\2\2\u010e") - buf.write("\u010d\3\2\2\2\u010f\63\3\2\2\2\u0110\u0114\7$\2\2\u0111") - buf.write("\u0113\5\62\30\2\u0112\u0111\3\2\2\2\u0113\u0116\3\2\2") - buf.write("\2\u0114\u0112\3\2\2\2\u0114\u0115\3\2\2\2\u0115\u0117") - buf.write("\3\2\2\2\u0116\u0114\3\2\2\2\u0117\u0118\7^\2\2\u0118") - buf.write("\u0119\7\17\2\2\u0119\u011a\7\f\2\2\u011a\u011b\3\2\2") - buf.write("\2\u011b\u011c\b\31\3\2\u011c\65\3\2\2\2\u011d\u011f\t") - buf.write("\3\2\2\u011e\u011d\3\2\2\2\u011f\u0120\3\2\2\2\u0120\u011e") - buf.write("\3\2\2\2\u0120\u0121\3\2\2\2\u0121\67\3\2\2\2\u0122\u0126") - buf.write("\t\4\2\2\u0123\u0125\t\5\2\2\u0124\u0123\3\2\2\2\u0125") - buf.write("\u0128\3\2\2\2\u0126\u0124\3\2\2\2\u0126\u0127\3\2\2\2") - buf.write("\u01279\3\2\2\2\u0128\u0126\3\2\2\2\u0129\u012d\t\6\2") - buf.write("\2\u012a\u012c\t\5\2\2\u012b\u012a\3\2\2\2\u012c\u012f") - buf.write("\3\2\2\2\u012d\u012b\3\2\2\2\u012d\u012e\3\2\2\2\u012e") - buf.write(";\3\2\2\2\u012f\u012d\3\2\2\2\u0130\u0131\7>\2\2\u0131") - buf.write("\u0132\7/\2\2\u0132=\3\2\2\2\u0133\u0134\7?\2\2\u0134") - buf.write("\u0135\7@\2\2\u0135?\3\2\2\2\u0136\u0137\7-\2\2\u0137") - buf.write("A\3\2\2\2\u0138\u0139\7/\2\2\u0139C\3\2\2\2\u013a\u013b") - buf.write("\7,\2\2\u013bE\3\2\2\2\u013c\u013d\7\61\2\2\u013dG\3\2") - buf.write("\2\2\u013e\u013f\7>\2\2\u013fI\3\2\2\2\u0140\u0141\7>") - buf.write("\2\2\u0141\u0142\7?\2\2\u0142K\3\2\2\2\u0143\u0144\7?") - buf.write("\2\2\u0144M\3\2\2\2\u0145\u0146\7\u0080\2\2\u0146O\3\2") - buf.write("\2\2\u0147\u0148\7*\2\2\u0148Q\3\2\2\2\u0149\u014a\7+") - buf.write("\2\2\u014aS\3\2\2\2\u014b\u014c\7}\2\2\u014cU\3\2\2\2") - buf.write("\u014d\u014e\7\177\2\2\u014eW\3\2\2\2\u014f\u0150\7B\2") - buf.write("\2\u0150Y\3\2\2\2\u0151\u0152\7\60\2\2\u0152[\3\2\2\2") - buf.write("\u0153\u0154\7.\2\2\u0154]\3\2\2\2\u0155\u0156\7<\2\2") - buf.write("\u0156_\3\2\2\2\u0157\u0158\7=\2\2\u0158a\3\2\2\2\u0159") - buf.write("\u015a\t\7\2\2\u015ac\3\2\2\2\u015b\u015c\t\b\2\2\u015c") - buf.write("e\3\2\2\2\u015d\u015e\t\t\2\2\u015eg\3\2\2\2\u015f\u0160") - buf.write("\t\n\2\2\u0160i\3\2\2\2\u0161\u0162\t\13\2\2\u0162k\3") - buf.write("\2\2\2\u0163\u0164\t\f\2\2\u0164m\3\2\2\2\u0165\u0166") - buf.write("\t\r\2\2\u0166o\3\2\2\2\u0167\u0168\t\16\2\2\u0168q\3") - buf.write("\2\2\2\u0169\u016a\t\17\2\2\u016as\3\2\2\2\u016b\u016c") - buf.write("\t\20\2\2\u016cu\3\2\2\2\u016d\u016e\t\21\2\2\u016ew\3") - buf.write("\2\2\2\u016f\u0170\t\22\2\2\u0170y\3\2\2\2\u0171\u0172") - buf.write("\t\23\2\2\u0172{\3\2\2\2\u0173\u0174\t\24\2\2\u0174}\3") - buf.write("\2\2\2\u0175\u0176\t\25\2\2\u0176\177\3\2\2\2\u0177\u0178") - buf.write("\t\26\2\2\u0178\u0081\3\2\2\2\u0179\u017a\t\27\2\2\u017a") - buf.write("\u0083\3\2\2\2\u017b\u017e\7^\2\2\u017c\u017f\t\30\2\2") - buf.write("\u017d\u017f\5\u0086B\2\u017e\u017c\3\2\2\2\u017e\u017d") - buf.write("\3\2\2\2\u017f\u0085\3\2\2\2\u0180\u0181\7w\2\2\u0181") - buf.write("\u0182\5\u0088C\2\u0182\u0183\5\u0088C\2\u0183\u0184\5") - buf.write("\u0088C\2\u0184\u0185\5\u0088C\2\u0185\u0087\3\2\2\2\u0186") - buf.write("\u0187\t\31\2\2\u0187\u0089\3\2\2\2\u0188\u018a\t\32\2") - buf.write("\2\u0189\u0188\3\2\2\2\u018a\u018b\3\2\2\2\u018b\u0189") - buf.write("\3\2\2\2\u018b\u018c\3\2\2\2\u018c\u018d\3\2\2\2\u018d") - buf.write("\u018e\bD\4\2\u018e\u008b\3\2\2\2\u018f\u0190\7/\2\2\u0190") - buf.write("\u0191\7/\2\2\u0191\u0195\3\2\2\2\u0192\u0194\n\33\2\2") - buf.write("\u0193\u0192\3\2\2\2\u0194\u0197\3\2\2\2\u0195\u0193\3") - buf.write("\2\2\2\u0195\u0196\3\2\2\2\u0196\u0199\3\2\2\2\u0197\u0195") - buf.write("\3\2\2\2\u0198\u019a\7\f\2\2\u0199\u0198\3\2\2\2\u0199") - buf.write("\u019a\3\2\2\2\u019a\u019b\3\2\2\2\u019b\u019c\bE\4\2") - buf.write("\u019c\u008d\3\2\2\2\u019d\u019e\7*\2\2\u019e\u019f\7") - buf.write(",\2\2\u019f\u01a0\3\2\2\2\u01a0\u01a1\bF\5\2\u01a1\u008f") - buf.write("\3\2\2\2\u01a2\u01a3\5\u008eF\2\u01a3\u01a4\5\u0090G\2") - buf.write("\u01a4\u01a5\5\u0092H\2\u01a5\u01ac\3\2\2\2\u01a6\u01a8") - buf.write("\13\2\2\2\u01a7\u01a6\3\2\2\2\u01a8\u01a9\3\2\2\2\u01a9") - buf.write("\u01aa\3\2\2\2\u01a9\u01a7\3\2\2\2\u01aa\u01ac\3\2\2\2") - buf.write("\u01ab\u01a2\3\2\2\2\u01ab\u01a7\3\2\2\2\u01ac\u01ad\3") - buf.write("\2\2\2\u01ad\u01ae\bG\4\2\u01ae\u0091\3\2\2\2\u01af\u01b0") - buf.write("\7,\2\2\u01b0\u01b1\7+\2\2\u01b1\u01b2\3\2\2\2\u01b2\u01b3") - buf.write("\bH\6\2\u01b3\u0093\3\2\2\2\u01b4\u01b6\5\62\30\2\u01b5") - buf.write("\u01b4\3\2\2\2\u01b6\u01b9\3\2\2\2\u01b7\u01b5\3\2\2\2") - buf.write("\u01b7\u01b8\3\2\2\2\u01b8\u01ba\3\2\2\2\u01b9\u01b7\3") - buf.write("\2\2\2\u01ba\u01bb\7^\2\2\u01bb\u01bc\7\17\2\2\u01bc\u01bd") - buf.write("\7\f\2\2\u01bd\u0095\3\2\2\2\u01be\u01c0\5\62\30\2\u01bf") - buf.write("\u01be\3\2\2\2\u01c0\u01c3\3\2\2\2\u01c1\u01bf\3\2\2\2") - buf.write("\u01c1\u01c2\3\2\2\2\u01c2\u01c4\3\2\2\2\u01c3\u01c1\3") - buf.write("\2\2\2\u01c4\u01c5\7$\2\2\u01c5\u01c6\3\2\2\2\u01c6\u01c7") - buf.write("\bJ\6\2\u01c7\u0097\3\2\2\2\u01c8\u01cc\5\64\31\2\u01c9") - buf.write("\u01cb\5\u0094I\2\u01ca\u01c9\3\2\2\2\u01cb\u01ce\3\2") - buf.write("\2\2\u01cc\u01ca\3\2\2\2\u01cc\u01cd\3\2\2\2\u01cd\u01cf") - buf.write("\3\2\2\2\u01ce\u01cc\3\2\2\2\u01cf\u01d0\5\u0096J\2\u01d0") - buf.write("\u0099\3\2\2\2\u01d1\u01d3\5\62\30\2\u01d2\u01d1\3\2\2") - buf.write("\2\u01d3\u01d4\3\2\2\2\u01d4\u01d2\3\2\2\2\u01d4\u01d5") - buf.write("\3\2\2\2\u01d5\u009b\3\2\2\2\u01d6\u01d7\7$\2\2\u01d7") - buf.write("\u01d8\3\2\2\2\u01d8\u01d9\bM\6\2\u01d9\u009d\3\2\2\2") - buf.write("\27\2\3\4\5\u00fd\u010a\u010e\u0114\u0120\u0126\u012d") - buf.write("\u017e\u018b\u0195\u0199\u01a9\u01ab\u01b7\u01c1\u01cc") - buf.write("\u01d4\7\7\5\2\7\4\2\b\2\2\7\3\2\6\2\2") + buf.write("\u0116\13\31\3\31\3\31\3\31\3\31\3\31\5\31\u011d\n\31") + buf.write("\3\31\3\31\3\32\6\32\u0122\n\32\r\32\16\32\u0123\3\33") + buf.write("\3\33\7\33\u0128\n\33\f\33\16\33\u012b\13\33\3\34\3\34") + buf.write("\7\34\u012f\n\34\f\34\16\34\u0132\13\34\3\35\3\35\3\35") + buf.write("\3\36\3\36\3\36\3\37\3\37\3 \3 \3!\3!\3\"\3\"\3#\3#\3") + buf.write("$\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(\3)\3)\3*\3*\3+\3+\3") + buf.write(",\3,\3-\3-\3.\3.\3/\3/\3\60\3\60\3\61\3\61\3\62\3\62\3") + buf.write("\63\3\63\3\64\3\64\3\65\3\65\3\66\3\66\3\67\3\67\38\3") + buf.write("8\39\39\3:\3:\3;\3;\3<\3<\3=\3=\3>\3>\3?\3?\3@\3@\3A\3") + buf.write("A\3A\5A\u0182\nA\3B\3B\3B\3B\3B\3B\3C\3C\3D\6D\u018d\n") + buf.write("D\rD\16D\u018e\3D\3D\3E\3E\3E\3E\7E\u0197\nE\fE\16E\u019a") + buf.write("\13E\3E\5E\u019d\nE\3E\3E\3F\3F\3F\3F\3F\3G\3G\3G\3G\3") + buf.write("G\6G\u01ab\nG\rG\16G\u01ac\5G\u01af\nG\3G\3G\3H\3H\3H") + buf.write("\3H\3H\3I\7I\u01b9\nI\fI\16I\u01bc\13I\3I\3I\3I\3I\3I") + buf.write("\5I\u01c3\nI\3J\7J\u01c6\nJ\fJ\16J\u01c9\13J\3J\3J\3J") + buf.write("\3J\3K\3K\7K\u01d1\nK\fK\16K\u01d4\13K\3K\3K\3L\6L\u01d9") + buf.write("\nL\rL\16L\u01da\3M\3M\3M\3M\3\u01ac\2N\6\3\b\4\n\5\f") + buf.write("\6\16\7\20\b\22\t\24\n\26\13\30\f\32\r\34\16\36\17 \20") + buf.write("\"\21$\22&\23(\24*\25,\26.\27\60\30\62\2\64\31\66\328") + buf.write("\33:\34<\35>\36@\37B D!F\"H#J$L%N&P\'R(T)V*X+Z,\\-^.`") + buf.write("/b\2d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2|\2~\2\u0080\2") + buf.write("\u0082\2\u0084\2\u0086\2\u0088\2\u008a\60\u008c\61\u008e") + buf.write("\62\u0090\63\u0092\64\u0094\65\u0096\66\u0098\67\u009a") + buf.write("8\u009c9\6\2\3\4\5\34\6\2\2\2\f\f\17\17$$\3\2\62;\3\2") + buf.write("C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEee\4\2FFff\4\2G") + buf.write("Ggg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2PPpp\4\2QQqq\4") + buf.write("\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4\2XXxx\4\2YYy") + buf.write("y\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2\13\f\16\17\"") + buf.write("\"\3\2\f\f\2\u01da\2\6\3\2\2\2\2\b\3\2\2\2\2\n\3\2\2\2") + buf.write("\2\f\3\2\2\2\2\16\3\2\2\2\2\20\3\2\2\2\2\22\3\2\2\2\2") + buf.write("\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32\3\2\2\2\2\34") + buf.write("\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2\2\2\2$\3\2\2") + buf.write("\2\2&\3\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3\2\2\2\2.\3\2") + buf.write("\2\2\2\60\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\28\3\2\2\2") + buf.write("\2:\3\2\2\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2\2\2\2B\3\2\2") + buf.write("\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3\2\2\2\2L\3\2") + buf.write("\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2\2\2\2V\3") + buf.write("\2\2\2\2X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2\2^\3\2\2\2\2") + buf.write("`\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2\2\u008e\3\2") + buf.write("\2\2\3\u0090\3\2\2\2\3\u0092\3\2\2\2\4\u0094\3\2\2\2\4") + buf.write("\u0096\3\2\2\2\4\u0098\3\2\2\2\5\u009a\3\2\2\2\5\u009c") + buf.write("\3\2\2\2\6\u009e\3\2\2\2\b\u00a4\3\2\2\2\n\u00a9\3\2\2") + buf.write("\2\f\u00af\3\2\2\2\16\u00b2\3\2\2\2\20\u00b5\3\2\2\2\22") + buf.write("\u00b8\3\2\2\2\24\u00c1\3\2\2\2\26\u00c8\3\2\2\2\30\u00cc") + buf.write("\3\2\2\2\32\u00d1\3\2\2\2\34\u00d6\3\2\2\2\36\u00db\3") + buf.write("\2\2\2 \u00e1\3\2\2\2\"\u00e6\3\2\2\2$\u00eb\3\2\2\2&") + buf.write("\u00ef\3\2\2\2(\u00f2\3\2\2\2*\u00f6\3\2\2\2,\u00fd\3") + buf.write("\2\2\2.\u00ff\3\2\2\2\60\u010a\3\2\2\2\62\u010e\3\2\2") + buf.write("\2\64\u0110\3\2\2\2\66\u0121\3\2\2\28\u0125\3\2\2\2:\u012c") + buf.write("\3\2\2\2<\u0133\3\2\2\2>\u0136\3\2\2\2@\u0139\3\2\2\2") + buf.write("B\u013b\3\2\2\2D\u013d\3\2\2\2F\u013f\3\2\2\2H\u0141\3") + buf.write("\2\2\2J\u0143\3\2\2\2L\u0146\3\2\2\2N\u0148\3\2\2\2P\u014a") + buf.write("\3\2\2\2R\u014c\3\2\2\2T\u014e\3\2\2\2V\u0150\3\2\2\2") + buf.write("X\u0152\3\2\2\2Z\u0154\3\2\2\2\\\u0156\3\2\2\2^\u0158") + buf.write("\3\2\2\2`\u015a\3\2\2\2b\u015c\3\2\2\2d\u015e\3\2\2\2") + buf.write("f\u0160\3\2\2\2h\u0162\3\2\2\2j\u0164\3\2\2\2l\u0166\3") + buf.write("\2\2\2n\u0168\3\2\2\2p\u016a\3\2\2\2r\u016c\3\2\2\2t\u016e") + buf.write("\3\2\2\2v\u0170\3\2\2\2x\u0172\3\2\2\2z\u0174\3\2\2\2") + buf.write("|\u0176\3\2\2\2~\u0178\3\2\2\2\u0080\u017a\3\2\2\2\u0082") + buf.write("\u017c\3\2\2\2\u0084\u017e\3\2\2\2\u0086\u0183\3\2\2\2") + buf.write("\u0088\u0189\3\2\2\2\u008a\u018c\3\2\2\2\u008c\u0192\3") + buf.write("\2\2\2\u008e\u01a0\3\2\2\2\u0090\u01ae\3\2\2\2\u0092\u01b2") + buf.write("\3\2\2\2\u0094\u01ba\3\2\2\2\u0096\u01c7\3\2\2\2\u0098") + buf.write("\u01ce\3\2\2\2\u009a\u01d8\3\2\2\2\u009c\u01dc\3\2\2\2") + buf.write("\u009e\u009f\5d\61\2\u009f\u00a0\5p\67\2\u00a0\u00a1\5") + buf.write("b\60\2\u00a1\u00a2\5z<\2\u00a2\u00a3\5z<\2\u00a3\7\3\2") + buf.write("\2\2\u00a4\u00a5\5h\63\2\u00a5\u00a6\5p\67\2\u00a6\u00a7") + buf.write("\5z<\2\u00a7\u00a8\5h\63\2\u00a8\t\3\2\2\2\u00a9\u00aa") + buf.write("\7h\2\2\u00aa\u00ab\5b\60\2\u00ab\u00ac\5p\67\2\u00ac") + buf.write("\u00ad\5z<\2\u00ad\u00ae\5h\63\2\u00ae\13\3\2\2\2\u00af") + buf.write("\u00b0\5j\64\2\u00b0\u00b1\5n\66\2\u00b1\r\3\2\2\2\u00b2") + buf.write("\u00b3\5n\66\2\u00b3\u00b4\5j\64\2\u00b4\17\3\2\2\2\u00b5") + buf.write("\u00b6\5n\66\2\u00b6\u00b7\5r8\2\u00b7\21\3\2\2\2\u00b8") + buf.write("\u00b9\5n\66\2\u00b9\u00ba\5r8\2\u00ba\u00bb\5l\65\2\u00bb") + buf.write("\u00bc\5h\63\2\u00bc\u00bd\5x;\2\u00bd\u00be\5n\66\2\u00be") + buf.write("\u00bf\5|=\2\u00bf\u00c0\5z<\2\u00c0\23\3\2\2\2\u00c1") + buf.write("\u00c2\5n\66\2\u00c2\u00c3\5z<\2\u00c3\u00c4\5\u0080?") + buf.write("\2\u00c4\u00c5\5t9\2\u00c5\u00c6\5n\66\2\u00c6\u00c7\5") + buf.write("f\62\2\u00c7\25\3\2\2\2\u00c8\u00c9\5p\67\2\u00c9\u00ca") + buf.write("\5h\63\2\u00ca\u00cb\5|=\2\u00cb\27\3\2\2\2\u00cc\u00cd") + buf.write("\5p\67\2\u00cd\u00ce\5t9\2\u00ce\u00cf\5t9\2\u00cf\u00d0") + buf.write("\5v:\2\u00d0\31\3\2\2\2\u00d1\u00d2\5v:\2\u00d2\u00d3") + buf.write("\5t9\2\u00d3\u00d4\5t9\2\u00d4\u00d5\5p\67\2\u00d5\33") + buf.write("\3\2\2\2\u00d6\u00d7\5|=\2\u00d7\u00d8\5l\65\2\u00d8\u00d9") + buf.write("\5h\63\2\u00d9\u00da\5r8\2\u00da\35\3\2\2\2\u00db\u00dc") + buf.write("\5\u0082@\2\u00dc\u00dd\5l\65\2\u00dd\u00de\5n\66\2\u00de") + buf.write("\u00df\5p\67\2\u00df\u00e0\5h\63\2\u00e0\37\3\2\2\2\u00e1") + buf.write("\u00e2\5d\61\2\u00e2\u00e3\5b\60\2\u00e3\u00e4\5z<\2\u00e4") + buf.write("\u00e5\5h\63\2\u00e5!\3\2\2\2\u00e6\u00e7\5h\63\2\u00e7") + buf.write("\u00e8\5z<\2\u00e8\u00e9\5b\60\2\u00e9\u00ea\5d\61\2\u00ea") + buf.write("#\3\2\2\2\u00eb\u00ec\5r8\2\u00ec\u00ed\5h\63\2\u00ed") + buf.write("\u00ee\5\u0082@\2\u00ee%\3\2\2\2\u00ef\u00f0\5t9\2\u00f0") + buf.write("\u00f1\5j\64\2\u00f1\'\3\2\2\2\u00f2\u00f3\5r8\2\u00f3") + buf.write("\u00f4\5t9\2\u00f4\u00f5\5|=\2\u00f5)\3\2\2\2\u00f6\u00f7") + buf.write("\7v\2\2\u00f7\u00f8\5x;\2\u00f8\u00f9\5~>\2\u00f9\u00fa") + buf.write("\5h\63\2\u00fa+\3\2\2\2\u00fb\u00fe\5\60\27\2\u00fc\u00fe") + buf.write("\5\u0098K\2\u00fd\u00fb\3\2\2\2\u00fd\u00fc\3\2\2\2\u00fe") + buf.write("-\3\2\2\2\u00ff\u0100\7$\2\2\u0100\u0101\3\2\2\2\u0101") + buf.write("\u0102\b\26\2\2\u0102/\3\2\2\2\u0103\u0104\5.\26\2\u0104") + buf.write("\u0105\5\u009aL\2\u0105\u0106\5\u009cM\2\u0106\u010b\3") + buf.write("\2\2\2\u0107\u0108\5.\26\2\u0108\u0109\5\u009cM\2\u0109") + buf.write("\u010b\3\2\2\2\u010a\u0103\3\2\2\2\u010a\u0107\3\2\2\2") + buf.write("\u010b\61\3\2\2\2\u010c\u010f\5\u0084A\2\u010d\u010f\n") + buf.write("\2\2\2\u010e\u010c\3\2\2\2\u010e\u010d\3\2\2\2\u010f\63") + buf.write("\3\2\2\2\u0110\u0114\7$\2\2\u0111\u0113\5\62\30\2\u0112") + buf.write("\u0111\3\2\2\2\u0113\u0116\3\2\2\2\u0114\u0112\3\2\2\2") + buf.write("\u0114\u0115\3\2\2\2\u0115\u011c\3\2\2\2\u0116\u0114\3") + buf.write("\2\2\2\u0117\u0118\7^\2\2\u0118\u0119\7\17\2\2\u0119\u011d") + buf.write("\7\f\2\2\u011a\u011b\7^\2\2\u011b\u011d\7\f\2\2\u011c") + buf.write("\u0117\3\2\2\2\u011c\u011a\3\2\2\2\u011d\u011e\3\2\2\2") + buf.write("\u011e\u011f\b\31\3\2\u011f\65\3\2\2\2\u0120\u0122\t\3") + buf.write("\2\2\u0121\u0120\3\2\2\2\u0122\u0123\3\2\2\2\u0123\u0121") + buf.write("\3\2\2\2\u0123\u0124\3\2\2\2\u0124\67\3\2\2\2\u0125\u0129") + buf.write("\t\4\2\2\u0126\u0128\t\5\2\2\u0127\u0126\3\2\2\2\u0128") + buf.write("\u012b\3\2\2\2\u0129\u0127\3\2\2\2\u0129\u012a\3\2\2\2") + buf.write("\u012a9\3\2\2\2\u012b\u0129\3\2\2\2\u012c\u0130\t\6\2") + buf.write("\2\u012d\u012f\t\5\2\2\u012e\u012d\3\2\2\2\u012f\u0132") + buf.write("\3\2\2\2\u0130\u012e\3\2\2\2\u0130\u0131\3\2\2\2\u0131") + buf.write(";\3\2\2\2\u0132\u0130\3\2\2\2\u0133\u0134\7>\2\2\u0134") + buf.write("\u0135\7/\2\2\u0135=\3\2\2\2\u0136\u0137\7?\2\2\u0137") + buf.write("\u0138\7@\2\2\u0138?\3\2\2\2\u0139\u013a\7-\2\2\u013a") + buf.write("A\3\2\2\2\u013b\u013c\7/\2\2\u013cC\3\2\2\2\u013d\u013e") + buf.write("\7,\2\2\u013eE\3\2\2\2\u013f\u0140\7\61\2\2\u0140G\3\2") + buf.write("\2\2\u0141\u0142\7>\2\2\u0142I\3\2\2\2\u0143\u0144\7>") + buf.write("\2\2\u0144\u0145\7?\2\2\u0145K\3\2\2\2\u0146\u0147\7?") + buf.write("\2\2\u0147M\3\2\2\2\u0148\u0149\7\u0080\2\2\u0149O\3\2") + buf.write("\2\2\u014a\u014b\7*\2\2\u014bQ\3\2\2\2\u014c\u014d\7+") + buf.write("\2\2\u014dS\3\2\2\2\u014e\u014f\7}\2\2\u014fU\3\2\2\2") + buf.write("\u0150\u0151\7\177\2\2\u0151W\3\2\2\2\u0152\u0153\7B\2") + buf.write("\2\u0153Y\3\2\2\2\u0154\u0155\7\60\2\2\u0155[\3\2\2\2") + buf.write("\u0156\u0157\7.\2\2\u0157]\3\2\2\2\u0158\u0159\7<\2\2") + buf.write("\u0159_\3\2\2\2\u015a\u015b\7=\2\2\u015ba\3\2\2\2\u015c") + buf.write("\u015d\t\7\2\2\u015dc\3\2\2\2\u015e\u015f\t\b\2\2\u015f") + buf.write("e\3\2\2\2\u0160\u0161\t\t\2\2\u0161g\3\2\2\2\u0162\u0163") + buf.write("\t\n\2\2\u0163i\3\2\2\2\u0164\u0165\t\13\2\2\u0165k\3") + buf.write("\2\2\2\u0166\u0167\t\f\2\2\u0167m\3\2\2\2\u0168\u0169") + buf.write("\t\r\2\2\u0169o\3\2\2\2\u016a\u016b\t\16\2\2\u016bq\3") + buf.write("\2\2\2\u016c\u016d\t\17\2\2\u016ds\3\2\2\2\u016e\u016f") + buf.write("\t\20\2\2\u016fu\3\2\2\2\u0170\u0171\t\21\2\2\u0171w\3") + buf.write("\2\2\2\u0172\u0173\t\22\2\2\u0173y\3\2\2\2\u0174\u0175") + buf.write("\t\23\2\2\u0175{\3\2\2\2\u0176\u0177\t\24\2\2\u0177}\3") + buf.write("\2\2\2\u0178\u0179\t\25\2\2\u0179\177\3\2\2\2\u017a\u017b") + buf.write("\t\26\2\2\u017b\u0081\3\2\2\2\u017c\u017d\t\27\2\2\u017d") + buf.write("\u0083\3\2\2\2\u017e\u0181\7^\2\2\u017f\u0182\t\30\2\2") + buf.write("\u0180\u0182\5\u0086B\2\u0181\u017f\3\2\2\2\u0181\u0180") + buf.write("\3\2\2\2\u0182\u0085\3\2\2\2\u0183\u0184\7w\2\2\u0184") + buf.write("\u0185\5\u0088C\2\u0185\u0186\5\u0088C\2\u0186\u0187\5") + buf.write("\u0088C\2\u0187\u0188\5\u0088C\2\u0188\u0087\3\2\2\2\u0189") + buf.write("\u018a\t\31\2\2\u018a\u0089\3\2\2\2\u018b\u018d\t\32\2") + buf.write("\2\u018c\u018b\3\2\2\2\u018d\u018e\3\2\2\2\u018e\u018c") + buf.write("\3\2\2\2\u018e\u018f\3\2\2\2\u018f\u0190\3\2\2\2\u0190") + buf.write("\u0191\bD\4\2\u0191\u008b\3\2\2\2\u0192\u0193\7/\2\2\u0193") + buf.write("\u0194\7/\2\2\u0194\u0198\3\2\2\2\u0195\u0197\n\33\2\2") + buf.write("\u0196\u0195\3\2\2\2\u0197\u019a\3\2\2\2\u0198\u0196\3") + buf.write("\2\2\2\u0198\u0199\3\2\2\2\u0199\u019c\3\2\2\2\u019a\u0198") + buf.write("\3\2\2\2\u019b\u019d\7\f\2\2\u019c\u019b\3\2\2\2\u019c") + buf.write("\u019d\3\2\2\2\u019d\u019e\3\2\2\2\u019e\u019f\bE\4\2") + buf.write("\u019f\u008d\3\2\2\2\u01a0\u01a1\7*\2\2\u01a1\u01a2\7") + buf.write(",\2\2\u01a2\u01a3\3\2\2\2\u01a3\u01a4\bF\5\2\u01a4\u008f") + buf.write("\3\2\2\2\u01a5\u01a6\5\u008eF\2\u01a6\u01a7\5\u0090G\2") + buf.write("\u01a7\u01a8\5\u0092H\2\u01a8\u01af\3\2\2\2\u01a9\u01ab") + buf.write("\13\2\2\2\u01aa\u01a9\3\2\2\2\u01ab\u01ac\3\2\2\2\u01ac") + buf.write("\u01ad\3\2\2\2\u01ac\u01aa\3\2\2\2\u01ad\u01af\3\2\2\2") + buf.write("\u01ae\u01a5\3\2\2\2\u01ae\u01aa\3\2\2\2\u01af\u01b0\3") + buf.write("\2\2\2\u01b0\u01b1\bG\4\2\u01b1\u0091\3\2\2\2\u01b2\u01b3") + buf.write("\7,\2\2\u01b3\u01b4\7+\2\2\u01b4\u01b5\3\2\2\2\u01b5\u01b6") + buf.write("\bH\6\2\u01b6\u0093\3\2\2\2\u01b7\u01b9\5\62\30\2\u01b8") + buf.write("\u01b7\3\2\2\2\u01b9\u01bc\3\2\2\2\u01ba\u01b8\3\2\2\2") + buf.write("\u01ba\u01bb\3\2\2\2\u01bb\u01c2\3\2\2\2\u01bc\u01ba\3") + buf.write("\2\2\2\u01bd\u01be\7^\2\2\u01be\u01bf\7\17\2\2\u01bf\u01c3") + buf.write("\7\f\2\2\u01c0\u01c1\7^\2\2\u01c1\u01c3\7\f\2\2\u01c2") + buf.write("\u01bd\3\2\2\2\u01c2\u01c0\3\2\2\2\u01c3\u0095\3\2\2\2") + buf.write("\u01c4\u01c6\5\62\30\2\u01c5\u01c4\3\2\2\2\u01c6\u01c9") + buf.write("\3\2\2\2\u01c7\u01c5\3\2\2\2\u01c7\u01c8\3\2\2\2\u01c8") + buf.write("\u01ca\3\2\2\2\u01c9\u01c7\3\2\2\2\u01ca\u01cb\7$\2\2") + buf.write("\u01cb\u01cc\3\2\2\2\u01cc\u01cd\bJ\6\2\u01cd\u0097\3") + buf.write("\2\2\2\u01ce\u01d2\5\64\31\2\u01cf\u01d1\5\u0094I\2\u01d0") + buf.write("\u01cf\3\2\2\2\u01d1\u01d4\3\2\2\2\u01d2\u01d0\3\2\2\2") + buf.write("\u01d2\u01d3\3\2\2\2\u01d3\u01d5\3\2\2\2\u01d4\u01d2\3") + buf.write("\2\2\2\u01d5\u01d6\5\u0096J\2\u01d6\u0099\3\2\2\2\u01d7") + buf.write("\u01d9\5\62\30\2\u01d8\u01d7\3\2\2\2\u01d9\u01da\3\2\2") + buf.write("\2\u01da\u01d8\3\2\2\2\u01da\u01db\3\2\2\2\u01db\u009b") + buf.write("\3\2\2\2\u01dc\u01dd\7$\2\2\u01dd\u01de\3\2\2\2\u01de") + buf.write("\u01df\bM\6\2\u01df\u009d\3\2\2\2\31\2\3\4\5\u00fd\u010a") + buf.write("\u010e\u0114\u011c\u0123\u0129\u0130\u0181\u018e\u0198") + buf.write("\u019c\u01ac\u01ae\u01ba\u01c2\u01c7\u01d2\u01da\7\7\5") + buf.write("\2\7\4\2\b\2\2\7\3\2\6\2\2") return buf.getvalue() From d3cf8de000e1744fa43309de4b4a72140d264b6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 12 Oct 2020 01:44:54 -0400 Subject: [PATCH 17/77] =?UTF-8?q?Se=20agreg=C3=B3=20el=20an=C3=A1lisis=20s?= =?UTF-8?q?em=C3=A1ntico=20Se=20cre=C3=B3=20una=20versi=C3=B3n=20prelimina?= =?UTF-8?q?r=20(incompleto)=20de=20la=20generaci=C3=B3n=20de=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grammar/COOL.g4 | 1 + src/COOL.py | 186 ++ src/COOLCompiler.py | 20 +- src/COOLParser.py | 2 +- src/COOLVisitor.py | 1387 +++++++++++++++ src/Visitors.py | 3135 +++++++++++++++++++++++++++++++++ tests/codegen/arith.cl | 16 +- tests/codegen/complex.cl | 30 +- tests/codegen/hello_world.cl | 7 +- tests/semantic/hello_world.cl | 3 +- 10 files changed, 4760 insertions(+), 27 deletions(-) create mode 100644 src/COOLVisitor.py create mode 100644 src/Visitors.py diff --git a/grammar/COOL.g4 b/grammar/COOL.g4 index 76a2f58f..7865fd05 100644 --- a/grammar/COOL.g4 +++ b/grammar/COOL.g4 @@ -2,6 +2,7 @@ parser grammar COOL; options { tokenVocab=COOL_LEX; + output=AST; } program diff --git a/src/COOL.py b/src/COOL.py index 98bb717d..d3628c54 100644 --- a/src/COOL.py +++ b/src/COOL.py @@ -239,6 +239,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitProgram" ): listener.exitProgram(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitProgram" ): + return visitor.visitProgram(self) + else: + return visitor.visitChildren(self) + @@ -300,6 +306,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitClasses" ): listener.exitClasses(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitClasses" ): + return visitor.visitClasses(self) + else: + return visitor.visitChildren(self) + def programBlocks(self): @@ -379,6 +391,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitClassDefine" ): listener.exitClassDefine(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitClassDefine" ): + return visitor.visitClassDefine(self) + else: + return visitor.visitChildren(self) + @@ -487,6 +505,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitMethod" ): listener.exitMethod(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitMethod" ): + return visitor.visitMethod(self) + else: + return visitor.visitChildren(self) + class PropertyContext(FeatureContext): @@ -514,6 +538,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitProperty" ): listener.exitProperty(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitProperty" ): + return visitor.visitProperty(self) + else: + return visitor.visitChildren(self) + def feature(self): @@ -625,6 +655,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitFormal" ): listener.exitFormal(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitFormal" ): + return visitor.visitFormal(self) + else: + return visitor.visitChildren(self) + @@ -714,6 +750,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitLetIn" ): listener.exitLetIn(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitLetIn" ): + return visitor.visitLetIn(self) + else: + return visitor.visitChildren(self) + class MinusContext(ExpressionContext): @@ -738,6 +780,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitMinus" ): listener.exitMinus(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitMinus" ): + return visitor.visitMinus(self) + else: + return visitor.visitChildren(self) + class StringContext(ExpressionContext): @@ -756,6 +804,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitString" ): listener.exitString(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitString" ): + return visitor.visitString(self) + else: + return visitor.visitChildren(self) + class IsvoidContext(ExpressionContext): @@ -777,6 +831,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitIsvoid" ): listener.exitIsvoid(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitIsvoid" ): + return visitor.visitIsvoid(self) + else: + return visitor.visitChildren(self) + class WhileContext(ExpressionContext): @@ -805,6 +865,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitWhile" ): listener.exitWhile(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitWhile" ): + return visitor.visitWhile(self) + else: + return visitor.visitChildren(self) + class DivisionContext(ExpressionContext): @@ -829,6 +895,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitDivision" ): listener.exitDivision(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitDivision" ): + return visitor.visitDivision(self) + else: + return visitor.visitChildren(self) + class NegativeContext(ExpressionContext): @@ -850,6 +922,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitNegative" ): listener.exitNegative(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitNegative" ): + return visitor.visitNegative(self) + else: + return visitor.visitChildren(self) + class BoolNotContext(ExpressionContext): @@ -871,6 +949,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitBoolNot" ): listener.exitBoolNot(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitBoolNot" ): + return visitor.visitBoolNot(self) + else: + return visitor.visitChildren(self) + class LessThanContext(ExpressionContext): @@ -895,6 +979,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitLessThan" ): listener.exitLessThan(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitLessThan" ): + return visitor.visitLessThan(self) + else: + return visitor.visitChildren(self) + class BlockContext(ExpressionContext): @@ -926,6 +1016,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitBlock" ): listener.exitBlock(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitBlock" ): + return visitor.visitBlock(self) + else: + return visitor.visitChildren(self) + class IdContext(ExpressionContext): @@ -944,6 +1040,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitId" ): listener.exitId(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitId" ): + return visitor.visitId(self) + else: + return visitor.visitChildren(self) + class MultiplyContext(ExpressionContext): @@ -968,6 +1070,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitMultiply" ): listener.exitMultiply(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitMultiply" ): + return visitor.visitMultiply(self) + else: + return visitor.visitChildren(self) + class IfContext(ExpressionContext): @@ -998,6 +1106,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitIf" ): listener.exitIf(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitIf" ): + return visitor.visitIf(self) + else: + return visitor.visitChildren(self) + class CaseContext(ExpressionContext): @@ -1051,6 +1165,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitCase" ): listener.exitCase(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitCase" ): + return visitor.visitCase(self) + else: + return visitor.visitChildren(self) + class OwnMethodCallContext(ExpressionContext): @@ -1084,6 +1204,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitOwnMethodCall" ): listener.exitOwnMethodCall(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitOwnMethodCall" ): + return visitor.visitOwnMethodCall(self) + else: + return visitor.visitChildren(self) + class AddContext(ExpressionContext): @@ -1108,6 +1234,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitAdd" ): listener.exitAdd(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitAdd" ): + return visitor.visitAdd(self) + else: + return visitor.visitChildren(self) + class NewContext(ExpressionContext): @@ -1128,6 +1260,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitNew" ): listener.exitNew(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitNew" ): + return visitor.visitNew(self) + else: + return visitor.visitChildren(self) + class ParenthesesContext(ExpressionContext): @@ -1151,6 +1289,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitParentheses" ): listener.exitParentheses(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitParentheses" ): + return visitor.visitParentheses(self) + else: + return visitor.visitChildren(self) + class AssignmentContext(ExpressionContext): @@ -1174,6 +1318,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitAssignment" ): listener.exitAssignment(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitAssignment" ): + return visitor.visitAssignment(self) + else: + return visitor.visitChildren(self) + class FalseContext(ExpressionContext): @@ -1192,6 +1342,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitFalse" ): listener.exitFalse(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitFalse" ): + return visitor.visitFalse(self) + else: + return visitor.visitChildren(self) + class IntContext(ExpressionContext): @@ -1210,6 +1366,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitInt" ): listener.exitInt(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitInt" ): + return visitor.visitInt(self) + else: + return visitor.visitChildren(self) + class EqualContext(ExpressionContext): @@ -1234,6 +1396,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitEqual" ): listener.exitEqual(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitEqual" ): + return visitor.visitEqual(self) + else: + return visitor.visitChildren(self) + class TrueContext(ExpressionContext): @@ -1252,6 +1420,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitTrue" ): listener.exitTrue(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitTrue" ): + return visitor.visitTrue(self) + else: + return visitor.visitChildren(self) + class LessEqualContext(ExpressionContext): @@ -1276,6 +1450,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitLessEqual" ): listener.exitLessEqual(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitLessEqual" ): + return visitor.visitLessEqual(self) + else: + return visitor.visitChildren(self) + class MethodCallContext(ExpressionContext): @@ -1315,6 +1495,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitMethodCall" ): listener.exitMethodCall(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitMethodCall" ): + return visitor.visitMethodCall(self) + else: + return visitor.visitChildren(self) + def expression(self, _p:int=0): diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index b2d7beab..8e08f495 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -7,6 +7,10 @@ from COOLParser import COOLParser from COOLParserErrorListener import COOLParserErrorListener from COOLListener import COOLListener +from Visitors import TypeCOOLVisitor +from Visitors import SemanticCOOLVisitor +from Visitors import CodegenVisitor +from collections import deque def main(argv): if not os.path.isfile(argv[1]): @@ -24,16 +28,28 @@ def main(argv): token = lexer.nextToken() if lexer.hasErrors: return sys.exit(errno.EPERM) - lexer.reset(); stream = CommonTokenStream(lexer) parser = COOLParser(stream) parser.removeErrorListeners() parser.addErrorListener(COOLParserErrorListener()) - tree = parser.program() if parser.getNumberOfSyntaxErrors() > 0: return sys.exit(errno.EPERM) + visitor = TypeCOOLVisitor() + visitor.visitProgram(tree, argv[1]) + typeTree = visitor.TypeTable + consTble = visitor.ConstantTable + semanticAnalizer = SemanticCOOLVisitor(typeTree) + codegenerator = CodegenVisitor(typeTree, consTble, visitor.Counter) + semanticAnalizer.visitProgram(tree) + + outFilename = os.path.splitext(argv[1])[0] + ".s" + codegenerator.visitProgram(tree, outFilename) + none = typeTree["Object"] + + + if __name__ == '__main__': main(sys.argv) diff --git a/src/COOLParser.py b/src/COOLParser.py index 6decdd97..abab6507 100644 --- a/src/COOLParser.py +++ b/src/COOLParser.py @@ -2,13 +2,13 @@ from io import StringIO from typing.io import TextIO from antlr4 import * -from COOL import COOL from antlr4.CommonTokenFactory import CommonTokenFactory from antlr4.atn.LexerATNSimulator import LexerATNSimulator from antlr4.InputStream import InputStream from antlr4.Recognizer import Recognizer from antlr4.Token import Token from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException +from COOL import * class COOLParser(COOL): def __init__(self, input=None, output:TextIO = sys.stdout): diff --git a/src/COOLVisitor.py b/src/COOLVisitor.py new file mode 100644 index 00000000..665425e5 --- /dev/null +++ b/src/COOLVisitor.py @@ -0,0 +1,1387 @@ +# Generated from COOL.g4 by ANTLR 4.7.2 +from collections import deque +from antlr4 import * +# if __name__ is not None and "." in __name__: +# from .COOL import COOL +# else: +# from COOL import COOL + +from COOL import * + +from src import COOLParser + +# This class defines a complete generic visitor for a parse tree produced by COOL. +class COOLVisitor(ParseTreeVisitor): + + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx:COOL.ProgramContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx:COOL.ClassesContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx:COOL.ClassDefineContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx:COOL.MethodContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx:COOL.PropertyContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx:COOL.FormalContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx:COOL.LetInContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx:COOL.MinusContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx:COOL.StringContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx:COOL.IsvoidContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx:COOL.WhileContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx:COOL.DivisionContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx:COOL.NegativeContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx:COOL.BoolNotContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx:COOL.LessThanContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx:COOL.BlockContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx:COOL.IdContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx:COOL.MultiplyContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx:COOL.IfContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx:COOL.CaseContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx:COOL.AddContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx:COOL.NewContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx:COOL.ParenthesesContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx:COOL.AssignmentContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx:COOL.FalseContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx:COOL.IntContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx:COOL.EqualContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx:COOL.TrueContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx:COOL.LessEqualContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx:COOL.MethodCallContext): + return self.visitChildren(ctx) + +class SemanticCOOLVisitor(ParseTreeVisitor): + + def join(self, class1: str, class2: str): + if class1 == "None" or class2 == "None": + return "None" + if self.TypeTable[class1].Deep == self.TypeTable[class2].Deep: + if self.TypeTable[class1].Name == self.TypeTable[class2].Name: + return class1 + else: + return self.join(self.TypeTable[class1].Parent, self.TypeTable[class2].Parent) + elif self.TypeTable[class1].Deep > self.TypeTable[class2].Deep: + return self.join(self.TypeTable[class1].Parent, class2) + else: + return self.join(class1, self.TypeTable[class2].Parent) + + def calculateDeep(self, coolClass: COOLClass): + if self.TypeTable.keys().__contains__(coolClass.Parent): + if self.TypeTable[coolClass.Parent].Deep != -1: + coolClass.Deep = self.TypeTable[coolClass.Parent].Deep + 1 + else: + self.calculateDeep(self.TypeTable[coolClass.Parent]) + coolClass.Deep = self.TypeTable[coolClass.Parent].Deep + 1 + elif coolClass.Name == "Object": + coolClass.Deep = 0 + else: + coolClass.Deep = 1 + coolClass.Parent = "Object" + + def searchMethod(self, coolClass: str, methodName: str): + if coolClass == "None": + return False + elif self.TypeTable[coolClass].Methods.keys().__contains__(methodName): + return True + else: + return self.searchMethod(self.TypeTable[coolClass].Parent, methodName) + + def searchAtribute(self, coolClass: str, atributeName: str): + if coolClass == "None": + return False + elif self.TypeTable[coolClass].Atributes.keys().__contains__(atributeName): + return True + else: + return self.searchAtribute(self.TypeTable[coolClass].Parent, atributeName) + + def searchMethodInfo(self, coolClass: str, methodName: str): + for method in self.TypeTable[coolClass].Methods.keys(): + if method == methodName: + return self.TypeTable[coolClass].Methods[method] + return self.searchMethodInfo(self.TypeTable[coolClass].Parent, methodName) + + def searchAtributeInfo(self, coolClass: str, atributeName: str): + for atribute in self.TypeTable[coolClass].Atributes.keys(): + if atribute == atributeName: + return self.TypeTable[coolClass].Atributes[atribute] + return self.searchAtributeInfo(self.TypeTable[coolClass].Parent, atributeName) + + + def __init__(self, typeTable: dict): + self.TypeTable = typeTable + self.ScopeManager = COOLScopeManager() + self.actualClass = "Object" + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx:COOL.ProgramContext): + for className in self.TypeTable.keys(): + self.calculateDeep(self.TypeTable[className]) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx:COOL.ClassesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx:COOL.ClassDefineContext): + coolClass = ctx.getChild(1).symbol + if(self.TypeTable[coolClass.text].Created): + line = str(coolClass.line) + column = str(coolClass.column) + error = "(" + line + "," + column + "): this class name already exist" + print(error) + elif ctx.getChild(2).symbol.text == "inherits": + classParent = ctx.getChild(3).symbol + if (self.TypeTable.keys().__contains__(classParent.text)): + if self.TypeTable[classParent.text].Sealed: + line = str(classParent.line) + column = str(classParent.column) + error = "(" + line + "," + column + "): this class is sealed" + print(error) + else: + self.TypeTable[coolClass.text].Created = True + self.TypeTable[coolClass.text].Sealed = False + self.ScopeManager.addScope() + self.ScopeManager.addIdentifier("self", coolClass.text) + self.actualClass = coolClass.text + self.visitChildren(ctx) + self.ScopeManager.deleteScope() + return + else: + line = str(classParent.line) + column = str(classParent.column) + error = "(" + line + "," + column + "): this class doesn't exist" + print(error) + else: + self.TypeTable[coolClass.text].Created = True + self.TypeTable[coolClass.text].Sealed = False + self.ScopeManager.addScope() + self.actualClass = coolClass.text + self.ScopeManager.addIdentifier("self", coolClass.text) + self.visitChildren(ctx) + self.ScopeManager.deleteScope() + return + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx:COOL.MethodContext): + coolClass = ctx.parentCtx.getChild(1).symbol.text + methodName = ctx.getChild(0).symbol.text + methodType = ctx.getChild(len(ctx.children) - 4).symbol + if self.ScopeManager.searchScope(methodName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this method name already exist" + print(error) + elif self.TypeTable.keys().__contains__(self.TypeTable[coolClass].Methods[methodName].Type) or methodType.text == "SELF_TYPE": + self.ScopeManager.addIdentifier(methodName, methodType.text) + self.ScopeManager.addScope() + self.visitChildren(ctx) + self.ScopeManager.deleteScope() + return + else: + line = str(methodType.line) + column = str(methodType.column) + error = "(" + line + "," + column + "): this type doesn't exist" + print(error) + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx:COOL.PropertyContext): + atributeType = ctx.getChild(2).symbol.text + atributeName = ctx.getChild(0).symbol.text + if self.ScopeManager.searchScope(atributeName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this atribute name already exist" + print(error) + return "None" + elif not(self.TypeTable.keys().__contains__(atributeType) or atributeType == "SELF_TYPE"): + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column) + error = "(" + line + "," + column + "): this type doesn't exist" + print(error) + return "None" + elif len(ctx.children) == 5: + atributeValue = ctx.getChild(4).accept(self) + if self.join(atributeType, atributeValue) != atributeType: + line = str(ctx.getChild(4).start.line) + column = str(ctx.getChild(4).start.column) + error = "(" + line + "," + column + "): the type of the expression is diferent of the type of the atribute" + print(error) + return "None" + else: + self.ScopeManager.addIdentifier(atributeName, atributeType) + return atributeType + else: + self.ScopeManager.addIdentifier(atributeName, atributeType) + return atributeType + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx:COOL.FormalContext): + paramName = ctx.getChild(0).symbol.text + paramType = ctx.getChild(2).symbol.text + if self.ScopeManager.searchScope(paramName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this param name already exist" + print(error) + elif self.TypeTable.keys().__contains__(paramType): + self.ScopeManager.addIdentifier(paramName, paramType) + return self.visitChildren(ctx) + else: + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column) + error = "(" + line + "," + column + "): this type doesn't exist" + print(error) + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx: COOL.IntContext): + return "Int" + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx: COOL.StringContext): + return "String" + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx: COOL.FalseContext): + return "Bool" + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx: COOL.TrueContext): + return "Bool" + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx: COOL.AddContext): + addValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + addValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + addValue = "None" + return addValue + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx:COOL.MinusContext): + minusValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + minusValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + minusValue = "None" + return minusValue + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx: COOL.MultiplyContext): + mulValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + mulValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + mulValue = "None" + return mulValue + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx: COOL.DivisionContext): + divValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + divValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + divValue = "None" + return divValue + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx: COOL.NegativeContext): + expressValue = ctx.getChild(1).accept(self) + if expressValue == "Int": + return "Int" + return "None" + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx:COOL.IsvoidContext): + self.visitChildren(ctx) + return "Bool" + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx: COOL.BoolNotContext): + expressValue = ctx.getChild(1).accept(self) + if expressValue == "Bool": + return "Bool" + return "None" + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx:COOL.LessThanContext): + lessValue = "Bool" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessValue = "None" + return lessValue + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx:COOL.LessEqualContext): + lessEqualValue = "Bool" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessEqualValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessEqualValue = "None" + return lessEqualValue + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx: COOL.EqualContext): + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue == "None" or rightValue == "None": + return "None" + if leftValue == rightValue: + return "Bool" + if leftValue == "String" or leftValue == "Int" or leftValue == "Bool": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is incorrect" + print(error) + return "None" + if rightValue == "String" or rightValue == "Int" or rightValue == "Bool": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is incorrect" + print(error) + return "None" + return "Bool" + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx: COOL.AssignmentContext): + variableName = ctx.getChild(0).symbol.text + asignValue = ctx.getChild(2).accept(self) + variableType = self.ScopeManager.searchforType(variableName) + if variableType == "None": + if self.searchAtribute(self.actualClass, variableName): + variableType = self.searchAtributeInfo(self.actualClass, variableName) + else: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this identifier does not exist" + print(error) + return "None" + if variableType == "SELF_TYPE": + variableType = self.actualClass + if self.join(asignValue, variableType) != variableType: + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is diferent that the identifier" + print(error) + return "None" + return variableType + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx: COOL.ParenthesesContext): + return ctx.getChild(1).accept(self) + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx: COOL.IdContext): + IdValue = ctx.getChild(0).symbol.text + if self.ScopeManager.searchIdentifier(IdValue): + return self.ScopeManager.searchforType(IdValue) + elif self.searchAtribute(self.actualClass, IdValue): + return self.searchAtributeInfo(self.actualClass, IdValue) + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this identifier does not exist" + print(error) + return "None" + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx:COOL.IfContext): + ifValue = ctx.getChild(1).accept(self) + thenValue = ctx.getChild(3).accept(self) + elseValue = ctx.getChild(5).accept(self) + if ifValue == "None" or ifValue == "Bool": + return self.join(thenValue, elseValue) + else: + line = str(ctx.getChild(1).start.line) + column = str(ctx.getChild(1).start.column) + error = "(" + line + "," + column + "): this expression is not boolean" + print(error) + return self.join(thenValue, elseValue) + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx: COOL.WhileContext): + whileValue = ctx.getChild(3).accept(self) + whileValue = ctx.getChild(1).accept(self) + if whileValue == "None" or whileValue == "Bool": + return "Object" + else: + line = str(ctx.getChild(1).start.line) + column = str(ctx.getChild(1).start.column) + error = "(" + line + "," + column + "): this expression is not boolean" + print(error) + return "Object" + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx:COOL.BlockContext): + blockValue = "None" + count = 1 + lengt = len(ctx.children) - 1 + while lengt > count: + blockValue = ctx.getChild(count).accept(self) + count = count + 2 + return blockValue + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx:COOL.CaseContext): + ctx.getChild(1).accept(self) + lengt = len(ctx.children) - 1 + count = 3 + caseValue = "None" + while lengt > count: + idName = ctx.getChild(count).symbol.text + count = count + 2 + idType = ctx.getChild(count).symbol.text + count = count + 2 + self.ScopeManager.addScope() + self.ScopeManager.addIdentifier(idName, idType) + if (caseValue == "None"): + caseValue = ctx.getChild(count).accept(self) + else: + caseValue = self.join(caseValue, ctx.getChild(count).accept(self)) + count = count + 2 + self.ScopeManager.deleteScope() + return caseValue + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx: COOL.NewContext): + return ctx.getChild(1).symbol.text + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): + methodType = "None" + if self.searchMethod(self.actualClass, ctx.getChild(0).symbol.text): + methodInfo = self.searchMethodInfo(self.actualClass, ctx.getChild(0).symbol.text) + if(methodInfo.Type == "SELF_TYPE"): + methodType = self.actualClass + else: + methodType = methodInfo.Type + if methodInfo.ParamsNumber == 0 and len(ctx.children) != 3: + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + elif len(ctx.children) != methodInfo.ParamsNumber * 2 + 2 and methodInfo.ParamsNumber != 0: + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + else: + count = 2 + for param in methodInfo.Params: + (_,paramType) = param + requestType = ctx.getChild(count).accept(self) + if (self.join(requestType, paramType) != paramType): + line = str(ctx.getChild(count).start.line) + column = str(ctx.getChild(count).start.column) + error = "(" + line + "," + column + "): the type of this param in the call is incorrect" + print(error) + methodType = "None" + count = count + 2 + else: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this method not exist in " + self.actualClass + print(error) + return methodType + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx:COOL.MethodCallContext): + methodType = "None" + length = 5 + currentClass = ctx.getChild(0).accept(self) + if (ctx.getChild(1).symbol.text == "@"): + length = length + 2 + parent = ctx.getChild(2).symbol.text + if self.join(currentClass, parent) == parent: + currentClass = parent + else: + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column) + error = "(" + line + "," + column + "): this class is not parent of " + currentClass + print(error) + return methodType + if self.searchMethod(currentClass, ctx.getChild(length - 3).symbol.text): + methodInfo = self.searchMethodInfo(currentClass, ctx.getChild(length - 3).symbol.text) + if (methodInfo.Type == "SELF_TYPE"): + methodType = currentClass + else: + methodType = methodInfo.Type + if (methodInfo.ParamsNumber == 0 and len(ctx.children) != length): + line = str(ctx.getChild(length - 3).start.line) + column = str(ctx.getChild(length - 3).start.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + elif (len(ctx.children) != methodInfo.ParamsNumber * 2 + length - 1) and methodInfo.ParamsNumber > 0: + line = str(ctx.getChild(length - 3).start.line) + column = str(ctx.getChild(length - 3).start.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + else: + count = length - 1 + for param in methodInfo.Params: + (_, paramType) = param + requestType = ctx.getChild(count).accept(self) + if (self.join(requestType, paramType) != paramType): + line = str(ctx.getChild(count).start.line) + column = str(ctx.getChild(count).start.column) + error = "(" + line + "," + column + "): the type of this param in the call is incorrect" + print(error) + methodType = "None" + count = count + 2 + else: + line = str(ctx.getChild(length - 3).symbol.line) + column = str(ctx.getChild(length - 3).symbol.column) + error = "(" + line + "," + column + "): this method not exist in " + currentClass + print(error) + return methodType + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx: COOL.LetInContext): + self.ScopeManager.addScope() + count = 0 + while(ctx.getChild(count).symbol.text != "in"): + idName = ctx.getChild(count + 1).symbol.text + count = count + 2 + idType = ctx.getChild(count + 1).symbol.text + if not(self.TypeTable.keys().__contains__(idType)) and idType != "SELF_TYPE": + self.ScopeManager.deleteScope() + line = str(ctx.getChild(count + 1).symbol.line) + column = str(ctx.getChild(count + 1).symbol.column) + error = "(" + line + "," + column + "): this class does not exist " + print(error) + return "None" + self.ScopeManager.addIdentifier(idName, idType) + count = count + 2 + if ctx.getChild(count).symbol.text == "<-": + idValue = ctx.getChild(count + 1).accept(self) + count = count + 2 + if self.join(idType, idValue) != idType: + self.ScopeManager.deleteScope() + line = str(ctx.getChild(count -1).start.line) + column = str(ctx.getChild(count - 1).start.column) + error = "(" + line + "," + column + "): the type of the expression is diferent of the type of the identifier" + print(error) + return "None" + + return ctx.getChild(count + 1).accept(self) + +class TypeCOOLVisitor(ParseTreeVisitor): + + TypeTable = {} + + Counter = 0 + + ConstantTable = list() + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx: COOL.ProgramContext): + self.TypeTable["Object"] = COOLClass("Object", "None", True, False) + self.TypeTable["Object"].Methods["abort"] = COOLMethod("abort", "Object", 0, None) + self.TypeTable["Object"].Methods["type_name"] = COOLMethod("type_name", "String", 0, None) + self.TypeTable["Object"].Methods["copy"] = COOLMethod("copy", "SELF_TYPE", 0, None) + self.TypeTable["String"] = COOLClass("String", "Object", True, True) + self.TypeTable["String"].Methods["length"] = COOLMethod("length", "Int", 0, None) + self.TypeTable["String"].Methods["concat"] = COOLMethod("concat", "String", 1, None) + self.TypeTable["String"].Methods["concat"].Params.append(("s", "String")) + self.TypeTable["String"].Methods["substr"] = COOLMethod("substr", "String", 2, None) + self.TypeTable["String"].Methods["substr"].Params.append(("i", "Int")) + self.TypeTable["String"].Methods["substr"].Params.append(("l", "Int")) + self.TypeTable["Int"] = COOLClass("Int", "Object", True, True) + self.TypeTable["Bool"] = COOLClass("Bool", "Object", True, True) + self.TypeTable["IO"] = COOLClass("IO", "Object", True, False) + self.TypeTable["IO"].Methods["in_string"] = COOLMethod("in_string", "String", 0, None) + self.TypeTable["IO"].Methods["in_int"] = COOLMethod("in_int", "Int", 0, None) + self.TypeTable["IO"].Methods["out_string"] = COOLMethod("out_string", "SELF_TYPE", 1, None) + self.TypeTable["IO"].Methods["out_string"].Params.append(("x", "String")) + self.TypeTable["IO"].Methods["out_int"] = COOLMethod("out_int", "SELF_TYPE", 1, None) + self.TypeTable["IO"].Methods["out_int"].Params.append(("x", "Int")) + self.ConstantTable.append(("", "String", "string_const0")) + self.Counter = 1 + self.ConstantTable.append((0, "Int", "int_const0")) + self.ConstantTable.append(("false", "Bool", "bool_const0")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx: COOL.ClassesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx: COOL.ClassDefineContext): + coolClass = ctx.getChild(1).symbol + if self.TypeTable.keys().__contains__(coolClass.text): + return + if ctx.getChild(2).symbol.text == "inherits": + classParent = ctx.getChild(3).symbol + self.TypeTable[coolClass.text] = COOLClass(coolClass.text, classParent.text, False, False) + return self.visitChildren(ctx) + else: + self.TypeTable[coolClass.text] = COOLClass(coolClass.text, "Object", False, False) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx: COOL.MethodContext): + name = ctx.getChild(0).symbol.text + cclass = ctx.parentCtx.getChild(1).symbol.text + if self.TypeTable[cclass].Methods.keys().__contains__(name): + return + n = len(ctx.children) - 4 + if ctx.getChild(n).symbol.text == ":": + n = n + 1 + type = ctx.getChild(n).symbol.text + lengt = len(ctx.children) - 8 + paramsNumber = 0 + if lengt > 0: + paramsNumber = 1 + while lengt > 1: + lengt = lengt - 2 + paramsNumber = paramsNumber + 1 + self.TypeTable[cclass].Methods[name] = COOLMethod(name, type, paramsNumber, ctx.getChild(len(ctx.children) - 2)) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx: COOL.PropertyContext): + cclass = ctx.parentCtx.getChild(1).symbol.text + name = ctx.getChild(0).symbol.text + if self.TypeTable[cclass].Atributes.keys().__contains__(name): + return + type = ctx.getChild(2).symbol.text + self.TypeTable[cclass].Atributes[name] = type + if len(ctx.children) == 4: + self.TypeTable[cclass].AtributeAsign[name] = ctx.getChild(4) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx: COOL.FormalContext): + parent = ctx.parentCtx + + className = parent.parentCtx.getChild(1).symbol.text + methodName = parent.getChild(0).symbol.text + method = self.TypeTable[className].Methods[methodName] + for param in method.Params: + (paramName, paramType) = param + if (paramName == ctx.getChild(0).symbol.text): + return + method.Params.append((ctx.getChild(0).symbol.text, ctx.getChild(2).symbol.text)) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx: COOL.LetInContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx: COOL.MinusContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx: COOL.StringContext): + constantName = ctx.getChild(0).symbol.text[1:-1] + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == constantName and consType == "String": + return self.visitChildren(ctx) + + self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) + self.Counter = self.Counter + 1 + length = len(constantName) + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == length and consType == "Int": + return self.visitChildren(ctx) + self.ConstantTable.append((length, "Int", f"int_const{length}")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx: COOL.IsvoidContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx: COOL.WhileContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx: COOL.DivisionContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx: COOL.NegativeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx: COOL.BoolNotContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx: COOL.LessThanContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx: COOL.BlockContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx: COOL.IdContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx: COOL.MultiplyContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx: COOL.IfContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx: COOL.CaseContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx: COOL.AddContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx: COOL.NewContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx: COOL.ParenthesesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx: COOL.AssignmentContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx: COOL.FalseContext): + for cons in self.ConstantTable: + (consName, consType, _) = cons + if consName == "false" and consType == "Bool": + return self.visitChildren(ctx) + + self.ConstantTable.append(("false", "Bool", "bool_const0")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx: COOL.IntContext): + constantName = int(ctx.getChild(0).symbol.text) + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == constantName and consType == "Int": + return self.visitChildren(ctx) + + self.ConstantTable.append((constantName, "Int", f"int_const{constantName}")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx: COOL.EqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx: COOL.TrueContext): + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == "true" and consType == "Bool": + return self.visitChildren(ctx) + + self.ConstantTable.append(("true", "Bool","bool_const1")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx: COOL.LessEqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx: COOL.MethodCallContext): + return self.visitChildren(ctx) + +class CodegenVisitor(ParseTreeVisitor): + + def __init__(self, typeTable: dict, constantTable: list, counter: int): + self.TypeTable = typeTable + self.ConstantTable = constantTable + self.Counter = counter + + + def genGlobalClases(self): + sol = "\t.data\n\t.align 2\n\t.global class_nameTab\n" + for clasName in self.TypeTable.keys(): + protoName = "\t.global " + clasName + "_protoObj\n" + sol = sol + protoName + sol = sol + "_string_tag:\n\t.word 1\n_int_tag:\n\t.word 2\n_bool_tag :\n\t.word 3\n" + return sol + + def genConstant(self, sol: str): + for const in self.ConstantTable: + (constName, constType, constLabel) = const + if constType == "Bool": + sol = sol + \ + f"\t.word -1\n" \ + f"{constLabel}:\n" \ + f"\t.word 5\n" \ + f"\t.word 4\n" \ + f"\t.word Bool_dispTab\n" \ + f"\t.word {constLabel[-1:-1]}\n" + elif constType == "Int": + sol = sol + \ + f"\t.word -1\n{constLabel}:\n" \ + f"\t.word 3\n\t.word 4\n" \ + f"\t.word Int_dispTab\n" \ + f"\t.word {constName}\n" + else: + length = int(len(constName) / 4) + 3 + if len(constName) % 4 != 0: + length = length + 1 + sol = sol + \ + f"\t.word -1\n{constLabel}:\n" \ + f"\t.word 4\n\t.word {length}\n" \ + f"\t.word String_dispTab\n" \ + f"\t.word int_const{len(constName)}\n" \ + f"\t.ascii {constName}\n" \ + f"\t.byte 0\n" \ + f"\t.align 2\n" + return sol + + def findLabel(self, name: str): + for const in self.ConstantTable: + (constName, constType, constLabel) = const + if constName == name and constType == "String": + return constLabel + + def genMethodNames(self, coolClass: str, coolMethods: list, className: str): + if coolClass == "None": + return "" + temp = "" + for method in self.TypeTable[coolClass].Methods: + if not (coolMethods.__contains__(method)): + temp = temp + f"\t.word {coolClass}.{method}\n" + coolMethods.append(method) + + code = self.genMethodNames(self.TypeTable[coolClass].Parent, coolMethods, className) + return code + temp + + + + def genAtributeNames(self, coolClass: str, coolAtributes: list): + if coolClass == "None": + return "" + temp = "" + listAtributes = list() + for atribute in self.TypeTable[coolClass].Atributes: + listAtributes.append(atribute) + if not (coolAtributes.__contains__(atribute)): + value = self.TypeTable[coolClass].Atributes[atribute] + if value == "Int" or value == "String" or value == "Bool": + temp = temp + f"\t.word {value.lower()}_constant0\n" + else: + temp = temp + f"\t.word 0\n" + coolAtributes.append(atribute) + + code = self.genAtributeNames(self.TypeTable[coolClass].Parent, coolAtributes) + if coolClass != "Object": + self.TypeTable[coolClass].TagAtributes = self.TypeTable[self.TypeTable[coolClass].Parent].TagAtributes + listAtributes + return code + temp + + def genClassTable(self): + classNameTab = "class_nameTab:\n" + class_objTab = "class_objTab:\n" + methods = "" + atributes = "" + counter = 0 + for className in self.TypeTable: + classNameTab = classNameTab + f"\t.word {self.findLabel(className)}\n" + temp = self.genMethodNames(className, list(), className) + class_objTab = class_objTab + \ + f"\t.word {className}_protObj\n" \ + f"\t.word {className}_init\n" + methods = methods + f"{className}_dispTab:\n" + temp + if className == "Int" or className == "Bool": + atributes = atributes + \ + f"\t.word -1\n" \ + f"{className}_protObj:\n" \ + f"\t.word {counter}\n" \ + f"\t.word 4\n" \ + f"\t.word {className}_dispTab\n" \ + f"\t.word 0\n" + elif className == "String": + atributes = atributes + \ + f"\t.word -1\n" \ + f"{className}_protObj:\n" \ + f"\t.word {counter}\n" \ + f"\t.word 5\n" \ + f"\t.word {className}_dispTab\n" \ + f"\t.word int_constant0\n" \ + f"\t.word 0\n" + else: + atributeList = list() + temp = self.genAtributeNames(className, atributeList) + atributes = atributes + \ + f"\t.word -1\n" \ + f"{className}_protObj:\n" \ + f"\t.word {counter}\n" \ + f"\t.word {len(atributeList) + 3}\n" \ + f"\t.word {className}_dispTab\n" \ + f"" + temp + self.TypeTable[className].Tag = counter + counter = counter + 1 + return classNameTab + class_objTab + methods + atributes + + def genClassAtributes(self, className: str): + if className == "None": + return "" + code = self.genClassAtributes(self.TypeTable[className].Parent) + for atribute in self.TypeTable[className].AtributeAsign: + code = code + self.TypeTable[className].AtributeAsign[atribute].accept(self) + return code + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx: COOL.ProgramContext): + for className in self.TypeTable: + constantName = className + self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) + self.Counter = self.Counter + 1 + length = len(constantName) + contain = True + for cons in self.ConstantTable: + (consName, consType, _) = cons + if consName == length and consType == "Int": + contain = False + if contain: + self.ConstantTable.append((length, "Int", f"int_const{length}")) + self.ConstantTable.append(("SELF_TYPE", "String", f"str_const{self.Counter}")) + contain = True + length = len("SELF_TYPE") + for cons in self.ConstantTable: + (consName, consType, _) = cons + if consName == length and consType == "Int": + contain = False + if contain: + self.ConstantTable.append((length, "Int", f"int_const{length}")) + code = self.genGlobalClases() + code = self.genConstant(code) + code = code + self.genClassTable() + code = code + \ + "\t.global heap_start\n" \ + "heap_start:\n" \ + "\t.word 0\n" \ + "\t.text\n" \ + "\t.global Main_init\n" \ + "\t.global Int_init\n" \ + "\t.global String_init\n" \ + "\t.global Bool_init\n" \ + "\t.global Main.main\n" + for className in self.TypeTable: + code = code + f"{className}_init:\n" + temp = self.genClassAtributes(className) + if len(temp) != 0: + code = code + \ + "\taddiu $sp $sp -12\n" \ + "\tsw $fp 12($sp)\n" \ + "\tsw $s0 8($sp)\n" \ + "\tsw $ra 4($sp)\n" \ + "\taddiu $fp $sp 4\n" \ + "\tmove $s0 $a0\n" + code = code + temp + code = code + \ + "\tmove $a0 $s0\n" \ + "\tlw $fp 12($sp)\n" \ + "\tlw $s0 8($sp)\n" \ + "\tlw $ra 4($sp)\n" \ + "\taddiu $sp $sp 12\n" + code = code + "\tjr $ra\n" + for className in self.TypeTable: + if not(className == "Object" or className == "String" or className == "Int" or className == "Bool" or className == "IO"): + for methodName in self.TypeTable[className].Methods: + code = code + f"{className}.{methodName}:\n" + code = code + \ + "\taddiu $sp $sp -12\n" \ + "\tsw $fp 12($sp)\n" \ + "\tsw $s0 8($sp)\n" \ + "\tsw $ra 4($sp)\n" \ + "\taddiu $fp $sp 4\n" \ + "\tmove $s0 $a0\n" + code = code + self.TypeTable[className].Methods[methodName].InstructionSet.accept(self) + code = code + \ + "\tmove $a0 $s0\n" \ + "\tlw $fp 12($sp)\n" \ + "\tlw $s0 8($sp)\n" \ + "\tlw $ra 4($sp)\n" \ + "\taddiu $sp $sp 12\n" + code = code + "\tjr $ra\n" + print(code) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx: COOL.ClassesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx: COOL.ClassDefineContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx: COOL.MethodContext): + return "" + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx: COOL.PropertyContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx: COOL.FormalContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx: COOL.LetInContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx: COOL.MinusContext): + code = ctx.getChild(0).accept(self) + code = code + \ + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy" + \ + "\tlw $t1 4($sp)\n" + \ + "\tlw $t1 12($t1)\n" + \ + "\tlw $t2 12($a0)\n" + \ + "\tsub $t1 $t1 $t2\n" + \ + "\tsw $t1 12($a0)\n" + \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx: COOL.StringContext): + name = ctx.getChild(0).symbol.text[1:-1] + for const in self.ConstantTable: + (constName, constType, constTag) = const + if constType == "String" and constName == name: + return f"\tla $a0 {constTag}\n" + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx: COOL.IsvoidContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx: COOL.WhileContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx: COOL.DivisionContext): + code = ctx.getChild(0).accept(self) + code = code + \ + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy" \ + "\tlw $t1 4($sp)\n" \ + "\tlw $t1 12($t1)\n" \ + "\tlw $t2 12($a0)\n" \ + "\tdiv $t1 $t2\n" \ + "\tmflo $t1" \ + "\tsw $t1 12($a0)\n" \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx: COOL.NegativeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx: COOL.BoolNotContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx: COOL.LessThanContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx: COOL.BlockContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx: COOL.IdContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx: COOL.MultiplyContext): + code = ctx.getChild(0).accept(self) + code = code + \ + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy" + \ + "\tlw $t1 4($sp)\n" + \ + "\tlw $t1 12($t1)\n" + \ + "\tlw $t2 12($a0)\n" + \ + "\tmul $t1 $t1 $t2\n" + \ + "\tsw $t1 12($a0)\n" + \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx: COOL.IfContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx: COOL.CaseContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): + length = len(ctx.children) + code = "" + if length > 3: + count = 2 + while length != count: + param = ctx.getChild(count).accept(self) + code = code + param + f"\tsw $a0 0($sp)\n\taddiu $sp $sp -4\n" + count = count + 2 + code = code + "\tmove $a0 $s0\n" + return code + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx: COOL.AddContext): + code = ctx.getChild(0).accept(self) + code = code + \ + "\tsw $a0 0 ($sp)\n"+ \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy"+ \ + "\tlw $t1 4($sp)\n"+ \ + "\tlw $t1 12($t1)\n"+ \ + "\tlw $t2 12($a0)\n"+ \ + "\tadd $t1 $t1 $t2\n"+ \ + "\tsw $t1 12($a0)\n"+ \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx: COOL.NewContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx: COOL.ParenthesesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx: COOL.AssignmentContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx: COOL.FalseContext): + return f"\tla $a0 {bool_const0}\n" + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx: COOL.IntContext): + name = ctx.getChild(0).symbol.text[1:-1] + for const in self.ConstantTable: + (constName, constType, constTag) = const + if constType == "Int" and constName == name: + return f"\tla $a0 {constTag}\n" + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx: COOL.EqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx: COOL.TrueContext): + return f"\tla $a0 {bool_const1}\n" + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx: COOL.LessEqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx: COOL.MethodCallContext): + return self.visitChildren(ctx) diff --git a/src/Visitors.py b/src/Visitors.py new file mode 100644 index 00000000..0bcd390c --- /dev/null +++ b/src/Visitors.py @@ -0,0 +1,3135 @@ +from collections import deque +from antlr4 import * +from COOL import * +from src import COOLParser + +class COOLClass: + def __init__(self, name: str, parent: str, created: bool, sealed: bool): + self.Name = name + self.Parent = parent + self.Created = created + self.Sealed = sealed + self.Deep = -1 + self.Methods = {} + self.TagMethods = list() + self.Atributes = {} + self.Tag = 0 + self.TagAtributes = list() + self.AtributeAsign = {} + +class COOLMethod: + def __init__(self, name: str, type: str, paramNumber: int, instructionSet): + self.Name = name + self.Type = type + self.Params = list() + self.ParamsNumber= paramNumber + self.InstructionSet = instructionSet + +class COOLScopeManager: + def __init__(self): + self.Stack = deque() + + def addScope(self): + self.Stack.append({}) + + def addIdentifier(self, name: str, type: str): + scope = self.Stack.pop() + scope[name] = type + self.Stack.append(scope) + + def deleteScope(self): + self.Stack.pop() + + def searchScope(self, identifier: str): + scope = self.Stack.pop() + self.Stack.append(scope) + return scope.keys().__contains__(identifier) + + def searchIdentifier(self, identifier: str): + for scope in reversed(self.Stack): + if(scope.keys().__contains__(identifier)): + return True + return False + + def searchforType(self, identifier: str): + for scope in reversed(self.Stack): + if(scope.keys().__contains__(identifier)): + return scope[identifier] + return "None" + +class SemanticCOOLVisitor(ParseTreeVisitor): + + def join(self, class1: str, class2: str): + if class1 == "None" or class2 == "None": + return "None" + if self.TypeTable[class1].Deep == self.TypeTable[class2].Deep: + if self.TypeTable[class1].Name == self.TypeTable[class2].Name: + return class1 + else: + return self.join(self.TypeTable[class1].Parent, self.TypeTable[class2].Parent) + elif self.TypeTable[class1].Deep > self.TypeTable[class2].Deep: + return self.join(self.TypeTable[class1].Parent, class2) + else: + return self.join(class1, self.TypeTable[class2].Parent) + + def calculateDeep(self, coolClass: COOLClass): + if self.TypeTable.keys().__contains__(coolClass.Parent): + if self.TypeTable[coolClass.Parent].Deep != -1: + coolClass.Deep = self.TypeTable[coolClass.Parent].Deep + 1 + else: + self.calculateDeep(self.TypeTable[coolClass.Parent]) + coolClass.Deep = self.TypeTable[coolClass.Parent].Deep + 1 + elif coolClass.Name == "Object": + coolClass.Deep = 0 + else: + coolClass.Deep = 1 + coolClass.Parent = "Object" + + def searchMethod(self, coolClass: str, methodName: str): + if coolClass == "None": + return False + elif self.TypeTable[coolClass].Methods.keys().__contains__(methodName): + return True + else: + return self.searchMethod(self.TypeTable[coolClass].Parent, methodName) + + def searchAtribute(self, coolClass: str, atributeName: str): + if coolClass == "None": + return False + elif self.TypeTable[coolClass].Atributes.keys().__contains__(atributeName): + return True + else: + return self.searchAtribute(self.TypeTable[coolClass].Parent, atributeName) + + def searchMethodInfo(self, coolClass: str, methodName: str): + for method in self.TypeTable[coolClass].Methods.keys(): + if method == methodName: + return self.TypeTable[coolClass].Methods[method] + return self.searchMethodInfo(self.TypeTable[coolClass].Parent, methodName) + + def searchAtributeInfo(self, coolClass: str, atributeName: str): + for atribute in self.TypeTable[coolClass].Atributes.keys(): + if atribute == atributeName: + return self.TypeTable[coolClass].Atributes[atribute] + return self.searchAtributeInfo(self.TypeTable[coolClass].Parent, atributeName) + + + def __init__(self, typeTable: dict): + self.TypeTable = typeTable + self.ScopeManager = COOLScopeManager() + self.actualClass = "Object" + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx:COOL.ProgramContext): + for className in self.TypeTable.keys(): + self.calculateDeep(self.TypeTable[className]) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx:COOL.ClassesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx:COOL.ClassDefineContext): + coolClass = ctx.getChild(1).symbol + if(self.TypeTable[coolClass.text].Created): + line = str(coolClass.line) + column = str(coolClass.column) + error = "(" + line + "," + column + "): this class name already exist" + print(error) + elif ctx.getChild(2).symbol.text == "inherits": + classParent = ctx.getChild(3).symbol + if (self.TypeTable.keys().__contains__(classParent.text)): + if self.TypeTable[classParent.text].Sealed: + line = str(classParent.line) + column = str(classParent.column) + error = "(" + line + "," + column + "): this class is sealed" + print(error) + else: + self.TypeTable[coolClass.text].Created = True + self.TypeTable[coolClass.text].Sealed = False + self.ScopeManager.addScope() + self.ScopeManager.addIdentifier("self", coolClass.text) + self.actualClass = coolClass.text + self.visitChildren(ctx) + self.ScopeManager.deleteScope() + return + else: + line = str(classParent.line) + column = str(classParent.column) + error = "(" + line + "," + column + "): this class doesn't exist" + print(error) + else: + self.TypeTable[coolClass.text].Created = True + self.TypeTable[coolClass.text].Sealed = False + self.ScopeManager.addScope() + self.actualClass = coolClass.text + self.ScopeManager.addIdentifier("self", coolClass.text) + self.visitChildren(ctx) + self.ScopeManager.deleteScope() + return + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx:COOL.MethodContext): + coolClass = ctx.parentCtx.getChild(1).symbol.text + methodName = ctx.getChild(0).symbol.text + methodType = ctx.getChild(len(ctx.children) - 4).symbol + if self.ScopeManager.searchScope(methodName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this method name already exist" + print(error) + elif self.TypeTable.keys().__contains__(self.TypeTable[coolClass].Methods[methodName].Type) or methodType.text == "SELF_TYPE": + self.ScopeManager.addIdentifier(methodName, methodType.text) + self.ScopeManager.addScope() + self.visitChildren(ctx) + self.ScopeManager.deleteScope() + return + else: + line = str(methodType.line) + column = str(methodType.column) + error = "(" + line + "," + column + "): this type doesn't exist" + print(error) + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx:COOL.PropertyContext): + atributeType = ctx.getChild(2).symbol.text + atributeName = ctx.getChild(0).symbol.text + if self.ScopeManager.searchScope(atributeName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this atribute name already exist" + print(error) + return "None" + elif not(self.TypeTable.keys().__contains__(atributeType) or atributeType == "SELF_TYPE"): + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column) + error = "(" + line + "," + column + "): this type doesn't exist" + print(error) + return "None" + elif len(ctx.children) == 5: + atributeValue = ctx.getChild(4).accept(self) + if self.join(atributeType, atributeValue) != atributeType: + line = str(ctx.getChild(4).start.line) + column = str(ctx.getChild(4).start.column) + error = "(" + line + "," + column + "): the type of the expression is diferent of the type of the atribute" + print(error) + return "None" + else: + self.ScopeManager.addIdentifier(atributeName, atributeType) + return atributeType + else: + self.ScopeManager.addIdentifier(atributeName, atributeType) + return atributeType + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx:COOL.FormalContext): + paramName = ctx.getChild(0).symbol.text + paramType = ctx.getChild(2).symbol.text + if self.ScopeManager.searchScope(paramName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this param name already exist" + print(error) + elif self.TypeTable.keys().__contains__(paramType): + self.ScopeManager.addIdentifier(paramName, paramType) + return self.visitChildren(ctx) + else: + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column) + error = "(" + line + "," + column + "): this type doesn't exist" + print(error) + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx: COOL.IntContext): + return "Int" + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx: COOL.StringContext): + return "String" + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx: COOL.FalseContext): + return "Bool" + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx: COOL.TrueContext): + return "Bool" + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx: COOL.AddContext): + addValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + addValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + addValue = "None" + return addValue + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx:COOL.MinusContext): + minusValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + minusValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + minusValue = "None" + return minusValue + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx: COOL.MultiplyContext): + mulValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + mulValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + mulValue = "None" + return mulValue + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx: COOL.DivisionContext): + divValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + divValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + divValue = "None" + return divValue + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx: COOL.NegativeContext): + expressValue = ctx.getChild(1).accept(self) + if expressValue == "Int": + return "Int" + return "None" + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx:COOL.IsvoidContext): + self.visitChildren(ctx) + return "Bool" + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx: COOL.BoolNotContext): + expressValue = ctx.getChild(1).accept(self) + if expressValue == "Bool": + return "Bool" + return "None" + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx:COOL.LessThanContext): + lessValue = "Bool" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessValue = "None" + return lessValue + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx:COOL.LessEqualContext): + lessEqualValue = "Bool" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessEqualValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessEqualValue = "None" + return lessEqualValue + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx: COOL.EqualContext): + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue == "None" or rightValue == "None": + return "None" + if leftValue == rightValue: + return "Bool" + if leftValue == "String" or leftValue == "Int" or leftValue == "Bool": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is incorrect" + print(error) + return "None" + if rightValue == "String" or rightValue == "Int" or rightValue == "Bool": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is incorrect" + print(error) + return "None" + return "Bool" + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx: COOL.AssignmentContext): + variableName = ctx.getChild(0).symbol.text + asignValue = ctx.getChild(2).accept(self) + variableType = self.ScopeManager.searchforType(variableName) + if variableType == "None": + if self.searchAtribute(self.actualClass, variableName): + variableType = self.searchAtributeInfo(self.actualClass, variableName) + else: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this identifier does not exist" + print(error) + return "None" + if variableType == "SELF_TYPE": + variableType = self.actualClass + if self.join(asignValue, variableType) != variableType: + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is diferent that the identifier" + print(error) + return "None" + return variableType + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx: COOL.ParenthesesContext): + return ctx.getChild(1).accept(self) + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx: COOL.IdContext): + IdValue = ctx.getChild(0).symbol.text + if self.ScopeManager.searchIdentifier(IdValue): + return self.ScopeManager.searchforType(IdValue) + elif self.searchAtribute(self.actualClass, IdValue): + return self.searchAtributeInfo(self.actualClass, IdValue) + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this identifier does not exist" + print(error) + return "None" + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx:COOL.IfContext): + ifValue = ctx.getChild(1).accept(self) + thenValue = ctx.getChild(3).accept(self) + elseValue = ctx.getChild(5).accept(self) + if ifValue == "None" or ifValue == "Bool": + return self.join(thenValue, elseValue) + else: + line = str(ctx.getChild(1).start.line) + column = str(ctx.getChild(1).start.column) + error = "(" + line + "," + column + "): this expression is not boolean" + print(error) + return self.join(thenValue, elseValue) + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx: COOL.WhileContext): + whileValue = ctx.getChild(3).accept(self) + whileValue = ctx.getChild(1).accept(self) + if whileValue == "None" or whileValue == "Bool": + return "Object" + else: + line = str(ctx.getChild(1).start.line) + column = str(ctx.getChild(1).start.column) + error = "(" + line + "," + column + "): this expression is not boolean" + print(error) + return "Object" + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx:COOL.BlockContext): + blockValue = "None" + count = 1 + lengt = len(ctx.children) - 1 + while lengt > count: + blockValue = ctx.getChild(count).accept(self) + count = count + 2 + return blockValue + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx:COOL.CaseContext): + ctx.getChild(1).accept(self) + lengt = len(ctx.children) - 1 + count = 3 + caseValue = "None" + while lengt > count: + idName = ctx.getChild(count).symbol.text + count = count + 2 + idType = ctx.getChild(count).symbol.text + count = count + 2 + self.ScopeManager.addScope() + self.ScopeManager.addIdentifier(idName, idType) + if (caseValue == "None"): + caseValue = ctx.getChild(count).accept(self) + else: + caseValue = self.join(caseValue, ctx.getChild(count).accept(self)) + count = count + 2 + self.ScopeManager.deleteScope() + return caseValue + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx: COOL.NewContext): + return ctx.getChild(1).symbol.text + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): + methodType = "None" + if self.searchMethod(self.actualClass, ctx.getChild(0).symbol.text): + methodInfo = self.searchMethodInfo(self.actualClass, ctx.getChild(0).symbol.text) + if(methodInfo.Type == "SELF_TYPE"): + methodType = self.actualClass + else: + methodType = methodInfo.Type + if methodInfo.ParamsNumber == 0 and len(ctx.children) != 3: + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + elif len(ctx.children) != methodInfo.ParamsNumber * 2 + 2 and methodInfo.ParamsNumber != 0: + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + else: + count = 2 + for param in methodInfo.Params: + (_,paramType) = param + requestType = ctx.getChild(count).accept(self) + if (self.join(requestType, paramType) != paramType): + line = str(ctx.getChild(count).start.line) + column = str(ctx.getChild(count).start.column) + error = "(" + line + "," + column + "): the type of this param in the call is incorrect" + print(error) + methodType = "None" + count = count + 2 + else: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this method not exist in " + self.actualClass + print(error) + return methodType + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx:COOL.MethodCallContext): + methodType = "None" + length = 5 + currentClass = ctx.getChild(0).accept(self) + if (ctx.getChild(1).symbol.text == "@"): + length = length + 2 + parent = ctx.getChild(2).symbol.text + if self.join(currentClass, parent) == parent: + currentClass = parent + else: + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column) + error = "(" + line + "," + column + "): this class is not parent of " + currentClass + print(error) + return methodType + if self.searchMethod(currentClass, ctx.getChild(length - 3).symbol.text): + methodInfo = self.searchMethodInfo(currentClass, ctx.getChild(length - 3).symbol.text) + if (methodInfo.Type == "SELF_TYPE"): + methodType = currentClass + else: + methodType = methodInfo.Type + if (methodInfo.ParamsNumber == 0 and len(ctx.children) != length): + line = str(ctx.getChild(length - 3).start.line) + column = str(ctx.getChild(length - 3).start.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + elif (len(ctx.children) != methodInfo.ParamsNumber * 2 + length - 1) and methodInfo.ParamsNumber > 0: + line = str(ctx.getChild(length - 3).start.line) + column = str(ctx.getChild(length - 3).start.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + else: + count = length - 1 + for param in methodInfo.Params: + (_, paramType) = param + requestType = ctx.getChild(count).accept(self) + if (self.join(requestType, paramType) != paramType): + line = str(ctx.getChild(count).start.line) + column = str(ctx.getChild(count).start.column) + error = "(" + line + "," + column + "): the type of this param in the call is incorrect" + print(error) + methodType = "None" + count = count + 2 + else: + line = str(ctx.getChild(length - 3).symbol.line) + column = str(ctx.getChild(length - 3).symbol.column) + error = "(" + line + "," + column + "): this method not exist in " + currentClass + print(error) + return methodType + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx: COOL.LetInContext): + self.ScopeManager.addScope() + count = 0 + while(ctx.getChild(count).symbol.text != "in"): + idName = ctx.getChild(count + 1).symbol.text + count = count + 2 + idType = ctx.getChild(count + 1).symbol.text + if not(self.TypeTable.keys().__contains__(idType)) and idType != "SELF_TYPE": + self.ScopeManager.deleteScope() + line = str(ctx.getChild(count + 1).symbol.line) + column = str(ctx.getChild(count + 1).symbol.column) + error = "(" + line + "," + column + "): this class does not exist " + print(error) + return "None" + self.ScopeManager.addIdentifier(idName, idType) + count = count + 2 + if ctx.getChild(count).symbol.text == "<-": + idValue = ctx.getChild(count + 1).accept(self) + count = count + 2 + if self.join(idType, idValue) != idType: + self.ScopeManager.deleteScope() + line = str(ctx.getChild(count -1).start.line) + column = str(ctx.getChild(count - 1).start.column) + error = "(" + line + "," + column + "): the type of the expression is diferent of the type of the identifier" + print(error) + return "None" + + return ctx.getChild(count + 1).accept(self) + +class TypeCOOLVisitor(ParseTreeVisitor): + + TypeTable = {} + + Counter = 0 + + ConstantTable = list() + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx: COOL.ProgramContext, fileName: str): + self.TypeTable["Object"] = COOLClass("Object", "None", True, False) + self.TypeTable["Object"].Methods["abort"] = COOLMethod("abort", "Object", 0, None) + self.TypeTable["Object"].Methods["type_name"] = COOLMethod("type_name", "String", 0, None) + self.TypeTable["Object"].Methods["copy"] = COOLMethod("copy", "SELF_TYPE", 0, None) + self.TypeTable["String"] = COOLClass("String", "Object", True, True) + self.TypeTable["String"].Methods["length"] = COOLMethod("length", "Int", 0, None) + self.TypeTable["String"].Methods["concat"] = COOLMethod("concat", "String", 1, None) + self.TypeTable["String"].Methods["concat"].Params.append(("s", "String")) + self.TypeTable["String"].Methods["substr"] = COOLMethod("substr", "String", 2, None) + self.TypeTable["String"].Methods["substr"].Params.append(("i", "Int")) + self.TypeTable["String"].Methods["substr"].Params.append(("l", "Int")) + self.TypeTable["Int"] = COOLClass("Int", "Object", True, True) + self.TypeTable["Bool"] = COOLClass("Bool", "Object", True, True) + self.TypeTable["IO"] = COOLClass("IO", "Object", True, False) + self.TypeTable["IO"].Methods["in_string"] = COOLMethod("in_string", "String", 0, None) + self.TypeTable["IO"].Methods["in_int"] = COOLMethod("in_int", "Int", 0, None) + self.TypeTable["IO"].Methods["out_string"] = COOLMethod("out_string", "SELF_TYPE", 1, None) + self.TypeTable["IO"].Methods["out_string"].Params.append(("x", "String")) + self.TypeTable["IO"].Methods["out_int"] = COOLMethod("out_int", "SELF_TYPE", 1, None) + self.TypeTable["IO"].Methods["out_int"].Params.append(("x", "Int")) + self.ConstantTable.append(("", "String", "str_const0")) + self.ConstantTable.append((0, "Int", "int_const0")) + self.ConstantTable.append(("false", "Bool", "bool_const0")) + self.ConstantTable.append((fileName, "String", "str_const1")) + self.ConstantTable.append((len(fileName), "Int", F"int_const{len(fileName)}")) + self.Counter = 2 + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx: COOL.ClassesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx: COOL.ClassDefineContext): + coolClass = ctx.getChild(1).symbol + if self.TypeTable.keys().__contains__(coolClass.text): + return + if ctx.getChild(2).symbol.text == "inherits": + classParent = ctx.getChild(3).symbol + self.TypeTable[coolClass.text] = COOLClass(coolClass.text, classParent.text, False, False) + return self.visitChildren(ctx) + else: + self.TypeTable[coolClass.text] = COOLClass(coolClass.text, "Object", False, False) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx: COOL.MethodContext): + name = ctx.getChild(0).symbol.text + cclass = ctx.parentCtx.getChild(1).symbol.text + if self.TypeTable[cclass].Methods.keys().__contains__(name): + return + n = len(ctx.children) - 4 + if ctx.getChild(n).symbol.text == ":": + n = n + 1 + type = ctx.getChild(n).symbol.text + lengt = len(ctx.children) - 8 + paramsNumber = 0 + if lengt > 0: + paramsNumber = 1 + while lengt > 1: + lengt = lengt - 2 + paramsNumber = paramsNumber + 1 + self.TypeTable[cclass].Methods[name] = COOLMethod(name, type, paramsNumber, ctx.getChild(len(ctx.children) - 2)) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx: COOL.PropertyContext): + cclass = ctx.parentCtx.getChild(1).symbol.text + name = ctx.getChild(0).symbol.text + if self.TypeTable[cclass].Atributes.keys().__contains__(name): + return + type = ctx.getChild(2).symbol.text + self.TypeTable[cclass].Atributes[name] = type + if len(ctx.children) == 5: + self.TypeTable[cclass].AtributeAsign[name] = ctx.getChild(4) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx: COOL.FormalContext): + parent = ctx.parentCtx + + className = parent.parentCtx.getChild(1).symbol.text + methodName = parent.getChild(0).symbol.text + method = self.TypeTable[className].Methods[methodName] + for param in method.Params: + (paramName, paramType) = param + if (paramName == ctx.getChild(0).symbol.text): + return + method.Params.append((ctx.getChild(0).symbol.text, ctx.getChild(2).symbol.text)) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx: COOL.LetInContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx: COOL.MinusContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx: COOL.StringContext): + constantName = ctx.getChild(0).symbol.text[1:-1] + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == constantName and consType == "String": + return self.visitChildren(ctx) + + self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) + self.Counter = self.Counter + 1 + length = len(constantName) + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == length and consType == "Int": + return self.visitChildren(ctx) + self.ConstantTable.append((length, "Int", f"int_const{length}")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx: COOL.IsvoidContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx: COOL.WhileContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx: COOL.DivisionContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx: COOL.NegativeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx: COOL.BoolNotContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx: COOL.LessThanContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx: COOL.BlockContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx: COOL.IdContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx: COOL.MultiplyContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx: COOL.IfContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx: COOL.CaseContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx: COOL.AddContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx: COOL.NewContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx: COOL.ParenthesesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx: COOL.AssignmentContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx: COOL.FalseContext): + for cons in self.ConstantTable: + (consName, consType, _) = cons + if consName == "false" and consType == "Bool": + return self.visitChildren(ctx) + + self.ConstantTable.append(("false", "Bool", "bool_const0")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx: COOL.IntContext): + constantName = int(ctx.getChild(0).symbol.text) + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == constantName and consType == "Int": + return self.visitChildren(ctx) + + self.ConstantTable.append((constantName, "Int", f"int_const{constantName}")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx: COOL.EqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx: COOL.TrueContext): + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == "true" and consType == "Bool": + return self.visitChildren(ctx) + + self.ConstantTable.append(("true", "Bool","bool_const1")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx: COOL.LessEqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx: COOL.MethodCallContext): + return self.visitChildren(ctx) + +class CodegenVisitor(ParseTreeVisitor): + + CurrentClass : COOLClass + + def __init__(self, typeTable: dict, constantTable: list, counter: int): + self.TypeTable = typeTable + self.ConstantTable = constantTable + self.Counter = counter + self.LabelCounter = 0 + + def genGlobalClases(self): + sol = "\t.data\n\t.align 2\n\t.globl class_nameTab\n" + for clasName in self.TypeTable.keys(): + protoName = "\t.globl " + clasName + "_protObj\n" + sol = sol + protoName + sol = sol + "_string_tag:\n\t.word 1\n_int_tag:\n\t.word 2\n_bool_tag :\n\t.word 3\n" + return sol + + def genConstant(self, sol: str): + for const in self.ConstantTable: + (constName, constType, constLabel) = const + if constType == "Bool": + sol = sol + \ + f"\t.word -1\n" \ + f"{constLabel}:\n" \ + f"\t.word 5\n" \ + f"\t.word 4\n" \ + f"\t.word Bool_dispTab\n" \ + f"\t.word {constLabel[-1]}\n" + elif constType == "Int": + sol = sol + \ + f"\t.word -1\n{constLabel}:\n" \ + f"\t.word 3\n\t.word 4\n" \ + f"\t.word Int_dispTab\n" \ + f"\t.word {constName}\n" + else: + length = int(len(constName) / 4) + 3 + if len(constName) % 4 != 0: + length = length + 1 + sol = sol + \ + f"\t.word -1\n{constLabel}:\n" \ + f"\t.word 4\n\t.word {length}\n" \ + f"\t.word String_dispTab\n" \ + f"\t.word int_const{len(constName)}\n" \ + f"\t.ascii \"{constName}\"\n" \ + f"\t.byte 0\n" \ + f"\t.align 2\n" + return sol + + def findLabel(self, name: str): + for const in self.ConstantTable: + (constName, constType, constLabel) = const + if constName == name and constType == "String": + return constLabel + + def genMethodNames(self, coolClass: str, coolMethods: list, className: str): + if coolClass == "None": + return "" + temp = "" + methodList = list() + for method in self.TypeTable[coolClass].Methods: + if not (coolMethods.__contains__(method)): + temp = temp + f"\t.word {coolClass}.{method}\n" + methodList.append(method) + coolMethods.append(method) + + code = self.genMethodNames(self.TypeTable[coolClass].Parent, coolMethods, className) + if coolClass != "Object": + self.TypeTable[coolClass].TagMethods = self.TypeTable[self.TypeTable[coolClass].Parent].TagMethods + methodList + else: + self.TypeTable[coolClass].TagMethods = methodList + return code + temp + + + + def genAtributeNames(self, coolClass: str, coolAtributes: list): + if coolClass == "None": + return "" + temp = "" + listAtributes = list() + for atribute in self.TypeTable[coolClass].Atributes: + if not (coolAtributes.__contains__(atribute)): + listAtributes.append(atribute) + value = self.TypeTable[coolClass].Atributes[atribute] + if value == "Int" or value == "String" or value == "Bool": + temp = temp + f"\t.word {value.lower()}_constant0\n" + else: + temp = temp + f"\t.word 0\n" + coolAtributes.append(atribute) + + code = self.genAtributeNames(self.TypeTable[coolClass].Parent, coolAtributes) + if coolClass != "Object": + self.TypeTable[coolClass].TagAtributes = self.TypeTable[self.TypeTable[coolClass].Parent].TagAtributes + listAtributes + return code + temp + + def genClassTable(self): + classNameTab = "class_nameTab:\n" + class_objTab = "class_objTab:\n" + methods = "" + atributes = "" + counter = 0 + for className in self.TypeTable: + classNameTab = classNameTab + f"\t.word {self.findLabel(className)}\n" + temp = self.genMethodNames(className, list(), className) + class_objTab = class_objTab + \ + f"\t.word {className}_protObj\n" \ + f"\t.word {className}_init\n" + methods = methods + f"{className}_dispTab:\n" + temp + if className == "Int" or className == "Bool": + atributes = atributes + \ + f"\t.word -1\n" \ + f"{className}_protObj:\n" \ + f"\t.word {counter}\n" \ + f"\t.word 4\n" \ + f"\t.word {className}_dispTab\n" \ + f"\t.word 0\n" + elif className == "String": + atributes = atributes + \ + f"\t.word -1\n" \ + f"{className}_protObj:\n" \ + f"\t.word {counter}\n" \ + f"\t.word 5\n" \ + f"\t.word {className}_dispTab\n" \ + f"\t.word int_constant0\n" \ + f"\t.word 0\n" + else: + atributeList = list() + temp = self.genAtributeNames(className, atributeList) + atributes = atributes + \ + f"\t.word -1\n" \ + f"{className}_protObj:\n" \ + f"\t.word {counter}\n" \ + f"\t.word {len(atributeList) + 3}\n" \ + f"\t.word {className}_dispTab\n" \ + f"" + temp + self.TypeTable[className].Tag = counter + counter = counter + 1 + return classNameTab + class_objTab + methods + atributes + + def genClassAtributes(self, className: str): + if className == "None": + return "" + code = self.genClassAtributes(self.TypeTable[className].Parent) + for atribute in self.TypeTable[className].AtributeAsign: + code = code + (self.TypeTable[className].AtributeAsign[atribute].accept(self) or "") + return code + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): + for className in self.TypeTable: + constantName = className + self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) + self.Counter = self.Counter + 1 + length = len(constantName) + contain = True + for cons in self.ConstantTable: + (consName, consType, _) = cons + if consName == length and consType == "Int": + contain = False + if contain: + self.ConstantTable.append((length, "Int", f"int_const{length}")) + self.ConstantTable.append(("SELF_TYPE", "String", f"str_const{self.Counter}")) + contain = True + length = len("SELF_TYPE") + for cons in self.ConstantTable: + (consName, consType, _) = cons + if consName == length and consType == "Int": + contain = False + if contain: + self.ConstantTable.append((length, "Int", f"int_const{length}")) + code = self.genGlobalClases() + code = self.genConstant(code) + code = code + self.genClassTable() + code = code + \ + "\t.globl heap_start\n" \ + "heap_start:\n" \ + "\t.word 0\n" \ + "\t.text\n" \ + "\t.globl Main_init\n" \ + "\t.globl Int_init\n" \ + "\t.globl String_init\n" \ + "\t.globl Bool_init\n" \ + "\t.globl Main.main\n" + for className in self.TypeTable: + code = code + f"{className}_init:\n" + temp = self.genClassAtributes(className) + if len(temp) != 0: + code = code + \ + "\taddiu $sp $sp -12\n" \ + "\tsw $fp 12($sp)\n" \ + "\tsw $s0 8($sp)\n" \ + "\tsw $ra 4($sp)\n" \ + "\taddiu $fp $sp 4\n" \ + "\tmove $s0 $a0\n" + code = code + temp + code = code + \ + "\tmove $a0 $s0\n" \ + "\tlw $fp 12($sp)\n" \ + "\tlw $s0 8($sp)\n" \ + "\tlw $ra 4($sp)\n" \ + "\taddiu $sp $sp 12\n" + code = code + "\tjr $ra\n" + for className in self.TypeTable: + if not(className == "Object" or className == "String" or className == "Int" or className == "Bool" or className == "IO"): + self.CurrentClass = self.TypeTable[className] + for methodName in self.TypeTable[className].Methods: + code = code + f"{className}.{methodName}:\n" + code = code + \ + "\taddiu $sp $sp -12\n" \ + "\tsw $fp 12($sp)\n" \ + "\tsw $s0 8($sp)\n" \ + "\tsw $ra 4($sp)\n" \ + "\taddiu $fp $sp 4\n" \ + "\tmove $s0 $a0\n" + code = code + (self.TypeTable[className].Methods[methodName].InstructionSet.accept(self) or "") + code = code + \ + "\tmove $a0 $s0\n" \ + "\tlw $fp 12($sp)\n" \ + "\tlw $s0 8($sp)\n" \ + "\tlw $ra 4($sp)\n" \ + "\taddiu $sp $sp 12\n" + code = code + "\tjr $ra\n" + + code = self.RuntimeMessages + \ + "\n" + \ + self.MemManagerNoGCInit + \ + "\n" + \ + code + \ + "\n" + \ + self.RuntimeCode + \ + "\n" + \ + self.MemManagerNoGC + + outFile = open(outFilename, "w"); + outFile.write(code) + #print(code) + + return + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx: COOL.ClassesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx: COOL.ClassDefineContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx: COOL.MethodContext): + return "" + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx: COOL.PropertyContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx: COOL.FormalContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx: COOL.LetInContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx: COOL.MinusContext): + code = ctx.getChild(0).accept(self) + code = code + \ + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy\n" + \ + "\tlw $t1 4($sp)\n" + \ + "\tlw $t1 12($t1)\n" + \ + "\tlw $t2 12($a0)\n" + \ + "\tsub $t1 $t1 $t2\n" + \ + "\tsw $t1 12($a0)\n" + \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx: COOL.StringContext): + name = ctx.getChild(0).symbol.text[1:-1] + for const in self.ConstantTable: + (constName, constType, constTag) = const + if constType == "String" and constName == name: + return f"\tla $a0 {constTag}\n" + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx: COOL.IsvoidContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx: COOL.WhileContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx: COOL.DivisionContext): + code = ctx.getChild(0).accept(self) + code += \ + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code += ctx.getChild(2).accept(self) + code += \ + "\tjal Object.copy\n" \ + "\tlw $t1 4($sp)\n" \ + "\tlw $t1 12($t1)\n" \ + "\tlw $t2 12($a0)\n" \ + "\tdiv $t1 $t2\n" \ + "\tmflo $t1\n" \ + "\tsw $t1 12($a0)\n" \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx: COOL.NegativeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx: COOL.BoolNotContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx: COOL.LessThanContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx: COOL.BlockContext): + counter = 1 + length = len(ctx.children) - 1 + code = "" + while(counter < length ): + code += (ctx.getChild(counter).accept(self)) + counter += 2 + return code + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx: COOL.IdContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx: COOL.MultiplyContext): + code = ctx.getChild(0).accept(self) + code = code + \ + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy\n" + \ + "\tlw $t1 4($sp)\n" + \ + "\tlw $t1 12($t1)\n" + \ + "\tlw $t2 12($a0)\n" + \ + "\tmul $t1 $t1 $t2\n" + \ + "\tsw $t1 12($a0)\n" + \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx: COOL.IfContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx: COOL.CaseContext): + return "" + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): + length = len(ctx.children) + code = "" + if length > 3: + count = 2 + while length != count: + param = (ctx.getChild(count).accept(self) or "") + code += param + \ + f"\tsw $a0 0($sp)\n" \ + f"\taddiu $sp $sp -4\n" + count = count + 2 + methodIdx = self.CurrentClass.TagMethods.index(ctx.getChild(0).symbol.text) + code += "\tmove $a0 $s0\n" \ + "\tlw $t1 8($a0)\n" \ + f"\tlw $t1 {methodIdx * 4}($t1)\n" \ + "\tjalr $t1\n" + return code + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx: COOL.AddContext): + code = ctx.getChild(0).accept(self) or "" + code = code + \ + "\tsw $a0 0 ($sp)\n"+ \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy\n"+ \ + "\tlw $t1 4($sp)\n"+ \ + "\tlw $t1 12($t1)\n"+ \ + "\tlw $t2 12($a0)\n"+ \ + "\tadd $t1 $t1 $t2\n"+ \ + "\tsw $t1 12($a0)\n"+ \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx: COOL.NewContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx: COOL.ParenthesesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx: COOL.AssignmentContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx: COOL.FalseContext): + return f"\tla $a0 {bool_const0}\n" + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx: COOL.IntContext): + val = int(ctx.getChild(0).symbol.text) + for const in self.ConstantTable: + (constVal, constType, constTag) = const + if constType == "Int" and constVal == val: + return f"\tla $a0 {constTag}\n" + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx: COOL.EqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx: COOL.TrueContext): + return f"\tla $a0 {bool_const1}\n" + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx: COOL.LessEqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx: COOL.MethodCallContext): + # line = ctx.getChild(1).symbol.line + # f"\tbne $t2 $zero label{self.LabelCounter}\n" \ + # "\tla $a0 str_const1\n" \ + # f"\tli $t1 {line}\n" \ + # "\tjal _dispatch_abort\n" \ + # f"label{self.LabelCounter}:\n" \ + # self.LabelCounter += 1 + return "" + + RuntimeMessages = """ +# +# Messages for the Runtime +# + .data + +_abort_msg: .asciiz "Abort called from class " +_colon_msg: .asciiz ":" +_dispatch_msg: .asciiz ": Dispatch to void.\\n" +_cabort_msg: .asciiz "No match in case statement for Class " +_cabort_msg2: .asciiz "Match on void in case statement.\\n" +_nl: .asciiz "\\n" +_term_msg: .asciiz "\nCOOL program successfully executed\\n" +_sabort_msg1: .asciiz "Index to substr is negative\\n" +_sabort_msg2: .asciiz "Index to substr is too big\\n" +_sabort_msg3: .asciiz "Length to substr too long\\n" +_sabort_msg4: .asciiz "Length to substr is negative\\n" +_sabort_msg: .asciiz "Execution aborted.\\n" +_objcopy_msg: .asciiz "Object.copy: Invalid object size.\\n" +_gc_abort_msg: .asciiz "GC bug!\\n" + +# +# Messages for the GenGC garabge collector +# + +_GenGC_INITERROR: .asciiz "GenGC: Unable to initialize the garbage collector.\\n" +_GenGC_COLLECT: .asciiz "Garbage collecting ...\\n" +_GenGC_Major: .asciiz "Major ...\\n" +_GenGC_Minor: .asciiz "Minor ...\\n" +#_GenGC_COLLECT: .asciiz "" +_GenGC_MINORERROR: .asciiz "GenGC: Error during minor garbage collection.\\n" +_GenGC_MAJORERROR: .asciiz "GenGC: Error during major garbage collection.\\n" + +# +# Messages for the NoGC garabge collector +# + +_NoGC_COLLECT: .asciiz "Increasing heap...\\n" +#_NoGC_COLLECT: .asciiz "" +""" + + MemManagerNoGCInit = """ + .data + .align 2 + + .globl _MemMgr_INITIALIZER +_MemMgr_INITIALIZER: + .word _NoGC_Init + .globl _MemMgr_COLLECTOR +_MemMgr_COLLECTOR: + .word _NoGC_Collect + .globl _MemMgr_TEST +_MemMgr_TEST: + .word 0 +""" + + MemManagerGenGCInit = """ + .data + .align 2 + + .globl _MemMgr_INITIALIZER + _MemMgr_INITIALIZER: + .word _GenGC_Init + .globl _MemMgr_COLLECTOR + _MemMgr_COLLECTOR: + .word _GenGC_Collect + .globl _MemMgr_TEST + _MemMgr_TEST: + .word 0 + """ + + RuntimeCode = """ +# +# Define some constants +# + +obj_eyecatch=-4 # Unique id to verify any object +obj_tag=0 +obj_size=4 +obj_disp=8 +obj_attr=12 +int_slot=12 +bool_slot=12 +str_size=12 # This is a pointer to an Int object!!! +str_field=16 # The beginning of the ascii sequence +str_maxsize=1026 # the maximum string length + +# +# The REG mask tells the garbage collector which register(s) it +# should automatically update on a garbage collection. Note that +# this is (ANDed) with the ARU mask before the garbage collector +# reads it. Only the registers specified in the garbage collector's +# ARU mask can be automatically updated. +# +# BITS---------------------------- +# 3 2 1 0 +# 10987654321098765432109876543210 +# -------------------------------- +# +# 00000000011111110000000000000000 <- initial Register (REG) mask +# +--++--++--++--++--++--++--++--+ $s0-$s6 +# 0 0 7 F 0 0 0 0 ($16-$22) +# + +MemMgr_REG_MASK=0x007F0000 + + .text + .globl main +main: + li $v0 9 + move $a0 $zero + syscall # sbrk + move $a0 $sp # initialize the garbage collector + li $a1 MemMgr_REG_MASK + move $a2 $v0 + jal _MemMgr_Init # sets $gp and $s7 (limit) + la $a0 Main_protObj # create the Main object + jal Object.copy # Call copy + addiu $sp $sp -4 + sw $a0 4($sp) # save the Main object on the stack + move $s0 $a0 # set $s0 to point to self + jal Main_init # initialize the Main object + jal Main.main # Invoke main method + addiu $sp $sp 4 # restore the stack + la $a0 _term_msg # show terminal message + li $v0 4 + syscall + li $v0 10 + syscall # syscall 10 (exit) + +# +# Polymorphic equality testing function: +# Two objects are equal if they are +# - identical (pointer equality, inlined in code) +# - have same tag and are of type BOOL,STRING,INT and contain the +# same data +# +# INPUT: The two objects are passed in $t1 and $t2 +# OUTPUT: Initial value of $a0, if the objects are equal +# Initial value of $a1, otherwise +# +# The tags for Int,Bool,String are found in the global locations +# _int_tag, _bool_tag, _string_tag, which are initialized by the +# data part of the generated code. This removes a consistency problem +# between this file and the generated code. +# + + .globl equality_test +equality_test: # ops in $t1 $t2 + # true in A0, false in A1 + # assume $t1, $t2 are not equal + beq $t1 $zero _eq_false # $t2 can't also be void + beq $t2 $zero _eq_false # $t1 can't also be void + lw $v0 obj_tag($t1) # get tags + lw $v1 obj_tag($t2) + bne $v1 $v0 _eq_false # compare tags + lw $a2 _int_tag # load int tag + beq $v1 $a2 _eq_int # Integers + lw $a2 _bool_tag # load bool tag + beq $v1 $a2 _eq_int # Booleans + lw $a2 _string_tag # load string tag + bne $v1 $a2 _eq_false # Not a primitive type +_eq_str: # handle strings + lw $v0, str_size($t1) # get string size objs + lw $v1, str_size($t2) + lw $v0, int_slot($v0) # get string sizes + lw $v1, int_slot($v1) + bne $v1 $v0 _eq_false + beqz $v1 _eq_true # 0 length strings are equal + add $t1 str_field # Point to start of string + add $t2 str_field + move $t0 $v0 # Keep string length as counter +_eq_l1: + lbu $v0,0($t1) # get char + add $t1 1 + lbu $v1,0($t2) + add $t2 1 + bne $v1 $v0 _eq_false + addiu $t0 $t0 -1 # Decrement counter + bnez $t0 _eq_l1 + b _eq_true # end of strings + +_eq_int: # handles booleans and ints + lw $v0,int_slot($t1) # load values + lw $v1,int_slot($t2) + bne $v1 $v0 _eq_false +_eq_true: + jr $ra # return true +_eq_false: + move $a0 $a1 # move false into accumulator + jr $ra + +# +# _dispatch_abort +# +# filename in $a0 +# line number in $t1 +# +# Prints error message and exits. +# Called on dispatch to void. +# + .globl _dispatch_abort +_dispatch_abort: + sw $t1 0($sp) # save line number + addiu $sp $sp -4 + addiu $a0 $a0 str_field # adjust to beginning of string + li $v0 4 + syscall # print file name + la $a0 _colon_msg + li $v0 4 + syscall # print ":" + lw $a0 4($sp) # + li $v0 1 + syscall # print line number + li $v0 4 + la $a0 _dispatch_msg + syscall # print dispatch-to-void message + li $v0 10 + syscall # exit + + +# +# _case_abort2 +# +# filename in $a0 +# line number in $t1 +# +# Prints error message and exits. +# Called on case on void. +# + .globl _case_abort2 +_case_abort2: + sw $t1 0($sp) # save line number + addiu $sp $sp -4 + addiu $a0 $a0 str_field # adjust to beginning of string + li $v0 4 + syscall # print file name + la $a0 _colon_msg + li $v0 4 + syscall # print ":" + lw $a0 4($sp) # + li $v0 1 + syscall # print line number + li $v0 4 + la $a0 _cabort_msg2 + syscall # print case-on-void message + li $v0 10 + syscall # exit + +# +# +# _case_abort +# Is called when a case statement has no match +# +# INPUT: $a0 contains the object on which the case was +# performed +# +# Does not return! +# + .globl _case_abort +_case_abort: # $a0 contains case expression obj. + move $s0 $a0 # save the expression object + la $a0 _cabort_msg + li $v0 4 + syscall # print_str + la $t1 class_nameTab + lw $v0 obj_tag($s0) # Get object tag + sll $v0 $v0 2 # *4 + addu $t1 $t1 $v0 + lw $t1 0($t1) # Load class name string obj. + addiu $a0 $t1 str_field # Adjust to beginning of str + li $v0 4 # print_str + syscall + la $a0 _nl + li $v0 4 # print_str + syscall + li $v0 10 + syscall # Exit + + +# +# Copy method +# +# Copies an object and returns a pointer to a new object in +# the heap. Note that to increase performance, the stack frame +# is not set up unless it is absolutely needed. As a result, +# the frame is setup just before the call to "_MemMgr_Alloc" and +# is destroyed just after it. The increase in performance +# occurs becuase the calls to "_MemMgr_Alloc" happen very +# infrequently when the heap needs to be garbage collected. +# +# INPUT: $a0: object to be copied to free space in heap +# +# OUTPUT: $a0: points to the newly created copy. +# +# Registers modified: +# $t0, $t1, $t2, $v0, $v1, $a0, $a1, $a2, $gp, $s7 +# + + .globl Object.copy +Object.copy: + addiu $sp $sp -8 # create stack frame + sw $ra 8($sp) + sw $a0 4($sp) + + jal _MemMgr_Test # test GC area + + lw $a0 4($sp) # get object size + lw $a0 obj_size($a0) + blez $a0 _objcopy_error # check for invalid size + sll $a0 $a0 2 # convert words to bytes + addiu $a0 $a0 4 # account for eyecatcher + jal _MemMgr_Alloc # allocate storage + addiu $a1 $a0 4 # pointer to new object + + lw $a0 4($sp) # the self object + lw $ra 8($sp) # restore return address + addiu $sp $sp 8 # remove frame + lw $t0 obj_size($a0) # get size of object + sll $t0 $t0 2 # convert words to bytes + b _objcopy_allocated # get on with the copy + +# A faster version of Object.copy, for internal use (does not call +# _MemMgr_Test, and if possible not _MemMgr_Alloc) + +_quick_copy: + lw $t0 obj_size($a0) # get size of object to copy + blez $t0 _objcopy_error # check for invalid size + sll $t0 $t0 2 # convert words to bytes + addiu $t1 $t0 4 # account for eyecatcher + add $gp $gp $t1 # allocate memory + sub $a1 $gp $t0 # pointer to new object + blt $gp $s7 _objcopy_allocated # check allocation +_objcopy_allocate: + sub $gp $a1 4 # restore the original $gp + addiu $sp $sp -8 # frame size + sw $ra 8($sp) # save return address + sw $a0 4($sp) # save self + move $a0 $t1 # put bytes to allocate in $a0 + jal _MemMgr_Alloc # allocate storage + addiu $a1 $a0 4 # pointer to new object + lw $a0 4($sp) # the self object + lw $ra 8($sp) # restore return address + addiu $sp $sp 8 # remove frame + lw $t0 obj_size($a0) # get size of object + sll $t0 $t0 2 # convert words to bytes +_objcopy_allocated: + addiu $t1 $0 -1 + sw $t1 obj_eyecatch($a1) # store eyecatcher + add $t0 $t0 $a0 # find limit of copy + move $t1 $a1 # save source +_objcopy_loop: + lw $v0 0($a0) # copy word + sw $v0 0($t1) + addiu $a0 $a0 4 # update source + addiu $t1 $t1 4 # update destination + bne $a0 $t0 _objcopy_loop # loop +_objcopy_end: + move $a0 $a1 # put new object in $a0 + jr $ra # return +_objcopy_error: + la $a0 _objcopy_msg # show error message + li $v0 4 + syscall + li $v0 10 # exit + syscall + +# +# +# Object.abort +# +# The abort method for the object class (usually inherited by +# all other classes) +# +# INPUT: $a0 contains the object on which abort() was dispatched. +# + + .globl Object.abort +Object.abort: + move $s0 $a0 # save self + li $v0 4 + la $a0 _abort_msg + syscall # print_str + la $t1 class_nameTab + lw $v0 obj_tag($s0) # Get object tag + sll $v0 $v0 2 # *4 + addu $t1 $t1 $v0 + lw $t1 0($t1) # Load class name string obj. + addiu $a0 $t1 str_field # Adjust to beginning of str + li $v0 4 # print_str + syscall + la $a0 _nl + li $v0 4 + syscall # print new line + li $v0 10 + syscall # Exit + +# +# +# Object.type_name +# +# INPUT: $a0 object who's class name is desired +# OUTPUT: $a0 reference to class name string object +# + + .globl Object.type_name +Object.type_name: + la $t1 class_nameTab + lw $v0 obj_tag($a0) # Get object tag + sll $v0 $v0 2 # *4 + addu $t1 $t1 $v0 # index table + lw $a0 0($t1) # Load class name string obj. + jr $ra + +# +# +# IO.out_string +# +# Prints out the contents of a string object argument +# which is on top of the stack. +# +# $a0 is preserved! +# + + .globl IO.out_string +IO.out_string: + addiu $sp $sp -4 + sw $a0 4($sp) # save self + lw $a0 8($sp) # get arg + addiu $a0 $a0 str_field # Adjust to beginning of str + li $v0 4 # print_str + syscall + lw $a0 4($sp) # return self + addiu $sp $sp 8 # pop argument + jr $ra + +# +# +# IO.out_int +# +# Prints out the contents of an integer object on top of the +# stack. +# +# $a0 is preserved! +# + + .globl IO.out_int +IO.out_int: + addiu $sp $sp -4 + sw $a0 4($sp) # save self + lw $a0 8($sp) # get arg + lw $a0 int_slot($a0) # Fetch int + li $v0 1 # print_int + syscall + lw $a0 4($sp) # return self + addiu $sp $sp 8 # pop argument + jr $ra + +# +# +# IO.in_int +# +# Returns an integer object read from the terminal in $a0 +# + + .globl IO.in_int +IO.in_int: + addiu $sp $sp -4 + sw $ra 4($sp) # save return address + + la $a0 Int_protObj + jal _quick_copy # Call copy + jal Int_init + + addiu $sp $sp -4 + sw $a0 4($sp) # save new object + + li $v0, 5 # read int + syscall + + lw $a0 4($sp) + addiu $sp $sp 4 + + + sw $v0 int_slot($a0) # store int read into obj + lw $ra 4($sp) + addiu $sp $sp 4 + jr $ra + +# +# +# IO.in_string +# +# Returns a string object read from the terminal, removing the +# '\\n' +# +# OUTPUT: $a0 the read string object +# + + .globl IO.in_string +IO.in_string: + addiu $sp $sp -8 + sw $ra 8($sp) # save return address + sw $0 4($sp) # init GC area + + jal _MemMgr_Test # test GC area + + la $a0 Int_protObj # Int object for string size + jal _quick_copy + jal Int_init + sw $a0 4($sp) # save it + + li $a0 str_field # size of string obj. header + addiu $a0 $a0 str_maxsize # max size of string data + jal _MemMgr_QAlloc # make sure enough room + + la $a0 String_protObj # make string object + jal _quick_copy + jal String_init + lw $t0 4($sp) # get size object + sw $t0 str_size($a0) # store size object in string + sw $a0 4($sp) # save string object + + addiu $gp $gp -4 # overwrite last word + +_instr_ok: + li $a1 str_maxsize # largest string to read + move $a0 $gp + li $v0, 8 # read string + syscall + + move $t0 $gp # t0 to beginning of string +_instr_find_end: + lb $v0 0($gp) + addiu $gp $gp 1 + bnez $v0 _instr_find_end + + # $gp points just after the null byte + lb $v0 0($t0) # is first byte '\\0'? + bnez $v0 _instr_noteof + + # we read nothing. Return '\\n' (we don't have '\\0'!!!) + add $v0 $zero 10 # load '\\n' into $v0 + sb $v0 -1($gp) + sb $zero 0($gp) # terminate + addiu $gp $gp 1 + b _instr_nonl + +_instr_noteof: + # Check if there really is a '\\n' + lb $v0 -2($gp) + bne $v0 10 _instr_nonl + + # Write '\\0' over '\\n' + sb $zero -2($gp) # Set end of string where '\\n' was + addiu $gp $gp -1 # adjust for '\\n' + +_instr_nonl: + lw $a0 4($sp) # get pointer to new str obj + lw $t1 str_size($a0) # get pointer to int obj + + sub $t0 $gp $a0 + subu $t0 str_field # calc actual str size + addiu $t0 -1 # adjust for '\\0' + sw $t0 int_slot($t1) # store string size in int obj + addi $gp $gp 3 # was already 1 past '\\0' + and $gp $gp 0xfffffffc # word align $gp + + sub $t0 $gp $a0 # calc length + srl $t0 $t0 2 # divide by 4 + sw $t0 obj_size($a0) # set size field of obj + + lw $ra 8($sp) # restore return address + addiu $sp $sp 8 + jr $ra # return + +# +# +# String.length +# Returns Int Obj with string length of self +# +# INPUT: $a0 the string object +# OUTPUT: $a0 the int object which is the size of the string +# + + .globl String.length +String.length: + lw $a0 str_size($a0) # fetch attr + jr $ra # Return + +# +# String.concat +# +# Concatenates arg1 onto the end of self and returns a pointer +# to the new object. +# +# INPUT: $a0: the first string object (self) +# Top of stack: the second string object (arg1) +# +# OUTPUT: $a0 the new string object +# + + .globl String.concat +String.concat: + + addiu $sp $sp -16 + sw $ra 16($sp) # save return address + sw $a0 12($sp) # save self arg. + sw $0 8($sp) # init GC area + sw $0 4($sp) # init GC area + + jal _MemMgr_Test # test GC area + + lw $a0 12($sp) + lw $a0 str_size($a0) + jal _quick_copy # Call copy + sw $a0 8($sp) # save new size object + + lw $t1 20($sp) # load arg object + lw $t1 str_size($t1) # get size object + lw $t1 int_slot($t1) # arg string size + blez $t1 _strcat_argempty # nothing to add + lw $t0 12($sp) # load self object + lw $t0 str_size($t0) # get size object + lw $t0 int_slot($t0) # self string size + addu $t0 $t0 $t1 # new size + sw $t0 int_slot($a0) # store new size + + addiu $a0 $t0 str_field # size to allocate + addiu $a0 $a0 4 # include '\\0', +3 to align + and $a0 $a0 0xFFFFFFFC # align on word boundary + addiu $a0 $a0 1 # make size odd for GC <-| + sw $a0 4($sp) # save size in bytes | + addiu $a0 $a0 3 # include eyecatcher(4) -1 + jal _MemMgr_QAlloc # check memory + + lw $a0 12($sp) # copy self + jal _quick_copy # Call copy + lw $t0 8($sp) # get the Int object + sw $t0 str_size($a0) # store it in the str obj. + + sub $t1 $gp $a0 # bytes allocated by _quick_copy + lw $t0 4($sp) # get size in bytes (no eyecatcher) + sub $t0 $t0 1 # Remove extra 1 (was for GC) + sub $t1 $t0 $t1 # more memory needed + addu $gp $gp $t1 # allocate rest + srl $t0 $t0 2 # convert to words + sw $t0 obj_size($a0) # save new object size + + lw $t0 12($sp) # get original self object + lw $t0 str_size($t0) # get size object + lw $t0 int_slot($t0) # self string size + addiu $t1 $a0 str_field # points to start of string data + addu $t1 $t1 $t0 # points to end: '\\0' + lw $t0 20($sp) # load arg object + addiu $t2 $t0 str_field # points to start of arg data + lw $t0 str_size($t0) # get arg size + lw $t0 int_slot($t0) + addu $t0 $t0 $t2 # find limit of copy + +_strcat_copy: + lb $v0 0($t2) # load from source + sb $v0 0($t1) # save in destination + addiu $t2 $t2 1 # advance each index + addiu $t1 $t1 1 + bne $t2 $t0 _strcat_copy # check limit + sb $0 0($t1) # add '\\0' + + lw $ra 16($sp) # restore return address + addiu $sp $sp 20 # pop argument + jr $ra # return + +_strcat_argempty: + lw $a0 12($sp) # load original self + lw $ra 16($sp) # restore return address + addiu $sp $sp 20 # pop argument + jr $ra # return + +# +# +# String.substr(i,l) +# Returns the sub string of self from i with length l +# Offset starts at 0. +# +# INPUT: $a0 the string +# length int object on top of stack (-4) +# index int object below length on stack (-8) +# OUTPUT: The substring object in $a0 +# + + .globl String.substr +String.substr: + addiu $sp $sp -12 # frame + sw $ra 4($sp) # save return + sw $a0 12($sp) # save self + sw $0 8($sp) # init GC area + + jal _MemMgr_Test # test GC area + + lw $a0 12($sp) + lw $v0 obj_size($a0) + la $a0 Int_protObj # ask if enough room to allocate + lw $a0 obj_size($a0) # a string object, an int object, + add $a0 $a0 $v0 # and the string data + addiu $a0 $a0 2 # include 2 eyecatchers + sll $a0 $a0 2 + addi $a0 $a0 str_maxsize + jal _MemMgr_QAlloc + +_ss_ok: + la $a0 Int_protObj + jal _quick_copy + jal Int_init + sw $a0 8($sp) # save new length obj + la $a0 String_protObj + jal _quick_copy + jal String_init # new obj ptr in $a0 + move $a2 $a0 # use a2 to make copy + addiu $gp $gp -4 # backup alloc ptr + lw $a1 12($sp) # load orig + lw $t1 20($sp) # index obj + lw $t2 16($sp) # length obj + lw $t0 str_size($a1) + lw $v1 int_slot($t1) # index + lw $v0 int_slot($t0) # size of orig + bltz $v1 _ss_abort1 # index is smaller than 0 + bgt $v1 $v0 _ss_abort2 # index > orig + lw $t3 int_slot($t2) # sub length + add $v1 $v1 $t3 # index+sublength + bgt $v1 $v0 _ss_abort3 + bltz $t3 _ss_abort4 + lw $t4 8($sp) # load new length obj + sw $t3 int_slot($t4) # save new size + sw $t4 str_size($a0) # store size in string + lw $v1 int_slot($t1) # index + addiu $a1 $a1 str_field # advance src to str + add $a1 $a1 $v1 # advance to indexed char + addiu $a2 $a2 str_field # advance dst to str + beqz $t3 _ss_end # empty length +_ss_loop: + lb $v0 0($a1) + addiu $a1 $a1 1 # inc src + sb $v0 0($a2) + addiu $a2 $a2 1 # inc dst + addiu $t3 $t3 -1 # dec ctr + bnez $t3 _ss_loop +_ss_end: + sb $zero 0($a2) # null terminate + move $gp $a2 + addiu $gp $gp 4 # realign the heap ptr + and $gp $gp 0xfffffffc + + sub $t0 $gp $a0 # calc object size + srl $t0 $t0 2 # div by 4 + sw $t0 obj_size($a0) + + lw $ra 4($sp) + addiu $sp $sp 20 # pop arguments + jr $ra + +_ss_abort1: + la $a0 _sabort_msg1 + b _ss_abort +_ss_abort2: + la $a0 _sabort_msg2 + b _ss_abort +_ss_abort3: + la $a0 _sabort_msg3 + b _ss_abort +_ss_abort4: + la $a0 _sabort_msg4 +_ss_abort: + li $v0 4 + syscall + la $a0 _sabort_msg + li $v0 4 + syscall + li $v0 10 # exit + syscall + +# +# MemMgr Memory Manager +# +# The MemMgr functions give a consistent view of the garbage collectors. +# This allows multiple collectors to exist in one file and the easy +# selection of different collectors. It includes functions to initialize +# the collector and to reserve memory and query its status. +# +# The following assumptions are made: +# +# 1) The allocation of memory involves incrementing the $gp pointer. +# The $s7 pointer serves as a limit. The collector function is +# called before $s7 is exceeded by $gp. +# +# 2) The initialization functions all take the same arguments as +# defined in "_MemMgr_Init". +# +# 3) The garbage collector functions all take the arguments. "$a0" +# contains the end of the stack to check for pointers. "$a1" +# contains the size in bytes needed by the program and must be +# preserved across the function call. +# + +# +# Initialize the Memory Manager +# +# Call the initialization routine for the garbage collector. +# +# INPUT: +# $a0: start of stack +# $a1: initial Register mask +# $a2: end of heap +# heap_start: start of the heap +# +# OUTPUT: +# $gp: lower bound of the work area +# $s7: upper bound of the work area +# +# Registers modified: +# $t0, initializer function +# + + .globl _MemMgr_Init +_MemMgr_Init: + addiu $sp $sp -4 + sw $ra 4($sp) # save return address + la $t0 _MemMgr_INITIALIZER # pointer to initialization + lw $t0 0($t0) + jalr $t0 # initialize + lw $ra 4($sp) # restore return address + addiu $sp $sp 4 + jr $ra # return + +# +# Memory Allocation +# +# Allocates the requested amount of memory and returns a pointer +# to the start of the block. +# +# INPUT: +# $a0: size of allocation in bytes +# $s7: limit pointer of the work area +# $gp: current allocation pointer +# heap_start: start of heap +# +# OUTPUT: +# $a0: pointer to new memory block +# +# Registers modified: +# $t0, $a1, collector function +# + + .globl _MemMgr_Alloc +_MemMgr_Alloc: + add $gp $gp $a0 # attempt to allocate storage + blt $gp $s7 _MemMgr_Alloc_end # check allocation + sub $gp $gp $a0 # restore $gp + addiu $sp $sp -4 + sw $ra 4($sp) # save return address + move $a1 $a0 # size + addiu $a0 $sp 4 # end of stack to collect + la $t0 _MemMgr_COLLECTOR # pointer to collector function + lw $t0 0($t0) + jalr $t0 # garbage collect + lw $ra 4($sp) # restore return address + addiu $sp $sp 4 + move $a0 $a1 # put size into $a0 + add $gp $gp $a0 # allocate storage +_MemMgr_Alloc_end: + sub $a0 $gp $a0 + jr $ra # return + +# +# Query Memory Allocation +# +# Verifies that the requested amount of memory can be allocated +# within the work area. +# +# INPUT: +# $a0: size of allocation in bytes +# $s7: limit pointer of the work area +# $gp: current allocation pointer +# heap_start: start of heap +# +# OUTPUT: +# $a0: size of allocation in bytes (unchanged) +# +# Registers modified: +# $t0, $a1, collector function +# + + .globl _MemMgr_QAlloc +_MemMgr_QAlloc: + add $t0 $gp $a0 # attempt to allocate storage + blt $t0 $s7 _MemMgr_QAlloc_end # check allocation + addiu $sp $sp -4 + sw $ra 4($sp) # save return address + move $a1 $a0 # size + addiu $a0 $sp 4 # end of stack to collect + la $t0 _MemMgr_COLLECTOR # pointer to collector function + lw $t0 0($t0) + jalr $t0 # garbage collect + lw $ra 4($sp) # restore return address + addiu $sp $sp 4 + move $a0 $a1 # put size into $a0 +_MemMgr_QAlloc_end: + jr $ra # return + +# +# Test heap consistency +# +# Runs the garbage collector in the hope that this will help detect +# garbage collection bugs earlier. +# +# INPUT: (the usual GC stuff) +# $s7: limit pointer of the work area +# $gp: current allocation pointer +# heap_start: start of heap +# +# OUTPUT: +# none +# +# Registers modified: +# $t0, $a1, collector function + + .globl _MemMgr_Test +_MemMgr_Test: + la $t0 _MemMgr_TEST # Check if testing enabled + lw $t0 0($t0) + beqz $t0 _MemMgr_Test_end + +# Allocate 0 bytes + addiu $sp $sp -4 # Save return address + sw $ra 4($sp) + li $a1 0 # size = 0 + addiu $a0 $sp 4 # end of stack to collect + la $t0 _MemMgr_COLLECTOR # pointer to collector function + lw $t0 0($t0) + jalr $t0 # garbage collect + lw $ra 4($sp) # restore return address + addiu $sp $sp 4 + +_MemMgr_Test_end: + jr $ra +""" + + MemManagerNoGC = """ +# +# NoGC Garbage Collector +# +# NoGC does not attempt to do any garbage collection. +# It simply expands the heap if more memory is needed. +# + +# +# Some constants +# + +NoGC_EXPANDSIZE=0x10000 # size to expand heap + +# +# Initialization +# +# INPUT: +# none +# +# OUTPUT: +# $gp: lower bound of the work area +# $s7: upper bound of the work area +# +# Registers modified: +# $a0, $v0 +# + .globl _NoGC_Init +_NoGC_Init: + la $gp heap_start # set $gp to the start of the heap + li $v0 9 # get heap end + move $a0 $zero + syscall # sbrk + move $s7 $v0 # set limit pointer + jr $ra + +# +# Collection +# +# Expand the heap as necessary. +# +# INPUT: +# $a1: size will need to allocate in bytes +# $s7: limit pointer of thw work area +# $gp: current allocation pointer +# +# OUTPUT: +# $a1: size will need to allocate in bytes (unchanged) +# +# Registers modified: +# $t0, $a0, $v0, $gp, $s7 +# + + .globl _NoGC_Collect +_NoGC_Collect: + la $a0 _NoGC_COLLECT # show collection message + li $v0 4 + syscall +_NoGC_Collect_loop: + add $t0 $gp $a1 # test allocation + blt $t0 $s7 _NoGC_Collect_ok # stop if enough + li $v0 9 # expand heap + li $a0 NoGC_EXPANDSIZE # set the size to expand the heap + syscall # sbrk + li $v0 9 # get heap end + move $a0 $zero + syscall # sbrk + move $s7 $v0 # set limit pointer + b _NoGC_Collect_loop # loop +_NoGC_Collect_ok: + jr $ra # return +""" + + MemManagerGenGC = """ +# +# GenGC Generational Garbage Collector +# +# This is an implementation of a generational garbage collector +# as described in "Simple Generational Garbage Collection and Fast +# Allocation" by Andrew W. Appel [Princeton University, March 1988]. +# This is a two generation scheme which uses an assignment table +# to handle root pointers located in the older generation objects. +# +# When the work area is filled, a minor garbage collection takes place +# which moves all live objects into the reserve area. These objects +# are then incorporated into the old area. New reserve and work areas +# are setup and allocation can continue in the work area. If a break- +# point is reached in the size of the old area just after a minor +# collection, a major collection then takes place. All live objects in +# the old area are then copied into the new area, expanding the heap if +# necessary. The X and new areas are then block copied back L1-L0 +# bytes to form the next old area. +# +# The assignment table is implemented as a stack growing towards the +# allocation pointer ($gp) in the work area. If they cross, a minor +# collection is then carried out. This allows the garbage collector to +# to have to keep a fixed table of assignments. As a result, programs +# with many assignments will tend not to be bogged down with extra +# garbage collections. +# +# The unused area was implemented to help keep the garbage collector +# from continually expanding the heap. This buffer zone allows major +# garbage collections to happen earlier, reducing the risk of expansions +# due to too many live objects in the old area. The histories kept by +# the garbage collector in MAJOR0, MAJOR1, MINOR0, and MINOR1 also help +# to prevent unnecessary expansions of the heap. If many live objects +# were recently collected, the garbage collections will start to occur +# sooner. +# +# Note that during a minor collection, the work area is guaranteed to +# fit within the reserve area. However, during a major collection, the +# old area will not necessarily fit in the new area. If the latter occurs, +# "_GenGC_OfsCopy" will detect this and expand the heap. +# +# The heap is expanded on two different occasions: +# +# 1) After a major collection, the old area is set to be at most +# 1/(2^GenGC_OLDRATIO) of the usable heap (L0 to L3). Note that +# first L4 is checked to see if any of the unused memory between L3 +# and L4 is enough to satisfy this requirement. If not, then the +# heap will be expanded. If it is, the appropriate amount will be +# transfered from the unused area to the work/reserve area. +# +# 2) During a major collection, if the live objects in the old area +# do not fit within the new area, the heap is expanded and $s7 +# is updated to reflact this. This value later gets stored back +# into L4. +# +# During a normal allocation and minor collections, the heap has the +# following form: +# +# Header +# | +# | Older generation objects +# | | +# | | Minor garbage collection area +# | | | +# | | | Allocation area +# | | | | +# | | | | Assignment table +# | | | | | +# | | | | | Unused +# | | | | | | +# v v v v v v +# +----+--------------+-----------------+-------------+---+---------+ +# |XXXX| Old Area | Reserve Area | Work Area |XXX| Unused | +# +----+--------------+-----------------+-------------+---+---------+ +# ^ ^ ^ ^ ^ ^ ^ ^ +# | | | | |--> <--| | | +# | L0 L1 L2 $gp $s7 L3 L4 +# | +# heap_start +# +# $gp (allocation pointer): points to the next free word in the work +# area during normal allocation. During a minor garbage collection, +# it points to the next free work in the reserve area. +# +# $s7 (limit pointer): points to the limit that $gp can traverse. Between +# it and L3 sits the assignment table which grows towards $gp. +# +# During a Major collection, the heap has the following form: +# +# Header +# | +# | Older generation objects +# | | +# | | Objects surviving last minor garbage collection +# | | | +# | | | Major garbage collection area +# | | | | +# v v v v +# +----+------------------+----------+------------------------------+ +# |XXXX| Old Area | X | New Area | +# +----+------------------+----------+------------------------------+ +# ^ ^ ^ ^ ^ ^ ^ +# | | | | | |--> | +# | L0 L1 | L2 $gp L4, $s7 +# | | +# heap_start breakpoint +# +# $gp (allocation pointer): During a major collection, this points +# into the next free word in the new area. +# +# $s7 (limit pointer): During a major collection, the points to the +# limit of heap memory. $gp is not allowed to pass this value. +# If the objects in the live old area cannot fit in the new area, +# more memory is allocated and $s7 is adjusted accordingly. +# +# breakpoint: Point where a major collection will occur. It is +# calculated by the following formula: +# +# breakpoint = MIN(L3-MAX(MAJOR0,MAJOR1)-MAX(MINOR0,MINOR1), +# L3-(L3-L0)/2) +# +# where (variables stored in the header): +# MAJOR0 = total size of objects in the new area after last major +# collection. +# MAJOR1 = (MAJOR0+MAJOR1)/2 +# MINOR0 = total size of objects in the reserve area after last +# minor collection. +# MINOR1 = (MINOR0+MINOR1)/2 +# +# The following assumptions are made in the garbage collection +# process: +# +# 1) Pointers on the Stack: +# Every word on the stack that ends in 0 (i.e., is even) and is +# a valid address in the heap is assumed to point to an object +# in the heap. Even heap addresses on the stack that are actually +# something else (e.g., raw integers) will probably cause an +# garbage collection error. +# +# 2) Object Layout: +# Besides the Int, String, and Bool objects (which are handled +# separately), the garbage collector assumes that each attribute +# in an object is a pointer to another object. It, however, +# still does as much as possible to verify this before actually +# updating any fields. +# +# 3) Pointer tests: +# In order to be verified as an object, a pointer must undergo +# certain tests: +# +# a) The pointer must point within the correct storage area. +# b) The word before the pointer (obj_eyecatch) must be the +# word 0xFFFF FFFF +# c) The word at the pointer must not be 0xFFFF FFFF (i.e. +# -1 cannot be a class tag) +# +# These tests are performed whenever any data could be a pointer +# to keep any non-pointers from being updated accidentally. The +# functions "_GenGC_ChkCopy" and "_GenGC_OfsCopy" are responsible +# for these checks. +# +# 4) The size stored in the object does not include the word required +# to store the eyecatcher for the object in the heap. This allows +# the prototype objects to not require its own eyecatcher. Also, +# a size of 0 is invalid because it is used as a flag by the garbage +# collector to indicate a forwarding pointer in the "obj_disp" field. +# +# 5) Roots are contained in the following areas: the stack, registers +# specified in the REG mask, and the assignment table. +# + +# +# Constants +# + +# +# GenGC header offsets from "heap_start" +# + +GenGC_HDRSIZE=44 # size of GenGC header +GenGC_HDRL0=0 # pointers to GenGC areas +GenGC_HDRL1=4 +GenGC_HDRL2=8 +GenGC_HDRL3=12 +GenGC_HDRL4=16 +GenGC_HDRMAJOR0=20 # history of major collections +GenGC_HDRMAJOR1=24 +GenGC_HDRMINOR0=28 # history of minor collections +GenGC_HDRMINOR1=32 +GenGC_HDRSTK=36 # start of stack +GenGC_HDRREG=40 # current REG mask + +# +# Granularity of heap expansion +# +# The heap is always expanded in multiples of 2^k, where +# k is the granularity. +# + +GenGC_HEAPEXPGRAN=14 # 2^14=16K + +# +# Old to usable heap size ratio +# +# After a major collection, the ratio of size of old area to the usable +# size of the heap is at most 1/(2^k) where k is the value provided. +# + +GenGC_OLDRATIO=2 # 1/(2^2)=.25=25% + +# +# Mask to speficy which registers can be automatically updated +# when a garbage collection occurs. The Automatic Register Update +# (ARU) mask has a bit set for all possible registers the +# garbage collector is able to handle. The Register (REG) mask +# determines which register(s) are actually updated. +# +# BITS---------------------------- +# 3 2 1 0 +# 10987654321098765432109876543210 +# -------------------------------- +# +# 11000011011111110000000000000000 <- Auto Register Update (ARU) mask +# +--++--++--++--++--++--++--++--+ $s0-$s6, $t8-$t9, $fp, $ra +# C 3 7 F 0 0 0 0 ($16-$22, $24-$25, $30, $31) +# + +GenGC_ARU_MASK=0xC37F0000 + +# +# Functions +# + +# +# Initialization +# +# Sets up the header information block for the garbage collector. +# This block is located at the start of the heap ("heap_start") +# and includes information needed by the garbage collector. It +# also calculates the barrier for the reserve and work areas and +# sets the L2 pointer accordingly, rounding off in favor of the +# reserve area. +# +# INPUT: +# $a0: start of stack +# $a1: initial Register mask +# $a2: end of heap +# heap_start: start of the heap +# +# OUTPUT: +# $gp: lower bound of the work area +# $s7: upper bound of the work area +# +# Registers modified: +# $t0, $t1, $v0, $a0 +# + + .globl _GenGC_Init +_GenGC_Init: + la $t0 heap_start + addiu $t1 $t0 GenGC_HDRSIZE + sw $t1 GenGC_HDRL0($t0) # save start of old area + sw $t1 GenGC_HDRL1($t0) # save start of reserve area + sub $t1 $a2 $t1 # find reserve/work area barrier + srl $t1 $t1 1 + and $t1 $t1 0xFFFFFFFC + blez $t1 _GenGC_Init_error # heap initially to small + sub $gp $a2 $t1 + sw $gp GenGC_HDRL2($t0) # save start of work area + sw $a2 GenGC_HDRL3($t0) # save end of work area + move $s7 $a2 # set limit pointer + sw $0 GenGC_HDRMAJOR0($t0) # clear histories + sw $0 GenGC_HDRMAJOR1($t0) + sw $0 GenGC_HDRMINOR0($t0) + sw $0 GenGC_HDRMINOR1($t0) + sw $a0 GenGC_HDRSTK($t0) # save stack start + sw $a1 GenGC_HDRREG($t0) # save register mask + li $v0 9 # get heap end + move $a0 $zero + syscall # sbrk + sw $v0 GenGC_HDRL4($t0) # save heap limit + jr $ra # return +_GenGC_Init_error: + la $a0 _GenGC_INITERROR # show error message + li $v0 4 + syscall + li $v0 10 # exit + syscall + +# +# Record Assignment +# +# Records an assignment in the assignment table. Note that because +# $s7 is always greater than $gp, an assignment can always be +# recorded. +# +# INPUT: +# $a1: pointer to the pointer being modified +# $s7: limit pointer of the work area +# $gp: current allocation pointer +# heap_start: start of heap +# +# Registers modified: +# $t0, $t1, $t2, $v0, $v1, $a0, $a1, $a2, $gp, $s7 +# + + .globl _GenGC_Assign +_GenGC_Assign: + addiu $s7 $s7 -4 + sw $a1 0($s7) # save pointer to assignment + bgt $s7 $gp _GenGC_Assign_done + addiu $sp $sp -4 + sw $ra 4($sp) # save return address + move $a1 $0 # size + addiu $a0 $sp 4 # end of stack to collect + jal _GenGC_Collect + lw $ra 4($sp) # restore return address + addiu $sp $sp 4 +_GenGC_Assign_done: + jr $ra # return + + .globl _gc_check +_gc_check: + beqz $a1, _gc_ok # void is ok + lw $a2 obj_eyecatch($a1) # and check if it is valid + addiu $a2 $a2 1 + bnez $a2 _gc_abort +_gc_ok: + jr $ra + +_gc_abort: + la $a0 _gc_abort_msg + li $v0 4 + syscall # print gc message + li $v0 10 + syscall # exit + + +# +# Generational Garbage Collection +# +# This function implements the generational garbage collection. +# It first calls the minor collector, "_GenGC_MinorC", and then +# updates its history in the header. The breakpoint is then +# calculated. If the breakpoint is reached or there is still not +# enough room to allocate the requested size, a major garbage +# collection then takes place by calling "_GenGC_MajorC". After +# the major collection, the size of the old area is analyzed. If +# it is greater than 1/(2^GenGC_OLDRATIO) of the total usable heap +# size (L0 to L3), the heap is expanded. Also, if there is still not +# enough room to allocate the requested size, the heap is expanded +# further to make sure that the specified amount of memory can be +# allocated. If there is enough room in the unused area (L3 to L4), +# this memory is used and the heap is not expanded. The $s7 and $gp +# pointers are then set as well as the L2 pointer. If a major collection +# is not done, the X area is incorporated into the old area +# (i.e. the L2 pointer is moved into L1) and $s7, $gp, and L2 are +# then set. +# +# INPUT: +# $a0: end of stack +# $a1: size will need to allocate in bytes +# $s7: limit pointer of thw work area +# $gp: current allocation pointer +# heap_start: start of heap +# +# OUTPUT: +# $a1: size will need to allocate in bytes (unchanged) +# +# Registers modified: +# $t0, $t1, $t2, $t3, $t4, $v0, $v1, $a0, $a2, $gp, $s7 +# + + .globl _GenGC_Collect +_GenGC_Collect: + addiu $sp $sp -12 + sw $ra 12($sp) # save return address + sw $a0 8($sp) # save stack end + sw $a1 4($sp) # save size + la $a0 _GenGC_COLLECT # print collection message + li $v0 4 + syscall + lw $a0 8($sp) # restore stack end + jal _GenGC_MinorC # minor collection + la $a1 heap_start + lw $t1 GenGC_HDRMINOR1($a1) + addu $t1 $t1 $a0 + srl $t1 $t1 1 + sw $t1 GenGC_HDRMINOR1($a1) # update histories + sw $a0 GenGC_HDRMINOR0($a1) + move $t0 $t1 # set $t0 to max of minor + bgt $t1 $a0 _GenGC_Collect_maxmaj + move $t0 $a0 +_GenGC_Collect_maxmaj: + lw $t1 GenGC_HDRMAJOR0($a1) # set $t1 to max of major + lw $t2 GenGC_HDRMAJOR1($a1) + bgt $t1 $t2 _GenGC_Collect_maxdef + move $t1 $t2 +_GenGC_Collect_maxdef: + lw $t2 GenGC_HDRL3($a1) + sub $t0 $t2 $t0 # set $t0 to L3-$t0-$t1 + sub $t0 $t0 $t1 + lw $t1 GenGC_HDRL0($a1) # set $t1 to L3-(L3-L0)/2 + sub $t1 $t2 $t1 + srl $t1 $t1 1 + sub $t1 $t2 $t1 + blt $t0 $t1 _GenGC_Collect_breakpt # set $t0 to minimum of above + move $t0 $t1 +_GenGC_Collect_breakpt: + lw $t1 GenGC_HDRL1($a1) # get end of old area + bge $t1 $t0 _GenGC_Collect_major + lw $t0 GenGC_HDRL2($a1) + lw $t1 GenGC_HDRL3($a1) + lw $t2 4($sp) # load requested size into $t2 + sub $t0 $t1 $t0 # find reserve/work area barrier + srl $t0 $t0 1 + and $t0 $t0 0xFFFFFFFC + sub $t0 $t1 $t0 # reserve/work barrier + addu $t2 $t0 $t2 # test allocation + bge $t2 $t1 _GenGC_Collect_major # check if work area too small +_GenGC_Collect_nomajor: + lw $t1 GenGC_HDRL2($a1) + sw $t1 GenGC_HDRL1($a1) # expand old area + sw $t0 GenGC_HDRL2($a1) # set new reserve/work barrier + move $gp $t0 # set $gp + lw $s7 GenGC_HDRL3($a1) # load limit into $s7 + b _GenGC_Collect_done +_GenGC_Collect_major: + la $a0 _GenGC_Major # print collection message + li $v0 4 + syscall + lw $a0 8($sp) # restore stack end + jal _GenGC_MajorC # major collection + la $a1 heap_start + lw $t1 GenGC_HDRMAJOR1($a1) + addu $t1 $t1 $a0 + srl $t1 $t1 1 + sw $t1 GenGC_HDRMAJOR1($a1) # update histories + sw $a0 GenGC_HDRMAJOR0($a1) + lw $t1 GenGC_HDRL3($a1) # find ratio of the old area + lw $t0 GenGC_HDRL0($a1) + sub $t1 $t1 $t0 + srl $t1 $t1 GenGC_OLDRATIO + addu $t1 $t0 $t1 + lw $t0 GenGC_HDRL1($a1) + sub $t0 $t0 $t1 + sll $t0 $t0 GenGC_OLDRATIO # amount to expand in $t0 + lw $t1 GenGC_HDRL3($a1) # load L3 + lw $t2 GenGC_HDRL1($a1) # load L1 + sub $t2 $t1 $t2 + srl $t2 $t2 1 + and $t2 $t2 0xFFFFFFFC + sub $t1 $t1 $t2 # reserve/work barrier + lw $t2 4($sp) # restore size + addu $t1 $t1 $t2 + lw $t2 GenGC_HDRL3($a1) # load L3 + sub $t1 $t1 $t2 # test allocation + addiu $t1 $t1 4 # adjust for round off errors + sll $t1 $t1 1 # need to allocate $t1 memory + blt $t1 $t0 _GenGC_Collect_enough # put max of $t0, $t1 in $t0 + move $t0 $t1 +_GenGC_Collect_enough: + blez $t0 _GenGC_Collect_setL2 # no need to expand + addiu $t1 $0 1 # put 1 in $t1 + sll $t1 $t1 GenGC_HEAPEXPGRAN # get granularity of expansion + addiu $t1 $t1 -1 # align to granularity + addu $t0 $t0 $t1 + nor $t1 $t1 $t1 + and $t0 $t0 $t1 # total memory needed + lw $t1 GenGC_HDRL3($a1) # load L3 + lw $t2 GenGC_HDRL4($a1) # load L4 + sub $t1 $t2 $t1 + sub $t2 $t0 $t1 # actual amount to allocate + bgtz $t2 _GenGC_Collect_getmem # check if really need to allocate +_GenGC_Collect_xfermem: + lw $s7 GenGC_HDRL3($a1) # load L3 + addu $s7 $s7 $t0 # expand by $t0, set $s7 + sw $s7 GenGC_HDRL3($a1) # save L3 + b _GenGC_Collect_findL2 +_GenGC_Collect_getmem: + li $v0 9 # sbrk + move $a0 $t2 # set the size to expand the heap + syscall + li $v0 9 + move $a0 $zero + syscall # get new end of heap in $v0 + sw $v0 GenGC_HDRL4($a1) # save L4 + sw $v0 GenGC_HDRL3($a1) # save L3 + move $s7 $v0 # set $s7 + b _GenGC_Collect_findL2 +_GenGC_Collect_setL2: + lw $s7 GenGC_HDRL3($a1) # load L3 +_GenGC_Collect_findL2: + lw $t1 GenGC_HDRL1($a1) # load L1 + sub $t1 $s7 $t1 + srl $t1 $t1 1 + and $t1 $t1 0xFFFFFFFC + sub $gp $s7 $t1 # reserve/work barrier + sw $gp GenGC_HDRL2($a1) # save L2 +_GenGC_Collect_done: + +# Clear new generation to catch missing pointers + move $t0 $gp +_GenGC_Clear_loop: + sw $zero 0($t0) + addiu $t0 $t0 4 + blt $t0 $s7 _GenGC_Clear_loop + + lw $a1 4($sp) # restore size + lw $ra 12($sp) # restore return address + addiu $sp $sp 12 + jr $ra # return + +# +# Check and Copy an Object +# +# Checks that the input pointer points to an object is a heap +# object. If so, it then checks for a forwarding pointer by +# checking for an object size of 0. If found, the forwarding +# pointer is returned. If not found, the object is copied to $gp +# and a pointer to it is returned. The following tests are done to +# determine if the object is a heap object: +# +# 1) The pointer is within the specified limits +# 2) The pointer is even +# 3) The word before the pointer is the eye catcher 0xFFFF FFFF +# 4) The word at the pointer is a valid tag (i.e. not equal to +# 0xFFFF FFFF) +# +# INPUT: +# $a0: pointer to check and copy +# $a1: lower bound object should be within. +# $a2: upper bound object should be within. +# $gp: current allocation pointer +# +# OUTPUT: +# $a0: if input points to a heap object then it is set to the +# new location of object. If not, it is unchanged. +# $a1: lower bound object should be within. (unchanged) +# $a2: upper bound object should be within. (unchanged) +# +# Registers modified: +# $t0, $t1, $t2, $v0, $a0, $gp +# + + .globl _GenGC_ChkCopy +_GenGC_ChkCopy: + blt $a0 $a1 _GenGC_ChkCopy_done # check bounds + bge $a0 $a2 _GenGC_ChkCopy_done + andi $t2 $a0 1 # check if odd + bnez $t2 _GenGC_ChkCopy_done + addiu $t2 $0 -1 + lw $t1 obj_eyecatch($a0) # check eyecatcher + bne $t2 $t1 _gc_abort + lw $t1 obj_tag($a0) # check object tag + beq $t2 $t1 _GenGC_ChkCopy_done + lw $t1 obj_size($a0) # get size of object + beqz $t1 _GenGC_ChkCopy_forward # if size = 0, get forwarding pointer + move $t0 $a0 # save pointer to old object in $t0 + addiu $gp $gp 4 # allocate memory for eyecatcher + move $a0 $gp # get address of new object + sw $t2 obj_eyecatch($a0) # save eye catcher + sll $t1 $t1 2 # convert words to bytes + addu $t1 $t0 $t1 # set $t1 to limit of copy + move $t2 $t0 # set $t2 to old object +_GenGC_ChkCopy_loop: + lw $v0 0($t0) # copy + sw $v0 0($gp) + addiu $t0 $t0 4 # update each index + addiu $gp $gp 4 + bne $t0 $t1 _GenGC_ChkCopy_loop # check for limit of copy + sw $0 obj_size($t2) # set size to 0 + sw $a0 obj_disp($t2) # save forwarding pointer +_GenGC_ChkCopy_done: + jr $ra # return +_GenGC_ChkCopy_forward: + lw $a0 obj_disp($a0) # get forwarding pointer + jr $ra # return + + +# +# Minor Garbage Collection +# +# This garbage collector is run when ever the space in the work +# area is used up by objects and the assignment table. The live +# objects are found and copied to the reserve area. The L2 pointer +# is then set to the end of the live objects. The collector consists +# of six phases: +# +# 1) Set $gp into the reserve area and set the inputs for ChkCopy +# +# 2) Scan the stack for root pointers into the heap. The beginning +# of the stack is in the header and the end is an input to this +# function. Look for the appropriate stack flags and act +# accordingly. Use "_GenGC_ChkCopy" to validate the pointer and +# get the new pointer, and then update the stack entry. +# +# 3) Check the registers specified in the Register (REG) mask to +# automatically update. This mask is stored in the header. If +# bit #n in the mask is set, register #n will be passed to +# "_GenGC_ChkCopy" and updated with its result. "_GenGC_SetRegMask" +# can be used to update this mask. +# +# 4) The assignemnt table is now checked. $s7 is moved from its +# current position until it hits the L3 pointer. Each entry is a +# pointer to the pointer that must be checked. Again, +# "_GenGC_ChkCopy" is used and the pointer updated. +# +# 5) At this point, all root objects are in the reserve area. This +# area is now traversed object by object (from L1 to $gp). It +# results in a breadth first search of the live objects collected. +# All attributes of objects are treated as pointers except the +# "Int", "Bool", and "String" objects. The first two are skipped +# completely, and the first attribute of the string object is +# analyzed (should be a pointer to an "Int" object). +# +# 6) At this point, L2 is set to the end of the live objects in the +# reserve area. This is in preparation for a major collection. +# The size of all the live objects collected is then computed and +# returned. +# +# INPUT: +# $a0: end of stack +# $s7: limit pointer of this area of storage +# $gp: current allocation pointer +# heap_start: start of heap +# +# OUTPUT: +# $a0: size of all live objects collected +# +# Registers modified: +# $t0, $t1, $t2, $t3, $t4, $v0, $v1, $a0, $a1, $a2, $gp, $s7 +# + + .globl _GenGC_MinorC +_GenGC_MinorC: + addiu $sp $sp -20 + sw $ra 20($sp) # save return address + la $t0 heap_start + lw $a1 GenGC_HDRL2($t0) # set lower bound to work area + move $a2 $s7 # set upper bound for ChkCopy + lw $gp GenGC_HDRL1($t0) # set $gp into reserve area + sw $a0 16($sp) # save stack end + lw $t0 GenGC_HDRSTK($t0) # set $t0 to stack start + move $t1 $a0 # set $t1 to stack end + ble $t0 $t1 _GenGC_MinorC_stackend # check for empty stack +_GenGC_MinorC_stackloop: # $t1 stack end, $t0 index + addiu $t0 $t0 -4 # update index + sw $t0 12($sp) # save stack index + lw $a0 4($t0) # get stack item + jal _GenGC_ChkCopy # check and copy + lw $t0 12($sp) # load stack index + sw $a0 4($t0) + lw $t1 16($sp) # restore stack end + bgt $t0 $t1 _GenGC_MinorC_stackloop # loop +_GenGC_MinorC_stackend: + la $t0 heap_start + lw $t0 GenGC_HDRREG($t0) # get Register mask + sw $t0 16($sp) # save Register mask +_GenGC_MinorC_reg16: + srl $t0 $t0 16 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg17 # check if set + move $a0 $16 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $16 $a0 # update register +_GenGC_MinorC_reg17: + lw $t0 16($sp) # restore mask + srl $t0 $t0 17 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg18 # check if set + move $a0 $17 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $17 $a0 # update register +_GenGC_MinorC_reg18: + lw $t0 16($sp) # restore mask + srl $t0 $t0 18 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg19 # check if set + move $a0 $18 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $18 $a0 # update register +_GenGC_MinorC_reg19: + lw $t0 16($sp) # restore mask + srl $t0 $t0 19 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg20 # check if set + move $a0 $19 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $19 $a0 # update register +_GenGC_MinorC_reg20: + lw $t0 16($sp) # restore mask + srl $t0 $t0 20 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg21 # check if set + move $a0 $20 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $20 $a0 # update register +_GenGC_MinorC_reg21: + lw $t0 16($sp) # restore mask + srl $t0 $t0 21 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg22 # check if set + move $a0 $21 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $21 $a0 # update register +_GenGC_MinorC_reg22: + lw $t0 16($sp) # restore mask + srl $t0 $t0 22 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg24 # check if set + move $a0 $22 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $22 $a0 # update register +_GenGC_MinorC_reg24: + lw $t0 16($sp) # restore mask + srl $t0 $t0 24 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg25 # check if set + move $a0 $24 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $24 $a0 # update register +_GenGC_MinorC_reg25: + lw $t0 16($sp) # restore mask + srl $t0 $t0 25 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg30 # check if set + move $a0 $25 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $25 $a0 # update register +_GenGC_MinorC_reg30: + lw $t0 16($sp) # restore mask + srl $t0 $t0 30 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg31 # check if set + move $a0 $30 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $30 $a0 # update register +_GenGC_MinorC_reg31: + lw $t0 16($sp) # restore mask + srl $t0 $t0 31 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_regend # check if set + move $a0 $31 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $31 $a0 # update register +_GenGC_MinorC_regend: + la $t0 heap_start + lw $t3 GenGC_HDRL0($t0) # lower limit of old area + lw $t4 GenGC_HDRL1($t0) # upper limit of old area + lw $t0 GenGC_HDRL3($t0) # get L3 + sw $t0 16($sp) # save index limit + bge $s7 $t0 _GenGC_MinorC_assnend # check for no assignments +_GenGC_MinorC_assnloop: # $s7 index, $t0 limit + lw $a0 0($s7) # get table entry + blt $a0 $t3 _GenGC_MinorC_assnnext # must point into old area + bge $a0 $t4 _GenGC_MinorC_assnnext + lw $a0 0($a0) # get pointer to check + jal _GenGC_ChkCopy # check and copy + lw $t0 0($s7) + sw $a0 0($t0) # update pointer + lw $t0 16($sp) # restore index limit +_GenGC_MinorC_assnnext: + addiu $s7 $s7 4 # update index + blt $s7 $t0 _GenGC_MinorC_assnloop # loop +_GenGC_MinorC_assnend: + la $t0 heap_start + lw $t0 GenGC_HDRL1($t0) # start of reserve area + bge $t0 $gp _GenGC_MinorC_heapend # check for no objects +_GenGC_MinorC_heaploop: # $t0: index, $gp: limit + addiu $t0 $t0 4 # skip over eyecatcher + addiu $t1 $0 -1 # check for eyecatcher + lw $t2 obj_eyecatch($t0) + bne $t1 $t2 _GenGC_MinorC_error # eyecatcher not found + lw $a0 obj_size($t0) # get object size + sll $a0 $a0 2 # words to bytes + lw $t1 obj_tag($t0) # get the object's tag + lw $t2 _int_tag # test for int object + beq $t1 $t2 _GenGC_MinorC_int + lw $t2 _bool_tag # test for bool object + beq $t1 $t2 _GenGC_MinorC_bool + lw $t2 _string_tag # test for string object + beq $t1 $t2 _GenGC_MinorC_string +_GenGC_MinorC_other: + addi $t1 $t0 obj_attr # start at first attribute + add $t2 $t0 $a0 # limit of attributes + bge $t1 $t2 _GenGC_MinorC_nextobj # check for no attributes + sw $t0 16($sp) # save pointer to object + sw $a0 12($sp) # save object size + sw $t2 4($sp) # save limit +_GenGC_MinorC_objloop: # $t1: index, $t2: limit + sw $t1 8($sp) # save index + lw $a0 0($t1) # set pointer to check + jal _GenGC_ChkCopy +""" diff --git a/tests/codegen/arith.cl b/tests/codegen/arith.cl index af5951cf..a1035961 100755 --- a/tests/codegen/arith.cl +++ b/tests/codegen/arith.cl @@ -158,14 +158,14 @@ class A2I { if char = "0" then 0 else if char = "1" then 1 else if char = "2" then 2 else - if char = "3" then 3 else - if char = "4" then 4 else - if char = "5" then 5 else - if char = "6" then 6 else - if char = "7" then 7 else - if char = "8" then 8 else - if char = "9" then 9 else - { abort(); 0; } (* the 0 is needed to satisfy the + if char = "3" then 3 else + if char = "4" then 4 else + if char = "5" then 5 else + if char = "6" then 6 else + if char = "7" then 7 else + if char = "8" then 8 else + if char = "9" then 9 else + { abort(); 0; } (* the 0 is needed to satisfy the typchecker *) fi fi fi fi fi fi fi fi fi fi }; diff --git a/tests/codegen/complex.cl b/tests/codegen/complex.cl index 0b7aa44e..bad142df 100755 --- a/tests/codegen/complex.cl +++ b/tests/codegen/complex.cl @@ -1,22 +1,11 @@ -class Main inherits IO { - main() : IO { - (let c : Complex <- (new Complex).init(1, 1) in - if c.reflect_X().reflect_Y() = c.reflect_0() - then out_string("=)\n") - else out_string("=(\n") - fi - ) - }; -}; - class Complex inherits IO { x : Int; y : Int; - init(a : Int, b : Int) : Complex { + init(a : Int, b : Int) : SELF_TYPE { { - x = a; - y = b; + x <- a; + y <- b; self; } }; @@ -50,3 +39,16 @@ class Complex inherits IO { } }; }; + +class Main inherits IO { + main() : IO { + (let c : Complex <- (new Complex).init(1, 1) in + if c.reflect_X().reflect_Y() = c.reflect_0() + then out_string("=)\n") + else out_string("=(\n") + fi + ) + }; +}; + + diff --git a/tests/codegen/hello_world.cl b/tests/codegen/hello_world.cl index 0c818f90..2055d2a7 100755 --- a/tests/codegen/hello_world.cl +++ b/tests/codegen/hello_world.cl @@ -1,5 +1,10 @@ class Main inherits IO { + x : Int <- 1; main(): IO { - out_string("Hello, World.\n") + { + out_string("Hello, World ("); + out_int(3*2-7*2*2); + out_string(").\n"); + } }; }; diff --git a/tests/semantic/hello_world.cl b/tests/semantic/hello_world.cl index 0c818f90..dc62ec76 100755 --- a/tests/semantic/hello_world.cl +++ b/tests/semantic/hello_world.cl @@ -1,5 +1,6 @@ class Main inherits IO { - main(): IO { + main(): SELF_TYPE { out_string("Hello, World.\n") }; }; + From 072a3229f1dafe042a7efabb0698bb7035a61216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Tue, 17 Nov 2020 18:32:22 -0500 Subject: [PATCH 18/77] =?UTF-8?q?Se=20agregaron=20los=20casos=20de=20prueb?= =?UTF-8?q?a=20par=20el=20an=C3=A1lisis=20sem=C3=A1ntico=20Se=20creo=20un?= =?UTF-8?q?=20FileStream=20nuevo=20para=20substituir=20los=20tabs=20por=20?= =?UTF-8?q?espacios=20Se=20arreglaron=20algunos=20errores=20en=20el=20an?= =?UTF-8?q?=C3=A1lisis=20sem=C3=A1ntico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + src/COOLCompiler.py | 10 +- src/NoTabsFileStream.py | 24 ++ src/Visitors.py | 383 +++++++++++++++---------- tests/semantic/arithmetic1.cl | 11 + tests/semantic/arithmetic10.cl | 15 + tests/semantic/arithmetic10_error.txt | 1 + tests/semantic/arithmetic11.cl | 14 + tests/semantic/arithmetic11_error.txt | 1 + tests/semantic/arithmetic12.cl | 14 + tests/semantic/arithmetic12_error.txt | 1 + tests/semantic/arithmetic1_error.txt | 1 + tests/semantic/arithmetic2.cl | 11 + tests/semantic/arithmetic2_error.txt | 1 + tests/semantic/arithmetic3.cl | 11 + tests/semantic/arithmetic3_error.txt | 1 + tests/semantic/arithmetic4.cl | 11 + tests/semantic/arithmetic4_error.txt | 1 + tests/semantic/arithmetic5.cl | 11 + tests/semantic/arithmetic5_error.txt | 1 + tests/semantic/arithmetic6.cl | 11 + tests/semantic/arithmetic6_error.txt | 1 + tests/semantic/arithmetic7.cl | 12 + tests/semantic/arithmetic7_error.txt | 1 + tests/semantic/arithmetic8.cl | 13 + tests/semantic/arithmetic8_error.txt | 1 + tests/semantic/arithmetic9.cl | 15 + tests/semantic/arithmetic9_error.txt | 1 + tests/semantic/assignment1.cl | 7 + tests/semantic/assignment1_error.txt | 1 + tests/semantic/assignment2.cl | 13 + tests/semantic/assignment2_error.txt | 1 + tests/semantic/assignment3.cl | 14 + tests/semantic/assignment3_error.txt | 1 + tests/semantic/attributes1.cl | 13 + tests/semantic/attributes1_error.txt | 1 + tests/semantic/attributes2.cl | 13 + tests/semantic/attributes2_error.txt | 1 + tests/semantic/attributes3.cl | 25 ++ tests/semantic/attributes3_error.txt | 1 + tests/semantic/attributes4.cl | 39 +++ tests/semantic/attributes4_error.txt | 1 + tests/semantic/basics1.cl | 10 + tests/semantic/basics1_error.txt | 1 + tests/semantic/basics2.cl | 9 + tests/semantic/basics2_error.txt | 1 + tests/semantic/basics3.cl | 9 + tests/semantic/basics3_error.txt | 1 + tests/semantic/basics4.cl | 9 + tests/semantic/basics4_error.txt | 1 + tests/semantic/basics5.cl | 9 + tests/semantic/basics5_error.txt | 1 + tests/semantic/basics6.cl | 9 + tests/semantic/basics6_error.txt | 1 + tests/semantic/basics7.cl | 9 + tests/semantic/basics7_error.txt | 1 + tests/semantic/basics8.cl | 9 + tests/semantic/basics8_error.txt | 1 + tests/semantic/blocks1.cl | 31 ++ tests/semantic/blocks1_error.txt | 1 + tests/semantic/case1.cl | 23 ++ tests/semantic/case1_error.txt | 1 + tests/semantic/case2.cl | 23 ++ tests/semantic/case2_error.txt | 1 + tests/semantic/case3.cl | 23 ++ tests/semantic/case3_error.txt | 1 + tests/semantic/class1.cl | 9 + tests/semantic/class1_error.txt | 2 + tests/semantic/conditionals1.cl | 14 + tests/semantic/conditionals1_error.txt | 1 + tests/semantic/conditionals2.cl | 24 ++ tests/semantic/conditionals2_error.txt | 2 + tests/semantic/dispatch1.cl | 33 +++ tests/semantic/dispatch1_error.txt | 1 + tests/semantic/dispatch2.cl | 34 +++ tests/semantic/dispatch2_error.txt | 1 + tests/semantic/dispatch3.cl | 36 +++ tests/semantic/dispatch3_error.txt | 1 + tests/semantic/dispatch4.cl | 36 +++ tests/semantic/dispatch4_error.txt | 1 + tests/semantic/dispatch5.cl | 31 ++ tests/semantic/dispatch5_error.txt | 1 + tests/semantic/dispatch6.cl | 32 +++ tests/semantic/dispatch6_error.txt | 1 + tests/semantic/eq1.cl | 17 ++ tests/semantic/eq1_error.txt | 1 + tests/semantic/eq2.cl | 17 ++ tests/semantic/eq2_error.txt | 1 + tests/semantic/eq3.cl | 17 ++ tests/semantic/eq3_error.txt | 1 + tests/semantic/eq4.cl | 17 ++ tests/semantic/eq4_error.txt | 1 + tests/semantic/features1.cl | 19 ++ tests/semantic/features1_error.txt | 1 + tests/semantic/features2.cl | 19 ++ tests/semantic/features2_error.txt | 1 + tests/semantic/features3.cl | 15 + tests/semantic/features3_error.txt | 1 + tests/semantic/inheritance1.cl | 19 ++ tests/semantic/inheritance1_error.txt | 1 + tests/semantic/inheritance2.cl | 19 ++ tests/semantic/inheritance2_error.txt | 1 + tests/semantic/inheritance3.cl | 13 + tests/semantic/inheritance3_error.txt | 1 + tests/semantic/inheritance4.cl | 19 ++ tests/semantic/inheritance4_error.txt | 1 + tests/semantic/inheritance5.cl | 21 ++ tests/semantic/inheritance5_error.txt | 1 + tests/semantic/isvoid1.cl | 26 ++ tests/semantic/isvoid1_error.txt | 1 + tests/semantic/let1.cl | 15 + tests/semantic/let1_error.txt | 1 + tests/semantic/let2.cl | 15 + tests/semantic/let2_error.txt | 1 + tests/semantic/let3.cl | 15 + tests/semantic/let3_error.txt | 1 + tests/semantic/loops1.cl | 8 + tests/semantic/loops1_error.txt | 1 + tests/semantic/loops2.cl | 9 + tests/semantic/loops2_error.txt | 1 + tests/semantic/methods1.cl | 12 + tests/semantic/methods1_error.txt | 1 + tests/semantic/methods2.cl | 12 + tests/semantic/methods2_error.txt | 1 + tests/semantic/methods3.cl | 14 + tests/semantic/methods3_error.txt | 1 + tests/semantic/methods4.cl | 19 ++ tests/semantic/methods4_error.txt | 1 + tests/semantic/methods5.cl | 20 ++ tests/semantic/methods5_error.txt | 1 + tests/semantic/methods6.cl | 27 ++ tests/semantic/methods6_error.txt | 1 + tests/semantic/methods7.cl | 12 + tests/semantic/methods7_error.txt | 1 + tests/semantic/methods8.cl | 12 + tests/semantic/methods8_error.txt | 1 + tests/semantic/new1.cl | 31 ++ tests/semantic/new1_error.txt | 1 + tests/semantic/self1.cl | 11 + tests/semantic/self1_error.txt | 1 + tests/semantic/self2.cl | 10 + tests/semantic/self2_error.txt | 1 + tests/semantic/self3.cl | 10 + tests/semantic/self3_error.txt | 1 + tests/semantic/self4.cl | 10 + tests/semantic/self4_error.txt | 1 + 146 files changed, 1540 insertions(+), 148 deletions(-) create mode 100644 src/NoTabsFileStream.py create mode 100644 tests/semantic/arithmetic1.cl create mode 100644 tests/semantic/arithmetic10.cl create mode 100644 tests/semantic/arithmetic10_error.txt create mode 100644 tests/semantic/arithmetic11.cl create mode 100644 tests/semantic/arithmetic11_error.txt create mode 100644 tests/semantic/arithmetic12.cl create mode 100644 tests/semantic/arithmetic12_error.txt create mode 100644 tests/semantic/arithmetic1_error.txt create mode 100644 tests/semantic/arithmetic2.cl create mode 100644 tests/semantic/arithmetic2_error.txt create mode 100644 tests/semantic/arithmetic3.cl create mode 100644 tests/semantic/arithmetic3_error.txt create mode 100644 tests/semantic/arithmetic4.cl create mode 100644 tests/semantic/arithmetic4_error.txt create mode 100644 tests/semantic/arithmetic5.cl create mode 100644 tests/semantic/arithmetic5_error.txt create mode 100644 tests/semantic/arithmetic6.cl create mode 100644 tests/semantic/arithmetic6_error.txt create mode 100644 tests/semantic/arithmetic7.cl create mode 100644 tests/semantic/arithmetic7_error.txt create mode 100644 tests/semantic/arithmetic8.cl create mode 100644 tests/semantic/arithmetic8_error.txt create mode 100644 tests/semantic/arithmetic9.cl create mode 100644 tests/semantic/arithmetic9_error.txt create mode 100644 tests/semantic/assignment1.cl create mode 100644 tests/semantic/assignment1_error.txt create mode 100644 tests/semantic/assignment2.cl create mode 100644 tests/semantic/assignment2_error.txt create mode 100644 tests/semantic/assignment3.cl create mode 100644 tests/semantic/assignment3_error.txt create mode 100644 tests/semantic/attributes1.cl create mode 100644 tests/semantic/attributes1_error.txt create mode 100644 tests/semantic/attributes2.cl create mode 100644 tests/semantic/attributes2_error.txt create mode 100644 tests/semantic/attributes3.cl create mode 100644 tests/semantic/attributes3_error.txt create mode 100644 tests/semantic/attributes4.cl create mode 100644 tests/semantic/attributes4_error.txt create mode 100644 tests/semantic/basics1.cl create mode 100644 tests/semantic/basics1_error.txt create mode 100644 tests/semantic/basics2.cl create mode 100644 tests/semantic/basics2_error.txt create mode 100644 tests/semantic/basics3.cl create mode 100644 tests/semantic/basics3_error.txt create mode 100644 tests/semantic/basics4.cl create mode 100644 tests/semantic/basics4_error.txt create mode 100644 tests/semantic/basics5.cl create mode 100644 tests/semantic/basics5_error.txt create mode 100644 tests/semantic/basics6.cl create mode 100644 tests/semantic/basics6_error.txt create mode 100644 tests/semantic/basics7.cl create mode 100644 tests/semantic/basics7_error.txt create mode 100644 tests/semantic/basics8.cl create mode 100644 tests/semantic/basics8_error.txt create mode 100644 tests/semantic/blocks1.cl create mode 100644 tests/semantic/blocks1_error.txt create mode 100644 tests/semantic/case1.cl create mode 100644 tests/semantic/case1_error.txt create mode 100644 tests/semantic/case2.cl create mode 100644 tests/semantic/case2_error.txt create mode 100644 tests/semantic/case3.cl create mode 100644 tests/semantic/case3_error.txt create mode 100644 tests/semantic/class1.cl create mode 100644 tests/semantic/class1_error.txt create mode 100644 tests/semantic/conditionals1.cl create mode 100644 tests/semantic/conditionals1_error.txt create mode 100644 tests/semantic/conditionals2.cl create mode 100644 tests/semantic/conditionals2_error.txt create mode 100644 tests/semantic/dispatch1.cl create mode 100644 tests/semantic/dispatch1_error.txt create mode 100644 tests/semantic/dispatch2.cl create mode 100644 tests/semantic/dispatch2_error.txt create mode 100644 tests/semantic/dispatch3.cl create mode 100644 tests/semantic/dispatch3_error.txt create mode 100644 tests/semantic/dispatch4.cl create mode 100644 tests/semantic/dispatch4_error.txt create mode 100644 tests/semantic/dispatch5.cl create mode 100644 tests/semantic/dispatch5_error.txt create mode 100644 tests/semantic/dispatch6.cl create mode 100644 tests/semantic/dispatch6_error.txt create mode 100644 tests/semantic/eq1.cl create mode 100644 tests/semantic/eq1_error.txt create mode 100644 tests/semantic/eq2.cl create mode 100644 tests/semantic/eq2_error.txt create mode 100644 tests/semantic/eq3.cl create mode 100644 tests/semantic/eq3_error.txt create mode 100644 tests/semantic/eq4.cl create mode 100644 tests/semantic/eq4_error.txt create mode 100644 tests/semantic/features1.cl create mode 100644 tests/semantic/features1_error.txt create mode 100644 tests/semantic/features2.cl create mode 100644 tests/semantic/features2_error.txt create mode 100644 tests/semantic/features3.cl create mode 100644 tests/semantic/features3_error.txt create mode 100644 tests/semantic/inheritance1.cl create mode 100644 tests/semantic/inheritance1_error.txt create mode 100644 tests/semantic/inheritance2.cl create mode 100644 tests/semantic/inheritance2_error.txt create mode 100644 tests/semantic/inheritance3.cl create mode 100644 tests/semantic/inheritance3_error.txt create mode 100644 tests/semantic/inheritance4.cl create mode 100644 tests/semantic/inheritance4_error.txt create mode 100644 tests/semantic/inheritance5.cl create mode 100644 tests/semantic/inheritance5_error.txt create mode 100644 tests/semantic/isvoid1.cl create mode 100644 tests/semantic/isvoid1_error.txt create mode 100644 tests/semantic/let1.cl create mode 100644 tests/semantic/let1_error.txt create mode 100644 tests/semantic/let2.cl create mode 100644 tests/semantic/let2_error.txt create mode 100644 tests/semantic/let3.cl create mode 100644 tests/semantic/let3_error.txt create mode 100644 tests/semantic/loops1.cl create mode 100644 tests/semantic/loops1_error.txt create mode 100644 tests/semantic/loops2.cl create mode 100644 tests/semantic/loops2_error.txt create mode 100644 tests/semantic/methods1.cl create mode 100644 tests/semantic/methods1_error.txt create mode 100644 tests/semantic/methods2.cl create mode 100644 tests/semantic/methods2_error.txt create mode 100644 tests/semantic/methods3.cl create mode 100644 tests/semantic/methods3_error.txt create mode 100644 tests/semantic/methods4.cl create mode 100644 tests/semantic/methods4_error.txt create mode 100644 tests/semantic/methods5.cl create mode 100644 tests/semantic/methods5_error.txt create mode 100644 tests/semantic/methods6.cl create mode 100644 tests/semantic/methods6_error.txt create mode 100644 tests/semantic/methods7.cl create mode 100644 tests/semantic/methods7_error.txt create mode 100644 tests/semantic/methods8.cl create mode 100644 tests/semantic/methods8_error.txt create mode 100644 tests/semantic/new1.cl create mode 100644 tests/semantic/new1_error.txt create mode 100644 tests/semantic/self1.cl create mode 100644 tests/semantic/self1_error.txt create mode 100644 tests/semantic/self2.cl create mode 100644 tests/semantic/self2_error.txt create mode 100644 tests/semantic/self3.cl create mode 100644 tests/semantic/self3_error.txt create mode 100644 tests/semantic/self4.cl create mode 100644 tests/semantic/self4_error.txt diff --git a/.gitignore b/.gitignore index ebfe77c1..eb544d4e 100644 --- a/.gitignore +++ b/.gitignore @@ -409,3 +409,6 @@ dmypy.json # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) /.idea +/gen +/grammar/antlr_cool.bat +/tests/codegen/*.s diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 8e08f495..85bf37a8 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -11,14 +11,16 @@ from Visitors import SemanticCOOLVisitor from Visitors import CodegenVisitor from collections import deque +from NoTabsFileStream import NoTabsFileStream + def main(argv): if not os.path.isfile(argv[1]): print("invalid input filename: " + argv[1]) return sys.exit(errno.EPERM) - input = FileStream(argv[1]) - + input = NoTabsFileStream(argv[1]) + s = "" lexer = COOLLexer(input) lexer.removeErrorListeners() lexer.addErrorListener(COOLLexerErrorListener()) @@ -44,8 +46,8 @@ def main(argv): codegenerator = CodegenVisitor(typeTree, consTble, visitor.Counter) semanticAnalizer.visitProgram(tree) - outFilename = os.path.splitext(argv[1])[0] + ".s" - codegenerator.visitProgram(tree, outFilename) + # outFilename = os.path.splitext(argv[1])[0] + ".s" + # codegenerator.visitProgram(tree, outFilename) none = typeTree["Object"] diff --git a/src/NoTabsFileStream.py b/src/NoTabsFileStream.py new file mode 100644 index 00000000..cce514c0 --- /dev/null +++ b/src/NoTabsFileStream.py @@ -0,0 +1,24 @@ + +from antlr4.FileStream import FileStream + + +class NoTabsFileStream(FileStream): + + def __init__(self, fileName:str, tabSpaces: int = 4): + self.tabSpaces = tabSpaces + super().__init__(fileName) + + def readDataFrom(self, fileName:str, encoding:str, errors:str='strict'): + s = super().readDataFrom(fileName, encoding, errors) + r = "" + for t in s: + if t == '\t': + i = self.tabSpaces + while i > 0: + r += ' ' + i -= 1 + else: + r += t + return r + + diff --git a/src/Visitors.py b/src/Visitors.py index 0bcd390c..49ec5f34 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -11,6 +11,8 @@ def __init__(self, name: str, parent: str, created: bool, sealed: bool): self.Sealed = sealed self.Deep = -1 self.Methods = {} + self.VisitedMethods = list() + self.VisitedAtributes = list() self.TagMethods = list() self.Atributes = {} self.Tag = 0 @@ -72,12 +74,17 @@ def join(self, class1: str, class2: str): else: return self.join(class1, self.TypeTable[class2].Parent) - def calculateDeep(self, coolClass: COOLClass): - if self.TypeTable.keys().__contains__(coolClass.Parent): + def calculateDeep(self, coolClass: COOLClass, classList: list): + if coolClass.Deep != -1: + return + elif self.TypeTable.keys().__contains__(coolClass.Parent): if self.TypeTable[coolClass.Parent].Deep != -1: coolClass.Deep = self.TypeTable[coolClass.Parent].Deep + 1 + elif classList.__contains__(coolClass.Parent): + coolClass.Deep = 1 else: - self.calculateDeep(self.TypeTable[coolClass.Parent]) + classList.append(coolClass.Name) + self.calculateDeep(self.TypeTable[coolClass.Parent], classList) coolClass.Deep = self.TypeTable[coolClass.Parent].Deep + 1 elif coolClass.Name == "Object": coolClass.Deep = 0 @@ -122,7 +129,7 @@ def __init__(self, typeTable: dict): # Visit a parse tree produced by COOL#program. def visitProgram(self, ctx:COOL.ProgramContext): for className in self.TypeTable.keys(): - self.calculateDeep(self.TypeTable[className]) + self.calculateDeep(self.TypeTable[className], list()) return self.visitChildren(ctx) # Visit a parse tree produced by COOL#classes. @@ -134,16 +141,24 @@ def visitClassDefine(self, ctx:COOL.ClassDefineContext): coolClass = ctx.getChild(1).symbol if(self.TypeTable[coolClass.text].Created): line = str(coolClass.line) - column = str(coolClass.column) - error = "(" + line + "," + column + "): this class name already exist" + column = str(coolClass.column + 1) + if coolClass.text == "Bool" or coolClass.text == "Int" or coolClass.text == "String" or coolClass.text == "IO" or coolClass.text == "Object": + error = f"({line}, {column}) - SemanticError: Redefinition of basic class {coolClass.text}" + else: + error = f"({line}, {column}) - SemanticError: Classes may not be redefined" print(error) elif ctx.getChild(2).symbol.text == "inherits": classParent = ctx.getChild(3).symbol if (self.TypeTable.keys().__contains__(classParent.text)): if self.TypeTable[classParent.text].Sealed: line = str(classParent.line) - column = str(classParent.column) - error = "(" + line + "," + column + "): this class is sealed" + column = str(classParent.column + 1) + error = f"({line}, {column}) - SemanticError: Class {coolClass.text} cannot inherit class {classParent.text}" + print(error) + elif not (self.TypeTable[coolClass.text].Deep > self.TypeTable[classParent.text].Deep): + line = str(classParent.line) + column = str(classParent.column + 1) + error = f"({line}, {column}) - SemanticError: Class {coolClass.text}, or an ancestor of {coolClass.text}, is involved in an inheritance cycle." print(error) else: self.TypeTable[coolClass.text].Created = True @@ -156,8 +171,8 @@ def visitClassDefine(self, ctx:COOL.ClassDefineContext): return else: line = str(classParent.line) - column = str(classParent.column) - error = "(" + line + "," + column + "): this class doesn't exist" + column = str(classParent.column + 1) + error = f"({line}, {column}) - TypeError: Class {coolClass.text} inherits from an undefined class {classParent.text}." print(error) else: self.TypeTable[coolClass.text].Created = True @@ -173,71 +188,143 @@ def visitClassDefine(self, ctx:COOL.ClassDefineContext): def visitMethod(self, ctx:COOL.MethodContext): coolClass = ctx.parentCtx.getChild(1).symbol.text methodName = ctx.getChild(0).symbol.text - methodType = ctx.getChild(len(ctx.children) - 4).symbol - if self.ScopeManager.searchScope(methodName): + methodType = ctx.getChild(len(ctx.children) - 4).symbol + if self.TypeTable[coolClass].VisitedMethods.__contains__(methodName): line = str(ctx.getChild(0).symbol.line) - column = str(ctx.getChild(0).symbol.column) - error = "(" + line + "," + column + "): this method name already exist" + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Method {methodName} is multiply defined." print(error) - elif self.TypeTable.keys().__contains__(self.TypeTable[coolClass].Methods[methodName].Type) or methodType.text == "SELF_TYPE": + return + if self.searchMethod(self.TypeTable[coolClass].Parent, methodName): + ancestorMethod = self.searchMethodInfo(self.TypeTable[coolClass].Parent,methodName) + if ancestorMethod.ParamsNumber != self.TypeTable[coolClass].Methods[methodName].ParamsNumber: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) SemanticError: Incompatible number of formal parameters in redefined method {methodName}." + print(error) + return + if ancestorMethod.Type != methodType.text: + line = str(methodType.line) + column = str(methodType.column + 1) + error = f"({line}, {column}) SemanticError: In redefined method {methodName}, return type {methodType.text} is different from original return type {ancestorMethod.Type}." + print(error) + return + if self.TypeTable.keys().__contains__(self.TypeTable[coolClass].Methods[methodName].Type) or methodType.text == "SELF_TYPE": self.ScopeManager.addIdentifier(methodName, methodType.text) + self.TypeTable[coolClass].VisitedMethods.append(methodName) self.ScopeManager.addScope() - self.visitChildren(ctx) + i = 2 + while(i < len(ctx.children) - 4): + ctx.getChild(i).accept(self) + i += 2 + methodValue = ctx.getChild(len(ctx.children) - 2).accept(self) + if self.join(methodType.text, methodValue) != methodType.text: + line = str(ctx.getChild(len(ctx.children) - 2).start.line) + column = str(ctx.getChild(len(ctx.children) - 2).start.column + 1) + error = f"({line}, {column}) - TypeError: Inferred return type {methodValue} of method {methodName} does not conform to declared return type {methodType.text}." + print(error) self.ScopeManager.deleteScope() return else: line = str(methodType.line) - column = str(methodType.column) - error = "(" + line + "," + column + "): this type doesn't exist" + column = str(methodType.column + 1) + error = f"({line}, {column}) - TypeError: Undefined return type {methodType.text} in method {methodName}." print(error) # Visit a parse tree produced by COOL#property. def visitProperty(self, ctx:COOL.PropertyContext): atributeType = ctx.getChild(2).symbol.text + coolClass = ctx.parentCtx.getChild(1).symbol.text atributeName = ctx.getChild(0).symbol.text - if self.ScopeManager.searchScope(atributeName): + if self.TypeTable[coolClass].VisitedAtributes.__contains__(atributeName): line = str(ctx.getChild(0).symbol.line) - column = str(ctx.getChild(0).symbol.column) - error = "(" + line + "," + column + "): this atribute name already exist" + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Attribute {atributeName} is multiply defined in class." print(error) return "None" + elif atributeName == "self": + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: 'self' cannot be the name of an atribute." + print(error) + return elif not(self.TypeTable.keys().__contains__(atributeType) or atributeType == "SELF_TYPE"): line = str(ctx.getChild(2).symbol.line) - column = str(ctx.getChild(2).symbol.column) - error = "(" + line + "," + column + "): this type doesn't exist" + column = str(ctx.getChild(2).symbol.column + 1) + error = f"({line}, {column}) - TypeError: Class {atributeType} of attribute {atributeName} is undefined." + print(error) + return "None" + elif self.TypeTable[self.TypeTable[coolClass].Parent].Atributes.keys().__contains__(atributeName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Attribute {atributeName} is an attribute of an inherited class." print(error) return "None" elif len(ctx.children) == 5: atributeValue = ctx.getChild(4).accept(self) if self.join(atributeType, atributeValue) != atributeType: line = str(ctx.getChild(4).start.line) - column = str(ctx.getChild(4).start.column) - error = "(" + line + "," + column + "): the type of the expression is diferent of the type of the atribute" + column = str(ctx.getChild(4).start.column + 1) + error = f"({line}, {column}) - TypeError: Inferred type {atributeValue} of initialization of attribute {atributeName} does not conform to declared type {atributeType}." print(error) return "None" else: self.ScopeManager.addIdentifier(atributeName, atributeType) + self.TypeTable[coolClass].VisitedAtributes.append(atributeName) return atributeType else: self.ScopeManager.addIdentifier(atributeName, atributeType) + self.TypeTable[coolClass].VisitedAtributes.append(atributeName) return atributeType # Visit a parse tree produced by COOL#formal. def visitFormal(self, ctx:COOL.FormalContext): paramName = ctx.getChild(0).symbol.text paramType = ctx.getChild(2).symbol.text + method = ctx.parentCtx + coolClass = method.parentCtx.getChild(1).symbol.text + methodName = method.getChild(0).symbol.text + if paramName == "self": + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: 'self' cannot be the name of a formal parameter." + print(error) + return if self.ScopeManager.searchScope(paramName): line = str(ctx.getChild(0).symbol.line) - column = str(ctx.getChild(0).symbol.column) - error = "(" + line + "," + column + "): this param name already exist" + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Formal parameter {paramName} is multiply defined." print(error) - elif self.TypeTable.keys().__contains__(paramType): - self.ScopeManager.addIdentifier(paramName, paramType) - return self.visitChildren(ctx) + return + if self.searchMethod(self.TypeTable[coolClass].Parent, methodName): + ancestorMethod = self.searchMethodInfo(self.TypeTable[coolClass].Parent,methodName) + exist = False + i = 0 + for param in self.TypeTable[coolClass].Methods[methodName].Params: + (pName, pType) = param + if pName == paramName: + exist = True + (_, acType) = ancestorMethod.Params.__getitem__(i) + if paramType != acType: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: In redefined method {methodName}, parameter type {paramType} is different from original type {acType}." + print(error) + return + i += 1 + if not exist: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: In ancestor method {methodName}, dont exist param {paramName}." + print(error) + return + if self.TypeTable.keys().__contains__(paramType): + self.ScopeManager.addIdentifier(paramName, paramType) + return self.visitChildren(ctx) else: line = str(ctx.getChild(2).symbol.line) - column = str(ctx.getChild(2).symbol.column) - error = "(" + line + "," + column + "): this type doesn't exist" + column = str(ctx.getChild(2).symbol.column + 1) + error = f"({line}, {column}) - TypeError: Class {paramType} of formal parameter {paramName} is undefined." print(error) # Visit a parse tree produced by COOL#int. @@ -261,16 +348,10 @@ def visitAdd(self, ctx: COOL.AddContext): addValue = "Int" leftValue = ctx.getChild(0).accept(self) rightValue = ctx.getChild(2).accept(self) - if leftValue != "Int": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" - print(error) - addValue = "None" - if rightValue != "Int": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" + if leftValue != "Int" or rightValue != "Int": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} + {rightValue}" print(error) addValue = "None" return addValue @@ -280,16 +361,10 @@ def visitMinus(self, ctx:COOL.MinusContext): minusValue = "Int" leftValue = ctx.getChild(0).accept(self) rightValue = ctx.getChild(2).accept(self) - if leftValue != "Int": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" - print(error) - minusValue = "None" - if rightValue != "Int": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" + if leftValue != "Int" or rightValue != "Int": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} - {rightValue}" print(error) minusValue = "None" return minusValue @@ -299,16 +374,10 @@ def visitMultiply(self, ctx: COOL.MultiplyContext): mulValue = "Int" leftValue = ctx.getChild(0).accept(self) rightValue = ctx.getChild(2).accept(self) - if leftValue != "Int": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" - print(error) - mulValue = "None" - if rightValue != "Int": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" + if leftValue != "Int" or rightValue != "Int": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} * {rightValue}" print(error) mulValue = "None" return mulValue @@ -318,16 +387,10 @@ def visitDivision(self, ctx: COOL.DivisionContext): divValue = "Int" leftValue = ctx.getChild(0).accept(self) rightValue = ctx.getChild(2).accept(self) - if leftValue != "Int": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" - print(error) - divValue = "None" - if rightValue != "Int": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" + if leftValue != "Int" or rightValue != "Int": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} / {rightValue}" print(error) divValue = "None" return divValue @@ -337,7 +400,12 @@ def visitNegative(self, ctx: COOL.NegativeContext): expressValue = ctx.getChild(1).accept(self) if expressValue == "Int": return "Int" - return "None" + else: + line = str(ctx.getChild(1).start.line) + column = str(ctx.getChild(1).start.column) + error = f"({line}, {column}) - TypeError: Argument of '~' has type {expressValue} instead of Int." + print(error) + return "None" # Visit a parse tree produced by COOL#isvoid. def visitIsvoid(self, ctx:COOL.IsvoidContext): @@ -349,23 +417,22 @@ def visitBoolNot(self, ctx: COOL.BoolNotContext): expressValue = ctx.getChild(1).accept(self) if expressValue == "Bool": return "Bool" - return "None" + else: + line = str(ctx.getChild(1).start.line) + column = str(ctx.getChild(1).start.column + 1) + error = f"({line}, {column}) - TypeError: Argument of 'not' has type {expressValue} instead of Bool." + print(error) + return "None" # Visit a parse tree produced by COOL#lessThan. def visitLessThan(self, ctx:COOL.LessThanContext): lessValue = "Bool" leftValue = ctx.getChild(0).accept(self) rightValue = ctx.getChild(2).accept(self) - if leftValue != "Int": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" - print(error) - lessValue = "None" - if rightValue != "Int": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" + if leftValue != "Int" or rightValue != "Int": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} < {rightValue}" print(error) lessValue = "None" return lessValue @@ -375,16 +442,10 @@ def visitLessEqual(self, ctx:COOL.LessEqualContext): lessEqualValue = "Bool" leftValue = ctx.getChild(0).accept(self) rightValue = ctx.getChild(2).accept(self) - if leftValue != "Int": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" - print(error) - lessEqualValue = "None" - if rightValue != "Int": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" + if leftValue != "Int" or rightValue != "Int": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} <= {rightValue}" print(error) lessEqualValue = "None" return lessEqualValue @@ -395,21 +456,22 @@ def visitEqual(self, ctx: COOL.EqualContext): rightValue = ctx.getChild(2).accept(self) if leftValue == "None" or rightValue == "None": return "None" - if leftValue == rightValue: + elif leftValue == rightValue: return "Bool" - if leftValue == "String" or leftValue == "Int" or leftValue == "Bool": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is incorrect" + elif leftValue == "String" or leftValue == "Int" or leftValue == "Bool": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: Illegal comparison with a basic type." print(error) return "None" - if rightValue == "String" or rightValue == "Int" or rightValue == "Bool": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is incorrect" + elif rightValue == "String" or rightValue == "Int" or rightValue == "Bool": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: Illegal comparison with a basic type." print(error) return "None" - return "Bool" + else: + return "Bool" # Visit a parse tree produced by COOL#assignment. def visitAssignment(self, ctx: COOL.AssignmentContext): @@ -421,19 +483,25 @@ def visitAssignment(self, ctx: COOL.AssignmentContext): variableType = self.searchAtributeInfo(self.actualClass, variableName) else: line = str(ctx.getChild(0).symbol.line) - column = str(ctx.getChild(0).symbol.column) - error = "(" + line + "," + column + "): this identifier does not exist" + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - NameError: Undeclared identifier {variableName}." print(error) return "None" if variableType == "SELF_TYPE": variableType = self.actualClass if self.join(asignValue, variableType) != variableType: line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is diferent that the identifier" + column = str(ctx.getChild(2).start.column + 1) + error = f"({line}, {column}) - TypeError: Cannot assign {asignValue} expression to {variableType} identifier." + print(error) + return "None" + if variableName == "self": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Cannot assign to 'self'." print(error) return "None" - return variableType + return asignValue # Visit a parse tree produced by COOL#parentheses. def visitParentheses(self, ctx: COOL.ParenthesesContext): @@ -447,8 +515,8 @@ def visitId(self, ctx: COOL.IdContext): elif self.searchAtribute(self.actualClass, IdValue): return self.searchAtributeInfo(self.actualClass, IdValue) line = str(ctx.getChild(0).symbol.line) - column = str(ctx.getChild(0).symbol.column) - error = "(" + line + "," + column + "): this identifier does not exist" + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - NameError: Undeclared identifier {IdValue}." print(error) return "None" @@ -461,8 +529,8 @@ def visitIf(self, ctx:COOL.IfContext): return self.join(thenValue, elseValue) else: line = str(ctx.getChild(1).start.line) - column = str(ctx.getChild(1).start.column) - error = "(" + line + "," + column + "): this expression is not boolean" + column = str(ctx.getChild(1).start.column + 1) + error = f"({line}, {column}) - TypeError: Predicate of 'if' does not have type Bool." print(error) return self.join(thenValue, elseValue) @@ -474,8 +542,8 @@ def visitWhile(self, ctx: COOL.WhileContext): return "Object" else: line = str(ctx.getChild(1).start.line) - column = str(ctx.getChild(1).start.column) - error = "(" + line + "," + column + "): this expression is not boolean" + column = str(ctx.getChild(1).start.column + 1) + error = f"({line}, {column}) - TypeError: Loop condition does not have type Bool." print(error) return "Object" @@ -495,11 +563,23 @@ def visitCase(self, ctx:COOL.CaseContext): lengt = len(ctx.children) - 1 count = 3 caseValue = "None" + typeList = [] while lengt > count: idName = ctx.getChild(count).symbol.text count = count + 2 idType = ctx.getChild(count).symbol.text + if not (self.TypeTable.keys().__contains__(idType)): + line = str(ctx.getChild(count).symbol.line) + column = str(ctx.getChild(count).symbol.column + 1) + error = f"({line}, {column}) - TypeError: Class {idType} of case branch is undefined." + print(error) + if typeList.__contains__(idType): + line = str(ctx.getChild(count).symbol.line) + column = str(ctx.getChild(count).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Duplicate branch {idType} in case statement." + print(error) count = count + 2 + typeList.append(idType) self.ScopeManager.addScope() self.ScopeManager.addIdentifier(idName, idType) if (caseValue == "None"): @@ -512,7 +592,13 @@ def visitCase(self, ctx:COOL.CaseContext): # Visit a parse tree produced by COOL#new. def visitNew(self, ctx: COOL.NewContext): - return ctx.getChild(1).symbol.text + typeName = ctx.getChild(1).symbol.text + if not self.TypeTable.keys().__contains__(typeName): + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: 'new' used with undefined class {typeName}." + print(error) + return typeName # Visit a parse tree produced by COOL#ownMethodCall. def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): @@ -525,32 +611,32 @@ def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): methodType = methodInfo.Type if methodInfo.ParamsNumber == 0 and len(ctx.children) != 3: line = str(ctx.getChild(1).symbol.line) - column = str(ctx.getChild(1).symbol.column) - error = "(" + line + "," + column + "): the number of params in the call is incorrect" + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(1).symbol.text} called with wrong number of arguments." print(error) methodType = "None" elif len(ctx.children) != methodInfo.ParamsNumber * 2 + 2 and methodInfo.ParamsNumber != 0: line = str(ctx.getChild(1).symbol.line) - column = str(ctx.getChild(1).symbol.column) - error = "(" + line + "," + column + "): the number of params in the call is incorrect" + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(1).symbol.text} called with wrong number of arguments." print(error) methodType = "None" else: count = 2 for param in methodInfo.Params: - (_,paramType) = param + (paramName,paramType) = param requestType = ctx.getChild(count).accept(self) if (self.join(requestType, paramType) != paramType): line = str(ctx.getChild(count).start.line) - column = str(ctx.getChild(count).start.column) - error = "(" + line + "," + column + "): the type of this param in the call is incorrect" + column = str(ctx.getChild(count).start.column + 1) + error = f"({line}, {column}) - TypeError: In call of method {ctx.getChild(1).symbol.text}, type {requestType} of parameter {paramName} does not conform to declared type {paramType}." print(error) methodType = "None" count = count + 2 else: line = str(ctx.getChild(0).symbol.line) - column = str(ctx.getChild(0).symbol.column) - error = "(" + line + "," + column + "): this method not exist in " + self.actualClass + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) AttributeError: Dispatch to undefined method {ctx.getChild(0).symbol.text}." print(error) return methodType @@ -565,9 +651,9 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): if self.join(currentClass, parent) == parent: currentClass = parent else: - line = str(ctx.getChild(2).symbol.line) - column = str(ctx.getChild(2).symbol.column) - error = "(" + line + "," + column + "): this class is not parent of " + currentClass + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column) + error = f"({line}, {column}) - SemanticError: Expression type {currentClass} does not conform to declared static dispatch type {parent}." print(error) return methodType if self.searchMethod(currentClass, ctx.getChild(length - 3).symbol.text): @@ -577,33 +663,33 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): else: methodType = methodInfo.Type if (methodInfo.ParamsNumber == 0 and len(ctx.children) != length): - line = str(ctx.getChild(length - 3).start.line) - column = str(ctx.getChild(length - 3).start.column) - error = "(" + line + "," + column + "): the number of params in the call is incorrect" + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(2).symbol.text} called with wrong number of arguments." print(error) methodType = "None" elif (len(ctx.children) != methodInfo.ParamsNumber * 2 + length - 1) and methodInfo.ParamsNumber > 0: - line = str(ctx.getChild(length - 3).start.line) - column = str(ctx.getChild(length - 3).start.column) - error = "(" + line + "," + column + "): the number of params in the call is incorrect" + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(2).symbol.text} called with wrong number of arguments." print(error) methodType = "None" else: count = length - 1 for param in methodInfo.Params: - (_, paramType) = param + (paramName, paramType) = param requestType = ctx.getChild(count).accept(self) if (self.join(requestType, paramType) != paramType): line = str(ctx.getChild(count).start.line) - column = str(ctx.getChild(count).start.column) - error = "(" + line + "," + column + "): the type of this param in the call is incorrect" + column = str(ctx.getChild(count).start.column + 1) + error = f"({line}, {column}) - TypeError: In call of method {ctx.getChild(2).symbol.text}, type {requestType} of parameter {paramName} does not conform to declared type {paramType}." print(error) methodType = "None" count = count + 2 else: line = str(ctx.getChild(length - 3).symbol.line) - column = str(ctx.getChild(length - 3).symbol.column) - error = "(" + line + "," + column + "): this method not exist in " + currentClass + column = str(ctx.getChild(length - 3).symbol.column + 1) + error = f"({line}, {column}) AttributeError: Dispatch to undefined method {ctx.getChild(length - 3).symbol.text}." print(error) return methodType @@ -613,13 +699,20 @@ def visitLetIn(self, ctx: COOL.LetInContext): count = 0 while(ctx.getChild(count).symbol.text != "in"): idName = ctx.getChild(count + 1).symbol.text + if idName == "self": + self.ScopeManager.deleteScope() + line = str(ctx.getChild(count + 1).symbol.line) + column = str(ctx.getChild(count + 1).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: 'self' cannot be bound in a 'let' expression." + print(error) + return "None" count = count + 2 idType = ctx.getChild(count + 1).symbol.text if not(self.TypeTable.keys().__contains__(idType)) and idType != "SELF_TYPE": self.ScopeManager.deleteScope() line = str(ctx.getChild(count + 1).symbol.line) - column = str(ctx.getChild(count + 1).symbol.column) - error = "(" + line + "," + column + "): this class does not exist " + column = str(ctx.getChild(count + 1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: Class {idType} of let-bound identifier {idName} is undefined." print(error) return "None" self.ScopeManager.addIdentifier(idName, idType) @@ -630,12 +723,14 @@ def visitLetIn(self, ctx: COOL.LetInContext): if self.join(idType, idValue) != idType: self.ScopeManager.deleteScope() line = str(ctx.getChild(count -1).start.line) - column = str(ctx.getChild(count - 1).start.column) - error = "(" + line + "," + column + "): the type of the expression is diferent of the type of the identifier" + column = str(ctx.getChild(count - 1).start.column + 1) + error = f"({line}, {column}) - TypeError: Inferred type of {idValue} initialization of {idName} does not conform to identifier's declared type {idType}." print(error) return "None" - return ctx.getChild(count + 1).accept(self) + temp = ctx.getChild(count + 1).accept(self) + self.ScopeManager.deleteScope() + return temp class TypeCOOLVisitor(ParseTreeVisitor): diff --git a/tests/semantic/arithmetic1.cl b/tests/semantic/arithmetic1.cl new file mode 100644 index 00000000..8f73a60b --- /dev/null +++ b/tests/semantic/arithmetic1.cl @@ -0,0 +1,11 @@ +--The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Int <- 1 * 2 / 3 - 4 + new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x + new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic10.cl b/tests/semantic/arithmetic10.cl new file mode 100644 index 00000000..bbfe6cdb --- /dev/null +++ b/tests/semantic/arithmetic10.cl @@ -0,0 +1,15 @@ +(* +The expression ~ is the integer +complement of . The expression must have static type Int and the entire expression +has static type Int. +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in ~new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic10_error.txt b/tests/semantic/arithmetic10_error.txt new file mode 100644 index 00000000..b2be0476 --- /dev/null +++ b/tests/semantic/arithmetic10_error.txt @@ -0,0 +1 @@ +(13, 19) - TypeError: Inferred type Int of initialization of attribute test does not conform to declared type Bool. \ No newline at end of file diff --git a/tests/semantic/arithmetic11.cl b/tests/semantic/arithmetic11.cl new file mode 100644 index 00000000..fc067dc1 --- /dev/null +++ b/tests/semantic/arithmetic11.cl @@ -0,0 +1,14 @@ +(* +The expression not is the boolean complement of . The expression + must have static type Bool and the entire expression has static type Bool. +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in not 1 + new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic11_error.txt b/tests/semantic/arithmetic11_error.txt new file mode 100644 index 00000000..bb4b8e1c --- /dev/null +++ b/tests/semantic/arithmetic11_error.txt @@ -0,0 +1 @@ +(13, 24) - TypeError: Argument of 'not' has type Int instead of Bool. \ No newline at end of file diff --git a/tests/semantic/arithmetic12.cl b/tests/semantic/arithmetic12.cl new file mode 100644 index 00000000..2e012fc4 --- /dev/null +++ b/tests/semantic/arithmetic12.cl @@ -0,0 +1,14 @@ +(* +The expression not is the boolean complement of . The expression + must have static type Bool and the entire expression has static type Bool. +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in not 1 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic12_error.txt b/tests/semantic/arithmetic12_error.txt new file mode 100644 index 00000000..d25eab65 --- /dev/null +++ b/tests/semantic/arithmetic12_error.txt @@ -0,0 +1 @@ +(12, 18) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type Int. \ No newline at end of file diff --git a/tests/semantic/arithmetic1_error.txt b/tests/semantic/arithmetic1_error.txt new file mode 100644 index 00000000..a74ebf3d --- /dev/null +++ b/tests/semantic/arithmetic1_error.txt @@ -0,0 +1 @@ +(10, 27) - TypeError: non-Int arguments: Int + String diff --git a/tests/semantic/arithmetic2.cl b/tests/semantic/arithmetic2.cl new file mode 100644 index 00000000..56de8aa6 --- /dev/null +++ b/tests/semantic/arithmetic2.cl @@ -0,0 +1,11 @@ +--The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Int <- 1 + 2 * 3 / 4 - new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x - new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic2_error.txt b/tests/semantic/arithmetic2_error.txt new file mode 100644 index 00000000..2c7952af --- /dev/null +++ b/tests/semantic/arithmetic2_error.txt @@ -0,0 +1 @@ +(10, 27) - TypeError: non-Int arguments: Int - String diff --git a/tests/semantic/arithmetic3.cl b/tests/semantic/arithmetic3.cl new file mode 100644 index 00000000..2abf42a1 --- /dev/null +++ b/tests/semantic/arithmetic3.cl @@ -0,0 +1,11 @@ +--The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Int <- 1 - 2 + 3 * 4 / new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x / new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic3_error.txt b/tests/semantic/arithmetic3_error.txt new file mode 100644 index 00000000..81d88331 --- /dev/null +++ b/tests/semantic/arithmetic3_error.txt @@ -0,0 +1 @@ +(10, 27) - TypeError: non-Int arguments: Int / String diff --git a/tests/semantic/arithmetic4.cl b/tests/semantic/arithmetic4.cl new file mode 100644 index 00000000..2c7dd4fc --- /dev/null +++ b/tests/semantic/arithmetic4.cl @@ -0,0 +1,11 @@ +--The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Int <- 1 / 2 - 3 + 4 * new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x * new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic4_error.txt b/tests/semantic/arithmetic4_error.txt new file mode 100644 index 00000000..1ca6df02 --- /dev/null +++ b/tests/semantic/arithmetic4_error.txt @@ -0,0 +1 @@ +(10, 27) - TypeError: non-Int arguments: Int * String \ No newline at end of file diff --git a/tests/semantic/arithmetic5.cl b/tests/semantic/arithmetic5.cl new file mode 100644 index 00000000..bc08c6e8 --- /dev/null +++ b/tests/semantic/arithmetic5.cl @@ -0,0 +1,11 @@ +--The static type of the expression is Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Int <- 1 / 2 - 3 + 4 * new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x * new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic5_error.txt b/tests/semantic/arithmetic5_error.txt new file mode 100644 index 00000000..dd534684 --- /dev/null +++ b/tests/semantic/arithmetic5_error.txt @@ -0,0 +1 @@ +(9, 19) - TypeError: Inferred type Int of initialization of attribute test does not conform to declared type Bool. diff --git a/tests/semantic/arithmetic6.cl b/tests/semantic/arithmetic6.cl new file mode 100644 index 00000000..a0c3d03f --- /dev/null +++ b/tests/semantic/arithmetic6.cl @@ -0,0 +1,11 @@ + --The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 <= new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in 1 <= new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; diff --git a/tests/semantic/arithmetic6_error.txt b/tests/semantic/arithmetic6_error.txt new file mode 100644 index 00000000..2e43dfc1 --- /dev/null +++ b/tests/semantic/arithmetic6_error.txt @@ -0,0 +1 @@ +(10, 22) - TypeError: non-Int arguments: Int <= String diff --git a/tests/semantic/arithmetic7.cl b/tests/semantic/arithmetic7.cl new file mode 100644 index 00000000..c00c75cd --- /dev/null +++ b/tests/semantic/arithmetic7.cl @@ -0,0 +1,12 @@ + --The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in 1 < new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; + diff --git a/tests/semantic/arithmetic7_error.txt b/tests/semantic/arithmetic7_error.txt new file mode 100644 index 00000000..6f353711 --- /dev/null +++ b/tests/semantic/arithmetic7_error.txt @@ -0,0 +1 @@ +(10, 22) - TypeError: non-Int arguments: Int < String diff --git a/tests/semantic/arithmetic8.cl b/tests/semantic/arithmetic8.cl new file mode 100644 index 00000000..3210bdb8 --- /dev/null +++ b/tests/semantic/arithmetic8.cl @@ -0,0 +1,13 @@ + --The rules are exactly the same as for the binary arithmetic operations, except that the result is a Bool. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in 1 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +}; + + diff --git a/tests/semantic/arithmetic8_error.txt b/tests/semantic/arithmetic8_error.txt new file mode 100644 index 00000000..ebcaa379 --- /dev/null +++ b/tests/semantic/arithmetic8_error.txt @@ -0,0 +1 @@ +(9, 18) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type Int. diff --git a/tests/semantic/arithmetic9.cl b/tests/semantic/arithmetic9.cl new file mode 100644 index 00000000..95579e13 --- /dev/null +++ b/tests/semantic/arithmetic9.cl @@ -0,0 +1,15 @@ +(* +The expression ~ is the integer +complement of . The expression must have static type Int and the entire expression +has static type Int. +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in 1 + ~new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; \ No newline at end of file diff --git a/tests/semantic/arithmetic9_error.txt b/tests/semantic/arithmetic9_error.txt new file mode 100644 index 00000000..99fafbbf --- /dev/null +++ b/tests/semantic/arithmetic9_error.txt @@ -0,0 +1 @@ +(14, 25) - TypeError: Argument of '~' has type String instead of Int. \ No newline at end of file diff --git a/tests/semantic/assignment1.cl b/tests/semantic/assignment1.cl new file mode 100644 index 00000000..19ab7021 --- /dev/null +++ b/tests/semantic/assignment1.cl @@ -0,0 +1,7 @@ +--The static type of the expression must conform to the declared type of the identifier + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: Int <- "String"; +}; diff --git a/tests/semantic/assignment1_error.txt b/tests/semantic/assignment1_error.txt new file mode 100644 index 00000000..6eb88301 --- /dev/null +++ b/tests/semantic/assignment1_error.txt @@ -0,0 +1 @@ +(6, 18) - TypeError: Inferred type String of initialization of attribute test does not conform to declared type Int. diff --git a/tests/semantic/assignment2.cl b/tests/semantic/assignment2.cl new file mode 100644 index 00000000..cace221a --- /dev/null +++ b/tests/semantic/assignment2.cl @@ -0,0 +1,13 @@ +--The static type of an assignment is the static type of . + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A): B { a <- new C }; + test2(a: A): D { a <- new C }; +}; diff --git a/tests/semantic/assignment2_error.txt b/tests/semantic/assignment2_error.txt new file mode 100644 index 00000000..ed10b7f3 --- /dev/null +++ b/tests/semantic/assignment2_error.txt @@ -0,0 +1 @@ +(12, 22) - TypeError: Inferred return type C of method test2 does not conform to declared return type D. diff --git a/tests/semantic/assignment3.cl b/tests/semantic/assignment3.cl new file mode 100644 index 00000000..eba0d69e --- /dev/null +++ b/tests/semantic/assignment3.cl @@ -0,0 +1,14 @@ +--The static type of an assignment is the static type of . + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + a: A; + b: B <- a <- new C; + d: D <- a <- new C; +}; diff --git a/tests/semantic/assignment3_error.txt b/tests/semantic/assignment3_error.txt new file mode 100644 index 00000000..bc9a718c --- /dev/null +++ b/tests/semantic/assignment3_error.txt @@ -0,0 +1 @@ +(13, 13) - TypeError: Inferred type C of initialization of attribute d does not conform to declared type D. \ No newline at end of file diff --git a/tests/semantic/attributes1.cl b/tests/semantic/attributes1.cl new file mode 100644 index 00000000..3fa0440e --- /dev/null +++ b/tests/semantic/attributes1.cl @@ -0,0 +1,13 @@ +--The static type of the expression must conform to the declared type of the attribute. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + test1: IO <- new Main; + test2: B <- new A; + + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/tests/semantic/attributes1_error.txt b/tests/semantic/attributes1_error.txt new file mode 100644 index 00000000..9cb8460c --- /dev/null +++ b/tests/semantic/attributes1_error.txt @@ -0,0 +1 @@ +(10, 17) - TypeError: Inferred type A of initialization of attribute test2 does not conform to declared type B. diff --git a/tests/semantic/attributes2.cl b/tests/semantic/attributes2.cl new file mode 100644 index 00000000..7937c2cc --- /dev/null +++ b/tests/semantic/attributes2.cl @@ -0,0 +1,13 @@ +--The static type of the expression must conform to the declared type of the attribute. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + test1: IO <- new Main; + test2: C <- new D; + + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/tests/semantic/attributes2_error.txt b/tests/semantic/attributes2_error.txt new file mode 100644 index 00000000..6d601b7c --- /dev/null +++ b/tests/semantic/attributes2_error.txt @@ -0,0 +1 @@ +(10, 17) - TypeError: Inferred type D of initialization of attribute test2 does not conform to declared type C. diff --git a/tests/semantic/attributes3.cl b/tests/semantic/attributes3.cl new file mode 100644 index 00000000..8a67decd --- /dev/null +++ b/tests/semantic/attributes3.cl @@ -0,0 +1,25 @@ +--Attributes are local to the class in which they are defined or inherited. + +class A { + a: Int <- 5; + test(x1: Int, y1: Int): Int { + let x: Int <- x1, y: Int <-y1 in { + x <- x + a; + y <- y + a; + if b then x + y else x - y fi; + } + }; +}; +class B inherits A { + b: Bool <- true; +}; +class C inherits B { + c: String <- "C"; +}; +class D inherits B { + d: IO <- new Main.main(); +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!") }; +}; \ No newline at end of file diff --git a/tests/semantic/attributes3_error.txt b/tests/semantic/attributes3_error.txt new file mode 100644 index 00000000..6195c816 --- /dev/null +++ b/tests/semantic/attributes3_error.txt @@ -0,0 +1 @@ +(9, 16) - NameError: Undeclared identifier b. diff --git a/tests/semantic/attributes4.cl b/tests/semantic/attributes4.cl new file mode 100644 index 00000000..a7f63adb --- /dev/null +++ b/tests/semantic/attributes4.cl @@ -0,0 +1,39 @@ +--Attributes are local to the class in which they are defined or inherited. + +class A { + a: Int <- 5; +}; +class B inherits A { + b: Bool <- true; + test(x1: Int, y1: Int): Int { + let x: Int <- x1, y: Int <-y1 in { + x <- x + a; + y <- y + a; + if b then x + y else x - y fi; + } + }; +}; +class D inherits B { + d: IO <- new Main.main(); + test3(x1: Int, y1: Int): IO { + let x: Int <- x1, y: Int <-y1, c: String <- "C" in { + x <- x + a; + y <- y + a; + if b then new IO.out_string(c) else d fi; + } + }; +}; +class C inherits B { + c: String <- "C"; + test2(x1: Int, y1: Int): IO { + let x: Int <- x1, y: Int <-y1 in { + x <- x + a; + y <- y + a; + if b then new IO.out_string(c) else d fi; + } + }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!") }; +}; \ No newline at end of file diff --git a/tests/semantic/attributes4_error.txt b/tests/semantic/attributes4_error.txt new file mode 100644 index 00000000..fa5fcfa8 --- /dev/null +++ b/tests/semantic/attributes4_error.txt @@ -0,0 +1 @@ +(32, 49) - NameError: Undeclared identifier d. \ No newline at end of file diff --git a/tests/semantic/basics1.cl b/tests/semantic/basics1.cl new file mode 100644 index 00000000..32ae1656 --- /dev/null +++ b/tests/semantic/basics1.cl @@ -0,0 +1,10 @@ +-- It is an error to redefine the IO class. + +class IO { + scan(): String { ":)" }; + print(s: String): IO { new IO }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/tests/semantic/basics1_error.txt b/tests/semantic/basics1_error.txt new file mode 100644 index 00000000..676f5049 --- /dev/null +++ b/tests/semantic/basics1_error.txt @@ -0,0 +1 @@ +(3, 7) - SemanticError: Redefinition of basic class IO. diff --git a/tests/semantic/basics2.cl b/tests/semantic/basics2.cl new file mode 100644 index 00000000..cf2b1cd2 --- /dev/null +++ b/tests/semantic/basics2.cl @@ -0,0 +1,9 @@ +-- It is an error to inherit from or redefine Int. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class A inherits Int { + is_prime(): Bool { false }; +}; diff --git a/tests/semantic/basics2_error.txt b/tests/semantic/basics2_error.txt new file mode 100644 index 00000000..69a3b681 --- /dev/null +++ b/tests/semantic/basics2_error.txt @@ -0,0 +1 @@ +(7, 18) - SemanticError: Class A cannot inherit class Int. diff --git a/tests/semantic/basics3.cl b/tests/semantic/basics3.cl new file mode 100644 index 00000000..fef017a8 --- /dev/null +++ b/tests/semantic/basics3.cl @@ -0,0 +1,9 @@ +-- It is an error to inherit from or redefine Int. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class Int { + is_prime(): Bool { false }; +}; \ No newline at end of file diff --git a/tests/semantic/basics3_error.txt b/tests/semantic/basics3_error.txt new file mode 100644 index 00000000..d8f80cb1 --- /dev/null +++ b/tests/semantic/basics3_error.txt @@ -0,0 +1 @@ +(7, 7) - SemanticError: Redefinition of basic class Int. diff --git a/tests/semantic/basics4.cl b/tests/semantic/basics4.cl new file mode 100644 index 00000000..9266ec79 --- /dev/null +++ b/tests/semantic/basics4.cl @@ -0,0 +1,9 @@ +-- It is an error to inherit from or redefine String. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class A inherits String { + is_palindrome(): Bool { false }; +}; \ No newline at end of file diff --git a/tests/semantic/basics4_error.txt b/tests/semantic/basics4_error.txt new file mode 100644 index 00000000..d5cd4c3d --- /dev/null +++ b/tests/semantic/basics4_error.txt @@ -0,0 +1 @@ +(7, 18) - SemanticError: Class A cannot inherit class String. diff --git a/tests/semantic/basics5.cl b/tests/semantic/basics5.cl new file mode 100644 index 00000000..bad5eff1 --- /dev/null +++ b/tests/semantic/basics5.cl @@ -0,0 +1,9 @@ +-- It is an error to inherit from or redefine String. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class String { + is_palindrome(): Bool { false }; +}; \ No newline at end of file diff --git a/tests/semantic/basics5_error.txt b/tests/semantic/basics5_error.txt new file mode 100644 index 00000000..8437accf --- /dev/null +++ b/tests/semantic/basics5_error.txt @@ -0,0 +1 @@ +(7, 7) - SemanticError: Redefinition of basic class String. diff --git a/tests/semantic/basics6.cl b/tests/semantic/basics6.cl new file mode 100644 index 00000000..47266ebe --- /dev/null +++ b/tests/semantic/basics6.cl @@ -0,0 +1,9 @@ +-- It is an error to inherit from or redefine Bool. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class A inherits Bool { + xor(b: Bool): Bool { false }; +}; \ No newline at end of file diff --git a/tests/semantic/basics6_error.txt b/tests/semantic/basics6_error.txt new file mode 100644 index 00000000..b4d22da1 --- /dev/null +++ b/tests/semantic/basics6_error.txt @@ -0,0 +1 @@ +(7, 18) - SemanticError: Class A cannot inherit class Bool. diff --git a/tests/semantic/basics7.cl b/tests/semantic/basics7.cl new file mode 100644 index 00000000..0f30aaec --- /dev/null +++ b/tests/semantic/basics7.cl @@ -0,0 +1,9 @@ +-- It is an error to inherit from or redefine Bool. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class Bool { + xor(b: Bool): Bool { false }; +}; \ No newline at end of file diff --git a/tests/semantic/basics7_error.txt b/tests/semantic/basics7_error.txt new file mode 100644 index 00000000..92660ab9 --- /dev/null +++ b/tests/semantic/basics7_error.txt @@ -0,0 +1 @@ +(7, 7) - SemanticError: Redefinition of basic class Bool. diff --git a/tests/semantic/basics8.cl b/tests/semantic/basics8.cl new file mode 100644 index 00000000..3b9697d4 --- /dev/null +++ b/tests/semantic/basics8.cl @@ -0,0 +1,9 @@ +-- It is an error redefine Object. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class Object { + xor(b: Bool): Bool { false }; +}; \ No newline at end of file diff --git a/tests/semantic/basics8_error.txt b/tests/semantic/basics8_error.txt new file mode 100644 index 00000000..652f47b3 --- /dev/null +++ b/tests/semantic/basics8_error.txt @@ -0,0 +1 @@ +(7, 7) - SemanticError: Redefinition of basic class Object. diff --git a/tests/semantic/blocks1.cl b/tests/semantic/blocks1.cl new file mode 100644 index 00000000..1e928908 --- /dev/null +++ b/tests/semantic/blocks1.cl @@ -0,0 +1,31 @@ +--The static type of a block is the static type of the last expression. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: B <- { + new A; + { + new B; + { + new C; + { + new D; + { + new E; + { + new F; + }; + }; + }; + }; + }; + }; +}; \ No newline at end of file diff --git a/tests/semantic/blocks1_error.txt b/tests/semantic/blocks1_error.txt new file mode 100644 index 00000000..2f0e2caf --- /dev/null +++ b/tests/semantic/blocks1_error.txt @@ -0,0 +1 @@ +(13, 16) - TypeError: Inferred type F of initialization of attribute test does not conform to declared type B. diff --git a/tests/semantic/case1.cl b/tests/semantic/case1.cl new file mode 100644 index 00000000..50fd5926 --- /dev/null +++ b/tests/semantic/case1.cl @@ -0,0 +1,23 @@ +--For each branch, let Ti be the static type of . The static type of a case expression is Join 1=i=n Ti. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- case "true" of + i: Int => New C; + b: Bool => New D; + s: String => New E; + esac; + + test: B <- case 0 of + b: Bool => new F; + i: Int => new E; + esac; +}; diff --git a/tests/semantic/case1_error.txt b/tests/semantic/case1_error.txt new file mode 100644 index 00000000..f05ce31b --- /dev/null +++ b/tests/semantic/case1_error.txt @@ -0,0 +1 @@ +(19, 16) - TypeError: Inferred type A of initialization of attribute test does not conform to declared type B. diff --git a/tests/semantic/case2.cl b/tests/semantic/case2.cl new file mode 100644 index 00000000..ae97b41d --- /dev/null +++ b/tests/semantic/case2.cl @@ -0,0 +1,23 @@ +-- The variables declared on each branch of a case must all have distinct types. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- case "true" of + i: Int => New C; + b: Bool => New D; + s: String => New E; + esac; + + test: A <- case 0 of + b: Bool => new F; + i: Bool => new E; + esac; +}; \ No newline at end of file diff --git a/tests/semantic/case2_error.txt b/tests/semantic/case2_error.txt new file mode 100644 index 00000000..302fec38 --- /dev/null +++ b/tests/semantic/case2_error.txt @@ -0,0 +1 @@ +(21, 20) - SemanticError: Duplicate branch Bool in case statement. \ No newline at end of file diff --git a/tests/semantic/case3.cl b/tests/semantic/case3.cl new file mode 100644 index 00000000..da79bbfe --- /dev/null +++ b/tests/semantic/case3.cl @@ -0,0 +1,23 @@ +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- case "true" of + i: Int => New C; + b: Bool => New D; + s: String => New E; + esac; + + test: A <- case 0 of + b: Bool => new F; + i: Ball => new E; + esac; +}; \ No newline at end of file diff --git a/tests/semantic/case3_error.txt b/tests/semantic/case3_error.txt new file mode 100644 index 00000000..fea261e5 --- /dev/null +++ b/tests/semantic/case3_error.txt @@ -0,0 +1 @@ +(21, 20) - TypeError: Class Ball of case branch is undefined. \ No newline at end of file diff --git a/tests/semantic/class1.cl b/tests/semantic/class1.cl new file mode 100644 index 00000000..ed83da9d --- /dev/null +++ b/tests/semantic/class1.cl @@ -0,0 +1,9 @@ +-- Classes may not be redefined. + +class Repeat { + sum(a: Int, b: Int): Int { a + b }; +}; + +class Repeat { + mult(a: Int, b: Int): Int { a * b }; +}; \ No newline at end of file diff --git a/tests/semantic/class1_error.txt b/tests/semantic/class1_error.txt new file mode 100644 index 00000000..86fb261e --- /dev/null +++ b/tests/semantic/class1_error.txt @@ -0,0 +1,2 @@ +(7, 7) - SemanticError: Classes may not be redefined + diff --git a/tests/semantic/conditionals1.cl b/tests/semantic/conditionals1.cl new file mode 100644 index 00000000..3446a8b0 --- /dev/null +++ b/tests/semantic/conditionals1.cl @@ -0,0 +1,14 @@ +--The predicate must have static type Bool. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + a: A <- if new F then new D else new C fi; +}; \ No newline at end of file diff --git a/tests/semantic/conditionals1_error.txt b/tests/semantic/conditionals1_error.txt new file mode 100644 index 00000000..b8634535 --- /dev/null +++ b/tests/semantic/conditionals1_error.txt @@ -0,0 +1 @@ +(13, 16) - TypeError: Predicate of 'if' does not have type Bool. diff --git a/tests/semantic/conditionals2.cl b/tests/semantic/conditionals2.cl new file mode 100644 index 00000000..9d6313d7 --- /dev/null +++ b/tests/semantic/conditionals2.cl @@ -0,0 +1,24 @@ +(* +Let T and F be the static types of the branches of the conditional. Then the static type of the +conditional is T t F. (think: Walk towards Object from each of T and F until the paths meet.) +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- if true then + new C + else + if false then new D + else new E fi + fi; + + test: B <- if not true then new F else new E fi; +}; diff --git a/tests/semantic/conditionals2_error.txt b/tests/semantic/conditionals2_error.txt new file mode 100644 index 00000000..d6f5fc30 --- /dev/null +++ b/tests/semantic/conditionals2_error.txt @@ -0,0 +1,2 @@ +(23, 16) - TypeError: Inferred type A of initialization of attribute test does not conform to declared type B. + diff --git a/tests/semantic/dispatch1.cl b/tests/semantic/dispatch1.cl new file mode 100644 index 00000000..1c0457fa --- /dev/null +++ b/tests/semantic/dispatch1.cl @@ -0,0 +1,33 @@ +(* +e0 .f(e1, . . . , en ) +Assume e0 has static type A. +Class A must have a method f +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + + back(s: String): B { { + out_string(s); + self; + } }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: B <- new D.back("Hello ").back("World!"); +}; \ No newline at end of file diff --git a/tests/semantic/dispatch1_error.txt b/tests/semantic/dispatch1_error.txt new file mode 100644 index 00000000..7fb22edc --- /dev/null +++ b/tests/semantic/dispatch1_error.txt @@ -0,0 +1 @@ +(32, 37) - AttributeError: Dispatch to undefined method back. diff --git a/tests/semantic/dispatch2.cl b/tests/semantic/dispatch2.cl new file mode 100644 index 00000000..5182912b --- /dev/null +++ b/tests/semantic/dispatch2.cl @@ -0,0 +1,34 @@ +(* +e0 .f(e1, . . . , en ) +Assume e0 has static type A. +Class A must have a method f +the dispatch and the definition of f must have the same number of arguments +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + + back(s: String): B { { + out_string(s); + self; + } }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: Int <- new D.back("Hello ").g(2, 2); +}; \ No newline at end of file diff --git a/tests/semantic/dispatch2_error.txt b/tests/semantic/dispatch2_error.txt new file mode 100644 index 00000000..a86c3534 --- /dev/null +++ b/tests/semantic/dispatch2_error.txt @@ -0,0 +1 @@ +(33, 39) - SemanticError: Method g called with wrong number of arguments. diff --git a/tests/semantic/dispatch3.cl b/tests/semantic/dispatch3.cl new file mode 100644 index 00000000..ecb1535d --- /dev/null +++ b/tests/semantic/dispatch3.cl @@ -0,0 +1,36 @@ +(* +e0 .f(e1, . . . , en ) +Assume e0 has static type A. +Class A must have a method f +the static type of the ith actual parameter must conform to the declared type of the ith formal parameter. +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + + back(s: String): B { { + out_string(s); + self; + } }; + + alphabet(a: A, b: B, c: C): D { self }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: B <- new D.alphabet(new D, new D, new D.back("Hello ")).back("World!"); +}; \ No newline at end of file diff --git a/tests/semantic/dispatch3_error.txt b/tests/semantic/dispatch3_error.txt new file mode 100644 index 00000000..0def5cf0 --- /dev/null +++ b/tests/semantic/dispatch3_error.txt @@ -0,0 +1 @@ +(35, 45) - TypeError: In call of method alphabet, type B of parameter c does not conform to declared type C. diff --git a/tests/semantic/dispatch4.cl b/tests/semantic/dispatch4.cl new file mode 100644 index 00000000..9cadd833 --- /dev/null +++ b/tests/semantic/dispatch4.cl @@ -0,0 +1,36 @@ +(* +e0 .f(e1, . . . , en ) +Assume e0 has static type A. +Class A must have a method f +If f has return type B and B is a class name, then the static type of the dispatch is B. +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + + back(s: String): B { { + out_string(s); + self; + } }; + + alphabet(a: A, b: B, c: C): D { self }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: D <- new D.alphabet(new D, new D.back("Hello "), new C).back("World!"); +}; \ No newline at end of file diff --git a/tests/semantic/dispatch4_error.txt b/tests/semantic/dispatch4_error.txt new file mode 100644 index 00000000..9699f166 --- /dev/null +++ b/tests/semantic/dispatch4_error.txt @@ -0,0 +1 @@ +(35, 16) - TypeError: Inferred type B of initialization of attribute test does not conform to declared type D. \ No newline at end of file diff --git a/tests/semantic/dispatch5.cl b/tests/semantic/dispatch5.cl new file mode 100644 index 00000000..b4437b1b --- /dev/null +++ b/tests/semantic/dispatch5.cl @@ -0,0 +1,31 @@ +(* +(,...,) is shorthand for self.(,...,). +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; + sum(m: Int, n: Int, p: Int): Int { m + n + p }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + + back(s: String): B { { + out_string(s); + g(2); + sum(1, 2, 3); + self; + } }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/tests/semantic/dispatch5_error.txt b/tests/semantic/dispatch5_error.txt new file mode 100644 index 00000000..d26bf34a --- /dev/null +++ b/tests/semantic/dispatch5_error.txt @@ -0,0 +1 @@ +(24, 9) - AttributeError: Dispatch to undefined method sum. diff --git a/tests/semantic/dispatch6.cl b/tests/semantic/dispatch6.cl new file mode 100644 index 00000000..dfb771fd --- /dev/null +++ b/tests/semantic/dispatch6.cl @@ -0,0 +1,32 @@ +(* +e@B.f() invokes the method +f in class B on the object that is the value of e. For this form of dispatch, the static type to the left of +@must conform to the type specified to the right of @. +*) + +class A { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; + sum(m: Int, n: Int, p: Int): Int { m + n + p }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + sum(v: Int, w: Int, z: Int): Int { v - w - z }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + a: A <- new D; + b: Int <- new D@B.sum(1, 2, 3); + test: Int <- a@B.sum(1, 2, 3); +}; diff --git a/tests/semantic/dispatch6_error.txt b/tests/semantic/dispatch6_error.txt new file mode 100644 index 00000000..ae9184b2 --- /dev/null +++ b/tests/semantic/dispatch6_error.txt @@ -0,0 +1 @@ +(31, 18) - TypeError: Expression type A does not conform to declared static dispatch type B. diff --git a/tests/semantic/eq1.cl b/tests/semantic/eq1.cl new file mode 100644 index 00000000..88f2a7ff --- /dev/null +++ b/tests/semantic/eq1.cl @@ -0,0 +1,17 @@ +(* +The comparison = is a special +case. If either or has static type Int, Bool, or String, then the other must have the +same static type. Any other types, including SELF TYPE, may be freely compared. +*) + +class A { }; +class B inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + x: Bool <- 1 = 2; + test: Bool <- 1 = new A; + y: Bool <- "1" = "2"; + z: Bool <- true = not false; +}; \ No newline at end of file diff --git a/tests/semantic/eq1_error.txt b/tests/semantic/eq1_error.txt new file mode 100644 index 00000000..f8142568 --- /dev/null +++ b/tests/semantic/eq1_error.txt @@ -0,0 +1 @@ +(14, 21) - TypeError: Illegal comparison with a basic type. diff --git a/tests/semantic/eq2.cl b/tests/semantic/eq2.cl new file mode 100644 index 00000000..d7685278 --- /dev/null +++ b/tests/semantic/eq2.cl @@ -0,0 +1,17 @@ +(* +The comparison = is a special +case. If either or has static type Int, Bool, or String, then the other must have the +same static type. Any other types, including SELF TYPE, may be freely compared. +*) + +class A { }; +class B inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + x: Bool <- 1 = 2; + y: Bool <- "1" = "2"; + test: Bool <- "1" = new B; + z: Bool <- true = not false; +}; diff --git a/tests/semantic/eq2_error.txt b/tests/semantic/eq2_error.txt new file mode 100644 index 00000000..a44ab0d5 --- /dev/null +++ b/tests/semantic/eq2_error.txt @@ -0,0 +1 @@ +(15, 23) - TypeError: Illegal comparison with a basic type. diff --git a/tests/semantic/eq3.cl b/tests/semantic/eq3.cl new file mode 100644 index 00000000..4dad693e --- /dev/null +++ b/tests/semantic/eq3.cl @@ -0,0 +1,17 @@ +(* +The comparison = is a special +case. If either or has static type Int, Bool, or String, then the other must have the +same static type. Any other types, including SELF TYPE, may be freely compared. +*) + +class A { }; +class B inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + x: Bool <- 1 = 2; + y: Bool <- "1" = "2"; + z: Bool <- true = not false; + test: Bool <- "true" = not false; +}; diff --git a/tests/semantic/eq3_error.txt b/tests/semantic/eq3_error.txt new file mode 100644 index 00000000..c4e27eb8 --- /dev/null +++ b/tests/semantic/eq3_error.txt @@ -0,0 +1 @@ +(16, 26) - TypeError: Illegal comparison with a basic type. diff --git a/tests/semantic/eq4.cl b/tests/semantic/eq4.cl new file mode 100644 index 00000000..11afc119 --- /dev/null +++ b/tests/semantic/eq4.cl @@ -0,0 +1,17 @@ +(* +The comparison = is a special +case. If either or has static type Int, Bool, or String, then the other must have the +same static type. Any other types, including SELF TYPE, may be freely compared. The result is a Bool. +*) + +class A { }; +class B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + x: Bool <- 1 = 2; + y: Bool <- "1" = "2"; + z: Bool <- new A = new B; + test: Int <- new A = new B; +}; diff --git a/tests/semantic/eq4_error.txt b/tests/semantic/eq4_error.txt new file mode 100644 index 00000000..3ead21d0 --- /dev/null +++ b/tests/semantic/eq4_error.txt @@ -0,0 +1 @@ +(16, 18) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type Int. diff --git a/tests/semantic/features1.cl b/tests/semantic/features1.cl new file mode 100644 index 00000000..66f650f4 --- /dev/null +++ b/tests/semantic/features1.cl @@ -0,0 +1,19 @@ +(* +No method name may be defined multiple times in +a class, and no attribute name may be defined multiple times in a class, but a method and an attribute +may have the same name. +*) + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A { + x: Int <- 3; + + x(): Int { 3 }; + + x: String <- ":)"; +}; \ No newline at end of file diff --git a/tests/semantic/features1_error.txt b/tests/semantic/features1_error.txt new file mode 100644 index 00000000..40033e9b --- /dev/null +++ b/tests/semantic/features1_error.txt @@ -0,0 +1 @@ +(18, 5) - SemanticError: Attribute x is multiply defined in class. \ No newline at end of file diff --git a/tests/semantic/features2.cl b/tests/semantic/features2.cl new file mode 100644 index 00000000..5b1f7e9d --- /dev/null +++ b/tests/semantic/features2.cl @@ -0,0 +1,19 @@ +(* +No method name may be defined multiple times in +a class, and no attribute name may be defined multiple times in a class, but a method and an attribute +may have the same name. +*) + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A { + x: Int <- 3; + + x(): String { "3" }; + + x(): String { ":)" }; +}; \ No newline at end of file diff --git a/tests/semantic/features2_error.txt b/tests/semantic/features2_error.txt new file mode 100644 index 00000000..117e0604 --- /dev/null +++ b/tests/semantic/features2_error.txt @@ -0,0 +1 @@ +(18, 5) - SemanticError: Method x is multiply defined. \ No newline at end of file diff --git a/tests/semantic/features3.cl b/tests/semantic/features3.cl new file mode 100644 index 00000000..a892d011 --- /dev/null +++ b/tests/semantic/features3.cl @@ -0,0 +1,15 @@ +-- Missing type + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A { + x: Int <- 3; + + x(): Int { 3 }; + + c: Cadena; +}; \ No newline at end of file diff --git a/tests/semantic/features3_error.txt b/tests/semantic/features3_error.txt new file mode 100644 index 00000000..53f1abe2 --- /dev/null +++ b/tests/semantic/features3_error.txt @@ -0,0 +1 @@ +(14, 8) - TypeError: Class Cadena of attribute c is undefined. \ No newline at end of file diff --git a/tests/semantic/inheritance1.cl b/tests/semantic/inheritance1.cl new file mode 100644 index 00000000..1d92da30 --- /dev/null +++ b/tests/semantic/inheritance1.cl @@ -0,0 +1,19 @@ +--It is illegal to redefine attribute names. + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A { + x: Int <- 3; + + x(): String { ":)" }; +}; + +class B inherits A { + x: Int; + + div(a: Int, b: Int): Int { a / b}; +}; \ No newline at end of file diff --git a/tests/semantic/inheritance1_error.txt b/tests/semantic/inheritance1_error.txt new file mode 100644 index 00000000..ec5b504e --- /dev/null +++ b/tests/semantic/inheritance1_error.txt @@ -0,0 +1 @@ +(16, 5) - SemanticError: Attribute x is an attribute of an inherited class. \ No newline at end of file diff --git a/tests/semantic/inheritance2.cl b/tests/semantic/inheritance2.cl new file mode 100644 index 00000000..d453eca0 --- /dev/null +++ b/tests/semantic/inheritance2.cl @@ -0,0 +1,19 @@ +--If C inherits from P, then P must have a class definition somewhere in the program. + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class Alo { + x: Int <- 3; + + x(): String { "3" }; +}; + +class B inherits A { + div(a: Int, b: Int): Int { a / b}; + + x: String <- "2"; +}; \ No newline at end of file diff --git a/tests/semantic/inheritance2_error.txt b/tests/semantic/inheritance2_error.txt new file mode 100644 index 00000000..1ec7669b --- /dev/null +++ b/tests/semantic/inheritance2_error.txt @@ -0,0 +1 @@ +(15, 18) - TypeError: Class B inherits from an undefined class A. \ No newline at end of file diff --git a/tests/semantic/inheritance3.cl b/tests/semantic/inheritance3.cl new file mode 100644 index 00000000..3ff170de --- /dev/null +++ b/tests/semantic/inheritance3.cl @@ -0,0 +1,13 @@ +--The parent-child relation on classes defines a graph. This graph may not contain cycles. + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A inherits A { + x: Int <- 3; + + x(): String { ":)" }; +}; \ No newline at end of file diff --git a/tests/semantic/inheritance3_error.txt b/tests/semantic/inheritance3_error.txt new file mode 100644 index 00000000..d17ca7f4 --- /dev/null +++ b/tests/semantic/inheritance3_error.txt @@ -0,0 +1 @@ +(9, 18) - SemanticError: Class A, or an ancestor of A, is involved in an inheritance cycle. \ No newline at end of file diff --git a/tests/semantic/inheritance4.cl b/tests/semantic/inheritance4.cl new file mode 100644 index 00000000..c985484b --- /dev/null +++ b/tests/semantic/inheritance4.cl @@ -0,0 +1,19 @@ +--The parent-child relation on classes defines a graph. This graph may not contain cycles. + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A inherits B { + x: Int <- 3; + + x(): String { ":)" }; +}; + +class B inherits A { + y: Int <- 2; + + div(a: Int, b: Int): Int { a / b}; +}; \ No newline at end of file diff --git a/tests/semantic/inheritance4_error.txt b/tests/semantic/inheritance4_error.txt new file mode 100644 index 00000000..b437ec66 --- /dev/null +++ b/tests/semantic/inheritance4_error.txt @@ -0,0 +1 @@ +(15, 18) - SemanticError: Class B, or an ancestor of B, is involved in an inheritance cycle. \ No newline at end of file diff --git a/tests/semantic/inheritance5.cl b/tests/semantic/inheritance5.cl new file mode 100644 index 00000000..f6ed885c --- /dev/null +++ b/tests/semantic/inheritance5.cl @@ -0,0 +1,21 @@ +--The parent-child relation on classes defines a graph. This graph may not contain cycles. + +class Main inherits IO { + main(): IO { out_string("hi!") }; + + main: IO <- out_string("bye!"); +}; + +class A inherits B { + x: Int <- 3; + + x(): String { ":)" }; +}; + +class B inherits C { + y: Int <- 2; + + div(a: Int, b: Int): Int { a / b}; +}; + +class C inherits A { }; \ No newline at end of file diff --git a/tests/semantic/inheritance5_error.txt b/tests/semantic/inheritance5_error.txt new file mode 100644 index 00000000..da72ba54 --- /dev/null +++ b/tests/semantic/inheritance5_error.txt @@ -0,0 +1 @@ +(21, 18) - SemanticError: Class C, or an ancestor of C, is involved in an inheritance cycle. \ No newline at end of file diff --git a/tests/semantic/isvoid1.cl b/tests/semantic/isvoid1.cl new file mode 100644 index 00000000..072720d8 --- /dev/null +++ b/tests/semantic/isvoid1.cl @@ -0,0 +1,26 @@ +--evaluates to true if expr is void and evaluates to false if expr is not void. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- if isvoid new F then + new C + else + if false then new D + else new E fi + fi; + + test: B <- isvoid if isvoid new F then + new C + else + if false then new D + else new E fi + fi; +}; \ No newline at end of file diff --git a/tests/semantic/isvoid1_error.txt b/tests/semantic/isvoid1_error.txt new file mode 100644 index 00000000..0922de90 --- /dev/null +++ b/tests/semantic/isvoid1_error.txt @@ -0,0 +1 @@ +(20, 16) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type B. diff --git a/tests/semantic/let1.cl b/tests/semantic/let1.cl new file mode 100644 index 00000000..26ef6302 --- /dev/null +++ b/tests/semantic/let1.cl @@ -0,0 +1,15 @@ +--The type of an initialization expression must conform to the declared type of the identifier. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: B <- new E in b; + test: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: C <- new E in b; +}; \ No newline at end of file diff --git a/tests/semantic/let1_error.txt b/tests/semantic/let1_error.txt new file mode 100644 index 00000000..16ecf780 --- /dev/null +++ b/tests/semantic/let1_error.txt @@ -0,0 +1 @@ +(14, 76) - TypeError: Inferred type E of initialization of b does not conform to identifier's declared type C. diff --git a/tests/semantic/let2.cl b/tests/semantic/let2.cl new file mode 100644 index 00000000..c5956ead --- /dev/null +++ b/tests/semantic/let2.cl @@ -0,0 +1,15 @@ +--The type of let is the type of the body. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: B <- new E in b; + test: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: A <- new E in b; +}; \ No newline at end of file diff --git a/tests/semantic/let2_error.txt b/tests/semantic/let2_error.txt new file mode 100644 index 00000000..b1e8a365 --- /dev/null +++ b/tests/semantic/let2_error.txt @@ -0,0 +1 @@ +(14, 16) - TypeError: Inferred type A of initialization of attribute test does not conform to declared type B. diff --git a/tests/semantic/let3.cl b/tests/semantic/let3.cl new file mode 100644 index 00000000..8c0670ab --- /dev/null +++ b/tests/semantic/let3.cl @@ -0,0 +1,15 @@ +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: B <- new E in b; + test: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: Cadena in new B; +}; \ No newline at end of file diff --git a/tests/semantic/let3_error.txt b/tests/semantic/let3_error.txt new file mode 100644 index 00000000..39c5315d --- /dev/null +++ b/tests/semantic/let3_error.txt @@ -0,0 +1 @@ +(14, 71) - TypeError: Class Cadena of let-bound identifier b is undefined. \ No newline at end of file diff --git a/tests/semantic/loops1.cl b/tests/semantic/loops1.cl new file mode 100644 index 00000000..de3a624d --- /dev/null +++ b/tests/semantic/loops1.cl @@ -0,0 +1,8 @@ +--The predicate must have static type Bool. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + i: Int <- 1; + test: Object <- while "true" loop i <- i + 1 pool; +}; \ No newline at end of file diff --git a/tests/semantic/loops1_error.txt b/tests/semantic/loops1_error.txt new file mode 100644 index 00000000..b160214b --- /dev/null +++ b/tests/semantic/loops1_error.txt @@ -0,0 +1 @@ +(7, 27) - TypeError: Loop condition does not have type Bool. \ No newline at end of file diff --git a/tests/semantic/loops2.cl b/tests/semantic/loops2.cl new file mode 100644 index 00000000..dea69fa1 --- /dev/null +++ b/tests/semantic/loops2.cl @@ -0,0 +1,9 @@ +--The static type of a loop expression is Object. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + i: Int <- 1; + test: Object <- while not false loop i <- i + 1 pool; + test2: Int <- while not false loop i <- i + 1 pool; +}; diff --git a/tests/semantic/loops2_error.txt b/tests/semantic/loops2_error.txt new file mode 100644 index 00000000..9711cdf6 --- /dev/null +++ b/tests/semantic/loops2_error.txt @@ -0,0 +1 @@ +(8, 19) - TypeError: Inferred type Object of initialization of attribute test2 does not conform to declared type Int. diff --git a/tests/semantic/methods1.cl b/tests/semantic/methods1.cl new file mode 100644 index 00000000..d1203197 --- /dev/null +++ b/tests/semantic/methods1.cl @@ -0,0 +1,12 @@ +--The identifiers used in the formal parameter list must be distinct + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A, a: B): Int { 4 }; +}; \ No newline at end of file diff --git a/tests/semantic/methods1_error.txt b/tests/semantic/methods1_error.txt new file mode 100644 index 00000000..06ab88a9 --- /dev/null +++ b/tests/semantic/methods1_error.txt @@ -0,0 +1 @@ +(11, 16) - SemanticError: Formal parameter a is multiply defined. diff --git a/tests/semantic/methods2.cl b/tests/semantic/methods2.cl new file mode 100644 index 00000000..3865f0e1 --- /dev/null +++ b/tests/semantic/methods2.cl @@ -0,0 +1,12 @@ +--The type of the method body must conform to the declared return type. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A, b: B): C { new D }; +}; \ No newline at end of file diff --git a/tests/semantic/methods2_error.txt b/tests/semantic/methods2_error.txt new file mode 100644 index 00000000..f7e4a330 --- /dev/null +++ b/tests/semantic/methods2_error.txt @@ -0,0 +1 @@ +(11, 27) - TypeError: Inferred return type D of method test does not conform to declared return type C. diff --git a/tests/semantic/methods3.cl b/tests/semantic/methods3.cl new file mode 100644 index 00000000..b92faeb9 --- /dev/null +++ b/tests/semantic/methods3.cl @@ -0,0 +1,14 @@ +--A formal parameter hides any definition of an attribute of the same name. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + a: C <- new C; + test(a: D): D { a }; + test2(a: B): C { a }; +}; \ No newline at end of file diff --git a/tests/semantic/methods3_error.txt b/tests/semantic/methods3_error.txt new file mode 100644 index 00000000..1165b759 --- /dev/null +++ b/tests/semantic/methods3_error.txt @@ -0,0 +1 @@ +(13, 22) - TypeError: Inferred return type B of method test2 does not conform to declared return type C. diff --git a/tests/semantic/methods4.cl b/tests/semantic/methods4.cl new file mode 100644 index 00000000..be8fa36e --- /dev/null +++ b/tests/semantic/methods4.cl @@ -0,0 +1,19 @@ +(* +The rule is +simple: If a class C inherits a method f from an ancestor class P, then C may override the inherited +definition of f provided the number of arguments, the types of the formal parameters, and the return +type are exactly the same in both definitions. +*) + +class A { + f(x: Int, y: Int): Int { x + y }; +}; +class B inherits A { + f(x: Int, y: Object): Int { x }; +}; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/tests/semantic/methods4_error.txt b/tests/semantic/methods4_error.txt new file mode 100644 index 00000000..9f1486de --- /dev/null +++ b/tests/semantic/methods4_error.txt @@ -0,0 +1 @@ +(12, 15) - SemanticError: In redefined method f, parameter type Object is different from original type Int. diff --git a/tests/semantic/methods5.cl b/tests/semantic/methods5.cl new file mode 100644 index 00000000..3905dfdd --- /dev/null +++ b/tests/semantic/methods5.cl @@ -0,0 +1,20 @@ +(* +The rule is +simple: If a class C inherits a method f from an ancestor class P, then C may override the inherited +definition of f provided the number of arguments, the types of the formal parameters, and the return +type are exactly the same in both definitions. +*) + +class A { + f(x: Int, y: Int): Int { x + y }; +}; +class B inherits A { + f(a: Int, b: Int): Object { a - b }; +}; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + diff --git a/tests/semantic/methods5_error.txt b/tests/semantic/methods5_error.txt new file mode 100644 index 00000000..8b6bdf36 --- /dev/null +++ b/tests/semantic/methods5_error.txt @@ -0,0 +1 @@ +(12, 24) - SemanticError: In redefined method f, return type Object is different from original return type Int. diff --git a/tests/semantic/methods6.cl b/tests/semantic/methods6.cl new file mode 100644 index 00000000..dd2b73da --- /dev/null +++ b/tests/semantic/methods6.cl @@ -0,0 +1,27 @@ +(* +The rule is +simple: If a class C inherits a method f from an ancestor class P, then C may override the inherited +definition of f provided the number of arguments, the types of the formal parameters, and the return +type are exactly the same in both definitions. +*) + +class A { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int, w: Int, z: Int): Int { v + w + z }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/tests/semantic/methods6_error.txt b/tests/semantic/methods6_error.txt new file mode 100644 index 00000000..8e32663b --- /dev/null +++ b/tests/semantic/methods6_error.txt @@ -0,0 +1 @@ +(22, 5) - SemanticError: Incompatible number of formal parameters in redefined method g. diff --git a/tests/semantic/methods7.cl b/tests/semantic/methods7.cl new file mode 100644 index 00000000..e5a01f68 --- /dev/null +++ b/tests/semantic/methods7.cl @@ -0,0 +1,12 @@ +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A, b: Ball): Int { 4 }; +}; \ No newline at end of file diff --git a/tests/semantic/methods7_error.txt b/tests/semantic/methods7_error.txt new file mode 100644 index 00000000..472cbd9d --- /dev/null +++ b/tests/semantic/methods7_error.txt @@ -0,0 +1 @@ +(11, 19) - TypeError: Class Ball of formal parameter b is undefined. \ No newline at end of file diff --git a/tests/semantic/methods8.cl b/tests/semantic/methods8.cl new file mode 100644 index 00000000..3fccab54 --- /dev/null +++ b/tests/semantic/methods8.cl @@ -0,0 +1,12 @@ +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A, b: B): Integrer { 4 }; +}; \ No newline at end of file diff --git a/tests/semantic/methods8_error.txt b/tests/semantic/methods8_error.txt new file mode 100644 index 00000000..dc9302ec --- /dev/null +++ b/tests/semantic/methods8_error.txt @@ -0,0 +1 @@ +(11, 23) - TypeError: Undefined return type Integrer in method test. \ No newline at end of file diff --git a/tests/semantic/new1.cl b/tests/semantic/new1.cl new file mode 100644 index 00000000..d007fc03 --- /dev/null +++ b/tests/semantic/new1.cl @@ -0,0 +1,31 @@ +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: F <- { + new A; + { + new Ball; + { + new C; + { + new D; + { + new E; + { + new F; + }; + }; + }; + }; + }; + }; +}; \ No newline at end of file diff --git a/tests/semantic/new1_error.txt b/tests/semantic/new1_error.txt new file mode 100644 index 00000000..612a3d42 --- /dev/null +++ b/tests/semantic/new1_error.txt @@ -0,0 +1 @@ +(16, 17) - TypeError: 'new' used with undefined class Ball. \ No newline at end of file diff --git a/tests/semantic/self1.cl b/tests/semantic/self1.cl new file mode 100644 index 00000000..3387fd26 --- /dev/null +++ b/tests/semantic/self1.cl @@ -0,0 +1,11 @@ +(* +But it is an error to assign to self or to bind self in a let, a +case, or as a formal parameter. It is also illegal to have attributes named self. +*) + + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: Main): IO { self <- a }; +}; diff --git a/tests/semantic/self1_error.txt b/tests/semantic/self1_error.txt new file mode 100644 index 00000000..6beb3cda --- /dev/null +++ b/tests/semantic/self1_error.txt @@ -0,0 +1 @@ +(10, 30) - SemanticError: Cannot assign to 'self'. diff --git a/tests/semantic/self2.cl b/tests/semantic/self2.cl new file mode 100644 index 00000000..2e6921a9 --- /dev/null +++ b/tests/semantic/self2.cl @@ -0,0 +1,10 @@ +(* +But it is an error to assign to self or to bind self in a let, a +case, or as a formal parameter. It is also illegal to have attributes named self. +*) + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(): IO { let self: Main <- new Main in self }; +}; diff --git a/tests/semantic/self2_error.txt b/tests/semantic/self2_error.txt new file mode 100644 index 00000000..20c883c9 --- /dev/null +++ b/tests/semantic/self2_error.txt @@ -0,0 +1 @@ +(9, 22) - SemanticError: 'self' cannot be bound in a 'let' expression. diff --git a/tests/semantic/self3.cl b/tests/semantic/self3.cl new file mode 100644 index 00000000..81709b4b --- /dev/null +++ b/tests/semantic/self3.cl @@ -0,0 +1,10 @@ +(* +But it is an error to assign to self or to bind self in a let, a +case, or as a formal parameter. It is also illegal to have attributes named self. +*) + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(self: IO): IO { self }; +}; diff --git a/tests/semantic/self3_error.txt b/tests/semantic/self3_error.txt new file mode 100644 index 00000000..0ae38200 --- /dev/null +++ b/tests/semantic/self3_error.txt @@ -0,0 +1 @@ +(9, 10) - SemanticError: 'self' cannot be the name of a formal parameter. diff --git a/tests/semantic/self4.cl b/tests/semantic/self4.cl new file mode 100644 index 00000000..526ad6be --- /dev/null +++ b/tests/semantic/self4.cl @@ -0,0 +1,10 @@ +(* +But it is an error to assign to self or to bind self in a let, a +case, or as a formal parameter. It is also illegal to have attributes named self. +*) + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + self: IO <- self; +}; \ No newline at end of file diff --git a/tests/semantic/self4_error.txt b/tests/semantic/self4_error.txt new file mode 100644 index 00000000..c19ca400 --- /dev/null +++ b/tests/semantic/self4_error.txt @@ -0,0 +1 @@ +(9, 5) - SemanticError: 'self' cannot be the name of an attribute. From 3d7257785abf2065cdc061a657a0ae764b4ad0e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Wed, 18 Nov 2020 09:18:25 -0500 Subject: [PATCH 19/77] Se creo un metodo que impide la ejecucion de la generarcion de codigo si fallo el analisis semantico --- src/COOLCompiler.py | 6 ++--- src/Visitors.py | 53 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 85bf37a8..d4c37048 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -45,9 +45,9 @@ def main(argv): semanticAnalizer = SemanticCOOLVisitor(typeTree) codegenerator = CodegenVisitor(typeTree, consTble, visitor.Counter) semanticAnalizer.visitProgram(tree) - - # outFilename = os.path.splitext(argv[1])[0] + ".s" - # codegenerator.visitProgram(tree, outFilename) + if semanticAnalizer.hasNoError: + outFilename = os.path.splitext(argv[1])[0] + ".s" + codegenerator.visitProgram(tree, outFilename) none = typeTree["Object"] diff --git a/src/Visitors.py b/src/Visitors.py index 49ec5f34..2358ece1 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -125,6 +125,7 @@ def __init__(self, typeTable: dict): self.TypeTable = typeTable self.ScopeManager = COOLScopeManager() self.actualClass = "Object" + self.hasNoError = True # Visit a parse tree produced by COOL#program. def visitProgram(self, ctx:COOL.ProgramContext): @@ -147,6 +148,7 @@ def visitClassDefine(self, ctx:COOL.ClassDefineContext): else: error = f"({line}, {column}) - SemanticError: Classes may not be redefined" print(error) + self.hasNoError = False elif ctx.getChild(2).symbol.text == "inherits": classParent = ctx.getChild(3).symbol if (self.TypeTable.keys().__contains__(classParent.text)): @@ -155,11 +157,13 @@ def visitClassDefine(self, ctx:COOL.ClassDefineContext): column = str(classParent.column + 1) error = f"({line}, {column}) - SemanticError: Class {coolClass.text} cannot inherit class {classParent.text}" print(error) + self.hasNoError = False elif not (self.TypeTable[coolClass.text].Deep > self.TypeTable[classParent.text].Deep): line = str(classParent.line) column = str(classParent.column + 1) error = f"({line}, {column}) - SemanticError: Class {coolClass.text}, or an ancestor of {coolClass.text}, is involved in an inheritance cycle." print(error) + self.hasNoError = False else: self.TypeTable[coolClass.text].Created = True self.TypeTable[coolClass.text].Sealed = False @@ -174,6 +178,7 @@ def visitClassDefine(self, ctx:COOL.ClassDefineContext): column = str(classParent.column + 1) error = f"({line}, {column}) - TypeError: Class {coolClass.text} inherits from an undefined class {classParent.text}." print(error) + self.hasNoError = False else: self.TypeTable[coolClass.text].Created = True self.TypeTable[coolClass.text].Sealed = False @@ -194,6 +199,7 @@ def visitMethod(self, ctx:COOL.MethodContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Method {methodName} is multiply defined." print(error) + self.hasNoError = False return if self.searchMethod(self.TypeTable[coolClass].Parent, methodName): ancestorMethod = self.searchMethodInfo(self.TypeTable[coolClass].Parent,methodName) @@ -202,12 +208,14 @@ def visitMethod(self, ctx:COOL.MethodContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) SemanticError: Incompatible number of formal parameters in redefined method {methodName}." print(error) + self.hasNoError = False return if ancestorMethod.Type != methodType.text: line = str(methodType.line) column = str(methodType.column + 1) error = f"({line}, {column}) SemanticError: In redefined method {methodName}, return type {methodType.text} is different from original return type {ancestorMethod.Type}." print(error) + self.hasNoError = False return if self.TypeTable.keys().__contains__(self.TypeTable[coolClass].Methods[methodName].Type) or methodType.text == "SELF_TYPE": self.ScopeManager.addIdentifier(methodName, methodType.text) @@ -223,6 +231,7 @@ def visitMethod(self, ctx:COOL.MethodContext): column = str(ctx.getChild(len(ctx.children) - 2).start.column + 1) error = f"({line}, {column}) - TypeError: Inferred return type {methodValue} of method {methodName} does not conform to declared return type {methodType.text}." print(error) + self.hasNoError = False self.ScopeManager.deleteScope() return else: @@ -230,6 +239,7 @@ def visitMethod(self, ctx:COOL.MethodContext): column = str(methodType.column + 1) error = f"({line}, {column}) - TypeError: Undefined return type {methodType.text} in method {methodName}." print(error) + self.hasNoError = False # Visit a parse tree produced by COOL#property. def visitProperty(self, ctx:COOL.PropertyContext): @@ -241,24 +251,28 @@ def visitProperty(self, ctx:COOL.PropertyContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Attribute {atributeName} is multiply defined in class." print(error) + self.hasNoError = False return "None" elif atributeName == "self": line = str(ctx.getChild(0).symbol.line) column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: 'self' cannot be the name of an atribute." print(error) + self.hasNoError = False return elif not(self.TypeTable.keys().__contains__(atributeType) or atributeType == "SELF_TYPE"): line = str(ctx.getChild(2).symbol.line) column = str(ctx.getChild(2).symbol.column + 1) error = f"({line}, {column}) - TypeError: Class {atributeType} of attribute {atributeName} is undefined." print(error) + self.hasNoError = False return "None" elif self.TypeTable[self.TypeTable[coolClass].Parent].Atributes.keys().__contains__(atributeName): line = str(ctx.getChild(0).symbol.line) column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Attribute {atributeName} is an attribute of an inherited class." print(error) + self.hasNoError = False return "None" elif len(ctx.children) == 5: atributeValue = ctx.getChild(4).accept(self) @@ -267,6 +281,7 @@ def visitProperty(self, ctx:COOL.PropertyContext): column = str(ctx.getChild(4).start.column + 1) error = f"({line}, {column}) - TypeError: Inferred type {atributeValue} of initialization of attribute {atributeName} does not conform to declared type {atributeType}." print(error) + self.hasNoError = False return "None" else: self.ScopeManager.addIdentifier(atributeName, atributeType) @@ -289,12 +304,14 @@ def visitFormal(self, ctx:COOL.FormalContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: 'self' cannot be the name of a formal parameter." print(error) + self.hasNoError = False return if self.ScopeManager.searchScope(paramName): line = str(ctx.getChild(0).symbol.line) column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Formal parameter {paramName} is multiply defined." print(error) + self.hasNoError = False return if self.searchMethod(self.TypeTable[coolClass].Parent, methodName): ancestorMethod = self.searchMethodInfo(self.TypeTable[coolClass].Parent,methodName) @@ -310,6 +327,7 @@ def visitFormal(self, ctx:COOL.FormalContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: In redefined method {methodName}, parameter type {paramType} is different from original type {acType}." print(error) + self.hasNoError = False return i += 1 if not exist: @@ -317,6 +335,7 @@ def visitFormal(self, ctx:COOL.FormalContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: In ancestor method {methodName}, dont exist param {paramName}." print(error) + self.hasNoError = False return if self.TypeTable.keys().__contains__(paramType): self.ScopeManager.addIdentifier(paramName, paramType) @@ -326,6 +345,7 @@ def visitFormal(self, ctx:COOL.FormalContext): column = str(ctx.getChild(2).symbol.column + 1) error = f"({line}, {column}) - TypeError: Class {paramType} of formal parameter {paramName} is undefined." print(error) + self.hasNoError = False # Visit a parse tree produced by COOL#int. def visitInt(self, ctx: COOL.IntContext): @@ -353,6 +373,7 @@ def visitAdd(self, ctx: COOL.AddContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} + {rightValue}" print(error) + self.hasNoError = False addValue = "None" return addValue @@ -366,6 +387,7 @@ def visitMinus(self, ctx:COOL.MinusContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} - {rightValue}" print(error) + self.hasNoError = False minusValue = "None" return minusValue @@ -379,6 +401,7 @@ def visitMultiply(self, ctx: COOL.MultiplyContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} * {rightValue}" print(error) + self.hasNoError = False mulValue = "None" return mulValue @@ -392,6 +415,7 @@ def visitDivision(self, ctx: COOL.DivisionContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} / {rightValue}" print(error) + self.hasNoError = False divValue = "None" return divValue @@ -402,9 +426,10 @@ def visitNegative(self, ctx: COOL.NegativeContext): return "Int" else: line = str(ctx.getChild(1).start.line) - column = str(ctx.getChild(1).start.column) + column = str(ctx.getChild(1).start.column + 1) error = f"({line}, {column}) - TypeError: Argument of '~' has type {expressValue} instead of Int." print(error) + self.hasNoError = False return "None" # Visit a parse tree produced by COOL#isvoid. @@ -422,6 +447,7 @@ def visitBoolNot(self, ctx: COOL.BoolNotContext): column = str(ctx.getChild(1).start.column + 1) error = f"({line}, {column}) - TypeError: Argument of 'not' has type {expressValue} instead of Bool." print(error) + self.hasNoError = False return "None" # Visit a parse tree produced by COOL#lessThan. @@ -434,6 +460,7 @@ def visitLessThan(self, ctx:COOL.LessThanContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} < {rightValue}" print(error) + self.hasNoError = False lessValue = "None" return lessValue @@ -447,6 +474,7 @@ def visitLessEqual(self, ctx:COOL.LessEqualContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} <= {rightValue}" print(error) + self.hasNoError = False lessEqualValue = "None" return lessEqualValue @@ -463,12 +491,14 @@ def visitEqual(self, ctx: COOL.EqualContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: Illegal comparison with a basic type." print(error) + self.hasNoError = False return "None" elif rightValue == "String" or rightValue == "Int" or rightValue == "Bool": line = str(ctx.getChild(1).symbol.line) column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: Illegal comparison with a basic type." print(error) + self.hasNoError = False return "None" else: return "Bool" @@ -486,6 +516,7 @@ def visitAssignment(self, ctx: COOL.AssignmentContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - NameError: Undeclared identifier {variableName}." print(error) + self.hasNoError = False return "None" if variableType == "SELF_TYPE": variableType = self.actualClass @@ -494,12 +525,14 @@ def visitAssignment(self, ctx: COOL.AssignmentContext): column = str(ctx.getChild(2).start.column + 1) error = f"({line}, {column}) - TypeError: Cannot assign {asignValue} expression to {variableType} identifier." print(error) + self.hasNoError = False return "None" if variableName == "self": line = str(ctx.getChild(1).symbol.line) column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Cannot assign to 'self'." print(error) + self.hasNoError = False return "None" return asignValue @@ -518,6 +551,7 @@ def visitId(self, ctx: COOL.IdContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - NameError: Undeclared identifier {IdValue}." print(error) + self.hasNoError = False return "None" # Visit a parse tree produced by COOL#if. @@ -532,6 +566,7 @@ def visitIf(self, ctx:COOL.IfContext): column = str(ctx.getChild(1).start.column + 1) error = f"({line}, {column}) - TypeError: Predicate of 'if' does not have type Bool." print(error) + self.hasNoError = False return self.join(thenValue, elseValue) # Visit a parse tree produced by COOL#while. @@ -545,6 +580,7 @@ def visitWhile(self, ctx: COOL.WhileContext): column = str(ctx.getChild(1).start.column + 1) error = f"({line}, {column}) - TypeError: Loop condition does not have type Bool." print(error) + self.hasNoError = False return "Object" # Visit a parse tree produced by COOL#block. @@ -573,11 +609,13 @@ def visitCase(self, ctx:COOL.CaseContext): column = str(ctx.getChild(count).symbol.column + 1) error = f"({line}, {column}) - TypeError: Class {idType} of case branch is undefined." print(error) + self.hasNoError = False if typeList.__contains__(idType): line = str(ctx.getChild(count).symbol.line) column = str(ctx.getChild(count).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Duplicate branch {idType} in case statement." print(error) + self.hasNoError = False count = count + 2 typeList.append(idType) self.ScopeManager.addScope() @@ -598,6 +636,7 @@ def visitNew(self, ctx: COOL.NewContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: 'new' used with undefined class {typeName}." print(error) + self.hasNoError = False return typeName # Visit a parse tree produced by COOL#ownMethodCall. @@ -614,12 +653,14 @@ def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(1).symbol.text} called with wrong number of arguments." print(error) + self.hasNoError = False methodType = "None" elif len(ctx.children) != methodInfo.ParamsNumber * 2 + 2 and methodInfo.ParamsNumber != 0: line = str(ctx.getChild(1).symbol.line) column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(1).symbol.text} called with wrong number of arguments." print(error) + self.hasNoError = False methodType = "None" else: count = 2 @@ -631,6 +672,7 @@ def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): column = str(ctx.getChild(count).start.column + 1) error = f"({line}, {column}) - TypeError: In call of method {ctx.getChild(1).symbol.text}, type {requestType} of parameter {paramName} does not conform to declared type {paramType}." print(error) + self.hasNoError = False methodType = "None" count = count + 2 else: @@ -638,6 +680,7 @@ def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) AttributeError: Dispatch to undefined method {ctx.getChild(0).symbol.text}." print(error) + self.hasNoError = False return methodType # Visit a parse tree produced by COOL#methodCall. @@ -655,6 +698,7 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): column = str(ctx.getChild(1).symbol.column) error = f"({line}, {column}) - SemanticError: Expression type {currentClass} does not conform to declared static dispatch type {parent}." print(error) + self.hasNoError = False return methodType if self.searchMethod(currentClass, ctx.getChild(length - 3).symbol.text): methodInfo = self.searchMethodInfo(currentClass, ctx.getChild(length - 3).symbol.text) @@ -667,12 +711,14 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): column = str(ctx.getChild(2).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(2).symbol.text} called with wrong number of arguments." print(error) + self.hasNoError = False methodType = "None" elif (len(ctx.children) != methodInfo.ParamsNumber * 2 + length - 1) and methodInfo.ParamsNumber > 0: line = str(ctx.getChild(2).symbol.line) column = str(ctx.getChild(2).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(2).symbol.text} called with wrong number of arguments." print(error) + self.hasNoError = False methodType = "None" else: count = length - 1 @@ -684,6 +730,7 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): column = str(ctx.getChild(count).start.column + 1) error = f"({line}, {column}) - TypeError: In call of method {ctx.getChild(2).symbol.text}, type {requestType} of parameter {paramName} does not conform to declared type {paramType}." print(error) + self.hasNoError = False methodType = "None" count = count + 2 else: @@ -691,6 +738,7 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): column = str(ctx.getChild(length - 3).symbol.column + 1) error = f"({line}, {column}) AttributeError: Dispatch to undefined method {ctx.getChild(length - 3).symbol.text}." print(error) + self.hasNoError = False return methodType # Visit a parse tree produced by COOL#letIn. @@ -705,6 +753,7 @@ def visitLetIn(self, ctx: COOL.LetInContext): column = str(ctx.getChild(count + 1).symbol.column + 1) error = f"({line}, {column}) - SemanticError: 'self' cannot be bound in a 'let' expression." print(error) + self.hasNoError = False return "None" count = count + 2 idType = ctx.getChild(count + 1).symbol.text @@ -714,6 +763,7 @@ def visitLetIn(self, ctx: COOL.LetInContext): column = str(ctx.getChild(count + 1).symbol.column + 1) error = f"({line}, {column}) - TypeError: Class {idType} of let-bound identifier {idName} is undefined." print(error) + self.hasNoError = False return "None" self.ScopeManager.addIdentifier(idName, idType) count = count + 2 @@ -726,6 +776,7 @@ def visitLetIn(self, ctx: COOL.LetInContext): column = str(ctx.getChild(count - 1).start.column + 1) error = f"({line}, {column}) - TypeError: Inferred type of {idValue} initialization of {idName} does not conform to identifier's declared type {idType}." print(error) + self.hasNoError = False return "None" temp = ctx.getChild(count + 1).accept(self) From 10043a7e5767f4d23416859c1904d9f29b2a88b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Thu, 26 Nov 2020 14:12:31 -0500 Subject: [PATCH 20/77] =?UTF-8?q?Ajustes=20en=20la=20generaci=C3=B3n=20de?= =?UTF-8?q?=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Visitors.py | 270 +++++++++++++++++++++++++++-------- tests/codegen/hello_world.cl | 12 +- 2 files changed, 222 insertions(+), 60 deletions(-) diff --git a/src/Visitors.py b/src/Visitors.py index 2358ece1..0c7dd42d 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -27,7 +27,7 @@ def __init__(self, name: str, type: str, paramNumber: int, instructionSet): self.ParamsNumber= paramNumber self.InstructionSet = instructionSet -class COOLScopeManager: +class SemanticScopeManager: def __init__(self): self.Stack = deque() @@ -59,8 +59,41 @@ def searchforType(self, identifier: str): return scope[identifier] return "None" -class SemanticCOOLVisitor(ParseTreeVisitor): +class GenScopeManager: + def __init__(self): + self.Stack = deque() + + def addScope(self): + self.Stack.append({}) + + def addIdentifier(self, name: str, type: str): + scope = self.Stack.pop() + scope[name] = type + self.Stack.append(scope) + + def deleteScope(self): + self.Stack.pop() + + def searchScope(self, identifier: str): + scope = self.Stack.pop() + self.Stack.append(scope) + return scope.keys().__contains__(identifier) + def searchIdentifier(self, identifier: str): + for scope in reversed(self.Stack): + if (len(scope) != 0): + if(scope.keys().__contains__(identifier)): + return self.Stack.index(scope) + return -1 + + def searchType(self, identifier: str): + for scope in reversed(self.Stack): + if (len(scope) != 0): + if(scope.keys().__contains__(identifier)): + return scope[identifier] + return "None" + +class SemanticCOOLVisitor(ParseTreeVisitor): def join(self, class1: str, class2: str): if class1 == "None" or class2 == "None": return "None" @@ -120,10 +153,9 @@ def searchAtributeInfo(self, coolClass: str, atributeName: str): return self.TypeTable[coolClass].Atributes[atribute] return self.searchAtributeInfo(self.TypeTable[coolClass].Parent, atributeName) - def __init__(self, typeTable: dict): self.TypeTable = typeTable - self.ScopeManager = COOLScopeManager() + self.ScopeManager = SemanticScopeManager() self.actualClass = "Object" self.hasNoError = True @@ -1021,11 +1053,28 @@ class CodegenVisitor(ParseTreeVisitor): CurrentClass : COOLClass + CurrentMethod: COOLMethod + + CurrentType: str + + def searchAtributeInfo(self, coolClass: str, atributeName: str): + for atribute in self.TypeTable[coolClass].Atributes.keys(): + if atribute == atributeName: + return self.TypeTable[coolClass].Atributes[atribute] + return self.searchAtributeInfo(self.TypeTable[coolClass].Parent, atributeName) + + def searchMethodInfo(self, coolClass: str, methodName: str): + for method in self.TypeTable[coolClass].Methods.keys(): + if method == methodName: + return self.TypeTable[coolClass].Methods[method].Type + return self.searchMethodInfo(self.TypeTable[coolClass].Parent, methodName) + def __init__(self, typeTable: dict, constantTable: list, counter: int): self.TypeTable = typeTable self.ConstantTable = constantTable self.Counter = counter self.LabelCounter = 0 + self.ScopeManager = GenScopeManager() def genGlobalClases(self): sol = "\t.data\n\t.align 2\n\t.globl class_nameTab\n" @@ -1090,8 +1139,6 @@ def genMethodNames(self, coolClass: str, coolMethods: list, className: str): self.TypeTable[coolClass].TagMethods = methodList return code + temp - - def genAtributeNames(self, coolClass: str, coolAtributes: list): if coolClass == "None": return "" @@ -1162,12 +1209,15 @@ def genClassAtributes(self, className: str): code = self.genClassAtributes(self.TypeTable[className].Parent) for atribute in self.TypeTable[className].AtributeAsign: code = code + (self.TypeTable[className].AtributeAsign[atribute].accept(self) or "") + pos = self.CurrentClass.TagAtributes.index(atribute) + code = code + f"\tsw $a0 {pos * 4 + 12}($s0)\n" return code # Visit a parse tree produced by COOL#program. def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): for className in self.TypeTable: constantName = className + self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) self.Counter = self.Counter + 1 length = len(constantName) @@ -1201,6 +1251,8 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): "\t.globl Bool_init\n" \ "\t.globl Main.main\n" for className in self.TypeTable: + self.CurrentClass = self.TypeTable[className] + self.CurrentType = className code = code + f"{className}_init:\n" temp = self.genClassAtributes(className) if len(temp) != 0: @@ -1222,7 +1274,16 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): for className in self.TypeTable: if not(className == "Object" or className == "String" or className == "Int" or className == "Bool" or className == "IO"): self.CurrentClass = self.TypeTable[className] - for methodName in self.TypeTable[className].Methods: + self.ScopeManager.addScope() + for atribute in self.CurrentClass.TagAtributes: + self.ScopeManager.addIdentifier(atribute,self.searchAtributeInfo(className, atribute)) + for methodName in self.CurrentClass.Methods: + self.CurrentMethod = self.CurrentClass.Methods[methodName] + self.CurrentType = self.CurrentMethod.Type + self.ScopeManager.addScope() + for param in self.CurrentClass.Methods[methodName].Params: + (paramName, paramType) = param + self.ScopeManager.addIdentifier(paramName, paramType) code = code + f"{className}.{methodName}:\n" code = code + \ "\taddiu $sp $sp -12\n" \ @@ -1239,6 +1300,9 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): "\tlw $ra 4($sp)\n" \ "\taddiu $sp $sp 12\n" code = code + "\tjr $ra\n" + self.ScopeManager.deleteScope() + + self.ScopeManager.deleteScope() code = self.RuntimeMessages + \ "\n" + \ @@ -1284,22 +1348,23 @@ def visitLetIn(self, ctx: COOL.LetInContext): def visitMinus(self, ctx: COOL.MinusContext): code = ctx.getChild(0).accept(self) code = code + \ - "\tsw $a0 0 ($sp)\n" + \ - "\taddiu $sp $sp -4\n" + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" code = code + ctx.getChild(2).accept(self) code = code + \ - "\tjal Object.copy\n" + \ - "\tlw $t1 4($sp)\n" + \ - "\tlw $t1 12($t1)\n" + \ - "\tlw $t2 12($a0)\n" + \ - "\tsub $t1 $t1 $t2\n" + \ - "\tsw $t1 12($a0)\n" + \ - "\taddiu $sp $sp 4\n" + "\tjal Object.copy\n" + \ + "\tlw $t1 4($sp)\n" + \ + "\tlw $t1 12($t1)\n" + \ + "\tlw $t2 12($a0)\n" + \ + "\tsub $t1 $t1 $t2\n" + \ + "\tsw $t1 12($a0)\n" + \ + "\taddiu $sp $sp 4\n" return code # Visit a parse tree produced by COOL#string. def visitString(self, ctx: COOL.StringContext): name = ctx.getChild(0).symbol.text[1:-1] + self.CurrentType = "String" for const in self.ConstantTable: (constName, constType, constTag) = const if constType == "String" and constName == name: @@ -1317,18 +1382,18 @@ def visitWhile(self, ctx: COOL.WhileContext): def visitDivision(self, ctx: COOL.DivisionContext): code = ctx.getChild(0).accept(self) code += \ - "\tsw $a0 0 ($sp)\n" + \ - "\taddiu $sp $sp -4\n" + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" code += ctx.getChild(2).accept(self) code += \ - "\tjal Object.copy\n" \ - "\tlw $t1 4($sp)\n" \ - "\tlw $t1 12($t1)\n" \ - "\tlw $t2 12($a0)\n" \ - "\tdiv $t1 $t2\n" \ - "\tmflo $t1\n" \ - "\tsw $t1 12($a0)\n" \ - "\taddiu $sp $sp 4\n" + "\tjal Object.copy\n" \ + "\tlw $t1 4($sp)\n" \ + "\tlw $t1 12($t1)\n" \ + "\tlw $t2 12($a0)\n" \ + "\tdiv $t1 $t2\n" \ + "\tmflo $t1\n" \ + "\tsw $t1 12($a0)\n" \ + "\taddiu $sp $sp 4\n" return code # Visit a parse tree produced by COOL#negative. @@ -1355,23 +1420,58 @@ def visitBlock(self, ctx: COOL.BlockContext): # Visit a parse tree produced by COOL#id. def visitId(self, ctx: COOL.IdContext): - return self.visitChildren(ctx) + varName = ctx.getChild(0).symbol.text + if varName == "self": + self.CurrentType = self.CurrentClass.Name + return "\tlw $a0 ($s0)\n" + self.CurrentType = self.ScopeManager.searchType(varName) + option = self.ScopeManager.searchIdentifier(varName) + if option == 0: + return self.propertyId(ctx) + elif option == 1: + return self.formalId(ctx) + else: + return self.variableId(ctx) + + def propertyId(self, ctx: COOL.AssignmentContext): + varName = ctx.getChild(0).symbol.text + pos = self.CurrentClass.TagAtributes.index(varName) + code = f"\tlw $a0 {pos * 4 + 12}($s0)\n" + return code + + def formalId(self, ctx: COOL.AssignmentContext): + varName = ctx.getChild(0).symbol.text + varType = self.ScopeManager.Stack[1][varName] + pos = self.CurrentMethod.Params.index((varName,varType)) + total = self.CurrentMethod.ParamsNumber + code = f"\tlw $a0 {(pos - (total + 2)) * 4}($fp)\n" + return code + + def variableId(self, ctx: COOL.AssignmentContext): + varName = ctx.getChild(0).symbol.text + scope = self.ScopeManager.searchIdentifier(varName) + pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) + total = 0 + for scope in self.ScopeManager.Stack [2 : pos]: + total += len(list(scope.keys())) + code = f"\tlw $a0 {(total + pos) * 4}($fp)\n" + return code # Visit a parse tree produced by COOL#multiply. def visitMultiply(self, ctx: COOL.MultiplyContext): code = ctx.getChild(0).accept(self) code = code + \ - "\tsw $a0 0 ($sp)\n" + \ - "\taddiu $sp $sp -4\n" + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" code = code + ctx.getChild(2).accept(self) code = code + \ - "\tjal Object.copy\n" + \ - "\tlw $t1 4($sp)\n" + \ - "\tlw $t1 12($t1)\n" + \ - "\tlw $t2 12($a0)\n" + \ - "\tmul $t1 $t1 $t2\n" + \ - "\tsw $t1 12($a0)\n" + \ - "\taddiu $sp $sp 4\n" + "\tjal Object.copy\n" + \ + "\tlw $t1 4($sp)\n" + \ + "\tlw $t1 12($t1)\n" + \ + "\tlw $t2 12($a0)\n" + \ + "\tmul $t1 $t1 $t2\n" + \ + "\tsw $t1 12($a0)\n" + \ + "\taddiu $sp $sp 4\n" return code # Visit a parse tree produced by COOL#if. @@ -1394,32 +1494,34 @@ def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): f"\tsw $a0 0($sp)\n" \ f"\taddiu $sp $sp -4\n" count = count + 2 - methodIdx = self.CurrentClass.TagMethods.index(ctx.getChild(0).symbol.text) - code += "\tmove $a0 $s0\n" \ - "\tlw $t1 8($a0)\n" \ - f"\tlw $t1 {methodIdx * 4}($t1)\n" \ - "\tjalr $t1\n" + methodIdx = self.CurrentClass.TagMethods.index(ctx.getChild(0).symbol.text) + self.CurrentType = self.searchMethodInfo(self.CurrentClass.Name, ctx.getChild(0).symbol.text) + code += "\tmove $a0 $s0\n" \ + "\tlw $t1 8($a0)\n" \ + f"\tlw $t1 {methodIdx * 4}($t1)\n" \ + "\tjalr $t1\n" return code # Visit a parse tree produced by COOL#add. def visitAdd(self, ctx: COOL.AddContext): code = ctx.getChild(0).accept(self) or "" code = code + \ - "\tsw $a0 0 ($sp)\n"+ \ - "\taddiu $sp $sp -4\n" + "\tsw $a0 0 ($sp)\n"+ \ + "\taddiu $sp $sp -4\n" code = code + ctx.getChild(2).accept(self) code = code + \ - "\tjal Object.copy\n"+ \ - "\tlw $t1 4($sp)\n"+ \ - "\tlw $t1 12($t1)\n"+ \ - "\tlw $t2 12($a0)\n"+ \ - "\tadd $t1 $t1 $t2\n"+ \ - "\tsw $t1 12($a0)\n"+ \ - "\taddiu $sp $sp 4\n" + "\tjal Object.copy\n"+ \ + "\tlw $t1 4($sp)\n"+ \ + "\tlw $t1 12($t1)\n"+ \ + "\tlw $t2 12($a0)\n"+ \ + "\tadd $t1 $t1 $t2\n"+ \ + "\tsw $t1 12($a0)\n"+ \ + "\taddiu $sp $sp 4\n" return code # Visit a parse tree produced by COOL#new. def visitNew(self, ctx: COOL.NewContext): + self.CurrentType = ctx.getChild(1).symbol.text return self.visitChildren(ctx) # Visit a parse tree produced by COOL#parentheses. @@ -1428,15 +1530,50 @@ def visitParentheses(self, ctx: COOL.ParenthesesContext): # Visit a parse tree produced by COOL#assignment. def visitAssignment(self, ctx: COOL.AssignmentContext): - return self.visitChildren(ctx) + varName = ctx.getChild(0).symbol.text + option = self.ScopeManager.searchIdentifier(varName) + if option == 0: + return self.propertyAssignament(ctx) + elif option == 1: + return self.formalAssignament(ctx) + else: + return self.variableAssignament(ctx) + + def propertyAssignament(self, ctx: COOL.AssignmentContext): + varName = ctx.getChild(0).symbol.text + code = ctx.getChild(2).accept(self) + pos = self.CurrentClass.TagAtributes.index(varName) + code = code + f"\tsw $a0 {pos * 4 + 12}($s0)\n" + return code + + def formalAssignament(self, ctx: COOL.AssignmentContext): + varName = ctx.getChild(0).symbol.text + code = ctx.getChild(2).accept(self) + varType = self.ScopeManager.Stack[1][varName] + pos = self.CurrentMethod.Params.index((varName, varType)) + total = self.CurrentMethod.ParamsNumber + code = code + f"\tsw $a0 {(pos - (total + 2)) * 4}($fp)\n" + return code + + def variableAssignament(self, ctx: COOL.AssignmentContext): + varName = ctx.getChild(0).symbol.text + scope = self.ScopeManager.searchIdentifier(varName) + pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) + total = 0 + for scope in self.ScopeManager.Stack[2: pos]: + total += len(list(scope.keys())) + code = f"\tsw $a0 {(total + pos) * 4}($fp)\n" + return code # Visit a parse tree produced by COOL#false. def visitFalse(self, ctx: COOL.FalseContext): + self.CurrentType = "Bool" return f"\tla $a0 {bool_const0}\n" # Visit a parse tree produced by COOL#int. def visitInt(self, ctx: COOL.IntContext): val = int(ctx.getChild(0).symbol.text) + self.CurrentType = "Int" for const in self.ConstantTable: (constVal, constType, constTag) = const if constType == "Int" and constVal == val: @@ -1448,7 +1585,8 @@ def visitEqual(self, ctx: COOL.EqualContext): # Visit a parse tree produced by COOL#true. def visitTrue(self, ctx: COOL.TrueContext): - return f"\tla $a0 {bool_const1}\n" + self.CurrentType = "Bool" + return f"\tla $a0 bool_const1\n" # Visit a parse tree produced by COOL#lessEqual. def visitLessEqual(self, ctx: COOL.LessEqualContext): @@ -1456,13 +1594,27 @@ def visitLessEqual(self, ctx: COOL.LessEqualContext): # Visit a parse tree produced by COOL#methodCall. def visitMethodCall(self, ctx: COOL.MethodCallContext): - # line = ctx.getChild(1).symbol.line - # f"\tbne $t2 $zero label{self.LabelCounter}\n" \ - # "\tla $a0 str_const1\n" \ - # f"\tli $t1 {line}\n" \ - # "\tjal _dispatch_abort\n" \ - # f"label{self.LabelCounter}:\n" \ - # self.LabelCounter += 1 + length = 5 + code = ctx.getChild(0).accept(self) or "" + classId = self.CurrentType + if ctx.getChild(1).symbol.text == "@": + length += 2 + classId = ctx.getChild(2).symbol.text + if len(ctx.children) > length: + count = length - 1 + while length != count: + param = (ctx.getChild(count).accept(self) or "") + code += param + \ + f"\tsw $a0 0($sp)\n" \ + f"\taddiu $sp $sp -4\n" + count = count + 2 + methodIdx = self.TypeTable[classId].TagMethods.index(ctx.getChild(length - 3).symbol.text) + self.CurrentType = self.searchMethodInfo(self.CurrentClass.Name, ctx.getChild(length - 3).symbol.text) + code += "\tmove $a0 $s0\n" \ + "\tlw $t1 8($a0)\n" \ + f"\tlw $t1 {methodIdx * 4}($t1)\n" \ + "\tjalr $t1\n" + return code return "" RuntimeMessages = """ diff --git a/tests/codegen/hello_world.cl b/tests/codegen/hello_world.cl index 2055d2a7..7cefd7a3 100755 --- a/tests/codegen/hello_world.cl +++ b/tests/codegen/hello_world.cl @@ -1,9 +1,19 @@ class Main inherits IO { x : Int <- 1; + + sqrt (x : Int) : Int + { + x * x + }; + main(): IO { { out_string("Hello, World ("); - out_int(3*2-7*2*2); + out_int(x * 2); + x <- 0 -7; + x <- sqrt(x); + out_string(", "); + out_int(x); out_string(").\n"); } }; From d242872412db8ffa05fc216cef39cda4a6b5f928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sat, 28 Nov 2020 18:58:57 -0500 Subject: [PATCH 21/77] =?UTF-8?q?Se=20resolvieron=20varios=20bugs=20de=20l?= =?UTF-8?q?a=20generaci=C3=B3n=20de=20c=C3=B3digo.=20Se=20modificaron=20va?= =?UTF-8?q?rios=20de=20los=20programas=20de=20prueba=20para=20probar=20el?= =?UTF-8?q?=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Visitors.py | 309 ++++++++++++++++++++++++++++------- tests/codegen/arith.cl | 10 +- tests/codegen/atoi.cl | 73 ++++++--- tests/codegen/hello_world.cl | 16 +- 4 files changed, 317 insertions(+), 91 deletions(-) diff --git a/src/Visitors.py b/src/Visitors.py index 0c7dd42d..9de9207e 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -80,11 +80,13 @@ def searchScope(self, identifier: str): return scope.keys().__contains__(identifier) def searchIdentifier(self, identifier: str): + index = len(self.Stack) - 1 for scope in reversed(self.Stack): if (len(scope) != 0): if(scope.keys().__contains__(identifier)): - return self.Stack.index(scope) - return -1 + return index + index -= 1 + return index def searchType(self, identifier: str): for scope in reversed(self.Stack): @@ -603,7 +605,7 @@ def visitIf(self, ctx:COOL.IfContext): # Visit a parse tree produced by COOL#while. def visitWhile(self, ctx: COOL.WhileContext): - whileValue = ctx.getChild(3).accept(self) + ctx.getChild(3).accept(self) #chequea semanticamente el cuerpo whileValue = ctx.getChild(1).accept(self) if whileValue == "None" or whileValue == "Bool": return "Object" @@ -848,6 +850,7 @@ def visitProgram(self, ctx: COOL.ProgramContext, fileName: str): self.ConstantTable.append(("", "String", "str_const0")) self.ConstantTable.append((0, "Int", "int_const0")) self.ConstantTable.append(("false", "Bool", "bool_const0")) + self.ConstantTable.append(("true", "Bool", "bool_const1")) self.ConstantTable.append((fileName, "String", "str_const1")) self.ConstantTable.append((len(fileName), "Int", F"int_const{len(fileName)}")) self.Counter = 2 @@ -905,7 +908,6 @@ def visitProperty(self, ctx: COOL.PropertyContext): # Visit a parse tree produced by COOL#formal. def visitFormal(self, ctx: COOL.FormalContext): parent = ctx.parentCtx - className = parent.parentCtx.getChild(1).symbol.text methodName = parent.getChild(0).symbol.text method = self.TypeTable[className].Methods[methodName] @@ -1057,6 +1059,23 @@ class CodegenVisitor(ParseTreeVisitor): CurrentType: str + def join(self, class1: str, class2: str): + if class1 == "None" or class2 == "None": + return "None" + if class1 == "SELF_TYPE": + class1 = self.CurrentClass.Name + if class2 == "SELF_TYPE": + class2 = self.CurrentClass.Name + if self.TypeTable[class1].Deep == self.TypeTable[class2].Deep: + if self.TypeTable[class1].Name == self.TypeTable[class2].Name: + return class1 + else: + return self.join(self.TypeTable[class1].Parent, self.TypeTable[class2].Parent) + elif self.TypeTable[class1].Deep > self.TypeTable[class2].Deep: + return self.join(self.TypeTable[class1].Parent, class2) + else: + return self.join(class1, self.TypeTable[class2].Parent) + def searchAtributeInfo(self, coolClass: str, atributeName: str): for atribute in self.TypeTable[coolClass].Atributes.keys(): if atribute == atributeName: @@ -1091,14 +1110,14 @@ def genConstant(self, sol: str): sol = sol + \ f"\t.word -1\n" \ f"{constLabel}:\n" \ - f"\t.word 5\n" \ + f"\t.word 3\n" \ f"\t.word 4\n" \ f"\t.word Bool_dispTab\n" \ f"\t.word {constLabel[-1]}\n" elif constType == "Int": sol = sol + \ f"\t.word -1\n{constLabel}:\n" \ - f"\t.word 3\n\t.word 4\n" \ + f"\t.word 2\n\t.word 4\n" \ f"\t.word Int_dispTab\n" \ f"\t.word {constName}\n" else: @@ -1107,7 +1126,7 @@ def genConstant(self, sol: str): length = length + 1 sol = sol + \ f"\t.word -1\n{constLabel}:\n" \ - f"\t.word 4\n\t.word {length}\n" \ + f"\t.word 1\n\t.word {length}\n" \ f"\t.word String_dispTab\n" \ f"\t.word int_const{len(constName)}\n" \ f"\t.ascii \"{constName}\"\n" \ @@ -1125,20 +1144,23 @@ def genMethodNames(self, coolClass: str, coolMethods: list, className: str): if coolClass == "None": return "" temp = "" - methodList = list() for method in self.TypeTable[coolClass].Methods: if not (coolMethods.__contains__(method)): temp = temp + f"\t.word {coolClass}.{method}\n" - methodList.append(method) coolMethods.append(method) code = self.genMethodNames(self.TypeTable[coolClass].Parent, coolMethods, className) - if coolClass != "Object": - self.TypeTable[coolClass].TagMethods = self.TypeTable[self.TypeTable[coolClass].Parent].TagMethods + methodList - else: - self.TypeTable[coolClass].TagMethods = methodList return code + temp + def genMethodTags(self, coolClass: str, coolMethods: list, className: str): + if coolClass == "None": + return coolMethods + coolMethods = self.genMethodTags(self.TypeTable[coolClass].Parent, coolMethods, className) + for method in self.TypeTable[coolClass].Methods: + if not (coolMethods.__contains__(method)): + coolMethods.append(method) + return coolMethods + def genAtributeNames(self, coolClass: str, coolAtributes: list): if coolClass == "None": return "" @@ -1149,7 +1171,7 @@ def genAtributeNames(self, coolClass: str, coolAtributes: list): listAtributes.append(atribute) value = self.TypeTable[coolClass].Atributes[atribute] if value == "Int" or value == "String" or value == "Bool": - temp = temp + f"\t.word {value.lower()}_constant0\n" + temp = temp + f"\t.word {value.lower()}_const0\n" else: temp = temp + f"\t.word 0\n" coolAtributes.append(atribute) @@ -1187,7 +1209,7 @@ def genClassTable(self): f"\t.word {counter}\n" \ f"\t.word 5\n" \ f"\t.word {className}_dispTab\n" \ - f"\t.word int_constant0\n" \ + f"\t.word int_const0\n" \ f"\t.word 0\n" else: atributeList = list() @@ -1217,7 +1239,6 @@ def genClassAtributes(self, className: str): def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): for className in self.TypeTable: constantName = className - self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) self.Counter = self.Counter + 1 length = len(constantName) @@ -1228,6 +1249,7 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): contain = False if contain: self.ConstantTable.append((length, "Int", f"int_const{length}")) + self.TypeTable[className].TagMethods = self.genMethodTags(className,list(),className) self.ConstantTable.append(("SELF_TYPE", "String", f"str_const{self.Counter}")) contain = True length = len("SELF_TYPE") @@ -1253,6 +1275,7 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): for className in self.TypeTable: self.CurrentClass = self.TypeTable[className] self.CurrentType = className + self.CurrentMethod = "None" code = code + f"{className}_init:\n" temp = self.genClassAtributes(className) if len(temp) != 0: @@ -1293,12 +1316,12 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): "\taddiu $fp $sp 4\n" \ "\tmove $s0 $a0\n" code = code + (self.TypeTable[className].Methods[methodName].InstructionSet.accept(self) or "") + # "\tmove $a0 $s0\n" \ code = code + \ - "\tmove $a0 $s0\n" \ "\tlw $fp 12($sp)\n" \ "\tlw $s0 8($sp)\n" \ "\tlw $ra 4($sp)\n" \ - "\taddiu $sp $sp 12\n" + f"\taddiu $sp $sp {12+4*self.CurrentClass.Methods[methodName].ParamsNumber}\n" code = code + "\tjr $ra\n" self.ScopeManager.deleteScope() @@ -1342,7 +1365,31 @@ def visitFormal(self, ctx: COOL.FormalContext): # Visit a parse tree produced by COOL#letIn. def visitLetIn(self, ctx: COOL.LetInContext): - return self.visitChildren(ctx) + self.ScopeManager.addScope() + count = 0 + varNumber = 0 + code = "" + while (ctx.getChild(count).symbol.text != "in"): + idName = ctx.getChild(count + 1).symbol.text + varNumber += 1 + count = count + 2 + idType = ctx.getChild(count + 1).symbol.text + count = count + 2 + if ctx.getChild(count).symbol.text == "<-": + code += ctx.getChild(count + 1).accept(self) + count = count + 2 + else: + if idType == "String" or idType == "Int" or idType == "Bool": + code += f"\tla $a0 {idType.lower()}_const0\n" + else: + code += "li $a0 0\n" + code += f"\tsw $a0 0($sp)\n" \ + f"\taddiu $sp $sp -4\n" + self.ScopeManager.addIdentifier(idName, idType) + code += ctx.getChild(count + 1).accept(self) + code += f"\taddiu $sp $sp {varNumber * 4}\n" + self.ScopeManager.deleteScope() + return code # Visit a parse tree produced by COOL#minus. def visitMinus(self, ctx: COOL.MinusContext): @@ -1372,17 +1419,35 @@ def visitString(self, ctx: COOL.StringContext): # Visit a parse tree produced by COOL#isvoid. def visitIsvoid(self, ctx: COOL.IsvoidContext): - return self.visitChildren(ctx) + code = ctx.getChild(1).accept(self) + code += \ + "\tla $t1 bool_const0\n" \ + "\tla $t2 bool_const1\n" \ + "\tmovz $t1 $t2 $a0\n" \ + "\tmove $a0 $t1\n" + self.CurrentType = "Bool" + return code # Visit a parse tree produced by COOL#while. def visitWhile(self, ctx: COOL.WhileContext): - return self.visitChildren(ctx) + code = f"while_label{self.Counter}:\n" + code += ctx.getChild(1).accept(self) + code += "\tlw $t1 12($a0)\n" + \ + f"\tbgtz $t1 loop_label{self.Counter}\n" + \ + f"\tb pool_label{self.Counter}\n" + \ + f"loop_label{self.Counter}:\n" + code += ctx.getChild(3).accept(self) + code += f"\tb while_label{self.Counter}\n" + \ + f"pool_label{self.Counter}:\n" + self.CurrentType = "None" + self.Counter += 1 + return code # Visit a parse tree produced by COOL#division. def visitDivision(self, ctx: COOL.DivisionContext): code = ctx.getChild(0).accept(self) code += \ - "\tsw $a0 0 ($sp)\n" + \ + "\tsw $a0 0($sp)\n" + \ "\taddiu $sp $sp -4\n" code += ctx.getChild(2).accept(self) code += \ @@ -1398,15 +1463,48 @@ def visitDivision(self, ctx: COOL.DivisionContext): # Visit a parse tree produced by COOL#negative. def visitNegative(self, ctx: COOL.NegativeContext): - return self.visitChildren(ctx) + self.CurrentType = "Int" + code = ctx.getChild(1).accept(self) + code += \ + "\tjal Object.copy\n" \ + "\tlw $t1 12($a0)\n" \ + "\tnegu $t1 $t1\n" \ + "\tsw $t1 12($a0)\n" \ + "\tsw $a0 0($sp)\n" + return code # Visit a parse tree produced by COOL#boolNot. def visitBoolNot(self, ctx: COOL.BoolNotContext): - return self.visitChildren(ctx) + self.CurrentType = "Bool" + code = ctx.getChild(1).accept(self) + code += \ + "\tjal Object.copy\n" \ + "\tlw $t1 12($a0)\n" \ + "\tnegu $t2 $t1\n" \ + "\taddiu $t3 $t2 1\n"\ + "\tsw $t3 12($a0)\n" \ + "\tsw $a0 0($sp)\n" + return code # Visit a parse tree produced by COOL#lessThan. def visitLessThan(self, ctx: COOL.LessThanContext): - return self.visitChildren(ctx) + self.CurrentType = "Bool" + code = ctx.getChild(0).accept(self) + code += \ + "\tsw $a0 0($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code += ctx.getChild(2).accept(self) + code += \ + "\tjal Object.copy\n" \ + "\tlw $t0 4($sp)\n" \ + "\tlw $t1 12($t0)\n" \ + "\tlw $t2 12($a0)\n" \ + "\tslt $t3 $t1 $t2\n" \ + "\tla $a0 bool_const0\n" \ + "\tjal Object.copy\n" \ + "\tsw $t3 12($a0)\n" \ + "\taddiu $sp $sp 4\n" + return code # Visit a parse tree produced by COOL#block. def visitBlock(self, ctx: COOL.BlockContext): @@ -1426,9 +1524,9 @@ def visitId(self, ctx: COOL.IdContext): return "\tlw $a0 ($s0)\n" self.CurrentType = self.ScopeManager.searchType(varName) option = self.ScopeManager.searchIdentifier(varName) - if option == 0: + if option == 0 and self.CurrentMethod != "None": return self.propertyId(ctx) - elif option == 1: + elif option == 1 and self.CurrentMethod != "None": return self.formalId(ctx) else: return self.variableId(ctx) @@ -1444,17 +1542,19 @@ def formalId(self, ctx: COOL.AssignmentContext): varType = self.ScopeManager.Stack[1][varName] pos = self.CurrentMethod.Params.index((varName,varType)) total = self.CurrentMethod.ParamsNumber - code = f"\tlw $a0 {(pos - (total + 2)) * 4}($fp)\n" + code = f"\tlw $a0 {((total + 2) - pos) * 4}($fp)\n" return code def variableId(self, ctx: COOL.AssignmentContext): varName = ctx.getChild(0).symbol.text scope = self.ScopeManager.searchIdentifier(varName) - pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) - total = 0 - for scope in self.ScopeManager.Stack [2 : pos]: - total += len(list(scope.keys())) - code = f"\tlw $a0 {(total + pos) * 4}($fp)\n" + pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) + 1 + init = 2 + if self.CurrentMethod == "None": + init = 0 + for scope in list(self.ScopeManager.Stack)[init : scope]: + pos += len(list(scope.keys())) + code = f"\tlw $a0 {-(pos * 4)}($fp)\n" return code # Visit a parse tree produced by COOL#multiply. @@ -1476,11 +1576,67 @@ def visitMultiply(self, ctx: COOL.MultiplyContext): # Visit a parse tree produced by COOL#if. def visitIf(self, ctx: COOL.IfContext): - return self.visitChildren(ctx) + code = ctx.getChild(1).accept(self) + counter = self.Counter + self.Counter += 1 + code = code + \ + "\tlw $t1 12($a0)\n" + \ + f"\tbgtz $t1 then_label{counter}\n" + \ + f"\tb else_label{counter}\n" + \ + f"then_label{counter}:\n" + code = code +\ + ctx.getChild(3).accept(self) + \ + f"\tb fi_label{counter}\n" + \ + f"else_label{counter}:\n" + tempType = self.CurrentType + code = code +\ + ctx.getChild(5).accept(self) + \ + f"\tb fi_label{counter}\n" + \ + f"fi_label{counter}:\n" + self.CurrentType = self.join(tempType, self.CurrentType) + return code # Visit a parse tree produced by COOL#case. def visitCase(self, ctx: COOL.CaseContext): - return "" + counter = self.Counter + self.Counter += 1 + code = ctx.getChild(1).accept(self) +\ + "\tli $t1 0\n" \ + f"\tbeq $a0 $t1 abort{counter}\n" + lengt = len(ctx.children) - 1 + tempCode = f"abort{counter}:\n" \ + "\tjal _case_abort2\n" + count = 3 + while lengt > count: + idName = ctx.getChild(count).symbol.text + count = count + 2 + idType = ctx.getChild(count).symbol.text + count = count + 2 + self.ScopeManager.addScope() + self.ScopeManager.addIdentifier(idName, idType) + code += \ + f"\tlw $t1 0($a0)\n" \ + f"\tli $t2 {self.TypeTable[idType].Tag}\n" \ + f"\tbeq $t1 $t2 {idType}_case{counter}\n" + scope = self.ScopeManager.searchIdentifier(idName) + pos = list(self.ScopeManager.Stack[scope].keys()).index(idName) + 1 + init = 2 + if self.CurrentMethod == "None": + init = 0 + for scope in list(self.ScopeManager.Stack)[init: scope]: + pos += len(list(scope.keys())) + tempCode +=\ + f"{idType}_case{counter}:\n" \ + f"\tsw $a0 -{pos * 4}($fp)\n" + tempCode += ctx.getChild(count).accept(self) + tempCode += f"\tb esac{counter}\n" + self.ScopeManager.deleteScope() + count = count + 2 + code = code + \ + "\tjal _case_abort\n" + code += tempCode +\ + f"esac{counter}:\n" + return code # Visit a parse tree produced by COOL#ownMethodCall. def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): @@ -1522,19 +1678,21 @@ def visitAdd(self, ctx: COOL.AddContext): # Visit a parse tree produced by COOL#new. def visitNew(self, ctx: COOL.NewContext): self.CurrentType = ctx.getChild(1).symbol.text - return self.visitChildren(ctx) + return f"\tla $a0 {self.CurrentType}_protObj\n"\ + "\tjal Object.copy\n" \ + f"\tjal {self.CurrentType}_init\n" # Visit a parse tree produced by COOL#parentheses. def visitParentheses(self, ctx: COOL.ParenthesesContext): - return self.visitChildren(ctx) + return ctx.getChild(1).accept(self) # Visit a parse tree produced by COOL#assignment. def visitAssignment(self, ctx: COOL.AssignmentContext): varName = ctx.getChild(0).symbol.text option = self.ScopeManager.searchIdentifier(varName) - if option == 0: + if option == 0 and self.CurrentMethod != "None": return self.propertyAssignament(ctx) - elif option == 1: + elif option == 1 and self.CurrentMethod != "None": return self.formalAssignament(ctx) else: return self.variableAssignament(ctx) @@ -1558,17 +1716,20 @@ def formalAssignament(self, ctx: COOL.AssignmentContext): def variableAssignament(self, ctx: COOL.AssignmentContext): varName = ctx.getChild(0).symbol.text scope = self.ScopeManager.searchIdentifier(varName) - pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) - total = 0 - for scope in self.ScopeManager.Stack[2: pos]: - total += len(list(scope.keys())) - code = f"\tsw $a0 {(total + pos) * 4}($fp)\n" + pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) + 1 + init = 2 + if self.CurrentMethod == "None": + init = 0 + for scope in list(self.ScopeManager.Stack)[init: scope]: + pos += len(list(scope.keys())) + code = ctx.getChild(2).accept(self) + code += f"\tsw $a0 -{pos * 4}($fp)\n" return code # Visit a parse tree produced by COOL#false. def visitFalse(self, ctx: COOL.FalseContext): self.CurrentType = "Bool" - return f"\tla $a0 {bool_const0}\n" + return "\tla $a0 bool_const0\n" # Visit a parse tree produced by COOL#int. def visitInt(self, ctx: COOL.IntContext): @@ -1581,41 +1742,75 @@ def visitInt(self, ctx: COOL.IntContext): # Visit a parse tree produced by COOL#equal. def visitEqual(self, ctx: COOL.EqualContext): - return self.visitChildren(ctx) + code = ctx.getChild(0).accept(self) + code += \ + "\tsw $a0 0($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code += ctx.getChild(2).accept(self) + code += \ + "\tmove $t2 $a0\n" \ + "\tlw $t1 4($sp)\n" \ + "\taddiu $sp $sp 4\n" \ + "\tla $a0 bool_const1\n" \ + "\tla $a1 bool_const0\n" \ + "\tjal equality_test\n" + self.CurrentType = "Bool" + return code # Visit a parse tree produced by COOL#true. def visitTrue(self, ctx: COOL.TrueContext): self.CurrentType = "Bool" - return f"\tla $a0 bool_const1\n" + return "\tla $a0 bool_const1\n" # Visit a parse tree produced by COOL#lessEqual. def visitLessEqual(self, ctx: COOL.LessEqualContext): - return self.visitChildren(ctx) + code = ctx.getChild(0).accept(self) + code += \ + "\tsw $a0 0($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code += ctx.getChild(2).accept(self) + code += \ + "\tjal Object.copy\n" \ + "\tlw $t0 4($sp)\n" \ + "\tlw $t1 12($t0)\n" \ + "\tlw $t2 12($a0)\n" \ + "\tslt $t3 $t2 $t1\n" \ + "\tnegu $t4 $t3\n" \ + "\taddiu $t5 $t4 1\n" \ + "\tla $a0 bool_const0\n" \ + "\tjal Object.copy\n" \ + "\tsw $t5 12($a0)\n" \ + "\taddiu $sp $sp 4\n" + self.CurrentType = "Bool" + return code # Visit a parse tree produced by COOL#methodCall. def visitMethodCall(self, ctx: COOL.MethodCallContext): length = 5 - code = ctx.getChild(0).accept(self) or "" + methodPos = 2 + objCode = ctx.getChild(0).accept(self) + code = "" classId = self.CurrentType if ctx.getChild(1).symbol.text == "@": length += 2 + methodPos += 2 classId = ctx.getChild(2).symbol.text + count = methodPos + 2 if len(ctx.children) > length: - count = length - 1 + length = len(ctx.children) while length != count: param = (ctx.getChild(count).accept(self) or "") code += param + \ f"\tsw $a0 0($sp)\n" \ f"\taddiu $sp $sp -4\n" count = count + 2 - methodIdx = self.TypeTable[classId].TagMethods.index(ctx.getChild(length - 3).symbol.text) - self.CurrentType = self.searchMethodInfo(self.CurrentClass.Name, ctx.getChild(length - 3).symbol.text) - code += "\tmove $a0 $s0\n" \ - "\tlw $t1 8($a0)\n" \ - f"\tlw $t1 {methodIdx * 4}($t1)\n" \ - "\tjalr $t1\n" + methodIdx = self.TypeTable[classId].TagMethods.index(ctx.getChild(methodPos).symbol.text) + self.CurrentType = self.searchMethodInfo(classId, ctx.getChild(methodPos).symbol.text) + code += objCode + \ + "\tlw $t1 8($a0)\n" \ + f"\tlw $t1 {methodIdx * 4}($t1)\n" \ + "\tjalr $t1\n" return code - return "" RuntimeMessages = """ # diff --git a/tests/codegen/arith.cl b/tests/codegen/arith.cl index a1035961..9e7ce2c4 100755 --- a/tests/codegen/arith.cl +++ b/tests/codegen/arith.cl @@ -338,7 +338,13 @@ class Main inherits IO { main() : Object { { - avar <- (new A); + --avar <- (new A); + + avar <- (new C)@A.method5(avar.value()); + + -- print(avar); + +(* while flag loop { -- avar <- (new A).set_var(get_int()); @@ -423,7 +429,9 @@ class Main inherits IO { fi fi fi fi fi fi fi fi fi fi; } pool; +*) } + }; }; diff --git a/tests/codegen/atoi.cl b/tests/codegen/atoi.cl index fd8b2ea4..1ace1efb 100644 --- a/tests/codegen/atoi.cl +++ b/tests/codegen/atoi.cl @@ -13,9 +13,9 @@ something of type A2I, or simpl write (new A2I).method(argument). class A2I { c2i(char : String) : Int { - if char = "0" then 0 else - if char = "1" then 1 else - if char = "2" then 2 else + if char = "0" then 0 else + if char = "1" then 1 else + if char = "2" then 2 else if char = "3" then 3 else if char = "4" then 4 else if char = "5" then 5 else @@ -54,9 +54,13 @@ overflow. *) a2i(s : String) : Int { - if s.length() = 0 then 0 else - if s.substr(0,1) = "-" then ~a2i_aux(s.substr(1,s.length()-1)) else - if s.substr(0,1) = "+" then a2i_aux(s.substr(1,s.length()-1)) else + if s.length() = 0 then + 0 + else if s.substr(0,1) = "-" then + ~a2i_aux(s.substr(1,s.length()-1)) + else if s.substr(0,1) = "+" then + a2i_aux(s.substr(1,s.length()-1)) + else a2i_aux(s) fi fi fi }; @@ -66,21 +70,17 @@ overflow. example, this method is written iteratively. *) a2i_aux(s : String) : Int { - (let int : Int <- 0 in - { - (let j : Int <- s.length() in - (let i : Int <- 0 in - while i < j loop - { - int <- int * 10 + c2i(s.substr(i,1)); - i <- i + 1; - } - pool - ) - ); - int; - } - ) + (let int : Int <- 0 in { + (let j : Int <- s.length() in + (let i : Int <- 0 in + while i < j loop { + int <- int * 10 + c2i(s.substr(i,1)); + i <- i + 1; + } pool + ) + ); + int; + }) }; (* @@ -108,14 +108,35 @@ numbers are handled correctly. }; class Main inherits IO { - main () : Object { - let a : Int <- (new A2I).a2i("678987"), - b : String <- (new A2I).i2a(678987) in + + c2i(char : String) : Int { + if char = "0" then 0 else + if char = "1" then 1 else + if char = "2" then 2 else + if char = "3" then 3 else + if char = "4" then 4 else + if char = "5" then 5 else + if char = "6" then 6 else + if char = "7" then 7 else + if char = "8" then 8 else + if char = "9" then 9 else + { abort(); 0; } -- the 0 is needed to satisfy the typchecker + fi fi fi fi fi fi fi fi fi fi + }; + + counter : Int <- 0; + + main () : Object { { + + let a : Int <- (new A2I).a2i("678987"), + b : String <- (new A2I).i2a(678987) in { out_int(a) ; out_string(" == ") ; out_string(b) ; - out_string("\n"); - } + out_string("\n"); + }; + + } } ; } ; diff --git a/tests/codegen/hello_world.cl b/tests/codegen/hello_world.cl index 7cefd7a3..ce2679b0 100755 --- a/tests/codegen/hello_world.cl +++ b/tests/codegen/hello_world.cl @@ -1,6 +1,7 @@ class Main inherits IO { - x : Int <- 1; + x : Int <- let x : Int <- 5, y : Int <- 4 in (x + y); + y : Bool <- true; sqrt (x : Int) : Int { x * x @@ -8,13 +9,14 @@ class Main inherits IO { main(): IO { { - out_string("Hello, World ("); - out_int(x * 2); - x <- 0 -7; - x <- sqrt(x); - out_string(", "); + (*while x < 10 loop{ out_int(x); - out_string(").\n"); + out_string("\n"); + x <- x + 1; + } pool;*) + case x of y : Int => y <- 10 ;esac; + out_int(x); + } }; }; From 046088fa8fd82a1efb23677193b70a7ea8b93b8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 02:10:16 -0500 Subject: [PATCH 22/77] Se depuro la generacion de codigo usando los ejemplos de la definicion de COOL que cubren todo el espectro de instrucciones --- src/Visitors.py | 118 +++++++++++++++++------------- tests/codegen/arith.cl | 151 ++++++++++++++++++--------------------- tests/codegen/complex.cl | 8 +-- 3 files changed, 141 insertions(+), 136 deletions(-) diff --git a/src/Visitors.py b/src/Visitors.py index 9de9207e..ceb20b22 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -13,7 +13,7 @@ def __init__(self, name: str, parent: str, created: bool, sealed: bool): self.Methods = {} self.VisitedMethods = list() self.VisitedAtributes = list() - self.TagMethods = list() + self.TagMethods = {} self.Atributes = {} self.Tag = 0 self.TagAtributes = list() @@ -260,7 +260,10 @@ def visitMethod(self, ctx:COOL.MethodContext): ctx.getChild(i).accept(self) i += 2 methodValue = ctx.getChild(len(ctx.children) - 2).accept(self) - if self.join(methodType.text, methodValue) != methodType.text: + mType = methodType.text + if mType == "SELF_TYPE": + mType = coolClass + if self.join(mType, methodValue) !=mType: line = str(ctx.getChild(len(ctx.children) - 2).start.line) column = str(ctx.getChild(len(ctx.children) - 2).start.column + 1) error = f"({line}, {column}) - TypeError: Inferred return type {methodValue} of method {methodName} does not conform to declared return type {methodType.text}." @@ -847,11 +850,11 @@ def visitProgram(self, ctx: COOL.ProgramContext, fileName: str): self.TypeTable["IO"].Methods["out_string"].Params.append(("x", "String")) self.TypeTable["IO"].Methods["out_int"] = COOLMethod("out_int", "SELF_TYPE", 1, None) self.TypeTable["IO"].Methods["out_int"].Params.append(("x", "Int")) - self.ConstantTable.append(("", "String", "str_const0")) + self.ConstantTable.append(("", "String", "string_const0")) self.ConstantTable.append((0, "Int", "int_const0")) self.ConstantTable.append(("false", "Bool", "bool_const0")) self.ConstantTable.append(("true", "Bool", "bool_const1")) - self.ConstantTable.append((fileName, "String", "str_const1")) + self.ConstantTable.append((fileName, "String", "string_const1")) self.ConstantTable.append((len(fileName), "Int", F"int_const{len(fileName)}")) self.Counter = 2 return self.visitChildren(ctx) @@ -934,7 +937,7 @@ def visitString(self, ctx: COOL.StringContext): if consName == constantName and consType == "String": return self.visitChildren(ctx) - self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) + self.ConstantTable.append((constantName, "String", f"string_const{self.Counter}")) self.Counter = self.Counter + 1 length = len(constantName) for cons in self.ConstantTable: @@ -1140,25 +1143,19 @@ def findLabel(self, name: str): if constName == name and constType == "String": return constLabel - def genMethodNames(self, coolClass: str, coolMethods: list, className: str): - if coolClass == "None": - return "" - temp = "" - for method in self.TypeTable[coolClass].Methods: - if not (coolMethods.__contains__(method)): - temp = temp + f"\t.word {coolClass}.{method}\n" - coolMethods.append(method) + def genMethodNames(self, coolClass: str): + code = "" + for method in self.TypeTable[coolClass].TagMethods.values(): + code += f"\t.word {method}\n" - code = self.genMethodNames(self.TypeTable[coolClass].Parent, coolMethods, className) - return code + temp + return code - def genMethodTags(self, coolClass: str, coolMethods: list, className: str): + def genMethodTags(self, coolClass: str, coolMethods: dict): if coolClass == "None": return coolMethods - coolMethods = self.genMethodTags(self.TypeTable[coolClass].Parent, coolMethods, className) + coolMethods = self.genMethodTags(self.TypeTable[coolClass].Parent, coolMethods,) for method in self.TypeTable[coolClass].Methods: - if not (coolMethods.__contains__(method)): - coolMethods.append(method) + coolMethods[method] = f"{coolClass}.{method}" return coolMethods def genAtributeNames(self, coolClass: str, coolAtributes: list): @@ -1189,7 +1186,7 @@ def genClassTable(self): counter = 0 for className in self.TypeTable: classNameTab = classNameTab + f"\t.word {self.findLabel(className)}\n" - temp = self.genMethodNames(className, list(), className) + temp = self.genMethodNames(className) class_objTab = class_objTab + \ f"\t.word {className}_protObj\n" \ f"\t.word {className}_init\n" @@ -1239,7 +1236,7 @@ def genClassAtributes(self, className: str): def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): for className in self.TypeTable: constantName = className - self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) + self.ConstantTable.append((constantName, "String", f"string_const{self.Counter}")) self.Counter = self.Counter + 1 length = len(constantName) contain = True @@ -1249,8 +1246,8 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): contain = False if contain: self.ConstantTable.append((length, "Int", f"int_const{length}")) - self.TypeTable[className].TagMethods = self.genMethodTags(className,list(),className) - self.ConstantTable.append(("SELF_TYPE", "String", f"str_const{self.Counter}")) + self.TypeTable[className].TagMethods = self.genMethodTags(className,{}) + self.ConstantTable.append(("SELF_TYPE", "String", f"string_const{self.Counter}")) contain = True length = len("SELF_TYPE") for cons in self.ConstantTable: @@ -1276,6 +1273,10 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): self.CurrentClass = self.TypeTable[className] self.CurrentType = className self.CurrentMethod = "None" + self.CurrentClass = self.TypeTable[className] + self.ScopeManager.addScope() + for atribute in self.CurrentClass.TagAtributes: + self.ScopeManager.addIdentifier(atribute, self.searchAtributeInfo(className, atribute)) code = code + f"{className}_init:\n" temp = self.genClassAtributes(className) if len(temp) != 0: @@ -1294,12 +1295,13 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): "\tlw $ra 4($sp)\n" \ "\taddiu $sp $sp 12\n" code = code + "\tjr $ra\n" + self.ScopeManager.deleteScope() for className in self.TypeTable: if not(className == "Object" or className == "String" or className == "Int" or className == "Bool" or className == "IO"): self.CurrentClass = self.TypeTable[className] self.ScopeManager.addScope() for atribute in self.CurrentClass.TagAtributes: - self.ScopeManager.addIdentifier(atribute,self.searchAtributeInfo(className, atribute)) + self.ScopeManager.addIdentifier(atribute, self.searchAtributeInfo(className, atribute)) for methodName in self.CurrentClass.Methods: self.CurrentMethod = self.CurrentClass.Methods[methodName] self.CurrentType = self.CurrentMethod.Type @@ -1430,17 +1432,18 @@ def visitIsvoid(self, ctx: COOL.IsvoidContext): # Visit a parse tree produced by COOL#while. def visitWhile(self, ctx: COOL.WhileContext): - code = f"while_label{self.Counter}:\n" + labelCounter = self.Counter + self.Counter += 1 + code = f"while_label{labelCounter}:\n" code += ctx.getChild(1).accept(self) code += "\tlw $t1 12($a0)\n" + \ - f"\tbgtz $t1 loop_label{self.Counter}\n" + \ - f"\tb pool_label{self.Counter}\n" + \ - f"loop_label{self.Counter}:\n" + f"\tbgtz $t1 loop_label{labelCounter}\n" + \ + f"\tb pool_label{labelCounter}\n" + \ + f"loop_label{labelCounter}:\n" code += ctx.getChild(3).accept(self) - code += f"\tb while_label{self.Counter}\n" + \ - f"pool_label{self.Counter}:\n" + code += f"\tb while_label{labelCounter}\n" + \ + f"pool_label{labelCounter}:\n" self.CurrentType = "None" - self.Counter += 1 return code # Visit a parse tree produced by COOL#division. @@ -1469,21 +1472,19 @@ def visitNegative(self, ctx: COOL.NegativeContext): "\tjal Object.copy\n" \ "\tlw $t1 12($a0)\n" \ "\tnegu $t1 $t1\n" \ - "\tsw $t1 12($a0)\n" \ - "\tsw $a0 0($sp)\n" + "\tsw $t1 12($a0)\n" return code # Visit a parse tree produced by COOL#boolNot. def visitBoolNot(self, ctx: COOL.BoolNotContext): - self.CurrentType = "Bool" code = ctx.getChild(1).accept(self) code += \ "\tjal Object.copy\n" \ "\tlw $t1 12($a0)\n" \ "\tnegu $t2 $t1\n" \ - "\taddiu $t3 $t2 1\n"\ - "\tsw $t3 12($a0)\n" \ - "\tsw $a0 0($sp)\n" + "\taddiu $t1 $t2 1\n" \ + "\tsw $t1 12($a0)\n" + self.CurrentType = "Bool" return code # Visit a parse tree produced by COOL#lessThan. @@ -1521,10 +1522,10 @@ def visitId(self, ctx: COOL.IdContext): varName = ctx.getChild(0).symbol.text if varName == "self": self.CurrentType = self.CurrentClass.Name - return "\tlw $a0 ($s0)\n" + return "\tmove $a0 $s0\n" self.CurrentType = self.ScopeManager.searchType(varName) option = self.ScopeManager.searchIdentifier(varName) - if option == 0 and self.CurrentMethod != "None": + if option == 0: return self.propertyId(ctx) elif option == 1 and self.CurrentMethod != "None": return self.formalId(ctx) @@ -1588,6 +1589,8 @@ def visitIf(self, ctx: COOL.IfContext): ctx.getChild(3).accept(self) + \ f"\tb fi_label{counter}\n" + \ f"else_label{counter}:\n" + if self.CurrentType == "SELF_TYPE": + self.CurrentType = self.CurrentClass.Name tempType = self.CurrentType code = code +\ ctx.getChild(5).accept(self) + \ @@ -1614,6 +1617,8 @@ def visitCase(self, ctx: COOL.CaseContext): count = count + 2 self.ScopeManager.addScope() self.ScopeManager.addIdentifier(idName, idType) + if idType == "Object": + code += f"\tb {idType}_case{counter}\n" code += \ f"\tlw $t1 0($a0)\n" \ f"\tli $t2 {self.TypeTable[idType].Tag}\n" \ @@ -1650,7 +1655,7 @@ def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): f"\tsw $a0 0($sp)\n" \ f"\taddiu $sp $sp -4\n" count = count + 2 - methodIdx = self.CurrentClass.TagMethods.index(ctx.getChild(0).symbol.text) + methodIdx = list(self.CurrentClass.TagMethods).index(ctx.getChild(0).symbol.text) self.CurrentType = self.searchMethodInfo(self.CurrentClass.Name, ctx.getChild(0).symbol.text) code += "\tmove $a0 $s0\n" \ "\tlw $t1 8($a0)\n" \ @@ -1690,7 +1695,7 @@ def visitParentheses(self, ctx: COOL.ParenthesesContext): def visitAssignment(self, ctx: COOL.AssignmentContext): varName = ctx.getChild(0).symbol.text option = self.ScopeManager.searchIdentifier(varName) - if option == 0 and self.CurrentMethod != "None": + if option == 0: return self.propertyAssignament(ctx) elif option == 1 and self.CurrentMethod != "None": return self.formalAssignament(ctx) @@ -1710,7 +1715,7 @@ def formalAssignament(self, ctx: COOL.AssignmentContext): varType = self.ScopeManager.Stack[1][varName] pos = self.CurrentMethod.Params.index((varName, varType)) total = self.CurrentMethod.ParamsNumber - code = code + f"\tsw $a0 {(pos - (total + 2)) * 4}($fp)\n" + code = code + f"\tsw $a0 {((total + 2) - pos) * 4}($fp)\n" return code def variableAssignament(self, ctx: COOL.AssignmentContext): @@ -1750,10 +1755,15 @@ def visitEqual(self, ctx: COOL.EqualContext): code += \ "\tmove $t2 $a0\n" \ "\tlw $t1 4($sp)\n" \ - "\taddiu $sp $sp 4\n" \ + "\taddiu $sp $sp 4\n"\ "\tla $a0 bool_const1\n" \ - "\tla $a1 bool_const0\n" \ - "\tjal equality_test\n" + "\tla $a1 bool_const0\n" + if self.CurrentType == "String" or self.CurrentType == "Int" or self.CurrentType == "Bool": + code += "\tjal equality_test\n" + else: + code += \ + "\tsub $t3 $t2 $t1\n"\ + "\tmovn $a0 $a1 $t3\n" self.CurrentType = "Bool" return code @@ -1790,6 +1800,8 @@ def visitMethodCall(self, ctx: COOL.MethodCallContext): methodPos = 2 objCode = ctx.getChild(0).accept(self) code = "" + if self.CurrentType == "SELF_TYPE": + self.CurrentType = self.CurrentClass.Name classId = self.CurrentType if ctx.getChild(1).symbol.text == "@": length += 2 @@ -1804,12 +1816,18 @@ def visitMethodCall(self, ctx: COOL.MethodCallContext): f"\tsw $a0 0($sp)\n" \ f"\taddiu $sp $sp -4\n" count = count + 2 - methodIdx = self.TypeTable[classId].TagMethods.index(ctx.getChild(methodPos).symbol.text) + methodIdx = list(self.TypeTable[classId].TagMethods).index(ctx.getChild(methodPos).symbol.text) self.CurrentType = self.searchMethodInfo(classId, ctx.getChild(methodPos).symbol.text) - code += objCode + \ - "\tlw $t1 8($a0)\n" \ - f"\tlw $t1 {methodIdx * 4}($t1)\n" \ - "\tjalr $t1\n" + if ctx.getChild(1).symbol.text == "@": + code += objCode + \ + f"\tla $t1 {classId}_dispTab\n" \ + f"\tlw $t1 {methodIdx * 4}($t1)\n" \ + "\tjalr $t1\n" + else: + code += objCode + \ + f"\tlw $t1 8($a0)\n" \ + f"\tlw $t1 {methodIdx * 4}($t1)\n" \ + "\tjalr $t1\n" return code RuntimeMessages = """ diff --git a/tests/codegen/arith.cl b/tests/codegen/arith.cl index 9e7ce2c4..91f08cfc 100755 --- a/tests/codegen/arith.cl +++ b/tests/codegen/arith.cl @@ -318,12 +318,12 @@ class Main inherits IO { class_type(var : A) : IO { case var of - a : A => out_string("Class type is now A\n"); - b : B => out_string("Class type is now B\n"); - c : C => out_string("Class type is now C\n"); - d : D => out_string("Class type is now D\n"); - e : E => out_string("Class type is now E\n"); - o : Object => out_string("Oooops\n"); + a : A => out_string("Class type is now A\n"); + b : B => out_string("Class type is now B\n"); + c : C => out_string("Class type is now C\n"); + d : D => out_string("Class type is now D\n"); + e : E => out_string("Class type is now E\n"); + o : Object => out_string("Oooops\n"); esac }; @@ -338,16 +338,10 @@ class Main inherits IO { main() : Object { { - --avar <- (new A); + avar <- (new A); - avar <- (new C)@A.method5(avar.value()); + while flag loop { - -- print(avar); - -(* - while flag loop - { - -- avar <- (new A).set_var(get_int()); out_string("number "); print(avar); if is_even(avar.value()) then @@ -355,83 +349,76 @@ class Main inherits IO { else out_string("is odd!\n") fi; - -- print(avar); -- prints out answer + class_type(avar); + char <- menu(); - if char = "a" then -- add - { - a_var <- (new A).set_var(get_int()); - avar <- (new B).method2(avar.value(), a_var.value()); - } else - if char = "b" then -- negate - case avar of - c : C => avar <- c.method6(c.value()); - a : A => avar <- a.method3(a.value()); - o : Object => { - out_string("Oooops\n"); - abort(); 0; - }; - esac else - if char = "c" then -- diff - { - a_var <- (new A).set_var(get_int()); - avar <- (new D).method4(avar.value(), a_var.value()); - } else - if char = "d" then avar <- (new C)@A.method5(avar.value()) else - -- factorial - if char = "e" then avar <- (new C)@B.method5(avar.value()) else - -- square - if char = "f" then avar <- (new C)@C.method5(avar.value()) else - -- cube - if char = "g" then -- multiple of 3? - if ((new D).method7(avar.value())) - then -- avar <- (new A).method1(avar.value()) + if char = "a" then -- add + { + a_var <- (new A).set_var(get_int()); + avar <- (new B).method2(avar.value(), a_var.value()); + } + else if char = "b" then -- negate + case avar of + c : C => avar <- c.method6(c.value()); + a : A => avar <- a.method3(a.value()); + o : Object => { + out_string("Oooops\n"); + abort(); 0; + }; + esac + else if char = "c" then -- diff + { + a_var <- (new A).set_var(get_int()); + avar <- (new D).method4(avar.value(), a_var.value()); + } + else if char = "d" then + avar <- (new C)@A.method5(avar.value()) -- factorial + else if char = "e" then + avar <- (new C)@B.method5(avar.value()) -- square + else if char = "f" then + avar <- (new C)@C.method5(avar.value()) -- cube + else if char = "g" then -- multiple of 3? + if ((new D).method7(avar.value())) then { - out_string("number "); - print(avar); - out_string("is divisible by 3.\n"); + out_string("number "); + print(avar); + out_string("is divisible by 3.\n"); } - else -- avar <- (new A).set_var(0) + else { - out_string("number "); - print(avar); - out_string("is not divisible by 3.\n"); - } - fi else - if char = "h" then - (let x : A in - { - x <- (new E).method6(avar.value()); + out_string("number "); + print(avar); + out_string("is not divisible by 3.\n"); + } fi + else if char = "h" then + (let x : A in { + x <- (new E).method6(avar.value()); (let r : Int <- (avar.value() - (x.value() * 8)) in - { - out_string("number "); - print(avar); - out_string("is equal to "); - print(x); - out_string("times 8 with a remainder of "); - (let a : A2I <- new A2I in - { - out_string(a.i2a(r)); - out_string("\n"); - } - ); -- end let a: - } - ); -- end let r: + { + out_string("number "); + print(avar); + out_string("is equal to "); + print(x); + out_string("times 8 with a remainder of "); + (let a : A2I <- new A2I in + { + out_string(a.i2a(r)); + out_string("\n"); + }); -- end let a: + }); -- end let r: avar <- x; - } - ) -- end let x: - else - if char = "j" then avar <- (new A) - else - if char = "q" then flag <- false - else - avar <- (new A).method1(avar.value()) -- divide/8 - fi fi fi fi fi fi fi fi fi fi; - } + }) -- end let x: + else if char = "j" then + avar <- (new A) + else if char = "q" then + flag <- false + else + avar <- (new A).method1(avar.value()) -- divide/8 + fi fi fi fi fi fi fi fi fi fi; + } pool; -*) } - }; }; diff --git a/tests/codegen/complex.cl b/tests/codegen/complex.cl index bad142df..20c0e7d4 100755 --- a/tests/codegen/complex.cl +++ b/tests/codegen/complex.cl @@ -19,22 +19,22 @@ class Complex inherits IO { reflect_0() : Complex { { - x = ~x; - y = ~y; + x <- ~x; + y <- ~y; self; } }; reflect_X() : Complex { { - y = ~y; + y <- ~y; self; } }; reflect_Y() : Complex { { - x = ~x; + x <- ~x; self; } }; From ec24a5a7fcc08881ddbea41147cca7f6299c6b8f Mon Sep 17 00:00:00 2001 From: LSilvaO Date: Wed, 26 Feb 2020 10:55:32 -0500 Subject: [PATCH 23/77] Primera entrega lexer y parser --- doc/Readme.md | 6 +- src/COOL.interp | 111 ++ src/COOL.tokens | 68 + src/COOLCompiler.py | 15 + src/COOLLexer.interp | 178 ++ src/COOLLexer.py | 267 +++ src/COOLLexer.tokens | 68 + src/COOLListener.py | 298 ++++ src/COOLParser.py | 1757 +++++++++++++++++++ src/antlr4/BufferedTokenStream.py | 303 ++++ src/antlr4/CommonTokenFactory.py | 59 + src/antlr4/CommonTokenStream.py | 86 + src/antlr4/FileStream.py | 34 + src/antlr4/InputStream.py | 104 ++ src/antlr4/IntervalSet.py | 282 +++ src/antlr4/LL1Analyzer.py | 172 ++ src/antlr4/Lexer.py | 321 ++++ src/antlr4/ListTokenSource.py | 143 ++ src/antlr4/Parser.py | 572 ++++++ src/antlr4/ParserInterpreter.py | 165 ++ src/antlr4/ParserRuleContext.py | 186 ++ src/antlr4/PredictionContext.py | 623 +++++++ src/antlr4/Recognizer.py | 160 ++ src/antlr4/RuleContext.py | 228 +++ src/antlr4/StdinStream.py | 11 + src/antlr4/Token.py | 155 ++ src/antlr4/TokenStreamRewriter.py | 237 +++ src/antlr4/Utils.py | 33 + src/antlr4/__init__.py | 21 + src/antlr4/atn/ATN.py | 127 ++ src/antlr4/atn/ATNConfig.py | 154 ++ src/antlr4/atn/ATNConfigSet.py | 209 +++ src/antlr4/atn/ATNDeserializationOptions.py | 24 + src/antlr4/atn/ATNDeserializer.py | 528 ++++++ src/antlr4/atn/ATNSimulator.py | 47 + src/antlr4/atn/ATNState.py | 254 +++ src/antlr4/atn/ATNType.py | 17 + src/antlr4/atn/LexerATNSimulator.py | 568 ++++++ src/antlr4/atn/LexerAction.py | 291 +++ src/antlr4/atn/LexerActionExecutor.py | 142 ++ src/antlr4/atn/ParserATNSimulator.py | 1649 +++++++++++++++++ src/antlr4/atn/PredictionMode.py | 499 ++++++ src/antlr4/atn/SemanticContext.py | 320 ++++ src/antlr4/atn/Transition.py | 257 +++ src/antlr4/atn/__init__.py | 1 + src/antlr4/dfa/DFA.py | 133 ++ src/antlr4/dfa/DFASerializer.py | 72 + src/antlr4/dfa/DFAState.py | 120 ++ src/antlr4/dfa/__init__.py | 1 + src/antlr4/error/DiagnosticErrorListener.py | 107 ++ src/antlr4/error/ErrorListener.py | 73 + src/antlr4/error/ErrorStrategy.py | 698 ++++++++ src/antlr4/error/Errors.py | 172 ++ src/antlr4/error/__init__.py | 1 + src/antlr4/tree/Chunk.py | 29 + src/antlr4/tree/ParseTreeMatch.py | 118 ++ src/antlr4/tree/ParseTreePattern.py | 71 + src/antlr4/tree/ParseTreePatternMatcher.py | 373 ++++ src/antlr4/tree/RuleTagToken.py | 49 + src/antlr4/tree/TokenTagToken.py | 47 + src/antlr4/tree/Tree.py | 170 ++ src/antlr4/tree/Trees.py | 111 ++ src/antlr4/tree/__init__.py | 0 src/antlr4/xpath/XPath.py | 343 ++++ src/antlr4/xpath/__init__.py | 1 + src/coolc.sh | 5 +- 66 files changed, 14439 insertions(+), 5 deletions(-) create mode 100644 src/COOL.interp create mode 100644 src/COOL.tokens create mode 100644 src/COOLCompiler.py create mode 100644 src/COOLLexer.interp create mode 100644 src/COOLLexer.py create mode 100644 src/COOLLexer.tokens create mode 100644 src/COOLListener.py create mode 100644 src/COOLParser.py create mode 100644 src/antlr4/BufferedTokenStream.py create mode 100644 src/antlr4/CommonTokenFactory.py create mode 100644 src/antlr4/CommonTokenStream.py create mode 100644 src/antlr4/FileStream.py create mode 100644 src/antlr4/InputStream.py create mode 100644 src/antlr4/IntervalSet.py create mode 100644 src/antlr4/LL1Analyzer.py create mode 100644 src/antlr4/Lexer.py create mode 100644 src/antlr4/ListTokenSource.py create mode 100644 src/antlr4/Parser.py create mode 100644 src/antlr4/ParserInterpreter.py create mode 100644 src/antlr4/ParserRuleContext.py create mode 100644 src/antlr4/PredictionContext.py create mode 100644 src/antlr4/Recognizer.py create mode 100644 src/antlr4/RuleContext.py create mode 100644 src/antlr4/StdinStream.py create mode 100644 src/antlr4/Token.py create mode 100644 src/antlr4/TokenStreamRewriter.py create mode 100644 src/antlr4/Utils.py create mode 100644 src/antlr4/__init__.py create mode 100644 src/antlr4/atn/ATN.py create mode 100644 src/antlr4/atn/ATNConfig.py create mode 100644 src/antlr4/atn/ATNConfigSet.py create mode 100644 src/antlr4/atn/ATNDeserializationOptions.py create mode 100644 src/antlr4/atn/ATNDeserializer.py create mode 100644 src/antlr4/atn/ATNSimulator.py create mode 100644 src/antlr4/atn/ATNState.py create mode 100644 src/antlr4/atn/ATNType.py create mode 100644 src/antlr4/atn/LexerATNSimulator.py create mode 100644 src/antlr4/atn/LexerAction.py create mode 100644 src/antlr4/atn/LexerActionExecutor.py create mode 100644 src/antlr4/atn/ParserATNSimulator.py create mode 100644 src/antlr4/atn/PredictionMode.py create mode 100644 src/antlr4/atn/SemanticContext.py create mode 100644 src/antlr4/atn/Transition.py create mode 100644 src/antlr4/atn/__init__.py create mode 100644 src/antlr4/dfa/DFA.py create mode 100644 src/antlr4/dfa/DFASerializer.py create mode 100644 src/antlr4/dfa/DFAState.py create mode 100644 src/antlr4/dfa/__init__.py create mode 100644 src/antlr4/error/DiagnosticErrorListener.py create mode 100644 src/antlr4/error/ErrorListener.py create mode 100644 src/antlr4/error/ErrorStrategy.py create mode 100644 src/antlr4/error/Errors.py create mode 100644 src/antlr4/error/__init__.py create mode 100644 src/antlr4/tree/Chunk.py create mode 100644 src/antlr4/tree/ParseTreeMatch.py create mode 100644 src/antlr4/tree/ParseTreePattern.py create mode 100644 src/antlr4/tree/ParseTreePatternMatcher.py create mode 100644 src/antlr4/tree/RuleTagToken.py create mode 100644 src/antlr4/tree/TokenTagToken.py create mode 100644 src/antlr4/tree/Tree.py create mode 100644 src/antlr4/tree/Trees.py create mode 100644 src/antlr4/tree/__init__.py create mode 100644 src/antlr4/xpath/XPath.py create mode 100644 src/antlr4/xpath/__init__.py diff --git a/doc/Readme.md b/doc/Readme.md index 402477c8..59c61e34 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -4,9 +4,9 @@ **Nombre** | **Grupo** | **Github** --|--|-- -Nombre1 Apellido1 Apellido2 | C4xx | [@github_user](https://github.com/) -Nombre2 Apellido1 Apellido2 | C4xx | [@github_user](https://github.com/) -Nombre3 Apellido1 Apellido2 | C4xx | [@github_user](https://github.com/) +Liset Silva Oropesa | C411 | [@github_user](https://github.com/) +Pablo Antonio de Armas Suarez | C411 | [@github_user](https://github.com/) +Yenli Gil Machado | C412 | [@github_user](https://github.com/) ## Readme diff --git a/src/COOL.interp b/src/COOL.interp new file mode 100644 index 00000000..f2d42957 --- /dev/null +++ b/src/COOL.interp @@ -0,0 +1,111 @@ +token literal names: +null +';' +'{' +'}' +'(' +',' +')' +':' +'@' +'.' +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +'<-' +'=>' +'+' +'-' +'*' +'/' +'<' +'<=' +'=' +'~' +'(*' +'*)' +null +null +null + +token symbolic names: +null +null +null +null +null +null +null +null +null +null +CLASS +ELSE +FALSE +FI +IF +IN +INHERITS +ISVOID +LET +LOOP +POOL +THEN +WHILE +CASE +ESAC +NEW +OF +NOT +TRUE +STRING +INT +TYPEID +OBJECTID +ASSIGNMENT +CASE_ARROW +ADD +MINUS +MULTIPLY +DIVISION +LESS_THAN +LESS_EQUAL +EQUAL +INTEGER_NEGATIVE +OPEN_COMMENT +CLOSE_COMMENT +COMMENT +ONE_LINE_COMMENT +WHITESPACE + +rule names: +program +programBlocks +classDefine +feature +formal +expression + + +atn: +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 49, 226, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 22, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 28, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 34, 10, 4, 12, 4, 14, 4, 37, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 46, 10, 5, 12, 5, 14, 5, 49, 11, 5, 7, 5, 51, 10, 5, 12, 5, 14, 5, 54, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 68, 10, 5, 5, 5, 70, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 82, 10, 7, 12, 7, 14, 7, 85, 11, 7, 7, 7, 87, 10, 7, 12, 7, 14, 7, 90, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 111, 10, 7, 13, 7, 14, 7, 112, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 123, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 131, 10, 7, 7, 7, 133, 10, 7, 12, 7, 14, 7, 136, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 150, 10, 7, 13, 7, 14, 7, 151, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 176, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 202, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 210, 10, 7, 12, 7, 14, 7, 213, 11, 7, 7, 7, 215, 10, 7, 12, 7, 14, 7, 218, 11, 7, 3, 7, 7, 7, 221, 10, 7, 12, 7, 14, 7, 224, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 260, 2, 14, 3, 2, 2, 2, 4, 21, 3, 2, 2, 2, 6, 23, 3, 2, 2, 2, 8, 69, 3, 2, 2, 2, 10, 71, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 3, 3, 2, 2, 2, 16, 17, 5, 6, 4, 2, 17, 18, 7, 3, 2, 2, 18, 19, 5, 4, 3, 2, 19, 22, 3, 2, 2, 2, 20, 22, 7, 2, 2, 3, 21, 16, 3, 2, 2, 2, 21, 20, 3, 2, 2, 2, 22, 5, 3, 2, 2, 2, 23, 24, 7, 12, 2, 2, 24, 27, 7, 33, 2, 2, 25, 26, 7, 18, 2, 2, 26, 28, 7, 33, 2, 2, 27, 25, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 29, 3, 2, 2, 2, 29, 35, 7, 4, 2, 2, 30, 31, 5, 8, 5, 2, 31, 32, 7, 3, 2, 2, 32, 34, 3, 2, 2, 2, 33, 30, 3, 2, 2, 2, 34, 37, 3, 2, 2, 2, 35, 33, 3, 2, 2, 2, 35, 36, 3, 2, 2, 2, 36, 38, 3, 2, 2, 2, 37, 35, 3, 2, 2, 2, 38, 39, 7, 5, 2, 2, 39, 7, 3, 2, 2, 2, 40, 41, 7, 34, 2, 2, 41, 52, 7, 6, 2, 2, 42, 47, 5, 10, 6, 2, 43, 44, 7, 7, 2, 2, 44, 46, 5, 10, 6, 2, 45, 43, 3, 2, 2, 2, 46, 49, 3, 2, 2, 2, 47, 45, 3, 2, 2, 2, 47, 48, 3, 2, 2, 2, 48, 51, 3, 2, 2, 2, 49, 47, 3, 2, 2, 2, 50, 42, 3, 2, 2, 2, 51, 54, 3, 2, 2, 2, 52, 50, 3, 2, 2, 2, 52, 53, 3, 2, 2, 2, 53, 55, 3, 2, 2, 2, 54, 52, 3, 2, 2, 2, 55, 56, 7, 8, 2, 2, 56, 57, 7, 9, 2, 2, 57, 58, 7, 33, 2, 2, 58, 59, 7, 4, 2, 2, 59, 60, 5, 12, 7, 2, 60, 61, 7, 5, 2, 2, 61, 70, 3, 2, 2, 2, 62, 63, 7, 34, 2, 2, 63, 64, 7, 9, 2, 2, 64, 67, 7, 33, 2, 2, 65, 66, 7, 35, 2, 2, 66, 68, 5, 12, 7, 2, 67, 65, 3, 2, 2, 2, 67, 68, 3, 2, 2, 2, 68, 70, 3, 2, 2, 2, 69, 40, 3, 2, 2, 2, 69, 62, 3, 2, 2, 2, 70, 9, 3, 2, 2, 2, 71, 72, 7, 34, 2, 2, 72, 73, 7, 9, 2, 2, 73, 74, 7, 33, 2, 2, 74, 11, 3, 2, 2, 2, 75, 76, 8, 7, 1, 2, 76, 77, 7, 34, 2, 2, 77, 88, 7, 6, 2, 2, 78, 83, 5, 12, 7, 2, 79, 80, 7, 7, 2, 2, 80, 82, 5, 12, 7, 2, 81, 79, 3, 2, 2, 2, 82, 85, 3, 2, 2, 2, 83, 81, 3, 2, 2, 2, 83, 84, 3, 2, 2, 2, 84, 87, 3, 2, 2, 2, 85, 83, 3, 2, 2, 2, 86, 78, 3, 2, 2, 2, 87, 90, 3, 2, 2, 2, 88, 86, 3, 2, 2, 2, 88, 89, 3, 2, 2, 2, 89, 91, 3, 2, 2, 2, 90, 88, 3, 2, 2, 2, 91, 176, 7, 8, 2, 2, 92, 93, 7, 16, 2, 2, 93, 94, 5, 12, 7, 2, 94, 95, 7, 23, 2, 2, 95, 96, 5, 12, 7, 2, 96, 97, 7, 13, 2, 2, 97, 98, 5, 12, 7, 2, 98, 99, 7, 15, 2, 2, 99, 176, 3, 2, 2, 2, 100, 101, 7, 24, 2, 2, 101, 102, 5, 12, 7, 2, 102, 103, 7, 21, 2, 2, 103, 104, 5, 12, 7, 2, 104, 105, 7, 22, 2, 2, 105, 176, 3, 2, 2, 2, 106, 110, 7, 4, 2, 2, 107, 108, 5, 12, 7, 2, 108, 109, 7, 3, 2, 2, 109, 111, 3, 2, 2, 2, 110, 107, 3, 2, 2, 2, 111, 112, 3, 2, 2, 2, 112, 110, 3, 2, 2, 2, 112, 113, 3, 2, 2, 2, 113, 114, 3, 2, 2, 2, 114, 115, 7, 5, 2, 2, 115, 176, 3, 2, 2, 2, 116, 117, 7, 20, 2, 2, 117, 118, 7, 34, 2, 2, 118, 119, 7, 9, 2, 2, 119, 122, 7, 33, 2, 2, 120, 121, 7, 35, 2, 2, 121, 123, 5, 12, 7, 2, 122, 120, 3, 2, 2, 2, 122, 123, 3, 2, 2, 2, 123, 134, 3, 2, 2, 2, 124, 125, 7, 7, 2, 2, 125, 126, 7, 34, 2, 2, 126, 127, 7, 9, 2, 2, 127, 130, 7, 33, 2, 2, 128, 129, 7, 35, 2, 2, 129, 131, 5, 12, 7, 2, 130, 128, 3, 2, 2, 2, 130, 131, 3, 2, 2, 2, 131, 133, 3, 2, 2, 2, 132, 124, 3, 2, 2, 2, 133, 136, 3, 2, 2, 2, 134, 132, 3, 2, 2, 2, 134, 135, 3, 2, 2, 2, 135, 137, 3, 2, 2, 2, 136, 134, 3, 2, 2, 2, 137, 138, 7, 17, 2, 2, 138, 176, 5, 12, 7, 22, 139, 140, 7, 25, 2, 2, 140, 141, 5, 12, 7, 2, 141, 149, 7, 28, 2, 2, 142, 143, 7, 34, 2, 2, 143, 144, 7, 9, 2, 2, 144, 145, 7, 33, 2, 2, 145, 146, 7, 36, 2, 2, 146, 147, 5, 12, 7, 2, 147, 148, 7, 3, 2, 2, 148, 150, 3, 2, 2, 2, 149, 142, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 149, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 3, 2, 2, 2, 153, 154, 7, 26, 2, 2, 154, 176, 3, 2, 2, 2, 155, 156, 7, 27, 2, 2, 156, 176, 7, 33, 2, 2, 157, 158, 7, 44, 2, 2, 158, 176, 5, 12, 7, 19, 159, 160, 7, 19, 2, 2, 160, 176, 5, 12, 7, 18, 161, 162, 7, 29, 2, 2, 162, 176, 5, 12, 7, 10, 163, 164, 7, 6, 2, 2, 164, 165, 5, 12, 7, 2, 165, 166, 7, 8, 2, 2, 166, 176, 3, 2, 2, 2, 167, 176, 7, 34, 2, 2, 168, 176, 7, 32, 2, 2, 169, 176, 7, 31, 2, 2, 170, 176, 7, 30, 2, 2, 171, 176, 7, 14, 2, 2, 172, 173, 7, 34, 2, 2, 173, 174, 7, 35, 2, 2, 174, 176, 5, 12, 7, 3, 175, 75, 3, 2, 2, 2, 175, 92, 3, 2, 2, 2, 175, 100, 3, 2, 2, 2, 175, 106, 3, 2, 2, 2, 175, 116, 3, 2, 2, 2, 175, 139, 3, 2, 2, 2, 175, 155, 3, 2, 2, 2, 175, 157, 3, 2, 2, 2, 175, 159, 3, 2, 2, 2, 175, 161, 3, 2, 2, 2, 175, 163, 3, 2, 2, 2, 175, 167, 3, 2, 2, 2, 175, 168, 3, 2, 2, 2, 175, 169, 3, 2, 2, 2, 175, 170, 3, 2, 2, 2, 175, 171, 3, 2, 2, 2, 175, 172, 3, 2, 2, 2, 176, 222, 3, 2, 2, 2, 177, 178, 12, 17, 2, 2, 178, 179, 7, 39, 2, 2, 179, 221, 5, 12, 7, 18, 180, 181, 12, 16, 2, 2, 181, 182, 7, 40, 2, 2, 182, 221, 5, 12, 7, 17, 183, 184, 12, 15, 2, 2, 184, 185, 7, 37, 2, 2, 185, 221, 5, 12, 7, 16, 186, 187, 12, 14, 2, 2, 187, 188, 7, 38, 2, 2, 188, 221, 5, 12, 7, 15, 189, 190, 12, 13, 2, 2, 190, 191, 7, 41, 2, 2, 191, 221, 5, 12, 7, 14, 192, 193, 12, 12, 2, 2, 193, 194, 7, 42, 2, 2, 194, 221, 5, 12, 7, 13, 195, 196, 12, 11, 2, 2, 196, 197, 7, 43, 2, 2, 197, 221, 5, 12, 7, 12, 198, 201, 12, 27, 2, 2, 199, 200, 7, 10, 2, 2, 200, 202, 7, 33, 2, 2, 201, 199, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 3, 2, 2, 2, 203, 204, 7, 11, 2, 2, 204, 205, 7, 34, 2, 2, 205, 216, 7, 6, 2, 2, 206, 211, 5, 12, 7, 2, 207, 208, 7, 7, 2, 2, 208, 210, 5, 12, 7, 2, 209, 207, 3, 2, 2, 2, 210, 213, 3, 2, 2, 2, 211, 209, 3, 2, 2, 2, 211, 212, 3, 2, 2, 2, 212, 215, 3, 2, 2, 2, 213, 211, 3, 2, 2, 2, 214, 206, 3, 2, 2, 2, 215, 218, 3, 2, 2, 2, 216, 214, 3, 2, 2, 2, 216, 217, 3, 2, 2, 2, 217, 219, 3, 2, 2, 2, 218, 216, 3, 2, 2, 2, 219, 221, 7, 8, 2, 2, 220, 177, 3, 2, 2, 2, 220, 180, 3, 2, 2, 2, 220, 183, 3, 2, 2, 2, 220, 186, 3, 2, 2, 2, 220, 189, 3, 2, 2, 2, 220, 192, 3, 2, 2, 2, 220, 195, 3, 2, 2, 2, 220, 198, 3, 2, 2, 2, 221, 224, 3, 2, 2, 2, 222, 220, 3, 2, 2, 2, 222, 223, 3, 2, 2, 2, 223, 13, 3, 2, 2, 2, 224, 222, 3, 2, 2, 2, 22, 21, 27, 35, 47, 52, 67, 69, 83, 88, 112, 122, 130, 134, 151, 175, 201, 211, 216, 220, 222] \ No newline at end of file diff --git a/src/COOL.tokens b/src/COOL.tokens new file mode 100644 index 00000000..320277ee --- /dev/null +++ b/src/COOL.tokens @@ -0,0 +1,68 @@ +T__0=1 +T__1=2 +T__2=3 +T__3=4 +T__4=5 +T__5=6 +T__6=7 +T__7=8 +T__8=9 +CLASS=10 +ELSE=11 +FALSE=12 +FI=13 +IF=14 +IN=15 +INHERITS=16 +ISVOID=17 +LET=18 +LOOP=19 +POOL=20 +THEN=21 +WHILE=22 +CASE=23 +ESAC=24 +NEW=25 +OF=26 +NOT=27 +TRUE=28 +STRING=29 +INT=30 +TYPEID=31 +OBJECTID=32 +ASSIGNMENT=33 +CASE_ARROW=34 +ADD=35 +MINUS=36 +MULTIPLY=37 +DIVISION=38 +LESS_THAN=39 +LESS_EQUAL=40 +EQUAL=41 +INTEGER_NEGATIVE=42 +OPEN_COMMENT=43 +CLOSE_COMMENT=44 +COMMENT=45 +ONE_LINE_COMMENT=46 +WHITESPACE=47 +';'=1 +'{'=2 +'}'=3 +'('=4 +','=5 +')'=6 +':'=7 +'@'=8 +'.'=9 +'<-'=33 +'=>'=34 +'+'=35 +'-'=36 +'*'=37 +'/'=38 +'<'=39 +'<='=40 +'='=41 +'~'=42 +'(*'=43 +'*)'=44 diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py new file mode 100644 index 00000000..dd3d486b --- /dev/null +++ b/src/COOLCompiler.py @@ -0,0 +1,15 @@ +import sys +from antlr4 import * +from COOLLexer import COOLLexer +from COOLParser import COOLParser +from COOLListener import COOLListener + +def main(argv): + input = FileStream(argv[1]) + lexer = COOLLexer(input) + stream = CommonTokenStream(lexer) + parser = COOLParser(stream) + tree = parser.program() + +if __name__ == '__main__': + main(sys.argv) diff --git a/src/COOLLexer.interp b/src/COOLLexer.interp new file mode 100644 index 00000000..d78ed196 --- /dev/null +++ b/src/COOLLexer.interp @@ -0,0 +1,178 @@ +token literal names: +null +';' +'{' +'}' +'(' +',' +')' +':' +'@' +'.' +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +'<-' +'=>' +'+' +'-' +'*' +'/' +'<' +'<=' +'=' +'~' +'(*' +'*)' +null +null +null + +token symbolic names: +null +null +null +null +null +null +null +null +null +null +CLASS +ELSE +FALSE +FI +IF +IN +INHERITS +ISVOID +LET +LOOP +POOL +THEN +WHILE +CASE +ESAC +NEW +OF +NOT +TRUE +STRING +INT +TYPEID +OBJECTID +ASSIGNMENT +CASE_ARROW +ADD +MINUS +MULTIPLY +DIVISION +LESS_THAN +LESS_EQUAL +EQUAL +INTEGER_NEGATIVE +OPEN_COMMENT +CLOSE_COMMENT +COMMENT +ONE_LINE_COMMENT +WHITESPACE + +rule names: +T__0 +T__1 +T__2 +T__3 +T__4 +T__5 +T__6 +T__7 +T__8 +CLASS +ELSE +FALSE +FI +IF +IN +INHERITS +ISVOID +LET +LOOP +POOL +THEN +WHILE +CASE +ESAC +NEW +OF +NOT +TRUE +STRING +INT +TYPEID +OBJECTID +ASSIGNMENT +CASE_ARROW +ADD +MINUS +MULTIPLY +DIVISION +LESS_THAN +LESS_EQUAL +EQUAL +INTEGER_NEGATIVE +A +C +D +E +F +H +I +L +N +O +P +R +S +T +U +V +W +ESC +UNICODE +HEX +OPEN_COMMENT +CLOSE_COMMENT +COMMENT +ONE_LINE_COMMENT +WHITESPACE + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN + +mode names: +DEFAULT_MODE + +atn: +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 49, 386, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 7, 30, 252, 10, 30, 12, 30, 14, 30, 255, 11, 30, 3, 30, 3, 30, 3, 31, 6, 31, 260, 10, 31, 13, 31, 14, 31, 261, 3, 32, 3, 32, 7, 32, 266, 10, 32, 12, 32, 14, 32, 269, 11, 32, 3, 33, 3, 33, 7, 33, 273, 10, 33, 12, 33, 14, 33, 276, 11, 33, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 61, 5, 61, 338, 10, 61, 3, 62, 3, 62, 3, 62, 3, 62, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 3, 66, 3, 66, 3, 66, 7, 66, 357, 10, 66, 12, 66, 14, 66, 360, 11, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 67, 3, 67, 7, 67, 370, 10, 67, 12, 67, 14, 67, 373, 11, 67, 3, 67, 5, 67, 376, 10, 67, 3, 67, 3, 67, 3, 68, 6, 68, 381, 10, 68, 13, 68, 14, 68, 382, 3, 68, 3, 68, 3, 358, 2, 69, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 79, 41, 81, 42, 83, 43, 85, 44, 87, 2, 89, 2, 91, 2, 93, 2, 95, 2, 97, 2, 99, 2, 101, 2, 103, 2, 105, 2, 107, 2, 109, 2, 111, 2, 113, 2, 115, 2, 117, 2, 119, 2, 121, 2, 123, 2, 125, 2, 127, 45, 129, 46, 131, 47, 133, 48, 135, 49, 3, 2, 28, 4, 2, 36, 36, 94, 94, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 3, 2, 12, 12, 5, 2, 11, 12, 14, 15, 34, 34, 2, 376, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 127, 3, 2, 2, 2, 2, 129, 3, 2, 2, 2, 2, 131, 3, 2, 2, 2, 2, 133, 3, 2, 2, 2, 2, 135, 3, 2, 2, 2, 3, 137, 3, 2, 2, 2, 5, 139, 3, 2, 2, 2, 7, 141, 3, 2, 2, 2, 9, 143, 3, 2, 2, 2, 11, 145, 3, 2, 2, 2, 13, 147, 3, 2, 2, 2, 15, 149, 3, 2, 2, 2, 17, 151, 3, 2, 2, 2, 19, 153, 3, 2, 2, 2, 21, 155, 3, 2, 2, 2, 23, 161, 3, 2, 2, 2, 25, 166, 3, 2, 2, 2, 27, 172, 3, 2, 2, 2, 29, 175, 3, 2, 2, 2, 31, 178, 3, 2, 2, 2, 33, 181, 3, 2, 2, 2, 35, 190, 3, 2, 2, 2, 37, 197, 3, 2, 2, 2, 39, 201, 3, 2, 2, 2, 41, 206, 3, 2, 2, 2, 43, 211, 3, 2, 2, 2, 45, 216, 3, 2, 2, 2, 47, 222, 3, 2, 2, 2, 49, 227, 3, 2, 2, 2, 51, 232, 3, 2, 2, 2, 53, 236, 3, 2, 2, 2, 55, 239, 3, 2, 2, 2, 57, 243, 3, 2, 2, 2, 59, 248, 3, 2, 2, 2, 61, 259, 3, 2, 2, 2, 63, 263, 3, 2, 2, 2, 65, 270, 3, 2, 2, 2, 67, 277, 3, 2, 2, 2, 69, 280, 3, 2, 2, 2, 71, 283, 3, 2, 2, 2, 73, 285, 3, 2, 2, 2, 75, 287, 3, 2, 2, 2, 77, 289, 3, 2, 2, 2, 79, 291, 3, 2, 2, 2, 81, 293, 3, 2, 2, 2, 83, 296, 3, 2, 2, 2, 85, 298, 3, 2, 2, 2, 87, 300, 3, 2, 2, 2, 89, 302, 3, 2, 2, 2, 91, 304, 3, 2, 2, 2, 93, 306, 3, 2, 2, 2, 95, 308, 3, 2, 2, 2, 97, 310, 3, 2, 2, 2, 99, 312, 3, 2, 2, 2, 101, 314, 3, 2, 2, 2, 103, 316, 3, 2, 2, 2, 105, 318, 3, 2, 2, 2, 107, 320, 3, 2, 2, 2, 109, 322, 3, 2, 2, 2, 111, 324, 3, 2, 2, 2, 113, 326, 3, 2, 2, 2, 115, 328, 3, 2, 2, 2, 117, 330, 3, 2, 2, 2, 119, 332, 3, 2, 2, 2, 121, 334, 3, 2, 2, 2, 123, 339, 3, 2, 2, 2, 125, 345, 3, 2, 2, 2, 127, 347, 3, 2, 2, 2, 129, 350, 3, 2, 2, 2, 131, 353, 3, 2, 2, 2, 133, 365, 3, 2, 2, 2, 135, 380, 3, 2, 2, 2, 137, 138, 7, 61, 2, 2, 138, 4, 3, 2, 2, 2, 139, 140, 7, 125, 2, 2, 140, 6, 3, 2, 2, 2, 141, 142, 7, 127, 2, 2, 142, 8, 3, 2, 2, 2, 143, 144, 7, 42, 2, 2, 144, 10, 3, 2, 2, 2, 145, 146, 7, 46, 2, 2, 146, 12, 3, 2, 2, 2, 147, 148, 7, 43, 2, 2, 148, 14, 3, 2, 2, 2, 149, 150, 7, 60, 2, 2, 150, 16, 3, 2, 2, 2, 151, 152, 7, 66, 2, 2, 152, 18, 3, 2, 2, 2, 153, 154, 7, 48, 2, 2, 154, 20, 3, 2, 2, 2, 155, 156, 5, 89, 45, 2, 156, 157, 5, 101, 51, 2, 157, 158, 5, 87, 44, 2, 158, 159, 5, 111, 56, 2, 159, 160, 5, 111, 56, 2, 160, 22, 3, 2, 2, 2, 161, 162, 5, 93, 47, 2, 162, 163, 5, 101, 51, 2, 163, 164, 5, 111, 56, 2, 164, 165, 5, 93, 47, 2, 165, 24, 3, 2, 2, 2, 166, 167, 7, 104, 2, 2, 167, 168, 5, 87, 44, 2, 168, 169, 5, 101, 51, 2, 169, 170, 5, 111, 56, 2, 170, 171, 5, 93, 47, 2, 171, 26, 3, 2, 2, 2, 172, 173, 5, 95, 48, 2, 173, 174, 5, 99, 50, 2, 174, 28, 3, 2, 2, 2, 175, 176, 5, 99, 50, 2, 176, 177, 5, 95, 48, 2, 177, 30, 3, 2, 2, 2, 178, 179, 5, 99, 50, 2, 179, 180, 5, 103, 52, 2, 180, 32, 3, 2, 2, 2, 181, 182, 5, 99, 50, 2, 182, 183, 5, 103, 52, 2, 183, 184, 5, 97, 49, 2, 184, 185, 5, 93, 47, 2, 185, 186, 5, 109, 55, 2, 186, 187, 5, 99, 50, 2, 187, 188, 5, 113, 57, 2, 188, 189, 5, 111, 56, 2, 189, 34, 3, 2, 2, 2, 190, 191, 5, 99, 50, 2, 191, 192, 5, 111, 56, 2, 192, 193, 5, 117, 59, 2, 193, 194, 5, 105, 53, 2, 194, 195, 5, 99, 50, 2, 195, 196, 5, 91, 46, 2, 196, 36, 3, 2, 2, 2, 197, 198, 5, 101, 51, 2, 198, 199, 5, 93, 47, 2, 199, 200, 5, 113, 57, 2, 200, 38, 3, 2, 2, 2, 201, 202, 5, 101, 51, 2, 202, 203, 5, 105, 53, 2, 203, 204, 5, 105, 53, 2, 204, 205, 5, 107, 54, 2, 205, 40, 3, 2, 2, 2, 206, 207, 5, 107, 54, 2, 207, 208, 5, 105, 53, 2, 208, 209, 5, 105, 53, 2, 209, 210, 5, 101, 51, 2, 210, 42, 3, 2, 2, 2, 211, 212, 5, 113, 57, 2, 212, 213, 5, 97, 49, 2, 213, 214, 5, 93, 47, 2, 214, 215, 5, 103, 52, 2, 215, 44, 3, 2, 2, 2, 216, 217, 5, 119, 60, 2, 217, 218, 5, 97, 49, 2, 218, 219, 5, 99, 50, 2, 219, 220, 5, 101, 51, 2, 220, 221, 5, 93, 47, 2, 221, 46, 3, 2, 2, 2, 222, 223, 5, 89, 45, 2, 223, 224, 5, 87, 44, 2, 224, 225, 5, 111, 56, 2, 225, 226, 5, 93, 47, 2, 226, 48, 3, 2, 2, 2, 227, 228, 5, 93, 47, 2, 228, 229, 5, 111, 56, 2, 229, 230, 5, 87, 44, 2, 230, 231, 5, 89, 45, 2, 231, 50, 3, 2, 2, 2, 232, 233, 5, 103, 52, 2, 233, 234, 5, 93, 47, 2, 234, 235, 5, 119, 60, 2, 235, 52, 3, 2, 2, 2, 236, 237, 5, 105, 53, 2, 237, 238, 5, 95, 48, 2, 238, 54, 3, 2, 2, 2, 239, 240, 5, 103, 52, 2, 240, 241, 5, 105, 53, 2, 241, 242, 5, 113, 57, 2, 242, 56, 3, 2, 2, 2, 243, 244, 7, 118, 2, 2, 244, 245, 5, 109, 55, 2, 245, 246, 5, 115, 58, 2, 246, 247, 5, 93, 47, 2, 247, 58, 3, 2, 2, 2, 248, 253, 7, 36, 2, 2, 249, 252, 5, 121, 61, 2, 250, 252, 10, 2, 2, 2, 251, 249, 3, 2, 2, 2, 251, 250, 3, 2, 2, 2, 252, 255, 3, 2, 2, 2, 253, 251, 3, 2, 2, 2, 253, 254, 3, 2, 2, 2, 254, 256, 3, 2, 2, 2, 255, 253, 3, 2, 2, 2, 256, 257, 7, 36, 2, 2, 257, 60, 3, 2, 2, 2, 258, 260, 9, 3, 2, 2, 259, 258, 3, 2, 2, 2, 260, 261, 3, 2, 2, 2, 261, 259, 3, 2, 2, 2, 261, 262, 3, 2, 2, 2, 262, 62, 3, 2, 2, 2, 263, 267, 9, 4, 2, 2, 264, 266, 9, 5, 2, 2, 265, 264, 3, 2, 2, 2, 266, 269, 3, 2, 2, 2, 267, 265, 3, 2, 2, 2, 267, 268, 3, 2, 2, 2, 268, 64, 3, 2, 2, 2, 269, 267, 3, 2, 2, 2, 270, 274, 9, 6, 2, 2, 271, 273, 9, 5, 2, 2, 272, 271, 3, 2, 2, 2, 273, 276, 3, 2, 2, 2, 274, 272, 3, 2, 2, 2, 274, 275, 3, 2, 2, 2, 275, 66, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 277, 278, 7, 62, 2, 2, 278, 279, 7, 47, 2, 2, 279, 68, 3, 2, 2, 2, 280, 281, 7, 63, 2, 2, 281, 282, 7, 64, 2, 2, 282, 70, 3, 2, 2, 2, 283, 284, 7, 45, 2, 2, 284, 72, 3, 2, 2, 2, 285, 286, 7, 47, 2, 2, 286, 74, 3, 2, 2, 2, 287, 288, 7, 44, 2, 2, 288, 76, 3, 2, 2, 2, 289, 290, 7, 49, 2, 2, 290, 78, 3, 2, 2, 2, 291, 292, 7, 62, 2, 2, 292, 80, 3, 2, 2, 2, 293, 294, 7, 62, 2, 2, 294, 295, 7, 63, 2, 2, 295, 82, 3, 2, 2, 2, 296, 297, 7, 63, 2, 2, 297, 84, 3, 2, 2, 2, 298, 299, 7, 128, 2, 2, 299, 86, 3, 2, 2, 2, 300, 301, 9, 7, 2, 2, 301, 88, 3, 2, 2, 2, 302, 303, 9, 8, 2, 2, 303, 90, 3, 2, 2, 2, 304, 305, 9, 9, 2, 2, 305, 92, 3, 2, 2, 2, 306, 307, 9, 10, 2, 2, 307, 94, 3, 2, 2, 2, 308, 309, 9, 11, 2, 2, 309, 96, 3, 2, 2, 2, 310, 311, 9, 12, 2, 2, 311, 98, 3, 2, 2, 2, 312, 313, 9, 13, 2, 2, 313, 100, 3, 2, 2, 2, 314, 315, 9, 14, 2, 2, 315, 102, 3, 2, 2, 2, 316, 317, 9, 15, 2, 2, 317, 104, 3, 2, 2, 2, 318, 319, 9, 16, 2, 2, 319, 106, 3, 2, 2, 2, 320, 321, 9, 17, 2, 2, 321, 108, 3, 2, 2, 2, 322, 323, 9, 18, 2, 2, 323, 110, 3, 2, 2, 2, 324, 325, 9, 19, 2, 2, 325, 112, 3, 2, 2, 2, 326, 327, 9, 20, 2, 2, 327, 114, 3, 2, 2, 2, 328, 329, 9, 21, 2, 2, 329, 116, 3, 2, 2, 2, 330, 331, 9, 22, 2, 2, 331, 118, 3, 2, 2, 2, 332, 333, 9, 23, 2, 2, 333, 120, 3, 2, 2, 2, 334, 337, 7, 94, 2, 2, 335, 338, 9, 24, 2, 2, 336, 338, 5, 123, 62, 2, 337, 335, 3, 2, 2, 2, 337, 336, 3, 2, 2, 2, 338, 122, 3, 2, 2, 2, 339, 340, 7, 119, 2, 2, 340, 341, 5, 125, 63, 2, 341, 342, 5, 125, 63, 2, 342, 343, 5, 125, 63, 2, 343, 344, 5, 125, 63, 2, 344, 124, 3, 2, 2, 2, 345, 346, 9, 25, 2, 2, 346, 126, 3, 2, 2, 2, 347, 348, 7, 42, 2, 2, 348, 349, 7, 44, 2, 2, 349, 128, 3, 2, 2, 2, 350, 351, 7, 44, 2, 2, 351, 352, 7, 43, 2, 2, 352, 130, 3, 2, 2, 2, 353, 358, 5, 127, 64, 2, 354, 357, 5, 131, 66, 2, 355, 357, 11, 2, 2, 2, 356, 354, 3, 2, 2, 2, 356, 355, 3, 2, 2, 2, 357, 360, 3, 2, 2, 2, 358, 359, 3, 2, 2, 2, 358, 356, 3, 2, 2, 2, 359, 361, 3, 2, 2, 2, 360, 358, 3, 2, 2, 2, 361, 362, 5, 129, 65, 2, 362, 363, 3, 2, 2, 2, 363, 364, 8, 66, 2, 2, 364, 132, 3, 2, 2, 2, 365, 366, 7, 47, 2, 2, 366, 367, 7, 47, 2, 2, 367, 371, 3, 2, 2, 2, 368, 370, 10, 26, 2, 2, 369, 368, 3, 2, 2, 2, 370, 373, 3, 2, 2, 2, 371, 369, 3, 2, 2, 2, 371, 372, 3, 2, 2, 2, 372, 375, 3, 2, 2, 2, 373, 371, 3, 2, 2, 2, 374, 376, 7, 12, 2, 2, 375, 374, 3, 2, 2, 2, 375, 376, 3, 2, 2, 2, 376, 377, 3, 2, 2, 2, 377, 378, 8, 67, 2, 2, 378, 134, 3, 2, 2, 2, 379, 381, 9, 27, 2, 2, 380, 379, 3, 2, 2, 2, 381, 382, 3, 2, 2, 2, 382, 380, 3, 2, 2, 2, 382, 383, 3, 2, 2, 2, 383, 384, 3, 2, 2, 2, 384, 385, 8, 68, 2, 2, 385, 136, 3, 2, 2, 2, 14, 2, 251, 253, 261, 267, 274, 337, 356, 358, 371, 375, 382, 3, 8, 2, 2] \ No newline at end of file diff --git a/src/COOLLexer.py b/src/COOLLexer.py new file mode 100644 index 00000000..d53e933d --- /dev/null +++ b/src/COOLLexer.py @@ -0,0 +1,267 @@ +# Generated from C:\Software\ANTLR\cool\COOL.g4 by ANTLR 4.7.2 +from antlr4 import * +from io import StringIO +from typing.io import TextIO +import sys + + + +def serializedATN(): + with StringIO() as buf: + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\61") + buf.write("\u0182\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7") + buf.write("\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r") + buf.write("\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23") + buf.write("\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30") + buf.write("\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36") + buf.write("\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\4%\t%") + buf.write("\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t,\4-\t-\4.") + buf.write("\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64") + buf.write("\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:") + buf.write("\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\t") + buf.write("C\4D\tD\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\7\3") + buf.write("\7\3\b\3\b\3\t\3\t\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3") + buf.write("\13\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3") + buf.write("\16\3\16\3\17\3\17\3\17\3\20\3\20\3\20\3\21\3\21\3\21") + buf.write("\3\21\3\21\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\22") + buf.write("\3\22\3\22\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24") + buf.write("\3\25\3\25\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3\27") + buf.write("\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3\30\3\31") + buf.write("\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32\3\33\3\33\3\33") + buf.write("\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\35\3\36\3\36") + buf.write("\3\36\7\36\u00fc\n\36\f\36\16\36\u00ff\13\36\3\36\3\36") + buf.write("\3\37\6\37\u0104\n\37\r\37\16\37\u0105\3 \3 \7 \u010a") + buf.write("\n \f \16 \u010d\13 \3!\3!\7!\u0111\n!\f!\16!\u0114\13") + buf.write("!\3\"\3\"\3\"\3#\3#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3") + buf.write("(\3)\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3") + buf.write("\60\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65") + buf.write("\3\66\3\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<\3<\3=") + buf.write("\3=\3=\5=\u0152\n=\3>\3>\3>\3>\3>\3>\3?\3?\3@\3@\3@\3") + buf.write("A\3A\3A\3B\3B\3B\7B\u0165\nB\fB\16B\u0168\13B\3B\3B\3") + buf.write("B\3B\3C\3C\3C\3C\7C\u0172\nC\fC\16C\u0175\13C\3C\5C\u0178") + buf.write("\nC\3C\3C\3D\6D\u017d\nD\rD\16D\u017e\3D\3D\3\u0166\2") + buf.write("E\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31") + buf.write("\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31") + buf.write("\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O") + buf.write(")Q*S+U,W\2Y\2[\2]\2_\2a\2c\2e\2g\2i\2k\2m\2o\2q\2s\2u") + buf.write("\2w\2y\2{\2}\2\177-\u0081.\u0083/\u0085\60\u0087\61\3") + buf.write("\2\34\4\2$$^^\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2") + buf.write("CCcc\4\2EEee\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4") + buf.write("\2NNnn\4\2PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVv") + buf.write("v\4\2WWww\4\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2") + buf.write("\62;CHch\3\2\f\f\5\2\13\f\16\17\"\"\2\u0178\2\3\3\2\2") + buf.write("\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2") + buf.write("\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25") + buf.write("\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3") + buf.write("\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2") + buf.write("\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2") + buf.write("\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\2") + buf.write("9\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2") + buf.write("\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2") + buf.write("\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2") + buf.write("\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085") + buf.write("\3\2\2\2\2\u0087\3\2\2\2\3\u0089\3\2\2\2\5\u008b\3\2\2") + buf.write("\2\7\u008d\3\2\2\2\t\u008f\3\2\2\2\13\u0091\3\2\2\2\r") + buf.write("\u0093\3\2\2\2\17\u0095\3\2\2\2\21\u0097\3\2\2\2\23\u0099") + buf.write("\3\2\2\2\25\u009b\3\2\2\2\27\u00a1\3\2\2\2\31\u00a6\3") + buf.write("\2\2\2\33\u00ac\3\2\2\2\35\u00af\3\2\2\2\37\u00b2\3\2") + buf.write("\2\2!\u00b5\3\2\2\2#\u00be\3\2\2\2%\u00c5\3\2\2\2\'\u00c9") + buf.write("\3\2\2\2)\u00ce\3\2\2\2+\u00d3\3\2\2\2-\u00d8\3\2\2\2") + buf.write("/\u00de\3\2\2\2\61\u00e3\3\2\2\2\63\u00e8\3\2\2\2\65\u00ec") + buf.write("\3\2\2\2\67\u00ef\3\2\2\29\u00f3\3\2\2\2;\u00f8\3\2\2") + buf.write("\2=\u0103\3\2\2\2?\u0107\3\2\2\2A\u010e\3\2\2\2C\u0115") + buf.write("\3\2\2\2E\u0118\3\2\2\2G\u011b\3\2\2\2I\u011d\3\2\2\2") + buf.write("K\u011f\3\2\2\2M\u0121\3\2\2\2O\u0123\3\2\2\2Q\u0125\3") + buf.write("\2\2\2S\u0128\3\2\2\2U\u012a\3\2\2\2W\u012c\3\2\2\2Y\u012e") + buf.write("\3\2\2\2[\u0130\3\2\2\2]\u0132\3\2\2\2_\u0134\3\2\2\2") + buf.write("a\u0136\3\2\2\2c\u0138\3\2\2\2e\u013a\3\2\2\2g\u013c\3") + buf.write("\2\2\2i\u013e\3\2\2\2k\u0140\3\2\2\2m\u0142\3\2\2\2o\u0144") + buf.write("\3\2\2\2q\u0146\3\2\2\2s\u0148\3\2\2\2u\u014a\3\2\2\2") + buf.write("w\u014c\3\2\2\2y\u014e\3\2\2\2{\u0153\3\2\2\2}\u0159\3") + buf.write("\2\2\2\177\u015b\3\2\2\2\u0081\u015e\3\2\2\2\u0083\u0161") + buf.write("\3\2\2\2\u0085\u016d\3\2\2\2\u0087\u017c\3\2\2\2\u0089") + buf.write("\u008a\7=\2\2\u008a\4\3\2\2\2\u008b\u008c\7}\2\2\u008c") + buf.write("\6\3\2\2\2\u008d\u008e\7\177\2\2\u008e\b\3\2\2\2\u008f") + buf.write("\u0090\7*\2\2\u0090\n\3\2\2\2\u0091\u0092\7.\2\2\u0092") + buf.write("\f\3\2\2\2\u0093\u0094\7+\2\2\u0094\16\3\2\2\2\u0095\u0096") + buf.write("\7<\2\2\u0096\20\3\2\2\2\u0097\u0098\7B\2\2\u0098\22\3") + buf.write("\2\2\2\u0099\u009a\7\60\2\2\u009a\24\3\2\2\2\u009b\u009c") + buf.write("\5Y-\2\u009c\u009d\5e\63\2\u009d\u009e\5W,\2\u009e\u009f") + buf.write("\5o8\2\u009f\u00a0\5o8\2\u00a0\26\3\2\2\2\u00a1\u00a2") + buf.write("\5]/\2\u00a2\u00a3\5e\63\2\u00a3\u00a4\5o8\2\u00a4\u00a5") + buf.write("\5]/\2\u00a5\30\3\2\2\2\u00a6\u00a7\7h\2\2\u00a7\u00a8") + buf.write("\5W,\2\u00a8\u00a9\5e\63\2\u00a9\u00aa\5o8\2\u00aa\u00ab") + buf.write("\5]/\2\u00ab\32\3\2\2\2\u00ac\u00ad\5_\60\2\u00ad\u00ae") + buf.write("\5c\62\2\u00ae\34\3\2\2\2\u00af\u00b0\5c\62\2\u00b0\u00b1") + buf.write("\5_\60\2\u00b1\36\3\2\2\2\u00b2\u00b3\5c\62\2\u00b3\u00b4") + buf.write("\5g\64\2\u00b4 \3\2\2\2\u00b5\u00b6\5c\62\2\u00b6\u00b7") + buf.write("\5g\64\2\u00b7\u00b8\5a\61\2\u00b8\u00b9\5]/\2\u00b9\u00ba") + buf.write("\5m\67\2\u00ba\u00bb\5c\62\2\u00bb\u00bc\5q9\2\u00bc\u00bd") + buf.write("\5o8\2\u00bd\"\3\2\2\2\u00be\u00bf\5c\62\2\u00bf\u00c0") + buf.write("\5o8\2\u00c0\u00c1\5u;\2\u00c1\u00c2\5i\65\2\u00c2\u00c3") + buf.write("\5c\62\2\u00c3\u00c4\5[.\2\u00c4$\3\2\2\2\u00c5\u00c6") + buf.write("\5e\63\2\u00c6\u00c7\5]/\2\u00c7\u00c8\5q9\2\u00c8&\3") + buf.write("\2\2\2\u00c9\u00ca\5e\63\2\u00ca\u00cb\5i\65\2\u00cb\u00cc") + buf.write("\5i\65\2\u00cc\u00cd\5k\66\2\u00cd(\3\2\2\2\u00ce\u00cf") + buf.write("\5k\66\2\u00cf\u00d0\5i\65\2\u00d0\u00d1\5i\65\2\u00d1") + buf.write("\u00d2\5e\63\2\u00d2*\3\2\2\2\u00d3\u00d4\5q9\2\u00d4") + buf.write("\u00d5\5a\61\2\u00d5\u00d6\5]/\2\u00d6\u00d7\5g\64\2\u00d7") + buf.write(",\3\2\2\2\u00d8\u00d9\5w<\2\u00d9\u00da\5a\61\2\u00da") + buf.write("\u00db\5c\62\2\u00db\u00dc\5e\63\2\u00dc\u00dd\5]/\2\u00dd") + buf.write(".\3\2\2\2\u00de\u00df\5Y-\2\u00df\u00e0\5W,\2\u00e0\u00e1") + buf.write("\5o8\2\u00e1\u00e2\5]/\2\u00e2\60\3\2\2\2\u00e3\u00e4") + buf.write("\5]/\2\u00e4\u00e5\5o8\2\u00e5\u00e6\5W,\2\u00e6\u00e7") + buf.write("\5Y-\2\u00e7\62\3\2\2\2\u00e8\u00e9\5g\64\2\u00e9\u00ea") + buf.write("\5]/\2\u00ea\u00eb\5w<\2\u00eb\64\3\2\2\2\u00ec\u00ed") + buf.write("\5i\65\2\u00ed\u00ee\5_\60\2\u00ee\66\3\2\2\2\u00ef\u00f0") + buf.write("\5g\64\2\u00f0\u00f1\5i\65\2\u00f1\u00f2\5q9\2\u00f28") + buf.write("\3\2\2\2\u00f3\u00f4\7v\2\2\u00f4\u00f5\5m\67\2\u00f5") + buf.write("\u00f6\5s:\2\u00f6\u00f7\5]/\2\u00f7:\3\2\2\2\u00f8\u00fd") + buf.write("\7$\2\2\u00f9\u00fc\5y=\2\u00fa\u00fc\n\2\2\2\u00fb\u00f9") + buf.write("\3\2\2\2\u00fb\u00fa\3\2\2\2\u00fc\u00ff\3\2\2\2\u00fd") + buf.write("\u00fb\3\2\2\2\u00fd\u00fe\3\2\2\2\u00fe\u0100\3\2\2\2") + buf.write("\u00ff\u00fd\3\2\2\2\u0100\u0101\7$\2\2\u0101<\3\2\2\2") + buf.write("\u0102\u0104\t\3\2\2\u0103\u0102\3\2\2\2\u0104\u0105\3") + buf.write("\2\2\2\u0105\u0103\3\2\2\2\u0105\u0106\3\2\2\2\u0106>") + buf.write("\3\2\2\2\u0107\u010b\t\4\2\2\u0108\u010a\t\5\2\2\u0109") + buf.write("\u0108\3\2\2\2\u010a\u010d\3\2\2\2\u010b\u0109\3\2\2\2") + buf.write("\u010b\u010c\3\2\2\2\u010c@\3\2\2\2\u010d\u010b\3\2\2") + buf.write("\2\u010e\u0112\t\6\2\2\u010f\u0111\t\5\2\2\u0110\u010f") + buf.write("\3\2\2\2\u0111\u0114\3\2\2\2\u0112\u0110\3\2\2\2\u0112") + buf.write("\u0113\3\2\2\2\u0113B\3\2\2\2\u0114\u0112\3\2\2\2\u0115") + buf.write("\u0116\7>\2\2\u0116\u0117\7/\2\2\u0117D\3\2\2\2\u0118") + buf.write("\u0119\7?\2\2\u0119\u011a\7@\2\2\u011aF\3\2\2\2\u011b") + buf.write("\u011c\7-\2\2\u011cH\3\2\2\2\u011d\u011e\7/\2\2\u011e") + buf.write("J\3\2\2\2\u011f\u0120\7,\2\2\u0120L\3\2\2\2\u0121\u0122") + buf.write("\7\61\2\2\u0122N\3\2\2\2\u0123\u0124\7>\2\2\u0124P\3\2") + buf.write("\2\2\u0125\u0126\7>\2\2\u0126\u0127\7?\2\2\u0127R\3\2") + buf.write("\2\2\u0128\u0129\7?\2\2\u0129T\3\2\2\2\u012a\u012b\7\u0080") + buf.write("\2\2\u012bV\3\2\2\2\u012c\u012d\t\7\2\2\u012dX\3\2\2\2") + buf.write("\u012e\u012f\t\b\2\2\u012fZ\3\2\2\2\u0130\u0131\t\t\2") + buf.write("\2\u0131\\\3\2\2\2\u0132\u0133\t\n\2\2\u0133^\3\2\2\2") + buf.write("\u0134\u0135\t\13\2\2\u0135`\3\2\2\2\u0136\u0137\t\f\2") + buf.write("\2\u0137b\3\2\2\2\u0138\u0139\t\r\2\2\u0139d\3\2\2\2\u013a") + buf.write("\u013b\t\16\2\2\u013bf\3\2\2\2\u013c\u013d\t\17\2\2\u013d") + buf.write("h\3\2\2\2\u013e\u013f\t\20\2\2\u013fj\3\2\2\2\u0140\u0141") + buf.write("\t\21\2\2\u0141l\3\2\2\2\u0142\u0143\t\22\2\2\u0143n\3") + buf.write("\2\2\2\u0144\u0145\t\23\2\2\u0145p\3\2\2\2\u0146\u0147") + buf.write("\t\24\2\2\u0147r\3\2\2\2\u0148\u0149\t\25\2\2\u0149t\3") + buf.write("\2\2\2\u014a\u014b\t\26\2\2\u014bv\3\2\2\2\u014c\u014d") + buf.write("\t\27\2\2\u014dx\3\2\2\2\u014e\u0151\7^\2\2\u014f\u0152") + buf.write("\t\30\2\2\u0150\u0152\5{>\2\u0151\u014f\3\2\2\2\u0151") + buf.write("\u0150\3\2\2\2\u0152z\3\2\2\2\u0153\u0154\7w\2\2\u0154") + buf.write("\u0155\5}?\2\u0155\u0156\5}?\2\u0156\u0157\5}?\2\u0157") + buf.write("\u0158\5}?\2\u0158|\3\2\2\2\u0159\u015a\t\31\2\2\u015a") + buf.write("~\3\2\2\2\u015b\u015c\7*\2\2\u015c\u015d\7,\2\2\u015d") + buf.write("\u0080\3\2\2\2\u015e\u015f\7,\2\2\u015f\u0160\7+\2\2\u0160") + buf.write("\u0082\3\2\2\2\u0161\u0166\5\177@\2\u0162\u0165\5\u0083") + buf.write("B\2\u0163\u0165\13\2\2\2\u0164\u0162\3\2\2\2\u0164\u0163") + buf.write("\3\2\2\2\u0165\u0168\3\2\2\2\u0166\u0167\3\2\2\2\u0166") + buf.write("\u0164\3\2\2\2\u0167\u0169\3\2\2\2\u0168\u0166\3\2\2\2") + buf.write("\u0169\u016a\5\u0081A\2\u016a\u016b\3\2\2\2\u016b\u016c") + buf.write("\bB\2\2\u016c\u0084\3\2\2\2\u016d\u016e\7/\2\2\u016e\u016f") + buf.write("\7/\2\2\u016f\u0173\3\2\2\2\u0170\u0172\n\32\2\2\u0171") + buf.write("\u0170\3\2\2\2\u0172\u0175\3\2\2\2\u0173\u0171\3\2\2\2") + buf.write("\u0173\u0174\3\2\2\2\u0174\u0177\3\2\2\2\u0175\u0173\3") + buf.write("\2\2\2\u0176\u0178\7\f\2\2\u0177\u0176\3\2\2\2\u0177\u0178") + buf.write("\3\2\2\2\u0178\u0179\3\2\2\2\u0179\u017a\bC\2\2\u017a") + buf.write("\u0086\3\2\2\2\u017b\u017d\t\33\2\2\u017c\u017b\3\2\2") + buf.write("\2\u017d\u017e\3\2\2\2\u017e\u017c\3\2\2\2\u017e\u017f") + buf.write("\3\2\2\2\u017f\u0180\3\2\2\2\u0180\u0181\bD\2\2\u0181") + buf.write("\u0088\3\2\2\2\16\2\u00fb\u00fd\u0105\u010b\u0112\u0151") + buf.write("\u0164\u0166\u0173\u0177\u017e\3\b\2\2") + return buf.getvalue() + + +class COOLLexer(Lexer): + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] + + T__0 = 1 + T__1 = 2 + T__2 = 3 + T__3 = 4 + T__4 = 5 + T__5 = 6 + T__6 = 7 + T__7 = 8 + T__8 = 9 + CLASS = 10 + ELSE = 11 + FALSE = 12 + FI = 13 + IF = 14 + IN = 15 + INHERITS = 16 + ISVOID = 17 + LET = 18 + LOOP = 19 + POOL = 20 + THEN = 21 + WHILE = 22 + CASE = 23 + ESAC = 24 + NEW = 25 + OF = 26 + NOT = 27 + TRUE = 28 + STRING = 29 + INT = 30 + TYPEID = 31 + OBJECTID = 32 + ASSIGNMENT = 33 + CASE_ARROW = 34 + ADD = 35 + MINUS = 36 + MULTIPLY = 37 + DIVISION = 38 + LESS_THAN = 39 + LESS_EQUAL = 40 + EQUAL = 41 + INTEGER_NEGATIVE = 42 + OPEN_COMMENT = 43 + CLOSE_COMMENT = 44 + COMMENT = 45 + ONE_LINE_COMMENT = 46 + WHITESPACE = 47 + + channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] + + modeNames = [ "DEFAULT_MODE" ] + + literalNames = [ "", + "';'", "'{'", "'}'", "'('", "','", "')'", "':'", "'@'", "'.'", + "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", "'<='", "'='", + "'~'", "'(*'", "'*)'" ] + + symbolicNames = [ "", + "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", + "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", + "OF", "NOT", "TRUE", "STRING", "INT", "TYPEID", "OBJECTID", + "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", + "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_COMMENT", + "CLOSE_COMMENT", "COMMENT", "ONE_LINE_COMMENT", "WHITESPACE" ] + + ruleNames = [ "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", + "T__7", "T__8", "CLASS", "ELSE", "FALSE", "FI", "IF", + "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", + "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", + "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", + "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", + "EQUAL", "INTEGER_NEGATIVE", "A", "C", "D", "E", "F", + "H", "I", "L", "N", "O", "P", "R", "S", "T", "U", "V", + "W", "ESC", "UNICODE", "HEX", "OPEN_COMMENT", "CLOSE_COMMENT", + "COMMENT", "ONE_LINE_COMMENT", "WHITESPACE" ] + + grammarFileName = "COOL.g4" + + def __init__(self, input=None, output:TextIO = sys.stdout): + super().__init__(input, output) + self.checkVersion("4.7.2") + self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) + self._actions = None + self._predicates = None + + diff --git a/src/COOLLexer.tokens b/src/COOLLexer.tokens new file mode 100644 index 00000000..320277ee --- /dev/null +++ b/src/COOLLexer.tokens @@ -0,0 +1,68 @@ +T__0=1 +T__1=2 +T__2=3 +T__3=4 +T__4=5 +T__5=6 +T__6=7 +T__7=8 +T__8=9 +CLASS=10 +ELSE=11 +FALSE=12 +FI=13 +IF=14 +IN=15 +INHERITS=16 +ISVOID=17 +LET=18 +LOOP=19 +POOL=20 +THEN=21 +WHILE=22 +CASE=23 +ESAC=24 +NEW=25 +OF=26 +NOT=27 +TRUE=28 +STRING=29 +INT=30 +TYPEID=31 +OBJECTID=32 +ASSIGNMENT=33 +CASE_ARROW=34 +ADD=35 +MINUS=36 +MULTIPLY=37 +DIVISION=38 +LESS_THAN=39 +LESS_EQUAL=40 +EQUAL=41 +INTEGER_NEGATIVE=42 +OPEN_COMMENT=43 +CLOSE_COMMENT=44 +COMMENT=45 +ONE_LINE_COMMENT=46 +WHITESPACE=47 +';'=1 +'{'=2 +'}'=3 +'('=4 +','=5 +')'=6 +':'=7 +'@'=8 +'.'=9 +'<-'=33 +'=>'=34 +'+'=35 +'-'=36 +'*'=37 +'/'=38 +'<'=39 +'<='=40 +'='=41 +'~'=42 +'(*'=43 +'*)'=44 diff --git a/src/COOLListener.py b/src/COOLListener.py new file mode 100644 index 00000000..50a72320 --- /dev/null +++ b/src/COOLListener.py @@ -0,0 +1,298 @@ +# Generated from C:\Software\ANTLR\cool\COOL.g4 by ANTLR 4.7.2 +from antlr4 import * +if __name__ is not None and "." in __name__: + from .COOLParser import COOLParser +else: + from COOLParser import COOLParser + +# This class defines a complete listener for a parse tree produced by COOLParser. +class COOLListener(ParseTreeListener): + + # Enter a parse tree produced by COOLParser#program. + def enterProgram(self, ctx:COOLParser.ProgramContext): + pass + + # Exit a parse tree produced by COOLParser#program. + def exitProgram(self, ctx:COOLParser.ProgramContext): + pass + + + # Enter a parse tree produced by COOLParser#classes. + def enterClasses(self, ctx:COOLParser.ClassesContext): + pass + + # Exit a parse tree produced by COOLParser#classes. + def exitClasses(self, ctx:COOLParser.ClassesContext): + pass + + + # Enter a parse tree produced by COOLParser#eof. + def enterEof(self, ctx:COOLParser.EofContext): + pass + + # Exit a parse tree produced by COOLParser#eof. + def exitEof(self, ctx:COOLParser.EofContext): + pass + + + # Enter a parse tree produced by COOLParser#classDefine. + def enterClassDefine(self, ctx:COOLParser.ClassDefineContext): + pass + + # Exit a parse tree produced by COOLParser#classDefine. + def exitClassDefine(self, ctx:COOLParser.ClassDefineContext): + pass + + + # Enter a parse tree produced by COOLParser#method. + def enterMethod(self, ctx:COOLParser.MethodContext): + pass + + # Exit a parse tree produced by COOLParser#method. + def exitMethod(self, ctx:COOLParser.MethodContext): + pass + + + # Enter a parse tree produced by COOLParser#property. + def enterProperty(self, ctx:COOLParser.PropertyContext): + pass + + # Exit a parse tree produced by COOLParser#property. + def exitProperty(self, ctx:COOLParser.PropertyContext): + pass + + + # Enter a parse tree produced by COOLParser#formal. + def enterFormal(self, ctx:COOLParser.FormalContext): + pass + + # Exit a parse tree produced by COOLParser#formal. + def exitFormal(self, ctx:COOLParser.FormalContext): + pass + + + # Enter a parse tree produced by COOLParser#letIn. + def enterLetIn(self, ctx:COOLParser.LetInContext): + pass + + # Exit a parse tree produced by COOLParser#letIn. + def exitLetIn(self, ctx:COOLParser.LetInContext): + pass + + + # Enter a parse tree produced by COOLParser#minus. + def enterMinus(self, ctx:COOLParser.MinusContext): + pass + + # Exit a parse tree produced by COOLParser#minus. + def exitMinus(self, ctx:COOLParser.MinusContext): + pass + + + # Enter a parse tree produced by COOLParser#string. + def enterString(self, ctx:COOLParser.StringContext): + pass + + # Exit a parse tree produced by COOLParser#string. + def exitString(self, ctx:COOLParser.StringContext): + pass + + + # Enter a parse tree produced by COOLParser#isvoid. + def enterIsvoid(self, ctx:COOLParser.IsvoidContext): + pass + + # Exit a parse tree produced by COOLParser#isvoid. + def exitIsvoid(self, ctx:COOLParser.IsvoidContext): + pass + + + # Enter a parse tree produced by COOLParser#while. + def enterWhile(self, ctx:COOLParser.WhileContext): + pass + + # Exit a parse tree produced by COOLParser#while. + def exitWhile(self, ctx:COOLParser.WhileContext): + pass + + + # Enter a parse tree produced by COOLParser#division. + def enterDivision(self, ctx:COOLParser.DivisionContext): + pass + + # Exit a parse tree produced by COOLParser#division. + def exitDivision(self, ctx:COOLParser.DivisionContext): + pass + + + # Enter a parse tree produced by COOLParser#negative. + def enterNegative(self, ctx:COOLParser.NegativeContext): + pass + + # Exit a parse tree produced by COOLParser#negative. + def exitNegative(self, ctx:COOLParser.NegativeContext): + pass + + + # Enter a parse tree produced by COOLParser#boolNot. + def enterBoolNot(self, ctx:COOLParser.BoolNotContext): + pass + + # Exit a parse tree produced by COOLParser#boolNot. + def exitBoolNot(self, ctx:COOLParser.BoolNotContext): + pass + + + # Enter a parse tree produced by COOLParser#lessThan. + def enterLessThan(self, ctx:COOLParser.LessThanContext): + pass + + # Exit a parse tree produced by COOLParser#lessThan. + def exitLessThan(self, ctx:COOLParser.LessThanContext): + pass + + + # Enter a parse tree produced by COOLParser#block. + def enterBlock(self, ctx:COOLParser.BlockContext): + pass + + # Exit a parse tree produced by COOLParser#block. + def exitBlock(self, ctx:COOLParser.BlockContext): + pass + + + # Enter a parse tree produced by COOLParser#id. + def enterId(self, ctx:COOLParser.IdContext): + pass + + # Exit a parse tree produced by COOLParser#id. + def exitId(self, ctx:COOLParser.IdContext): + pass + + + # Enter a parse tree produced by COOLParser#multiply. + def enterMultiply(self, ctx:COOLParser.MultiplyContext): + pass + + # Exit a parse tree produced by COOLParser#multiply. + def exitMultiply(self, ctx:COOLParser.MultiplyContext): + pass + + + # Enter a parse tree produced by COOLParser#if. + def enterIf(self, ctx:COOLParser.IfContext): + pass + + # Exit a parse tree produced by COOLParser#if. + def exitIf(self, ctx:COOLParser.IfContext): + pass + + + # Enter a parse tree produced by COOLParser#case. + def enterCase(self, ctx:COOLParser.CaseContext): + pass + + # Exit a parse tree produced by COOLParser#case. + def exitCase(self, ctx:COOLParser.CaseContext): + pass + + + # Enter a parse tree produced by COOLParser#ownMethodCall. + def enterOwnMethodCall(self, ctx:COOLParser.OwnMethodCallContext): + pass + + # Exit a parse tree produced by COOLParser#ownMethodCall. + def exitOwnMethodCall(self, ctx:COOLParser.OwnMethodCallContext): + pass + + + # Enter a parse tree produced by COOLParser#add. + def enterAdd(self, ctx:COOLParser.AddContext): + pass + + # Exit a parse tree produced by COOLParser#add. + def exitAdd(self, ctx:COOLParser.AddContext): + pass + + + # Enter a parse tree produced by COOLParser#new. + def enterNew(self, ctx:COOLParser.NewContext): + pass + + # Exit a parse tree produced by COOLParser#new. + def exitNew(self, ctx:COOLParser.NewContext): + pass + + + # Enter a parse tree produced by COOLParser#parentheses. + def enterParentheses(self, ctx:COOLParser.ParenthesesContext): + pass + + # Exit a parse tree produced by COOLParser#parentheses. + def exitParentheses(self, ctx:COOLParser.ParenthesesContext): + pass + + + # Enter a parse tree produced by COOLParser#assignment. + def enterAssignment(self, ctx:COOLParser.AssignmentContext): + pass + + # Exit a parse tree produced by COOLParser#assignment. + def exitAssignment(self, ctx:COOLParser.AssignmentContext): + pass + + + # Enter a parse tree produced by COOLParser#false. + def enterFalse(self, ctx:COOLParser.FalseContext): + pass + + # Exit a parse tree produced by COOLParser#false. + def exitFalse(self, ctx:COOLParser.FalseContext): + pass + + + # Enter a parse tree produced by COOLParser#int. + def enterInt(self, ctx:COOLParser.IntContext): + pass + + # Exit a parse tree produced by COOLParser#int. + def exitInt(self, ctx:COOLParser.IntContext): + pass + + + # Enter a parse tree produced by COOLParser#equal. + def enterEqual(self, ctx:COOLParser.EqualContext): + pass + + # Exit a parse tree produced by COOLParser#equal. + def exitEqual(self, ctx:COOLParser.EqualContext): + pass + + + # Enter a parse tree produced by COOLParser#true. + def enterTrue(self, ctx:COOLParser.TrueContext): + pass + + # Exit a parse tree produced by COOLParser#true. + def exitTrue(self, ctx:COOLParser.TrueContext): + pass + + + # Enter a parse tree produced by COOLParser#lessEqual. + def enterLessEqual(self, ctx:COOLParser.LessEqualContext): + pass + + # Exit a parse tree produced by COOLParser#lessEqual. + def exitLessEqual(self, ctx:COOLParser.LessEqualContext): + pass + + + # Enter a parse tree produced by COOLParser#methodCall. + def enterMethodCall(self, ctx:COOLParser.MethodCallContext): + pass + + # Exit a parse tree produced by COOLParser#methodCall. + def exitMethodCall(self, ctx:COOLParser.MethodCallContext): + pass + + diff --git a/src/COOLParser.py b/src/COOLParser.py new file mode 100644 index 00000000..d30ff78b --- /dev/null +++ b/src/COOLParser.py @@ -0,0 +1,1757 @@ +# Generated from C:\Software\ANTLR\cool\COOL.g4 by ANTLR 4.7.2 +# encoding: utf-8 +from antlr4 import * +from io import StringIO +from typing.io import TextIO +import sys + + +def serializedATN(): + with StringIO() as buf: + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\61") + buf.write("\u00e2\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") + buf.write("\3\2\3\2\3\3\3\3\3\3\3\3\3\3\5\3\26\n\3\3\4\3\4\3\4\3") + buf.write("\4\5\4\34\n\4\3\4\3\4\3\4\3\4\7\4\"\n\4\f\4\16\4%\13\4") + buf.write("\3\4\3\4\3\5\3\5\3\5\3\5\3\5\7\5.\n\5\f\5\16\5\61\13\5") + buf.write("\7\5\63\n\5\f\5\16\5\66\13\5\3\5\3\5\3\5\3\5\3\5\3\5\3") + buf.write("\5\3\5\3\5\3\5\3\5\3\5\5\5D\n\5\5\5F\n\5\3\6\3\6\3\6\3") + buf.write("\6\3\7\3\7\3\7\3\7\3\7\3\7\7\7R\n\7\f\7\16\7U\13\7\7\7") + buf.write("W\n\7\f\7\16\7Z\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\6\7o\n\7\r") + buf.write("\7\16\7p\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\5\7{\n\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\5\7\u0083\n\7\7\7\u0085\n\7\f\7\16") + buf.write("\7\u0088\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\6\7\u0096\n\7\r\7\16\7\u0097\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\5\7\u00b0\n\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\5\7\u00ca\n\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\7\7\u00d2\n\7\f\7\16\7\u00d5\13\7\7\7\u00d7\n\7\f") + buf.write("\7\16\7\u00da\13\7\3\7\7\7\u00dd\n\7\f\7\16\7\u00e0\13") + buf.write("\7\3\7\2\3\f\b\2\4\6\b\n\f\2\2\2\u0104\2\16\3\2\2\2\4") + buf.write("\25\3\2\2\2\6\27\3\2\2\2\bE\3\2\2\2\nG\3\2\2\2\f\u00af") + buf.write("\3\2\2\2\16\17\5\4\3\2\17\3\3\2\2\2\20\21\5\6\4\2\21\22") + buf.write("\7\3\2\2\22\23\5\4\3\2\23\26\3\2\2\2\24\26\7\2\2\3\25") + buf.write("\20\3\2\2\2\25\24\3\2\2\2\26\5\3\2\2\2\27\30\7\f\2\2\30") + buf.write("\33\7!\2\2\31\32\7\22\2\2\32\34\7!\2\2\33\31\3\2\2\2\33") + buf.write("\34\3\2\2\2\34\35\3\2\2\2\35#\7\4\2\2\36\37\5\b\5\2\37") + buf.write(" \7\3\2\2 \"\3\2\2\2!\36\3\2\2\2\"%\3\2\2\2#!\3\2\2\2") + buf.write("#$\3\2\2\2$&\3\2\2\2%#\3\2\2\2&\'\7\5\2\2\'\7\3\2\2\2") + buf.write("()\7\"\2\2)\64\7\6\2\2*/\5\n\6\2+,\7\7\2\2,.\5\n\6\2-") + buf.write("+\3\2\2\2.\61\3\2\2\2/-\3\2\2\2/\60\3\2\2\2\60\63\3\2") + buf.write("\2\2\61/\3\2\2\2\62*\3\2\2\2\63\66\3\2\2\2\64\62\3\2\2") + buf.write("\2\64\65\3\2\2\2\65\67\3\2\2\2\66\64\3\2\2\2\678\7\b\2") + buf.write("\289\7\t\2\29:\7!\2\2:;\7\4\2\2;<\5\f\7\2<=\7\5\2\2=F") + buf.write("\3\2\2\2>?\7\"\2\2?@\7\t\2\2@C\7!\2\2AB\7#\2\2BD\5\f\7") + buf.write("\2CA\3\2\2\2CD\3\2\2\2DF\3\2\2\2E(\3\2\2\2E>\3\2\2\2F") + buf.write("\t\3\2\2\2GH\7\"\2\2HI\7\t\2\2IJ\7!\2\2J\13\3\2\2\2KL") + buf.write("\b\7\1\2LM\7\"\2\2MX\7\6\2\2NS\5\f\7\2OP\7\7\2\2PR\5\f") + buf.write("\7\2QO\3\2\2\2RU\3\2\2\2SQ\3\2\2\2ST\3\2\2\2TW\3\2\2\2") + buf.write("US\3\2\2\2VN\3\2\2\2WZ\3\2\2\2XV\3\2\2\2XY\3\2\2\2Y[\3") + buf.write("\2\2\2ZX\3\2\2\2[\u00b0\7\b\2\2\\]\7\20\2\2]^\5\f\7\2") + buf.write("^_\7\27\2\2_`\5\f\7\2`a\7\r\2\2ab\5\f\7\2bc\7\17\2\2c") + buf.write("\u00b0\3\2\2\2de\7\30\2\2ef\5\f\7\2fg\7\25\2\2gh\5\f\7") + buf.write("\2hi\7\26\2\2i\u00b0\3\2\2\2jn\7\4\2\2kl\5\f\7\2lm\7\3") + buf.write("\2\2mo\3\2\2\2nk\3\2\2\2op\3\2\2\2pn\3\2\2\2pq\3\2\2\2") + buf.write("qr\3\2\2\2rs\7\5\2\2s\u00b0\3\2\2\2tu\7\24\2\2uv\7\"\2") + buf.write("\2vw\7\t\2\2wz\7!\2\2xy\7#\2\2y{\5\f\7\2zx\3\2\2\2z{\3") + buf.write("\2\2\2{\u0086\3\2\2\2|}\7\7\2\2}~\7\"\2\2~\177\7\t\2\2") + buf.write("\177\u0082\7!\2\2\u0080\u0081\7#\2\2\u0081\u0083\5\f\7") + buf.write("\2\u0082\u0080\3\2\2\2\u0082\u0083\3\2\2\2\u0083\u0085") + buf.write("\3\2\2\2\u0084|\3\2\2\2\u0085\u0088\3\2\2\2\u0086\u0084") + buf.write("\3\2\2\2\u0086\u0087\3\2\2\2\u0087\u0089\3\2\2\2\u0088") + buf.write("\u0086\3\2\2\2\u0089\u008a\7\21\2\2\u008a\u00b0\5\f\7") + buf.write("\26\u008b\u008c\7\31\2\2\u008c\u008d\5\f\7\2\u008d\u0095") + buf.write("\7\34\2\2\u008e\u008f\7\"\2\2\u008f\u0090\7\t\2\2\u0090") + buf.write("\u0091\7!\2\2\u0091\u0092\7$\2\2\u0092\u0093\5\f\7\2\u0093") + buf.write("\u0094\7\3\2\2\u0094\u0096\3\2\2\2\u0095\u008e\3\2\2\2") + buf.write("\u0096\u0097\3\2\2\2\u0097\u0095\3\2\2\2\u0097\u0098\3") + buf.write("\2\2\2\u0098\u0099\3\2\2\2\u0099\u009a\7\32\2\2\u009a") + buf.write("\u00b0\3\2\2\2\u009b\u009c\7\33\2\2\u009c\u00b0\7!\2\2") + buf.write("\u009d\u009e\7,\2\2\u009e\u00b0\5\f\7\23\u009f\u00a0\7") + buf.write("\23\2\2\u00a0\u00b0\5\f\7\22\u00a1\u00a2\7\35\2\2\u00a2") + buf.write("\u00b0\5\f\7\n\u00a3\u00a4\7\6\2\2\u00a4\u00a5\5\f\7\2") + buf.write("\u00a5\u00a6\7\b\2\2\u00a6\u00b0\3\2\2\2\u00a7\u00b0\7") + buf.write("\"\2\2\u00a8\u00b0\7 \2\2\u00a9\u00b0\7\37\2\2\u00aa\u00b0") + buf.write("\7\36\2\2\u00ab\u00b0\7\16\2\2\u00ac\u00ad\7\"\2\2\u00ad") + buf.write("\u00ae\7#\2\2\u00ae\u00b0\5\f\7\3\u00afK\3\2\2\2\u00af") + buf.write("\\\3\2\2\2\u00afd\3\2\2\2\u00afj\3\2\2\2\u00aft\3\2\2") + buf.write("\2\u00af\u008b\3\2\2\2\u00af\u009b\3\2\2\2\u00af\u009d") + buf.write("\3\2\2\2\u00af\u009f\3\2\2\2\u00af\u00a1\3\2\2\2\u00af") + buf.write("\u00a3\3\2\2\2\u00af\u00a7\3\2\2\2\u00af\u00a8\3\2\2\2") + buf.write("\u00af\u00a9\3\2\2\2\u00af\u00aa\3\2\2\2\u00af\u00ab\3") + buf.write("\2\2\2\u00af\u00ac\3\2\2\2\u00b0\u00de\3\2\2\2\u00b1\u00b2") + buf.write("\f\21\2\2\u00b2\u00b3\7\'\2\2\u00b3\u00dd\5\f\7\22\u00b4") + buf.write("\u00b5\f\20\2\2\u00b5\u00b6\7(\2\2\u00b6\u00dd\5\f\7\21") + buf.write("\u00b7\u00b8\f\17\2\2\u00b8\u00b9\7%\2\2\u00b9\u00dd\5") + buf.write("\f\7\20\u00ba\u00bb\f\16\2\2\u00bb\u00bc\7&\2\2\u00bc") + buf.write("\u00dd\5\f\7\17\u00bd\u00be\f\r\2\2\u00be\u00bf\7)\2\2") + buf.write("\u00bf\u00dd\5\f\7\16\u00c0\u00c1\f\f\2\2\u00c1\u00c2") + buf.write("\7*\2\2\u00c2\u00dd\5\f\7\r\u00c3\u00c4\f\13\2\2\u00c4") + buf.write("\u00c5\7+\2\2\u00c5\u00dd\5\f\7\f\u00c6\u00c9\f\33\2\2") + buf.write("\u00c7\u00c8\7\n\2\2\u00c8\u00ca\7!\2\2\u00c9\u00c7\3") + buf.write("\2\2\2\u00c9\u00ca\3\2\2\2\u00ca\u00cb\3\2\2\2\u00cb\u00cc") + buf.write("\7\13\2\2\u00cc\u00cd\7\"\2\2\u00cd\u00d8\7\6\2\2\u00ce") + buf.write("\u00d3\5\f\7\2\u00cf\u00d0\7\7\2\2\u00d0\u00d2\5\f\7\2") + buf.write("\u00d1\u00cf\3\2\2\2\u00d2\u00d5\3\2\2\2\u00d3\u00d1\3") + buf.write("\2\2\2\u00d3\u00d4\3\2\2\2\u00d4\u00d7\3\2\2\2\u00d5\u00d3") + buf.write("\3\2\2\2\u00d6\u00ce\3\2\2\2\u00d7\u00da\3\2\2\2\u00d8") + buf.write("\u00d6\3\2\2\2\u00d8\u00d9\3\2\2\2\u00d9\u00db\3\2\2\2") + buf.write("\u00da\u00d8\3\2\2\2\u00db\u00dd\7\b\2\2\u00dc\u00b1\3") + buf.write("\2\2\2\u00dc\u00b4\3\2\2\2\u00dc\u00b7\3\2\2\2\u00dc\u00ba") + buf.write("\3\2\2\2\u00dc\u00bd\3\2\2\2\u00dc\u00c0\3\2\2\2\u00dc") + buf.write("\u00c3\3\2\2\2\u00dc\u00c6\3\2\2\2\u00dd\u00e0\3\2\2\2") + buf.write("\u00de\u00dc\3\2\2\2\u00de\u00df\3\2\2\2\u00df\r\3\2\2") + buf.write("\2\u00e0\u00de\3\2\2\2\26\25\33#/\64CESXpz\u0082\u0086") + buf.write("\u0097\u00af\u00c9\u00d3\u00d8\u00dc\u00de") + return buf.getvalue() + + +class COOLParser ( Parser ): + + grammarFileName = "COOL.g4" + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] + + sharedContextCache = PredictionContextCache() + + literalNames = [ "", "';'", "'{'", "'}'", "'('", "','", "')'", + "':'", "'@'", "'.'", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", + "'<='", "'='", "'~'", "'(*'", "'*)'" ] + + symbolicNames = [ "", "", "", "", + "", "", "", "", + "", "", "CLASS", "ELSE", "FALSE", + "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", + "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", + "NOT", "TRUE", "STRING", "INT", "TYPEID", "OBJECTID", + "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", + "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", + "OPEN_COMMENT", "CLOSE_COMMENT", "COMMENT", "ONE_LINE_COMMENT", + "WHITESPACE" ] + + RULE_program = 0 + RULE_programBlocks = 1 + RULE_classDefine = 2 + RULE_feature = 3 + RULE_formal = 4 + RULE_expression = 5 + + ruleNames = [ "program", "programBlocks", "classDefine", "feature", + "formal", "expression" ] + + EOF = Token.EOF + T__0=1 + T__1=2 + T__2=3 + T__3=4 + T__4=5 + T__5=6 + T__6=7 + T__7=8 + T__8=9 + CLASS=10 + ELSE=11 + FALSE=12 + FI=13 + IF=14 + IN=15 + INHERITS=16 + ISVOID=17 + LET=18 + LOOP=19 + POOL=20 + THEN=21 + WHILE=22 + CASE=23 + ESAC=24 + NEW=25 + OF=26 + NOT=27 + TRUE=28 + STRING=29 + INT=30 + TYPEID=31 + OBJECTID=32 + ASSIGNMENT=33 + CASE_ARROW=34 + ADD=35 + MINUS=36 + MULTIPLY=37 + DIVISION=38 + LESS_THAN=39 + LESS_EQUAL=40 + EQUAL=41 + INTEGER_NEGATIVE=42 + OPEN_COMMENT=43 + CLOSE_COMMENT=44 + COMMENT=45 + ONE_LINE_COMMENT=46 + WHITESPACE=47 + + def __init__(self, input:TokenStream, output:TextIO = sys.stdout): + super().__init__(input, output) + self.checkVersion("4.7.2") + self._interp = ParserATNSimulator(self, self.atn, self.decisionsToDFA, self.sharedContextCache) + self._predicates = None + + + + + class ProgramContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def programBlocks(self): + return self.getTypedRuleContext(COOLParser.ProgramBlocksContext,0) + + + def getRuleIndex(self): + return COOLParser.RULE_program + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterProgram" ): + listener.enterProgram(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitProgram" ): + listener.exitProgram(self) + + + + + def program(self): + + localctx = COOLParser.ProgramContext(self, self._ctx, self.state) + self.enterRule(localctx, 0, self.RULE_program) + try: + self.enterOuterAlt(localctx, 1) + self.state = 12 + self.programBlocks() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class ProgramBlocksContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return COOLParser.RULE_programBlocks + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) + + + + class ClassesContext(ProgramBlocksContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ProgramBlocksContext + super().__init__(parser) + self.copyFrom(ctx) + + def classDefine(self): + return self.getTypedRuleContext(COOLParser.ClassDefineContext,0) + + def programBlocks(self): + return self.getTypedRuleContext(COOLParser.ProgramBlocksContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterClasses" ): + listener.enterClasses(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitClasses" ): + listener.exitClasses(self) + + + class EofContext(ProgramBlocksContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ProgramBlocksContext + super().__init__(parser) + self.copyFrom(ctx) + + def EOF(self): + return self.getToken(COOLParser.EOF, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterEof" ): + listener.enterEof(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitEof" ): + listener.exitEof(self) + + + + def programBlocks(self): + + localctx = COOLParser.ProgramBlocksContext(self, self._ctx, self.state) + self.enterRule(localctx, 2, self.RULE_programBlocks) + try: + self.state = 19 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [COOLParser.CLASS]: + localctx = COOLParser.ClassesContext(self, localctx) + self.enterOuterAlt(localctx, 1) + self.state = 14 + self.classDefine() + self.state = 15 + self.match(COOLParser.T__0) + self.state = 16 + self.programBlocks() + pass + elif token in [COOLParser.EOF]: + localctx = COOLParser.EofContext(self, localctx) + self.enterOuterAlt(localctx, 2) + self.state = 18 + self.match(COOLParser.EOF) + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class ClassDefineContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def CLASS(self): + return self.getToken(COOLParser.CLASS, 0) + + def TYPEID(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.TYPEID) + else: + return self.getToken(COOLParser.TYPEID, i) + + def INHERITS(self): + return self.getToken(COOLParser.INHERITS, 0) + + def feature(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.FeatureContext) + else: + return self.getTypedRuleContext(COOLParser.FeatureContext,i) + + + def getRuleIndex(self): + return COOLParser.RULE_classDefine + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterClassDefine" ): + listener.enterClassDefine(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitClassDefine" ): + listener.exitClassDefine(self) + + + + + def classDefine(self): + + localctx = COOLParser.ClassDefineContext(self, self._ctx, self.state) + self.enterRule(localctx, 4, self.RULE_classDefine) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 21 + self.match(COOLParser.CLASS) + self.state = 22 + self.match(COOLParser.TYPEID) + self.state = 25 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOLParser.INHERITS: + self.state = 23 + self.match(COOLParser.INHERITS) + self.state = 24 + self.match(COOLParser.TYPEID) + + + self.state = 27 + self.match(COOLParser.T__1) + self.state = 33 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOLParser.OBJECTID: + self.state = 28 + self.feature() + self.state = 29 + self.match(COOLParser.T__0) + self.state = 35 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 36 + self.match(COOLParser.T__2) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class FeatureContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return COOLParser.RULE_feature + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) + + + + class MethodContext(FeatureContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.FeatureContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + def TYPEID(self): + return self.getToken(COOLParser.TYPEID, 0) + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + def formal(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.FormalContext) + else: + return self.getTypedRuleContext(COOLParser.FormalContext,i) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMethod" ): + listener.enterMethod(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMethod" ): + listener.exitMethod(self) + + + class PropertyContext(FeatureContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.FeatureContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + def TYPEID(self): + return self.getToken(COOLParser.TYPEID, 0) + def ASSIGNMENT(self): + return self.getToken(COOLParser.ASSIGNMENT, 0) + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterProperty" ): + listener.enterProperty(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitProperty" ): + listener.exitProperty(self) + + + + def feature(self): + + localctx = COOLParser.FeatureContext(self, self._ctx, self.state) + self.enterRule(localctx, 6, self.RULE_feature) + self._la = 0 # Token type + try: + self.state = 67 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input,6,self._ctx) + if la_ == 1: + localctx = COOLParser.MethodContext(self, localctx) + self.enterOuterAlt(localctx, 1) + self.state = 38 + self.match(COOLParser.OBJECTID) + self.state = 39 + self.match(COOLParser.T__3) + self.state = 50 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOLParser.OBJECTID: + self.state = 40 + self.formal() + self.state = 45 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOLParser.T__4: + self.state = 41 + self.match(COOLParser.T__4) + self.state = 42 + self.formal() + self.state = 47 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 52 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 53 + self.match(COOLParser.T__5) + self.state = 54 + self.match(COOLParser.T__6) + self.state = 55 + self.match(COOLParser.TYPEID) + self.state = 56 + self.match(COOLParser.T__1) + self.state = 57 + self.expression(0) + self.state = 58 + self.match(COOLParser.T__2) + pass + + elif la_ == 2: + localctx = COOLParser.PropertyContext(self, localctx) + self.enterOuterAlt(localctx, 2) + self.state = 60 + self.match(COOLParser.OBJECTID) + self.state = 61 + self.match(COOLParser.T__6) + self.state = 62 + self.match(COOLParser.TYPEID) + self.state = 65 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOLParser.ASSIGNMENT: + self.state = 63 + self.match(COOLParser.ASSIGNMENT) + self.state = 64 + self.expression(0) + + + pass + + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class FormalContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + + def TYPEID(self): + return self.getToken(COOLParser.TYPEID, 0) + + def getRuleIndex(self): + return COOLParser.RULE_formal + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterFormal" ): + listener.enterFormal(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitFormal" ): + listener.exitFormal(self) + + + + + def formal(self): + + localctx = COOLParser.FormalContext(self, self._ctx, self.state) + self.enterRule(localctx, 8, self.RULE_formal) + try: + self.enterOuterAlt(localctx, 1) + self.state = 69 + self.match(COOLParser.OBJECTID) + self.state = 70 + self.match(COOLParser.T__6) + self.state = 71 + self.match(COOLParser.TYPEID) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class ExpressionContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return COOLParser.RULE_expression + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) + + + class LetInContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def LET(self): + return self.getToken(COOLParser.LET, 0) + def OBJECTID(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.OBJECTID) + else: + return self.getToken(COOLParser.OBJECTID, i) + def TYPEID(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.TYPEID) + else: + return self.getToken(COOLParser.TYPEID, i) + def IN(self): + return self.getToken(COOLParser.IN, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def ASSIGNMENT(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.ASSIGNMENT) + else: + return self.getToken(COOLParser.ASSIGNMENT, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterLetIn" ): + listener.enterLetIn(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitLetIn" ): + listener.exitLetIn(self) + + + class MinusContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def MINUS(self): + return self.getToken(COOLParser.MINUS, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMinus" ): + listener.enterMinus(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMinus" ): + listener.exitMinus(self) + + + class StringContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def STRING(self): + return self.getToken(COOLParser.STRING, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterString" ): + listener.enterString(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitString" ): + listener.exitString(self) + + + class IsvoidContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def ISVOID(self): + return self.getToken(COOLParser.ISVOID, 0) + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterIsvoid" ): + listener.enterIsvoid(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitIsvoid" ): + listener.exitIsvoid(self) + + + class WhileContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def WHILE(self): + return self.getToken(COOLParser.WHILE, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def LOOP(self): + return self.getToken(COOLParser.LOOP, 0) + def POOL(self): + return self.getToken(COOLParser.POOL, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterWhile" ): + listener.enterWhile(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitWhile" ): + listener.exitWhile(self) + + + class DivisionContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def DIVISION(self): + return self.getToken(COOLParser.DIVISION, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterDivision" ): + listener.enterDivision(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitDivision" ): + listener.exitDivision(self) + + + class NegativeContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def INTEGER_NEGATIVE(self): + return self.getToken(COOLParser.INTEGER_NEGATIVE, 0) + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterNegative" ): + listener.enterNegative(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitNegative" ): + listener.exitNegative(self) + + + class BoolNotContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def NOT(self): + return self.getToken(COOLParser.NOT, 0) + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterBoolNot" ): + listener.enterBoolNot(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitBoolNot" ): + listener.exitBoolNot(self) + + + class LessThanContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def LESS_THAN(self): + return self.getToken(COOLParser.LESS_THAN, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterLessThan" ): + listener.enterLessThan(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitLessThan" ): + listener.exitLessThan(self) + + + class BlockContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterBlock" ): + listener.enterBlock(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitBlock" ): + listener.exitBlock(self) + + + class IdContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterId" ): + listener.enterId(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitId" ): + listener.exitId(self) + + + class MultiplyContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def MULTIPLY(self): + return self.getToken(COOLParser.MULTIPLY, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMultiply" ): + listener.enterMultiply(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMultiply" ): + listener.exitMultiply(self) + + + class IfContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def IF(self): + return self.getToken(COOLParser.IF, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def THEN(self): + return self.getToken(COOLParser.THEN, 0) + def ELSE(self): + return self.getToken(COOLParser.ELSE, 0) + def FI(self): + return self.getToken(COOLParser.FI, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterIf" ): + listener.enterIf(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitIf" ): + listener.exitIf(self) + + + class CaseContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def CASE(self): + return self.getToken(COOLParser.CASE, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def OF(self): + return self.getToken(COOLParser.OF, 0) + def ESAC(self): + return self.getToken(COOLParser.ESAC, 0) + def OBJECTID(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.OBJECTID) + else: + return self.getToken(COOLParser.OBJECTID, i) + def TYPEID(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.TYPEID) + else: + return self.getToken(COOLParser.TYPEID, i) + def CASE_ARROW(self, i:int=None): + if i is None: + return self.getTokens(COOLParser.CASE_ARROW) + else: + return self.getToken(COOLParser.CASE_ARROW, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterCase" ): + listener.enterCase(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitCase" ): + listener.exitCase(self) + + + class OwnMethodCallContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterOwnMethodCall" ): + listener.enterOwnMethodCall(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitOwnMethodCall" ): + listener.exitOwnMethodCall(self) + + + class AddContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def ADD(self): + return self.getToken(COOLParser.ADD, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterAdd" ): + listener.enterAdd(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitAdd" ): + listener.exitAdd(self) + + + class NewContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def NEW(self): + return self.getToken(COOLParser.NEW, 0) + def TYPEID(self): + return self.getToken(COOLParser.TYPEID, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterNew" ): + listener.enterNew(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitNew" ): + listener.exitNew(self) + + + class ParenthesesContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterParentheses" ): + listener.enterParentheses(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitParentheses" ): + listener.exitParentheses(self) + + + class AssignmentContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + def ASSIGNMENT(self): + return self.getToken(COOLParser.ASSIGNMENT, 0) + def expression(self): + return self.getTypedRuleContext(COOLParser.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterAssignment" ): + listener.enterAssignment(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitAssignment" ): + listener.exitAssignment(self) + + + class FalseContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def FALSE(self): + return self.getToken(COOLParser.FALSE, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterFalse" ): + listener.enterFalse(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitFalse" ): + listener.exitFalse(self) + + + class IntContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def INT(self): + return self.getToken(COOLParser.INT, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterInt" ): + listener.enterInt(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitInt" ): + listener.exitInt(self) + + + class EqualContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def EQUAL(self): + return self.getToken(COOLParser.EQUAL, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterEqual" ): + listener.enterEqual(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitEqual" ): + listener.exitEqual(self) + + + class TrueContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def TRUE(self): + return self.getToken(COOLParser.TRUE, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterTrue" ): + listener.enterTrue(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitTrue" ): + listener.exitTrue(self) + + + class LessEqualContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def LESS_EQUAL(self): + return self.getToken(COOLParser.LESS_EQUAL, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterLessEqual" ): + listener.enterLessEqual(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitLessEqual" ): + listener.exitLessEqual(self) + + + class MethodCallContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOLParser.ExpressionContext) + else: + return self.getTypedRuleContext(COOLParser.ExpressionContext,i) + + def OBJECTID(self): + return self.getToken(COOLParser.OBJECTID, 0) + def TYPEID(self): + return self.getToken(COOLParser.TYPEID, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMethodCall" ): + listener.enterMethodCall(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMethodCall" ): + listener.exitMethodCall(self) + + + + def expression(self, _p:int=0): + _parentctx = self._ctx + _parentState = self.state + localctx = COOLParser.ExpressionContext(self, self._ctx, _parentState) + _prevctx = localctx + _startState = 10 + self.enterRecursionRule(localctx, 10, self.RULE_expression, _p) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 173 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input,14,self._ctx) + if la_ == 1: + localctx = COOLParser.OwnMethodCallContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + + self.state = 74 + self.match(COOLParser.OBJECTID) + self.state = 75 + self.match(COOLParser.T__3) + self.state = 86 + self._errHandler.sync(self) + _la = self._input.LA(1) + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOLParser.T__1) | (1 << COOLParser.T__3) | (1 << COOLParser.FALSE) | (1 << COOLParser.IF) | (1 << COOLParser.ISVOID) | (1 << COOLParser.LET) | (1 << COOLParser.WHILE) | (1 << COOLParser.CASE) | (1 << COOLParser.NEW) | (1 << COOLParser.NOT) | (1 << COOLParser.TRUE) | (1 << COOLParser.STRING) | (1 << COOLParser.INT) | (1 << COOLParser.OBJECTID) | (1 << COOLParser.INTEGER_NEGATIVE))) != 0): + self.state = 76 + self.expression(0) + self.state = 81 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOLParser.T__4: + self.state = 77 + self.match(COOLParser.T__4) + self.state = 78 + self.expression(0) + self.state = 83 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 88 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 89 + self.match(COOLParser.T__5) + pass + + elif la_ == 2: + localctx = COOLParser.IfContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 90 + self.match(COOLParser.IF) + self.state = 91 + self.expression(0) + self.state = 92 + self.match(COOLParser.THEN) + self.state = 93 + self.expression(0) + self.state = 94 + self.match(COOLParser.ELSE) + self.state = 95 + self.expression(0) + self.state = 96 + self.match(COOLParser.FI) + pass + + elif la_ == 3: + localctx = COOLParser.WhileContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 98 + self.match(COOLParser.WHILE) + self.state = 99 + self.expression(0) + self.state = 100 + self.match(COOLParser.LOOP) + self.state = 101 + self.expression(0) + self.state = 102 + self.match(COOLParser.POOL) + pass + + elif la_ == 4: + localctx = COOLParser.BlockContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 104 + self.match(COOLParser.T__1) + self.state = 108 + self._errHandler.sync(self) + _la = self._input.LA(1) + while True: + self.state = 105 + self.expression(0) + self.state = 106 + self.match(COOLParser.T__0) + self.state = 110 + self._errHandler.sync(self) + _la = self._input.LA(1) + if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOLParser.T__1) | (1 << COOLParser.T__3) | (1 << COOLParser.FALSE) | (1 << COOLParser.IF) | (1 << COOLParser.ISVOID) | (1 << COOLParser.LET) | (1 << COOLParser.WHILE) | (1 << COOLParser.CASE) | (1 << COOLParser.NEW) | (1 << COOLParser.NOT) | (1 << COOLParser.TRUE) | (1 << COOLParser.STRING) | (1 << COOLParser.INT) | (1 << COOLParser.OBJECTID) | (1 << COOLParser.INTEGER_NEGATIVE))) != 0)): + break + + self.state = 112 + self.match(COOLParser.T__2) + pass + + elif la_ == 5: + localctx = COOLParser.LetInContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 114 + self.match(COOLParser.LET) + self.state = 115 + self.match(COOLParser.OBJECTID) + self.state = 116 + self.match(COOLParser.T__6) + self.state = 117 + self.match(COOLParser.TYPEID) + self.state = 120 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOLParser.ASSIGNMENT: + self.state = 118 + self.match(COOLParser.ASSIGNMENT) + self.state = 119 + self.expression(0) + + + self.state = 132 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOLParser.T__4: + self.state = 122 + self.match(COOLParser.T__4) + self.state = 123 + self.match(COOLParser.OBJECTID) + self.state = 124 + self.match(COOLParser.T__6) + self.state = 125 + self.match(COOLParser.TYPEID) + self.state = 128 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOLParser.ASSIGNMENT: + self.state = 126 + self.match(COOLParser.ASSIGNMENT) + self.state = 127 + self.expression(0) + + + self.state = 134 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 135 + self.match(COOLParser.IN) + self.state = 136 + self.expression(20) + pass + + elif la_ == 6: + localctx = COOLParser.CaseContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 137 + self.match(COOLParser.CASE) + self.state = 138 + self.expression(0) + self.state = 139 + self.match(COOLParser.OF) + self.state = 147 + self._errHandler.sync(self) + _la = self._input.LA(1) + while True: + self.state = 140 + self.match(COOLParser.OBJECTID) + self.state = 141 + self.match(COOLParser.T__6) + self.state = 142 + self.match(COOLParser.TYPEID) + self.state = 143 + self.match(COOLParser.CASE_ARROW) + self.state = 144 + self.expression(0) + self.state = 145 + self.match(COOLParser.T__0) + self.state = 149 + self._errHandler.sync(self) + _la = self._input.LA(1) + if not (_la==COOLParser.OBJECTID): + break + + self.state = 151 + self.match(COOLParser.ESAC) + pass + + elif la_ == 7: + localctx = COOLParser.NewContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 153 + self.match(COOLParser.NEW) + self.state = 154 + self.match(COOLParser.TYPEID) + pass + + elif la_ == 8: + localctx = COOLParser.NegativeContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 155 + self.match(COOLParser.INTEGER_NEGATIVE) + self.state = 156 + self.expression(17) + pass + + elif la_ == 9: + localctx = COOLParser.IsvoidContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 157 + self.match(COOLParser.ISVOID) + self.state = 158 + self.expression(16) + pass + + elif la_ == 10: + localctx = COOLParser.BoolNotContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 159 + self.match(COOLParser.NOT) + self.state = 160 + self.expression(8) + pass + + elif la_ == 11: + localctx = COOLParser.ParenthesesContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 161 + self.match(COOLParser.T__3) + self.state = 162 + self.expression(0) + self.state = 163 + self.match(COOLParser.T__5) + pass + + elif la_ == 12: + localctx = COOLParser.IdContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 165 + self.match(COOLParser.OBJECTID) + pass + + elif la_ == 13: + localctx = COOLParser.IntContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 166 + self.match(COOLParser.INT) + pass + + elif la_ == 14: + localctx = COOLParser.StringContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 167 + self.match(COOLParser.STRING) + pass + + elif la_ == 15: + localctx = COOLParser.TrueContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 168 + self.match(COOLParser.TRUE) + pass + + elif la_ == 16: + localctx = COOLParser.FalseContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 169 + self.match(COOLParser.FALSE) + pass + + elif la_ == 17: + localctx = COOLParser.AssignmentContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 170 + self.match(COOLParser.OBJECTID) + self.state = 171 + self.match(COOLParser.ASSIGNMENT) + self.state = 172 + self.expression(1) + pass + + + self._ctx.stop = self._input.LT(-1) + self.state = 220 + self._errHandler.sync(self) + _alt = self._interp.adaptivePredict(self._input,19,self._ctx) + while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: + if _alt==1: + if self._parseListeners is not None: + self.triggerExitRuleEvent() + _prevctx = localctx + self.state = 218 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input,18,self._ctx) + if la_ == 1: + localctx = COOLParser.MultiplyContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 175 + if not self.precpred(self._ctx, 15): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 15)") + self.state = 176 + self.match(COOLParser.MULTIPLY) + self.state = 177 + self.expression(16) + pass + + elif la_ == 2: + localctx = COOLParser.DivisionContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 178 + if not self.precpred(self._ctx, 14): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 14)") + self.state = 179 + self.match(COOLParser.DIVISION) + self.state = 180 + self.expression(15) + pass + + elif la_ == 3: + localctx = COOLParser.AddContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 181 + if not self.precpred(self._ctx, 13): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 13)") + self.state = 182 + self.match(COOLParser.ADD) + self.state = 183 + self.expression(14) + pass + + elif la_ == 4: + localctx = COOLParser.MinusContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 184 + if not self.precpred(self._ctx, 12): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 12)") + self.state = 185 + self.match(COOLParser.MINUS) + self.state = 186 + self.expression(13) + pass + + elif la_ == 5: + localctx = COOLParser.LessThanContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 187 + if not self.precpred(self._ctx, 11): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 11)") + self.state = 188 + self.match(COOLParser.LESS_THAN) + self.state = 189 + self.expression(12) + pass + + elif la_ == 6: + localctx = COOLParser.LessEqualContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 190 + if not self.precpred(self._ctx, 10): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 10)") + self.state = 191 + self.match(COOLParser.LESS_EQUAL) + self.state = 192 + self.expression(11) + pass + + elif la_ == 7: + localctx = COOLParser.EqualContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 193 + if not self.precpred(self._ctx, 9): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 9)") + self.state = 194 + self.match(COOLParser.EQUAL) + self.state = 195 + self.expression(10) + pass + + elif la_ == 8: + localctx = COOLParser.MethodCallContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 196 + if not self.precpred(self._ctx, 25): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 25)") + self.state = 199 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOLParser.T__7: + self.state = 197 + self.match(COOLParser.T__7) + self.state = 198 + self.match(COOLParser.TYPEID) + + + self.state = 201 + self.match(COOLParser.T__8) + self.state = 202 + self.match(COOLParser.OBJECTID) + self.state = 203 + self.match(COOLParser.T__3) + self.state = 214 + self._errHandler.sync(self) + _la = self._input.LA(1) + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOLParser.T__1) | (1 << COOLParser.T__3) | (1 << COOLParser.FALSE) | (1 << COOLParser.IF) | (1 << COOLParser.ISVOID) | (1 << COOLParser.LET) | (1 << COOLParser.WHILE) | (1 << COOLParser.CASE) | (1 << COOLParser.NEW) | (1 << COOLParser.NOT) | (1 << COOLParser.TRUE) | (1 << COOLParser.STRING) | (1 << COOLParser.INT) | (1 << COOLParser.OBJECTID) | (1 << COOLParser.INTEGER_NEGATIVE))) != 0): + self.state = 204 + self.expression(0) + self.state = 209 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOLParser.T__4: + self.state = 205 + self.match(COOLParser.T__4) + self.state = 206 + self.expression(0) + self.state = 211 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 216 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 217 + self.match(COOLParser.T__5) + pass + + + self.state = 222 + self._errHandler.sync(self) + _alt = self._interp.adaptivePredict(self._input,19,self._ctx) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.unrollRecursionContexts(_parentctx) + return localctx + + + + def sempred(self, localctx:RuleContext, ruleIndex:int, predIndex:int): + if self._predicates == None: + self._predicates = dict() + self._predicates[5] = self.expression_sempred + pred = self._predicates.get(ruleIndex, None) + if pred is None: + raise Exception("No predicate with index:" + str(ruleIndex)) + else: + return pred(localctx, predIndex) + + def expression_sempred(self, localctx:ExpressionContext, predIndex:int): + if predIndex == 0: + return self.precpred(self._ctx, 15) + + + if predIndex == 1: + return self.precpred(self._ctx, 14) + + + if predIndex == 2: + return self.precpred(self._ctx, 13) + + + if predIndex == 3: + return self.precpred(self._ctx, 12) + + + if predIndex == 4: + return self.precpred(self._ctx, 11) + + + if predIndex == 5: + return self.precpred(self._ctx, 10) + + + if predIndex == 6: + return self.precpred(self._ctx, 9) + + + if predIndex == 7: + return self.precpred(self._ctx, 25) + + + + + diff --git a/src/antlr4/BufferedTokenStream.py b/src/antlr4/BufferedTokenStream.py new file mode 100644 index 00000000..3634f085 --- /dev/null +++ b/src/antlr4/BufferedTokenStream.py @@ -0,0 +1,303 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. + +# This implementation of {@link TokenStream} loads tokens from a +# {@link TokenSource} on-demand, and places the tokens in a buffer to provide +# access to any previous token by index. +# +#

      +# This token stream ignores the value of {@link Token#getChannel}. If your +# parser requires the token stream filter tokens to only those on a particular +# channel, such as {@link Token#DEFAULT_CHANNEL} or +# {@link Token#HIDDEN_CHANNEL}, use a filtering token stream such a +# {@link CommonTokenStream}.

      +from io import StringIO +from antlr4.Token import Token +from antlr4.error.Errors import IllegalStateException + +# need forward declaration +Lexer = None + +# this is just to keep meaningful parameter types to Parser +class TokenStream(object): + + pass + + +class BufferedTokenStream(TokenStream): + + def __init__(self, tokenSource:Lexer): + # The {@link TokenSource} from which tokens for this stream are fetched. + self.tokenSource = tokenSource + + # A collection of all tokens fetched from the token source. The list is + # considered a complete view of the input once {@link #fetchedEOF} is set + # to {@code true}. + self.tokens = [] + + # The index into {@link #tokens} of the current token (next token to + # {@link #consume}). {@link #tokens}{@code [}{@link #p}{@code ]} should be + # {@link #LT LT(1)}. + # + #

      This field is set to -1 when the stream is first constructed or when + # {@link #setTokenSource} is called, indicating that the first token has + # not yet been fetched from the token source. For additional information, + # see the documentation of {@link IntStream} for a description of + # Initializing Methods.

      + self.index = -1 + + # Indicates whether the {@link Token#EOF} token has been fetched from + # {@link #tokenSource} and added to {@link #tokens}. This field improves + # performance for the following cases: + # + #
        + #
      • {@link #consume}: The lookahead check in {@link #consume} to prevent + # consuming the EOF symbol is optimized by checking the values of + # {@link #fetchedEOF} and {@link #p} instead of calling {@link #LA}.
      • + #
      • {@link #fetch}: The check to prevent adding multiple EOF symbols into + # {@link #tokens} is trivial with this field.
      • + #
          + self.fetchedEOF = False + + def mark(self): + return 0 + + def release(self, marker:int): + # no resources to release + pass + + def reset(self): + self.seek(0) + + def seek(self, index:int): + self.lazyInit() + self.index = self.adjustSeekIndex(index) + + def get(self, index:int): + self.lazyInit() + return self.tokens[index] + + def consume(self): + skipEofCheck = False + if self.index >= 0: + if self.fetchedEOF: + # the last token in tokens is EOF. skip check if p indexes any + # fetched token except the last. + skipEofCheck = self.index < len(self.tokens) - 1 + else: + # no EOF token in tokens. skip check if p indexes a fetched token. + skipEofCheck = self.index < len(self.tokens) + else: + # not yet initialized + skipEofCheck = False + + if not skipEofCheck and self.LA(1) == Token.EOF: + raise IllegalStateException("cannot consume EOF") + + if self.sync(self.index + 1): + self.index = self.adjustSeekIndex(self.index + 1) + + # Make sure index {@code i} in tokens has a token. + # + # @return {@code true} if a token is located at index {@code i}, otherwise + # {@code false}. + # @see #get(int i) + #/ + def sync(self, i:int): + n = i - len(self.tokens) + 1 # how many more elements we need? + if n > 0 : + fetched = self.fetch(n) + return fetched >= n + return True + + # Add {@code n} elements to buffer. + # + # @return The actual number of elements added to the buffer. + #/ + def fetch(self, n:int): + if self.fetchedEOF: + return 0 + for i in range(0, n): + t = self.tokenSource.nextToken() + t.tokenIndex = len(self.tokens) + self.tokens.append(t) + if t.type==Token.EOF: + self.fetchedEOF = True + return i + 1 + return n + + + # Get all tokens from start..stop inclusively#/ + def getTokens(self, start:int, stop:int, types:set=None): + if start<0 or stop<0: + return None + self.lazyInit() + subset = [] + if stop >= len(self.tokens): + stop = len(self.tokens)-1 + for i in range(start, stop): + t = self.tokens[i] + if t.type==Token.EOF: + break + if types is None or t.type in types: + subset.append(t) + return subset + + def LA(self, i:int): + return self.LT(i).type + + def LB(self, k:int): + if (self.index-k) < 0: + return None + return self.tokens[self.index-k] + + def LT(self, k:int): + self.lazyInit() + if k==0: + return None + if k < 0: + return self.LB(-k) + i = self.index + k - 1 + self.sync(i) + if i >= len(self.tokens): # return EOF token + # EOF must be last token + return self.tokens[len(self.tokens)-1] + return self.tokens[i] + + # Allowed derived classes to modify the behavior of operations which change + # the current stream position by adjusting the target token index of a seek + # operation. The default implementation simply returns {@code i}. If an + # exception is thrown in this method, the current stream index should not be + # changed. + # + #

          For example, {@link CommonTokenStream} overrides this method to ensure that + # the seek target is always an on-channel token.

          + # + # @param i The target token index. + # @return The adjusted target token index. + + def adjustSeekIndex(self, i:int): + return i + + def lazyInit(self): + if self.index == -1: + self.setup() + + def setup(self): + self.sync(0) + self.index = self.adjustSeekIndex(0) + + # Reset this token stream by setting its token source.#/ + def setTokenSource(self, tokenSource:Lexer): + self.tokenSource = tokenSource + self.tokens = [] + self.index = -1 + self.fetchedEOF = False + + + # Given a starting index, return the index of the next token on channel. + # Return i if tokens[i] is on channel. Return -1 if there are no tokens + # on channel between i and EOF. + #/ + def nextTokenOnChannel(self, i:int, channel:int): + self.sync(i) + if i>=len(self.tokens): + return -1 + token = self.tokens[i] + while token.channel!=channel: + if token.type==Token.EOF: + return -1 + i += 1 + self.sync(i) + token = self.tokens[i] + return i + + # Given a starting index, return the index of the previous token on channel. + # Return i if tokens[i] is on channel. Return -1 if there are no tokens + # on channel between i and 0. + def previousTokenOnChannel(self, i:int, channel:int): + while i>=0 and self.tokens[i].channel!=channel: + i -= 1 + return i + + # Collect all tokens on specified channel to the right of + # the current token up until we see a token on DEFAULT_TOKEN_CHANNEL or + # EOF. If channel is -1, find any non default channel token. + def getHiddenTokensToRight(self, tokenIndex:int, channel:int=-1): + self.lazyInit() + if tokenIndex<0 or tokenIndex>=len(self.tokens): + raise Exception(str(tokenIndex) + " not in 0.." + str(len(self.tokens)-1)) + from antlr4.Lexer import Lexer + nextOnChannel = self.nextTokenOnChannel(tokenIndex + 1, Lexer.DEFAULT_TOKEN_CHANNEL) + from_ = tokenIndex+1 + # if none onchannel to right, nextOnChannel=-1 so set to = last token + to = (len(self.tokens)-1) if nextOnChannel==-1 else nextOnChannel + return self.filterForChannel(from_, to, channel) + + + # Collect all tokens on specified channel to the left of + # the current token up until we see a token on DEFAULT_TOKEN_CHANNEL. + # If channel is -1, find any non default channel token. + def getHiddenTokensToLeft(self, tokenIndex:int, channel:int=-1): + self.lazyInit() + if tokenIndex<0 or tokenIndex>=len(self.tokens): + raise Exception(str(tokenIndex) + " not in 0.." + str(len(self.tokens)-1)) + from antlr4.Lexer import Lexer + prevOnChannel = self.previousTokenOnChannel(tokenIndex - 1, Lexer.DEFAULT_TOKEN_CHANNEL) + if prevOnChannel == tokenIndex - 1: + return None + # if none on channel to left, prevOnChannel=-1 then from=0 + from_ = prevOnChannel+1 + to = tokenIndex-1 + return self.filterForChannel(from_, to, channel) + + + def filterForChannel(self, left:int, right:int, channel:int): + hidden = [] + for i in range(left, right+1): + t = self.tokens[i] + if channel==-1: + from antlr4.Lexer import Lexer + if t.channel!= Lexer.DEFAULT_TOKEN_CHANNEL: + hidden.append(t) + elif t.channel==channel: + hidden.append(t) + if len(hidden)==0: + return None + return hidden + + def getSourceName(self): + return self.tokenSource.getSourceName() + + # Get the text of all tokens in this buffer.#/ + def getText(self, interval:tuple=None): + self.lazyInit() + self.fill() + if interval is None: + interval = (0, len(self.tokens)-1) + start = interval[0] + if isinstance(start, Token): + start = start.tokenIndex + stop = interval[1] + if isinstance(stop, Token): + stop = stop.tokenIndex + if start is None or stop is None or start<0 or stop<0: + return "" + if stop >= len(self.tokens): + stop = len(self.tokens)-1 + with StringIO() as buf: + for i in range(start, stop+1): + t = self.tokens[i] + if t.type==Token.EOF: + break + buf.write(t.text) + return buf.getvalue() + + + # Get all tokens from lexer until EOF#/ + def fill(self): + self.lazyInit() + while self.fetch(1000)==1000: + pass diff --git a/src/antlr4/CommonTokenFactory.py b/src/antlr4/CommonTokenFactory.py new file mode 100644 index 00000000..17296fab --- /dev/null +++ b/src/antlr4/CommonTokenFactory.py @@ -0,0 +1,59 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# This default implementation of {@link TokenFactory} creates +# {@link CommonToken} objects. +# +from antlr4.Token import CommonToken + +class TokenFactory(object): + + pass + +class CommonTokenFactory(TokenFactory): + # + # The default {@link CommonTokenFactory} instance. + # + #

          + # This token factory does not explicitly copy token text when constructing + # tokens.

          + # + DEFAULT = None + + def __init__(self, copyText:bool=False): + # Indicates whether {@link CommonToken#setText} should be called after + # constructing tokens to explicitly set the text. This is useful for cases + # where the input stream might not be able to provide arbitrary substrings + # of text from the input after the lexer creates a token (e.g. the + # implementation of {@link CharStream#getText} in + # {@link UnbufferedCharStream} throws an + # {@link UnsupportedOperationException}). Explicitly setting the token text + # allows {@link Token#getText} to be called at any time regardless of the + # input stream implementation. + # + #

          + # The default value is {@code false} to avoid the performance and memory + # overhead of copying text for every token unless explicitly requested.

          + # + self.copyText = copyText + + def create(self, source, type:int, text:str, channel:int, start:int, stop:int, line:int, column:int): + t = CommonToken(source, type, channel, start, stop) + t.line = line + t.column = column + if text is not None: + t.text = text + elif self.copyText and source[1] is not None: + t.text = source[1].getText(start,stop) + return t + + def createThin(self, type:int, text:str): + t = CommonToken(type=type) + t.text = text + return t + +CommonTokenFactory.DEFAULT = CommonTokenFactory() \ No newline at end of file diff --git a/src/antlr4/CommonTokenStream.py b/src/antlr4/CommonTokenStream.py new file mode 100644 index 00000000..f0837442 --- /dev/null +++ b/src/antlr4/CommonTokenStream.py @@ -0,0 +1,86 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# +# This class extends {@link BufferedTokenStream} with functionality to filter +# token streams to tokens on a particular channel (tokens where +# {@link Token#getChannel} returns a particular value). +# +#

          +# This token stream provides access to all tokens by index or when calling +# methods like {@link #getText}. The channel filtering is only used for code +# accessing tokens via the lookahead methods {@link #LA}, {@link #LT}, and +# {@link #LB}.

          +# +#

          +# By default, tokens are placed on the default channel +# ({@link Token#DEFAULT_CHANNEL}), but may be reassigned by using the +# {@code ->channel(HIDDEN)} lexer command, or by using an embedded action to +# call {@link Lexer#setChannel}. +#

          +# +#

          +# Note: lexer rules which use the {@code ->skip} lexer command or call +# {@link Lexer#skip} do not produce tokens at all, so input text matched by +# such a rule will not be available as part of the token stream, regardless of +# channel.

          +#/ + +from antlr4.BufferedTokenStream import BufferedTokenStream +from antlr4.Lexer import Lexer +from antlr4.Token import Token + + +class CommonTokenStream(BufferedTokenStream): + + def __init__(self, lexer:Lexer, channel:int=Token.DEFAULT_CHANNEL): + super().__init__(lexer) + self.channel = channel + + def adjustSeekIndex(self, i:int): + return self.nextTokenOnChannel(i, self.channel) + + def LB(self, k:int): + if k==0 or (self.index-k)<0: + return None + i = self.index + n = 1 + # find k good tokens looking backwards + while n <= k: + # skip off-channel tokens + i = self.previousTokenOnChannel(i - 1, self.channel) + n += 1 + if i < 0: + return None + return self.tokens[i] + + def LT(self, k:int): + self.lazyInit() + if k == 0: + return None + if k < 0: + return self.LB(-k) + i = self.index + n = 1 # we know tokens[pos] is a good one + # find k good tokens + while n < k: + # skip off-channel tokens, but make sure to not look past EOF + if self.sync(i + 1): + i = self.nextTokenOnChannel(i + 1, self.channel) + n += 1 + return self.tokens[i] + + # Count EOF just once.#/ + def getNumberOfOnChannelTokens(self): + n = 0 + self.fill() + for i in range(0, len(self.tokens)): + t = self.tokens[i] + if t.channel==self.channel: + n += 1 + if t.type==Token.EOF: + break + return n diff --git a/src/antlr4/FileStream.py b/src/antlr4/FileStream.py new file mode 100644 index 00000000..d7977361 --- /dev/null +++ b/src/antlr4/FileStream.py @@ -0,0 +1,34 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# This is an InputStream that is loaded from a file all at once +# when you construct the object. +# + +import codecs +import unittest +from antlr4.InputStream import InputStream + + +class FileStream(InputStream): + + def __init__(self, fileName:str, encoding:str='ascii', errors:str='strict'): + super().__init__(self.readDataFrom(fileName, encoding, errors)) + self.fileName = fileName + + def readDataFrom(self, fileName:str, encoding:str, errors:str='strict'): + # read binary to avoid line ending conversion + with open(fileName, 'rb') as file: + bytes = file.read() + return codecs.decode(bytes, encoding, errors) + + +class TestFileStream(unittest.TestCase): + + def testStream(self): + stream = FileStream(__file__) + self.assertTrue(stream.size>0) diff --git a/src/antlr4/InputStream.py b/src/antlr4/InputStream.py new file mode 100644 index 00000000..87e66af7 --- /dev/null +++ b/src/antlr4/InputStream.py @@ -0,0 +1,104 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# +import unittest + + +# +# Vacuum all input from a string and then treat it like a buffer. +# +from antlr4.Token import Token + + +class InputStream (object): + + def __init__(self, data: str): + self.name = "" + self.strdata = data + self._loadString() + + def _loadString(self): + self._index = 0 + self.data = [ord(c) for c in self.strdata] + self._size = len(self.data) + + @property + def index(self): + return self._index + + @property + def size(self): + return self._size + + # Reset the stream so that it's in the same state it was + # when the object was created *except* the data array is not + # touched. + # + def reset(self): + self._index = 0 + + def consume(self): + if self._index >= self._size: + assert self.LA(1) == Token.EOF + raise Exception("cannot consume EOF") + self._index += 1 + + def LA(self, offset: int): + if offset==0: + return 0 # undefined + if offset<0: + offset += 1 # e.g., translate LA(-1) to use offset=0 + pos = self._index + offset - 1 + if pos < 0 or pos >= self._size: # invalid + return Token.EOF + return self.data[pos] + + def LT(self, offset: int): + return self.LA(offset) + + # mark/release do nothing; we have entire buffer + def mark(self): + return -1 + + def release(self, marker: int): + pass + + # consume() ahead until p==_index; can't just set p=_index as we must + # update line and column. If we seek backwards, just set p + # + def seek(self, _index: int): + if _index<=self._index: + self._index = _index # just jump; don't update stream state (line, ...) + return + # seek forward + self._index = min(_index, self._size) + + def getText(self, start :int, stop: int): + if stop >= self._size: + stop = self._size-1 + if start >= self._size: + return "" + else: + return self.strdata[start:stop+1] + + def __str__(self): + return self.strdata + + +class TestInputStream(unittest.TestCase): + + def testStream(self): + stream = InputStream("abcde") + self.assertEqual(0, stream.index) + self.assertEqual(5, stream.size) + self.assertEqual(ord("a"), stream.LA(1)) + stream.consume() + self.assertEqual(1, stream.index) + stream.seek(5) + self.assertEqual(Token.EOF, stream.LA(1)) + self.assertEqual("bcd", stream.getText(1, 3)) + stream.reset() + self.assertEqual(0, stream.index) + diff --git a/src/antlr4/IntervalSet.py b/src/antlr4/IntervalSet.py new file mode 100644 index 00000000..54320994 --- /dev/null +++ b/src/antlr4/IntervalSet.py @@ -0,0 +1,282 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +from io import StringIO +import unittest +from antlr4.Token import Token + +# need forward declarations +IntervalSet = None + +class IntervalSet(object): + + def __init__(self): + self.intervals = None + self.readOnly = False + + def __iter__(self): + if self.intervals is not None: + for i in self.intervals: + for c in i: + yield c + + def __getitem__(self, item): + i = 0 + for k in self: + if i==item: + return k + else: + i += 1 + return Token.INVALID_TYPE + + def addOne(self, v:int): + self.addRange(range(v, v+1)) + + def addRange(self, v:range): + if self.intervals is None: + self.intervals = list() + self.intervals.append(v) + else: + # find insert pos + k = 0 + for i in self.intervals: + # distinct range -> insert + if v.stop adjust + elif v.stop==i.start: + self.intervals[k] = range(v.start, i.stop) + return + # overlapping range -> adjust and reduce + elif v.start<=i.stop: + self.intervals[k] = range(min(i.start,v.start), max(i.stop,v.stop)) + self.reduce(k) + return + k += 1 + # greater than any existing + self.intervals.append(v) + + def addSet(self, other:IntervalSet): + if other.intervals is not None: + for i in other.intervals: + self.addRange(i) + return self + + def reduce(self, k:int): + # only need to reduce if k is not the last + if k= r.stop: + self.intervals.pop(k+1) + self.reduce(k) + elif l.stop >= r.start: + self.intervals[k] = range(l.start, r.stop) + self.intervals.pop(k+1) + + def complement(self, start, stop): + result = IntervalSet() + result.addRange(range(start,stop+1)) + for i in self.intervals: + result.removeRange(i) + return result + + def __contains__(self, item): + if self.intervals is None: + return False + else: + return any(item in i for i in self.intervals) + + def __len__(self): + return sum(len(i) for i in self.intervals) + + def removeRange(self, v): + if v.start==v.stop-1: + self.removeOne(v.start) + elif self.intervals is not None: + k = 0 + for i in self.intervals: + # intervals are ordered + if v.stop<=i.start: + return + # check for including range, split it + elif v.start>i.start and v.stop=i.stop: + self.intervals.pop(k) + k -= 1 # need another pass + # check for lower boundary + elif v.start1: + buf.write("{") + first = True + for i in self.intervals: + for j in i: + if not first: + buf.write(", ") + buf.write(self.elementName(literalNames, symbolicNames, j)) + first = False + if len(self)>1: + buf.write("}") + return buf.getvalue() + + def elementName(self, literalNames:list, symbolicNames:list, a:int): + if a==Token.EOF: + return "" + elif a==Token.EPSILON: + return "" + else: + if a" + + +class TestIntervalSet(unittest.TestCase): + + def testEmpty(self): + s = IntervalSet() + self.assertIsNone(s.intervals) + self.assertFalse(30 in s) + + def testOne(self): + s = IntervalSet() + s.addOne(30) + self.assertTrue(30 in s) + self.assertFalse(29 in s) + self.assertFalse(31 in s) + + def testTwo(self): + s = IntervalSet() + s.addOne(30) + s.addOne(40) + self.assertTrue(30 in s) + self.assertTrue(40 in s) + self.assertFalse(35 in s) + + def testRange(self): + s = IntervalSet() + s.addRange(range(30,41)) + self.assertTrue(30 in s) + self.assertTrue(40 in s) + self.assertTrue(35 in s) + + def testDistinct1(self): + s = IntervalSet() + s.addRange(range(30,32)) + s.addRange(range(40,42)) + self.assertEquals(2,len(s.intervals)) + self.assertTrue(30 in s) + self.assertTrue(40 in s) + self.assertFalse(35 in s) + + def testDistinct2(self): + s = IntervalSet() + s.addRange(range(40,42)) + s.addRange(range(30,32)) + self.assertEquals(2,len(s.intervals)) + self.assertTrue(30 in s) + self.assertTrue(40 in s) + self.assertFalse(35 in s) + + def testContiguous1(self): + s = IntervalSet() + s.addRange(range(30,36)) + s.addRange(range(36,41)) + self.assertEquals(1,len(s.intervals)) + self.assertTrue(30 in s) + self.assertTrue(40 in s) + self.assertTrue(35 in s) + + def testContiguous2(self): + s = IntervalSet() + s.addRange(range(36,41)) + s.addRange(range(30,36)) + self.assertEquals(1,len(s.intervals)) + self.assertTrue(30 in s) + self.assertTrue(40 in s) + + def testOverlapping1(self): + s = IntervalSet() + s.addRange(range(30,40)) + s.addRange(range(35,45)) + self.assertEquals(1,len(s.intervals)) + self.assertTrue(30 in s) + self.assertTrue(44 in s) + + def testOverlapping2(self): + s = IntervalSet() + s.addRange(range(35,45)) + s.addRange(range(30,40)) + self.assertEquals(1,len(s.intervals)) + self.assertTrue(30 in s) + self.assertTrue(44 in s) + + def testOverlapping3(self): + s = IntervalSet() + s.addRange(range(30,32)) + s.addRange(range(40,42)) + s.addRange(range(50,52)) + s.addRange(range(20,61)) + self.assertEquals(1,len(s.intervals)) + self.assertTrue(20 in s) + self.assertTrue(60 in s) + + def testComplement(self): + s = IntervalSet() + s.addRange(range(10,21)) + c = s.complement(1,100) + self.assertTrue(1 in c) + self.assertTrue(100 in c) + self.assertTrue(10 not in c) + self.assertTrue(20 not in c) + + diff --git a/src/antlr4/LL1Analyzer.py b/src/antlr4/LL1Analyzer.py new file mode 100644 index 00000000..6b398fcd --- /dev/null +++ b/src/antlr4/LL1Analyzer.py @@ -0,0 +1,172 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ +from antlr4.IntervalSet import IntervalSet +from antlr4.Token import Token +from antlr4.PredictionContext import PredictionContext, SingletonPredictionContext, PredictionContextFromRuleContext +from antlr4.RuleContext import RuleContext +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNConfig import ATNConfig +from antlr4.atn.ATNState import ATNState, RuleStopState +from antlr4.atn.Transition import WildcardTransition, NotSetTransition, AbstractPredicateTransition, RuleTransition + + +class LL1Analyzer (object): + + #* Special value added to the lookahead sets to indicate that we hit + # a predicate during analysis if {@code seeThruPreds==false}. + #/ + HIT_PRED = Token.INVALID_TYPE + + def __init__(self, atn:ATN): + self.atn = atn + + #* + # Calculates the SLL(1) expected lookahead set for each outgoing transition + # of an {@link ATNState}. The returned array has one element for each + # outgoing transition in {@code s}. If the closure from transition + # i leads to a semantic predicate before matching a symbol, the + # element at index i of the result will be {@code null}. + # + # @param s the ATN state + # @return the expected symbols for each outgoing transition of {@code s}. + #/ + def getDecisionLookahead(self, s:ATNState): + if s is None: + return None + + count = len(s.transitions) + look = [] * count + for alt in range(0, count): + look[alt] = set() + lookBusy = set() + seeThruPreds = False # fail to get lookahead upon pred + self._LOOK(s.transition(alt).target, None, PredictionContext.EMPTY, + look[alt], lookBusy, set(), seeThruPreds, False) + # Wipe out lookahead for this alternative if we found nothing + # or we had a predicate when we !seeThruPreds + if len(look[alt])==0 or self.HIT_PRED in look[alt]: + look[alt] = None + return look + + #* + # Compute set of tokens that can follow {@code s} in the ATN in the + # specified {@code ctx}. + # + #

          If {@code ctx} is {@code null} and the end of the rule containing + # {@code s} is reached, {@link Token#EPSILON} is added to the result set. + # If {@code ctx} is not {@code null} and the end of the outermost rule is + # reached, {@link Token#EOF} is added to the result set.

          + # + # @param s the ATN state + # @param stopState the ATN state to stop at. This can be a + # {@link BlockEndState} to detect epsilon paths through a closure. + # @param ctx the complete parser context, or {@code null} if the context + # should be ignored + # + # @return The set of tokens that can follow {@code s} in the ATN in the + # specified {@code ctx}. + #/ + def LOOK(self, s:ATNState, stopState:ATNState=None, ctx:RuleContext=None): + r = IntervalSet() + seeThruPreds = True # ignore preds; get all lookahead + lookContext = PredictionContextFromRuleContext(s.atn, ctx) if ctx is not None else None + self._LOOK(s, stopState, lookContext, r, set(), set(), seeThruPreds, True) + return r + + #* + # Compute set of tokens that can follow {@code s} in the ATN in the + # specified {@code ctx}. + # + #

          If {@code ctx} is {@code null} and {@code stopState} or the end of the + # rule containing {@code s} is reached, {@link Token#EPSILON} is added to + # the result set. If {@code ctx} is not {@code null} and {@code addEOF} is + # {@code true} and {@code stopState} or the end of the outermost rule is + # reached, {@link Token#EOF} is added to the result set.

          + # + # @param s the ATN state. + # @param stopState the ATN state to stop at. This can be a + # {@link BlockEndState} to detect epsilon paths through a closure. + # @param ctx The outer context, or {@code null} if the outer context should + # not be used. + # @param look The result lookahead set. + # @param lookBusy A set used for preventing epsilon closures in the ATN + # from causing a stack overflow. Outside code should pass + # {@code new HashSet} for this argument. + # @param calledRuleStack A set used for preventing left recursion in the + # ATN from causing a stack overflow. Outside code should pass + # {@code new BitSet()} for this argument. + # @param seeThruPreds {@code true} to true semantic predicates as + # implicitly {@code true} and "see through them", otherwise {@code false} + # to treat semantic predicates as opaque and add {@link #HIT_PRED} to the + # result if one is encountered. + # @param addEOF Add {@link Token#EOF} to the result if the end of the + # outermost context is reached. This parameter has no effect if {@code ctx} + # is {@code null}. + #/ + def _LOOK(self, s:ATNState, stopState:ATNState , ctx:PredictionContext, look:IntervalSet, lookBusy:set, + calledRuleStack:set, seeThruPreds:bool, addEOF:bool): + c = ATNConfig(s, 0, ctx) + + if c in lookBusy: + return + lookBusy.add(c) + + if s == stopState: + if ctx is None: + look.addOne(Token.EPSILON) + return + elif ctx.isEmpty() and addEOF: + look.addOne(Token.EOF) + return + + if isinstance(s, RuleStopState ): + if ctx is None: + look.addOne(Token.EPSILON) + return + elif ctx.isEmpty() and addEOF: + look.addOne(Token.EOF) + return + + if ctx != PredictionContext.EMPTY: + # run thru all possible stack tops in ctx + for i in range(0, len(ctx)): + returnState = self.atn.states[ctx.getReturnState(i)] + removed = returnState.ruleIndex in calledRuleStack + try: + calledRuleStack.discard(returnState.ruleIndex) + self._LOOK(returnState, stopState, ctx.getParent(i), look, lookBusy, calledRuleStack, seeThruPreds, addEOF) + finally: + if removed: + calledRuleStack.add(returnState.ruleIndex) + return + + for t in s.transitions: + if type(t) == RuleTransition: + if t.target.ruleIndex in calledRuleStack: + continue + + newContext = SingletonPredictionContext.create(ctx, t.followState.stateNumber) + + try: + calledRuleStack.add(t.target.ruleIndex) + self._LOOK(t.target, stopState, newContext, look, lookBusy, calledRuleStack, seeThruPreds, addEOF) + finally: + calledRuleStack.remove(t.target.ruleIndex) + elif isinstance(t, AbstractPredicateTransition ): + if seeThruPreds: + self._LOOK(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF) + else: + look.addOne(self.HIT_PRED) + elif t.isEpsilon: + self._LOOK(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF) + elif type(t) == WildcardTransition: + look.addRange( range(Token.MIN_USER_TOKEN_TYPE, self.atn.maxTokenType + 1) ) + else: + set_ = t.label + if set_ is not None: + if isinstance(t, NotSetTransition): + set_ = set_.complement(Token.MIN_USER_TOKEN_TYPE, self.atn.maxTokenType) + look.addSet(set_) diff --git a/src/antlr4/Lexer.py b/src/antlr4/Lexer.py new file mode 100644 index 00000000..a60b5bcc --- /dev/null +++ b/src/antlr4/Lexer.py @@ -0,0 +1,321 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# A lexer is recognizer that draws input symbols from a character stream. +# lexer grammars result in a subclass of self object. A Lexer object +# uses simplified match() and error recovery mechanisms in the interest +# of speed. +#/ +from io import StringIO +from typing.io import TextIO +import sys +from antlr4.CommonTokenFactory import CommonTokenFactory +from antlr4.atn.LexerATNSimulator import LexerATNSimulator +from antlr4.InputStream import InputStream +from antlr4.Recognizer import Recognizer +from antlr4.Token import Token +from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException + +class TokenSource(object): + + pass + + +class Lexer(Recognizer, TokenSource): + + DEFAULT_MODE = 0 + MORE = -2 + SKIP = -3 + + DEFAULT_TOKEN_CHANNEL = Token.DEFAULT_CHANNEL + HIDDEN = Token.HIDDEN_CHANNEL + MIN_CHAR_VALUE = 0x0000 + MAX_CHAR_VALUE = 0x10FFFF + + def __init__(self, input:InputStream, output:TextIO = sys.stdout): + super().__init__() + self._input = input + self._output = output + self._factory = CommonTokenFactory.DEFAULT + self._tokenFactorySourcePair = (self, input) + + self._interp = None # child classes must populate this + + # The goal of all lexer rules/methods is to create a token object. + # self is an instance variable as multiple rules may collaborate to + # create a single token. nextToken will return self object after + # matching lexer rule(s). If you subclass to allow multiple token + # emissions, then set self to the last token to be matched or + # something nonnull so that the auto token emit mechanism will not + # emit another token. + self._token = None + + # What character index in the stream did the current token start at? + # Needed, for example, to get the text for current token. Set at + # the start of nextToken. + self._tokenStartCharIndex = -1 + + # The line on which the first character of the token resides#/ + self._tokenStartLine = -1 + + # The character position of first character within the line#/ + self._tokenStartColumn = -1 + + # Once we see EOF on char stream, next token will be EOF. + # If you have DONE : EOF ; then you see DONE EOF. + self._hitEOF = False + + # The channel number for the current token#/ + self._channel = Token.DEFAULT_CHANNEL + + # The token type for the current token#/ + self._type = Token.INVALID_TYPE + + self._modeStack = [] + self._mode = self.DEFAULT_MODE + + # You can set the text for the current token to override what is in + # the input char buffer. Use setText() or can set self instance var. + #/ + self._text = None + + + def reset(self): + # wack Lexer state variables + if self._input is not None: + self._input.seek(0) # rewind the input + self._token = None + self._type = Token.INVALID_TYPE + self._channel = Token.DEFAULT_CHANNEL + self._tokenStartCharIndex = -1 + self._tokenStartColumn = -1 + self._tokenStartLine = -1 + self._text = None + + self._hitEOF = False + self._mode = Lexer.DEFAULT_MODE + self._modeStack = [] + + self._interp.reset() + + # Return a token from self source; i.e., match a token on the char + # stream. + def nextToken(self): + if self._input is None: + raise IllegalStateException("nextToken requires a non-null input stream.") + + # Mark start location in char stream so unbuffered streams are + # guaranteed at least have text of current token + tokenStartMarker = self._input.mark() + try: + while True: + if self._hitEOF: + self.emitEOF() + return self._token + self._token = None + self._channel = Token.DEFAULT_CHANNEL + self._tokenStartCharIndex = self._input.index + self._tokenStartColumn = self._interp.column + self._tokenStartLine = self._interp.line + self._text = None + continueOuter = False + while True: + self._type = Token.INVALID_TYPE + ttype = self.SKIP + try: + ttype = self._interp.match(self._input, self._mode) + except LexerNoViableAltException as e: + self.notifyListeners(e) # report error + self.recover(e) + if self._input.LA(1)==Token.EOF: + self._hitEOF = True + if self._type == Token.INVALID_TYPE: + self._type = ttype + if self._type == self.SKIP: + continueOuter = True + break + if self._type!=self.MORE: + break + if continueOuter: + continue + if self._token is None: + self.emit() + return self._token + finally: + # make sure we release marker after match or + # unbuffered char stream will keep buffering + self._input.release(tokenStartMarker) + + # Instruct the lexer to skip creating a token for current lexer rule + # and look for another token. nextToken() knows to keep looking when + # a lexer rule finishes with token set to SKIP_TOKEN. Recall that + # if token==null at end of any token rule, it creates one for you + # and emits it. + #/ + def skip(self): + self._type = self.SKIP + + def more(self): + self._type = self.MORE + + def mode(self, m:int): + self._mode = m + + def pushMode(self, m:int): + if self._interp.debug: + print("pushMode " + str(m), file=self._output) + self._modeStack.append(self._mode) + self.mode(m) + + def popMode(self): + if len(self._modeStack)==0: + raise Exception("Empty Stack") + if self._interp.debug: + print("popMode back to "+ self._modeStack[:-1], file=self._output) + self.mode( self._modeStack.pop() ) + return self._mode + + # Set the char stream and reset the lexer#/ + @property + def inputStream(self): + return self._input + + @inputStream.setter + def inputStream(self, input:InputStream): + self._input = None + self._tokenFactorySourcePair = (self, self._input) + self.reset() + self._input = input + self._tokenFactorySourcePair = (self, self._input) + + @property + def sourceName(self): + return self._input.sourceName + + # By default does not support multiple emits per nextToken invocation + # for efficiency reasons. Subclass and override self method, nextToken, + # and getToken (to push tokens into a list and pull from that list + # rather than a single variable as self implementation does). + #/ + def emitToken(self, token:Token): + self._token = token + + # The standard method called to automatically emit a token at the + # outermost lexical rule. The token object should point into the + # char buffer start..stop. If there is a text override in 'text', + # use that to set the token's text. Override self method to emit + # custom Token objects or provide a new factory. + #/ + def emit(self): + t = self._factory.create(self._tokenFactorySourcePair, self._type, self._text, self._channel, self._tokenStartCharIndex, + self.getCharIndex()-1, self._tokenStartLine, self._tokenStartColumn) + self.emitToken(t) + return t + + def emitEOF(self): + cpos = self.column + lpos = self.line + eof = self._factory.create(self._tokenFactorySourcePair, Token.EOF, None, Token.DEFAULT_CHANNEL, self._input.index, + self._input.index-1, lpos, cpos) + self.emitToken(eof) + return eof + + @property + def type(self): + return self._type + + @type.setter + def type(self, type:int): + self._type = type + + @property + def line(self): + return self._interp.line + + @line.setter + def line(self, line:int): + self._interp.line = line + + @property + def column(self): + return self._interp.column + + @column.setter + def column(self, column:int): + self._interp.column = column + + # What is the index of the current character of lookahead?#/ + def getCharIndex(self): + return self._input.index + + # Return the text matched so far for the current token or any + # text override. + @property + def text(self): + if self._text is not None: + return self._text + else: + return self._interp.getText(self._input) + + # Set the complete text of self token; it wipes any previous + # changes to the text. + @text.setter + def text(self, txt:str): + self._text = txt + + # Return a list of all Token objects in input char stream. + # Forces load of all tokens. Does not include EOF token. + #/ + def getAllTokens(self): + tokens = [] + t = self.nextToken() + while t.type!=Token.EOF: + tokens.append(t) + t = self.nextToken() + return tokens + + def notifyListeners(self, e:LexerNoViableAltException): + start = self._tokenStartCharIndex + stop = self._input.index + text = self._input.getText(start, stop) + msg = "token recognition error at: '" + self.getErrorDisplay(text) + "'" + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, None, self._tokenStartLine, self._tokenStartColumn, msg, e) + + def getErrorDisplay(self, s:str): + with StringIO() as buf: + for c in s: + buf.write(self.getErrorDisplayForChar(c)) + return buf.getvalue() + + def getErrorDisplayForChar(self, c:str): + if ord(c[0])==Token.EOF: + return "" + elif c=='\n': + return "\\n" + elif c=='\t': + return "\\t" + elif c=='\r': + return "\\r" + else: + return c + + def getCharErrorDisplay(self, c:str): + return "'" + self.getErrorDisplayForChar(c) + "'" + + # Lexers can normally match any char in it's vocabulary after matching + # a token, so do the easy thing and just kill a character and hope + # it all works out. You can instead use the rule invocation stack + # to do sophisticated error recovery if you are in a fragment rule. + #/ + def recover(self, re:RecognitionException): + if self._input.LA(1) != Token.EOF: + if isinstance(re, LexerNoViableAltException): + # skip a char and try again + self._interp.consume(self._input) + else: + # TODO: Do we lose character or line position information? + self._input.consume() + diff --git a/src/antlr4/ListTokenSource.py b/src/antlr4/ListTokenSource.py new file mode 100644 index 00000000..eebc7564 --- /dev/null +++ b/src/antlr4/ListTokenSource.py @@ -0,0 +1,143 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# Provides an implementation of {@link TokenSource} as a wrapper around a list +# of {@link Token} objects. +# +#

          If the final token in the list is an {@link Token#EOF} token, it will be used +# as the EOF token for every call to {@link #nextToken} after the end of the +# list is reached. Otherwise, an EOF token will be created.

          +# +from antlr4.CommonTokenFactory import CommonTokenFactory +from antlr4.Lexer import TokenSource +from antlr4.Token import Token + + +class ListTokenSource(TokenSource): + + # Constructs a new {@link ListTokenSource} instance from the specified + # collection of {@link Token} objects and source name. + # + # @param tokens The collection of {@link Token} objects to provide as a + # {@link TokenSource}. + # @param sourceName The name of the {@link TokenSource}. If this value is + # {@code null}, {@link #getSourceName} will attempt to infer the name from + # the next {@link Token} (or the previous token if the end of the input has + # been reached). + # + # @exception NullPointerException if {@code tokens} is {@code null} + # + def __init__(self, tokens:list, sourceName:str=None): + if tokens is None: + raise ReferenceError("tokens cannot be null") + self.tokens = tokens + self.sourceName = sourceName + # The index into {@link #tokens} of token to return by the next call to + # {@link #nextToken}. The end of the input is indicated by this value + # being greater than or equal to the number of items in {@link #tokens}. + self.pos = 0 + # This field caches the EOF token for the token source. + self.eofToken = None + # This is the backing field for {@link #getTokenFactory} and + self._factory = CommonTokenFactory.DEFAULT + + + # + # {@inheritDoc} + # + @property + def column(self): + if self.pos < len(self.tokens): + return self.tokens[self.pos].column + elif self.eofToken is not None: + return self.eofToken.column + elif len(self.tokens) > 0: + # have to calculate the result from the line/column of the previous + # token, along with the text of the token. + lastToken = self.tokens[len(self.tokens) - 1] + tokenText = lastToken.text + if tokenText is not None: + lastNewLine = tokenText.rfind('\n') + if lastNewLine >= 0: + return len(tokenText) - lastNewLine - 1 + return lastToken.column + lastToken.stop - lastToken.start + 1 + + # only reach this if tokens is empty, meaning EOF occurs at the first + # position in the input + return 0 + + # + # {@inheritDoc} + # + def nextToken(self): + if self.pos >= len(self.tokens): + if self.eofToken is None: + start = -1 + if len(self.tokens) > 0: + previousStop = self.tokens[len(self.tokens) - 1].stop + if previousStop != -1: + start = previousStop + 1 + stop = max(-1, start - 1) + self.eofToken = self._factory.create((self, self.getInputStream()), + Token.EOF, "EOF", Token.DEFAULT_CHANNEL, start, stop, self.line, self.column) + return self.eofToken + t = self.tokens[self.pos] + if self.pos == len(self.tokens) - 1 and t.type == Token.EOF: + self.eofToken = t + self.pos += 1 + return t + + # + # {@inheritDoc} + # + @property + def line(self): + if self.pos < len(self.tokens): + return self.tokens[self.pos].line + elif self.eofToken is not None: + return self.eofToken.line + elif len(self.tokens) > 0: + # have to calculate the result from the line/column of the previous + # token, along with the text of the token. + lastToken = self.tokens[len(self.tokens) - 1] + line = lastToken.line + tokenText = lastToken.text + if tokenText is not None: + line += tokenText.count('\n') + + # if no text is available, assume the token did not contain any newline characters. + return line + + # only reach this if tokens is empty, meaning EOF occurs at the first + # position in the input + return 1 + + # + # {@inheritDoc} + # + def getInputStream(self): + if self.pos < len(self.tokens): + return self.tokens[self.pos].getInputStream() + elif self.eofToken is not None: + return self.eofToken.getInputStream() + elif len(self.tokens) > 0: + return self.tokens[len(self.tokens) - 1].getInputStream() + else: + # no input stream information is available + return None + + # + # {@inheritDoc} + # + def getSourceName(self): + if self.sourceName is not None: + return self.sourceName + inputStream = self.getInputStream() + if inputStream is not None: + return inputStream.getSourceName() + else: + return "List" \ No newline at end of file diff --git a/src/antlr4/Parser.py b/src/antlr4/Parser.py new file mode 100644 index 00000000..c461bbdc --- /dev/null +++ b/src/antlr4/Parser.py @@ -0,0 +1,572 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +import sys +from typing.io import TextIO +from antlr4.BufferedTokenStream import TokenStream +from antlr4.CommonTokenFactory import TokenFactory +from antlr4.error.ErrorStrategy import DefaultErrorStrategy +from antlr4.InputStream import InputStream +from antlr4.Recognizer import Recognizer +from antlr4.RuleContext import RuleContext +from antlr4.ParserRuleContext import ParserRuleContext +from antlr4.Token import Token +from antlr4.Lexer import Lexer +from antlr4.atn.ATNDeserializer import ATNDeserializer +from antlr4.atn.ATNDeserializationOptions import ATNDeserializationOptions +from antlr4.error.Errors import UnsupportedOperationException, RecognitionException +from antlr4.tree.ParseTreePatternMatcher import ParseTreePatternMatcher +from antlr4.tree.Tree import ParseTreeListener, TerminalNode, ErrorNode + +class TraceListener(ParseTreeListener): + + def __init__(self, parser): + self._parser = parser + + def enterEveryRule(self, ctx): + print("enter " + self._parser.ruleNames[ctx.getRuleIndex()] + ", LT(1)=" + self._parser._input.LT(1).text, file=self._parser._output) + + def visitTerminal(self, node): + + print("consume " + str(node.symbol) + " rule " + self._parser.ruleNames[self._parser._ctx.getRuleIndex()], file=self._parser._output) + + def visitErrorNode(self, node): + pass + + + def exitEveryRule(self, ctx): + print("exit " + self._parser.ruleNames[ctx.getRuleIndex()] + ", LT(1)=" + self._parser._input.LT(1).text, file=self._parser._output) + + +# self is all the parsing support code essentially; most of it is error recovery stuff.# +class Parser (Recognizer): + + # self field maps from the serialized ATN string to the deserialized {@link ATN} with + # bypass alternatives. + # + # @see ATNDeserializationOptions#isGenerateRuleBypassTransitions() + # + bypassAltsAtnCache = dict() + + def __init__(self, input:TokenStream, output:TextIO = sys.stdout): + super().__init__() + # The input stream. + self._input = None + self._output = output + # The error handling strategy for the parser. The default value is a new + # instance of {@link DefaultErrorStrategy}. + self._errHandler = DefaultErrorStrategy() + self._precedenceStack = list() + self._precedenceStack.append(0) + # The {@link ParserRuleContext} object for the currently executing rule. + # self is always non-null during the parsing process. + self._ctx = None + # Specifies whether or not the parser should construct a parse tree during + # the parsing process. The default value is {@code true}. + self.buildParseTrees = True + # When {@link #setTrace}{@code (true)} is called, a reference to the + # {@link TraceListener} is stored here so it can be easily removed in a + # later call to {@link #setTrace}{@code (false)}. The listener itself is + # implemented as a parser listener so self field is not directly used by + # other parser methods. + self._tracer = None + # The list of {@link ParseTreeListener} listeners registered to receive + # events during the parse. + self._parseListeners = None + # The number of syntax errors reported during parsing. self value is + # incremented each time {@link #notifyErrorListeners} is called. + self._syntaxErrors = 0 + self.setInputStream(input) + + # reset the parser's state# + def reset(self): + if self._input is not None: + self._input.seek(0) + self._errHandler.reset(self) + self._ctx = None + self._syntaxErrors = 0 + self.setTrace(False) + self._precedenceStack = list() + self._precedenceStack.append(0) + if self._interp is not None: + self._interp.reset() + + # Match current input symbol against {@code ttype}. If the symbol type + # matches, {@link ANTLRErrorStrategy#reportMatch} and {@link #consume} are + # called to complete the match process. + # + #

          If the symbol type does not match, + # {@link ANTLRErrorStrategy#recoverInline} is called on the current error + # strategy to attempt recovery. If {@link #getBuildParseTree} is + # {@code true} and the token index of the symbol returned by + # {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to + # the parse tree by calling {@link ParserRuleContext#addErrorNode}.

          + # + # @param ttype the token type to match + # @return the matched symbol + # @throws RecognitionException if the current input symbol did not match + # {@code ttype} and the error strategy could not recover from the + # mismatched symbol + + def match(self, ttype:int): + t = self.getCurrentToken() + if t.type==ttype: + self._errHandler.reportMatch(self) + self.consume() + else: + t = self._errHandler.recoverInline(self) + if self.buildParseTrees and t.tokenIndex==-1: + # we must have conjured up a new token during single token insertion + # if it's not the current symbol + self._ctx.addErrorNode(t) + return t + + # Match current input symbol as a wildcard. If the symbol type matches + # (i.e. has a value greater than 0), {@link ANTLRErrorStrategy#reportMatch} + # and {@link #consume} are called to complete the match process. + # + #

          If the symbol type does not match, + # {@link ANTLRErrorStrategy#recoverInline} is called on the current error + # strategy to attempt recovery. If {@link #getBuildParseTree} is + # {@code true} and the token index of the symbol returned by + # {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to + # the parse tree by calling {@link ParserRuleContext#addErrorNode}.

          + # + # @return the matched symbol + # @throws RecognitionException if the current input symbol did not match + # a wildcard and the error strategy could not recover from the mismatched + # symbol + + def matchWildcard(self): + t = self.getCurrentToken() + if t.type > 0: + self._errHandler.reportMatch(self) + self.consume() + else: + t = self._errHandler.recoverInline(self) + if self.buildParseTrees and t.tokenIndex == -1: + # we must have conjured up a new token during single token insertion + # if it's not the current symbol + self._ctx.addErrorNode(t) + + return t + + def getParseListeners(self): + return list() if self._parseListeners is None else self._parseListeners + + # Registers {@code listener} to receive events during the parsing process. + # + #

          To support output-preserving grammar transformations (including but not + # limited to left-recursion removal, automated left-factoring, and + # optimized code generation), calls to listener methods during the parse + # may differ substantially from calls made by + # {@link ParseTreeWalker#DEFAULT} used after the parse is complete. In + # particular, rule entry and exit events may occur in a different order + # during the parse than after the parser. In addition, calls to certain + # rule entry methods may be omitted.

          + # + #

          With the following specific exceptions, calls to listener events are + # deterministic, i.e. for identical input the calls to listener + # methods will be the same.

          + # + #
            + #
          • Alterations to the grammar used to generate code may change the + # behavior of the listener calls.
          • + #
          • Alterations to the command line options passed to ANTLR 4 when + # generating the parser may change the behavior of the listener calls.
          • + #
          • Changing the version of the ANTLR Tool used to generate the parser + # may change the behavior of the listener calls.
          • + #
          + # + # @param listener the listener to add + # + # @throws NullPointerException if {@code} listener is {@code null} + # + def addParseListener(self, listener:ParseTreeListener): + if listener is None: + raise ReferenceError("listener") + if self._parseListeners is None: + self._parseListeners = [] + self._parseListeners.append(listener) + + # + # Remove {@code listener} from the list of parse listeners. + # + #

          If {@code listener} is {@code null} or has not been added as a parse + # listener, self method does nothing.

          + # @param listener the listener to remove + # + def removeParseListener(self, listener:ParseTreeListener): + if self._parseListeners is not None: + self._parseListeners.remove(listener) + if len(self._parseListeners)==0: + self._parseListeners = None + + # Remove all parse listeners. + def removeParseListeners(self): + self._parseListeners = None + + # Notify any parse listeners of an enter rule event. + def triggerEnterRuleEvent(self): + if self._parseListeners is not None: + for listener in self._parseListeners: + listener.enterEveryRule(self._ctx) + self._ctx.enterRule(listener) + + # + # Notify any parse listeners of an exit rule event. + # + # @see #addParseListener + # + def triggerExitRuleEvent(self): + if self._parseListeners is not None: + # reverse order walk of listeners + for listener in reversed(self._parseListeners): + self._ctx.exitRule(listener) + listener.exitEveryRule(self._ctx) + + + # Gets the number of syntax errors reported during parsing. This value is + # incremented each time {@link #notifyErrorListeners} is called. + # + # @see #notifyErrorListeners + # + def getNumberOfSyntaxErrors(self): + return self._syntaxErrors + + def getTokenFactory(self): + return self._input.tokenSource._factory + + # Tell our token source and error strategy about a new way to create tokens.# + def setTokenFactory(self, factory:TokenFactory): + self._input.tokenSource._factory = factory + + # The ATN with bypass alternatives is expensive to create so we create it + # lazily. + # + # @throws UnsupportedOperationException if the current parser does not + # implement the {@link #getSerializedATN()} method. + # + def getATNWithBypassAlts(self): + serializedAtn = self.getSerializedATN() + if serializedAtn is None: + raise UnsupportedOperationException("The current parser does not support an ATN with bypass alternatives.") + result = self.bypassAltsAtnCache.get(serializedAtn, None) + if result is None: + deserializationOptions = ATNDeserializationOptions() + deserializationOptions.generateRuleBypassTransitions = True + result = ATNDeserializer(deserializationOptions).deserialize(serializedAtn) + self.bypassAltsAtnCache[serializedAtn] = result + return result + + # The preferred method of getting a tree pattern. For example, here's a + # sample use: + # + #
          +    # ParseTree t = parser.expr();
          +    # ParseTreePattern p = parser.compileParseTreePattern("<ID>+0", MyParser.RULE_expr);
          +    # ParseTreeMatch m = p.match(t);
          +    # String id = m.get("ID");
          +    # 
          + # + def compileParseTreePattern(self, pattern:str, patternRuleIndex:int, lexer:Lexer = None): + if lexer is None: + if self.getTokenStream() is not None: + tokenSource = self.getTokenStream().tokenSource + if isinstance( tokenSource, Lexer ): + lexer = tokenSource + if lexer is None: + raise UnsupportedOperationException("Parser can't discover a lexer to use") + + m = ParseTreePatternMatcher(lexer, self) + return m.compile(pattern, patternRuleIndex) + + + def getInputStream(self): + return self.getTokenStream() + + def setInputStream(self, input:InputStream): + self.setTokenStream(input) + + def getTokenStream(self): + return self._input + + # Set the token stream and reset the parser.# + def setTokenStream(self, input:TokenStream): + self._input = None + self.reset() + self._input = input + + # Match needs to return the current input symbol, which gets put + # into the label for the associated token ref; e.g., x=ID. + # + def getCurrentToken(self): + return self._input.LT(1) + + def notifyErrorListeners(self, msg:str, offendingToken:Token = None, e:RecognitionException = None): + if offendingToken is None: + offendingToken = self.getCurrentToken() + self._syntaxErrors += 1 + line = offendingToken.line + column = offendingToken.column + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, offendingToken, line, column, msg, e) + + # + # Consume and return the {@linkplain #getCurrentToken current symbol}. + # + #

          E.g., given the following input with {@code A} being the current + # lookahead symbol, self function moves the cursor to {@code B} and returns + # {@code A}.

          + # + #
          +    #  A B
          +    #  ^
          +    # 
          + # + # If the parser is not in error recovery mode, the consumed symbol is added + # to the parse tree using {@link ParserRuleContext#addChild(Token)}, and + # {@link ParseTreeListener#visitTerminal} is called on any parse listeners. + # If the parser is in error recovery mode, the consumed symbol is + # added to the parse tree using + # {@link ParserRuleContext#addErrorNode(Token)}, and + # {@link ParseTreeListener#visitErrorNode} is called on any parse + # listeners. + # + def consume(self): + o = self.getCurrentToken() + if o.type != Token.EOF: + self.getInputStream().consume() + hasListener = self._parseListeners is not None and len(self._parseListeners)>0 + if self.buildParseTrees or hasListener: + if self._errHandler.inErrorRecoveryMode(self): + node = self._ctx.addErrorNode(o) + else: + node = self._ctx.addTokenNode(o) + if hasListener: + for listener in self._parseListeners: + if isinstance(node, ErrorNode): + listener.visitErrorNode(node) + elif isinstance(node, TerminalNode): + listener.visitTerminal(node) + return o + + def addContextToParseTree(self): + # add current context to parent if we have a parent + if self._ctx.parentCtx is not None: + self._ctx.parentCtx.addChild(self._ctx) + + # Always called by generated parsers upon entry to a rule. Access field + # {@link #_ctx} get the current context. + # + def enterRule(self, localctx:ParserRuleContext , state:int , ruleIndex:int): + self.state = state + self._ctx = localctx + self._ctx.start = self._input.LT(1) + if self.buildParseTrees: + self.addContextToParseTree() + if self._parseListeners is not None: + self.triggerEnterRuleEvent() + + def exitRule(self): + self._ctx.stop = self._input.LT(-1) + # trigger event on _ctx, before it reverts to parent + if self._parseListeners is not None: + self.triggerExitRuleEvent() + self.state = self._ctx.invokingState + self._ctx = self._ctx.parentCtx + + def enterOuterAlt(self, localctx:ParserRuleContext, altNum:int): + localctx.setAltNumber(altNum) + # if we have new localctx, make sure we replace existing ctx + # that is previous child of parse tree + if self.buildParseTrees and self._ctx != localctx: + if self._ctx.parentCtx is not None: + self._ctx.parentCtx.removeLastChild() + self._ctx.parentCtx.addChild(localctx) + self._ctx = localctx + + # Get the precedence level for the top-most precedence rule. + # + # @return The precedence level for the top-most precedence rule, or -1 if + # the parser context is not nested within a precedence rule. + # + def getPrecedence(self): + if len(self._precedenceStack)==0: + return -1 + else: + return self._precedenceStack[-1] + + def enterRecursionRule(self, localctx:ParserRuleContext, state:int, ruleIndex:int, precedence:int): + self.state = state + self._precedenceStack.append(precedence) + self._ctx = localctx + self._ctx.start = self._input.LT(1) + if self._parseListeners is not None: + self.triggerEnterRuleEvent() # simulates rule entry for left-recursive rules + + # + # Like {@link #enterRule} but for recursive rules. + # + def pushNewRecursionContext(self, localctx:ParserRuleContext, state:int, ruleIndex:int): + previous = self._ctx + previous.parentCtx = localctx + previous.invokingState = state + previous.stop = self._input.LT(-1) + + self._ctx = localctx + self._ctx.start = previous.start + if self.buildParseTrees: + self._ctx.addChild(previous) + + if self._parseListeners is not None: + self.triggerEnterRuleEvent() # simulates rule entry for left-recursive rules + + def unrollRecursionContexts(self, parentCtx:ParserRuleContext): + self._precedenceStack.pop() + self._ctx.stop = self._input.LT(-1) + retCtx = self._ctx # save current ctx (return value) + # unroll so _ctx is as it was before call to recursive method + if self._parseListeners is not None: + while self._ctx is not parentCtx: + self.triggerExitRuleEvent() + self._ctx = self._ctx.parentCtx + else: + self._ctx = parentCtx + + # hook into tree + retCtx.parentCtx = parentCtx + + if self.buildParseTrees and parentCtx is not None: + # add return ctx into invoking rule's tree + parentCtx.addChild(retCtx) + + def getInvokingContext(self, ruleIndex:int): + ctx = self._ctx + while ctx is not None: + if ctx.ruleIndex == ruleIndex: + return ctx + ctx = ctx.parentCtx + return None + + + def precpred(self, localctx:RuleContext , precedence:int): + return precedence >= self._precedenceStack[-1] + + def inContext(self, context:str): + # TODO: useful in parser? + return False + + # + # Checks whether or not {@code symbol} can follow the current state in the + # ATN. The behavior of self method is equivalent to the following, but is + # implemented such that the complete context-sensitive follow set does not + # need to be explicitly constructed. + # + #
          +    # return getExpectedTokens().contains(symbol);
          +    # 
          + # + # @param symbol the symbol type to check + # @return {@code true} if {@code symbol} can follow the current state in + # the ATN, otherwise {@code false}. + # + def isExpectedToken(self, symbol:int): + atn = self._interp.atn + ctx = self._ctx + s = atn.states[self.state] + following = atn.nextTokens(s) + if symbol in following: + return True + if not Token.EPSILON in following: + return False + + while ctx is not None and ctx.invokingState>=0 and Token.EPSILON in following: + invokingState = atn.states[ctx.invokingState] + rt = invokingState.transitions[0] + following = atn.nextTokens(rt.followState) + if symbol in following: + return True + ctx = ctx.parentCtx + + if Token.EPSILON in following and symbol == Token.EOF: + return True + else: + return False + + # Computes the set of input symbols which could follow the current parser + # state and context, as given by {@link #getState} and {@link #getContext}, + # respectively. + # + # @see ATN#getExpectedTokens(int, RuleContext) + # + def getExpectedTokens(self): + return self._interp.atn.getExpectedTokens(self.state, self._ctx) + + def getExpectedTokensWithinCurrentRule(self): + atn = self._interp.atn + s = atn.states[self.state] + return atn.nextTokens(s) + + # Get a rule's index (i.e., {@code RULE_ruleName} field) or -1 if not found.# + def getRuleIndex(self, ruleName:str): + ruleIndex = self.getRuleIndexMap().get(ruleName, None) + if ruleIndex is not None: + return ruleIndex + else: + return -1 + + # Return List<String> of the rule names in your parser instance + # leading up to a call to the current rule. You could override if + # you want more details such as the file/line info of where + # in the ATN a rule is invoked. + # + # this is very useful for error messages. + # + def getRuleInvocationStack(self, p:RuleContext=None): + if p is None: + p = self._ctx + stack = list() + while p is not None: + # compute what follows who invoked us + ruleIndex = p.getRuleIndex() + if ruleIndex<0: + stack.append("n/a") + else: + stack.append(self.ruleNames[ruleIndex]) + p = p.parentCtx + return stack + + # For debugging and other purposes.# + def getDFAStrings(self): + return [ str(dfa) for dfa in self._interp.decisionToDFA] + + # For debugging and other purposes.# + def dumpDFA(self): + seenOne = False + for i in range(0, len(self._interp.decisionToDFA)): + dfa = self._interp.decisionToDFA[i] + if len(dfa.states)>0: + if seenOne: + print(file=self._output) + print("Decision " + str(dfa.decision) + ":", file=self._output) + print(dfa.toString(self.literalNames, self.symbolicNames), end='', file=self._output) + seenOne = True + + + def getSourceName(self): + return self._input.sourceName + + # During a parse is sometimes useful to listen in on the rule entry and exit + # events as well as token matches. self is for quick and dirty debugging. + # + def setTrace(self, trace:bool): + if not trace: + self.removeParseListener(self._tracer) + self._tracer = None + else: + if self._tracer is not None: + self.removeParseListener(self._tracer) + self._tracer = TraceListener(self) + self.addParseListener(self._tracer) diff --git a/src/antlr4/ParserInterpreter.py b/src/antlr4/ParserInterpreter.py new file mode 100644 index 00000000..117f67ba --- /dev/null +++ b/src/antlr4/ParserInterpreter.py @@ -0,0 +1,165 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# A parser simulator that mimics what ANTLR's generated +# parser code does. A ParserATNSimulator is used to make +# predictions via adaptivePredict but this class moves a pointer through the +# ATN to simulate parsing. ParserATNSimulator just +# makes us efficient rather than having to backtrack, for example. +# +# This properly creates parse trees even for left recursive rules. +# +# We rely on the left recursive rule invocation and special predicate +# transitions to make left recursive rules work. +# +# See TestParserInterpreter for examples. +# +from antlr4.dfa.DFA import DFA +from antlr4.BufferedTokenStream import TokenStream +from antlr4.Lexer import Lexer +from antlr4.Parser import Parser +from antlr4.ParserRuleContext import InterpreterRuleContext, ParserRuleContext +from antlr4.Token import Token +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNState import StarLoopEntryState, ATNState, LoopEndState +from antlr4.atn.ParserATNSimulator import ParserATNSimulator +from antlr4.PredictionContext import PredictionContextCache +from antlr4.atn.Transition import Transition +from antlr4.error.Errors import RecognitionException, UnsupportedOperationException, FailedPredicateException + + +class ParserInterpreter(Parser): + + def __init__(self, grammarFileName:str, tokenNames:list, ruleNames:list, atn:ATN, input:TokenStream): + super().__init__(input) + self.grammarFileName = grammarFileName + self.atn = atn + self.tokenNames = tokenNames + self.ruleNames = ruleNames + self.decisionToDFA = [ DFA(state) for state in atn.decisionToState ] + self.sharedContextCache = PredictionContextCache() + self._parentContextStack = list() + # identify the ATN states where pushNewRecursionContext must be called + self.pushRecursionContextStates = set() + for state in atn.states: + if not isinstance(state, StarLoopEntryState): + continue + if state.isPrecedenceDecision: + self.pushRecursionContextStates.add(state.stateNumber) + # get atn simulator that knows how to do predictions + self._interp = ParserATNSimulator(self, atn, self.decisionToDFA, self.sharedContextCache) + + # Begin parsing at startRuleIndex# + def parse(self, startRuleIndex:int): + startRuleStartState = self.atn.ruleToStartState[startRuleIndex] + rootContext = InterpreterRuleContext(None, ATNState.INVALID_STATE_NUMBER, startRuleIndex) + if startRuleStartState.isPrecedenceRule: + self.enterRecursionRule(rootContext, startRuleStartState.stateNumber, startRuleIndex, 0) + else: + self.enterRule(rootContext, startRuleStartState.stateNumber, startRuleIndex) + while True: + p = self.getATNState() + if p.stateType==ATNState.RULE_STOP : + # pop; return from rule + if len(self._ctx)==0: + if startRuleStartState.isPrecedenceRule: + result = self._ctx + parentContext = self._parentContextStack.pop() + self.unrollRecursionContexts(parentContext.a) + return result + else: + self.exitRule() + return rootContext + self.visitRuleStopState(p) + + else: + try: + self.visitState(p) + except RecognitionException as e: + self.state = self.atn.ruleToStopState[p.ruleIndex].stateNumber + self._ctx.exception = e + self._errHandler.reportError(self, e) + self._errHandler.recover(self, e) + + def enterRecursionRule(self, localctx:ParserRuleContext, state:int, ruleIndex:int, precedence:int): + self._parentContextStack.append((self._ctx, localctx.invokingState)) + super().enterRecursionRule(localctx, state, ruleIndex, precedence) + + def getATNState(self): + return self.atn.states[self.state] + + def visitState(self, p:ATNState): + edge = 0 + if len(p.transitions) > 1: + self._errHandler.sync(self) + edge = self._interp.adaptivePredict(self._input, p.decision, self._ctx) + else: + edge = 1 + + transition = p.transitions[edge - 1] + tt = transition.serializationType + if tt==Transition.EPSILON: + + if self.pushRecursionContextStates[p.stateNumber] and not isinstance(transition.target, LoopEndState): + t = self._parentContextStack[-1] + ctx = InterpreterRuleContext(t[0], t[1], self._ctx.ruleIndex) + self.pushNewRecursionContext(ctx, self.atn.ruleToStartState[p.ruleIndex].stateNumber, self._ctx.ruleIndex) + + elif tt==Transition.ATOM: + + self.match(transition.label) + + elif tt in [ Transition.RANGE, Transition.SET, Transition.NOT_SET]: + + if not transition.matches(self._input.LA(1), Token.MIN_USER_TOKEN_TYPE, Lexer.MAX_CHAR_VALUE): + self._errHandler.recoverInline(self) + self.matchWildcard() + + elif tt==Transition.WILDCARD: + + self.matchWildcard() + + elif tt==Transition.RULE: + + ruleStartState = transition.target + ruleIndex = ruleStartState.ruleIndex + ctx = InterpreterRuleContext(self._ctx, p.stateNumber, ruleIndex) + if ruleStartState.isPrecedenceRule: + self.enterRecursionRule(ctx, ruleStartState.stateNumber, ruleIndex, transition.precedence) + else: + self.enterRule(ctx, transition.target.stateNumber, ruleIndex) + + elif tt==Transition.PREDICATE: + + if not self.sempred(self._ctx, transition.ruleIndex, transition.predIndex): + raise FailedPredicateException(self) + + elif tt==Transition.ACTION: + + self.action(self._ctx, transition.ruleIndex, transition.actionIndex) + + elif tt==Transition.PRECEDENCE: + + if not self.precpred(self._ctx, transition.precedence): + msg = "precpred(_ctx, " + str(transition.precedence) + ")" + raise FailedPredicateException(self, msg) + + else: + raise UnsupportedOperationException("Unrecognized ATN transition type.") + + self.state = transition.target.stateNumber + + def visitRuleStopState(self, p:ATNState): + ruleStartState = self.atn.ruleToStartState[p.ruleIndex] + if ruleStartState.isPrecedenceRule: + parentContext = self._parentContextStack.pop() + self.unrollRecursionContexts(parentContext.a) + self.state = parentContext[1] + else: + self.exitRule() + + ruleTransition = self.atn.states[self.state].transitions[0] + self.state = ruleTransition.followState.stateNumber diff --git a/src/antlr4/ParserRuleContext.py b/src/antlr4/ParserRuleContext.py new file mode 100644 index 00000000..c5049eb7 --- /dev/null +++ b/src/antlr4/ParserRuleContext.py @@ -0,0 +1,186 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. + +#* A rule invocation record for parsing. +# +# Contains all of the information about the current rule not stored in the +# RuleContext. It handles parse tree children list, Any ATN state +# tracing, and the default values available for rule indications: +# start, stop, rule index, current alt number, current +# ATN state. +# +# Subclasses made for each rule and grammar track the parameters, +# return values, locals, and labels specific to that rule. These +# are the objects that are returned from rules. +# +# Note text is not an actual field of a rule return value; it is computed +# from start and stop using the input stream's toString() method. I +# could add a ctor to this so that we can pass in and store the input +# stream, but I'm not sure we want to do that. It would seem to be undefined +# to get the .text property anyway if the rule matches tokens from multiple +# input streams. +# +# I do not use getters for fields of objects that are used simply to +# group values such as this aggregate. The getters/setters are there to +# satisfy the superclass interface. + +from antlr4.RuleContext import RuleContext +from antlr4.Token import Token +from antlr4.tree.Tree import ParseTreeListener, ParseTree, TerminalNodeImpl, ErrorNodeImpl, TerminalNode, \ + INVALID_INTERVAL + +# need forward declaration +ParserRuleContext = None + +class ParserRuleContext(RuleContext): + + def __init__(self, parent:ParserRuleContext = None, invokingStateNumber:int = None ): + super().__init__(parent, invokingStateNumber) + #* If we are debugging or building a parse tree for a visitor, + # we need to track all of the tokens and rule invocations associated + # with this rule's context. This is empty for parsing w/o tree constr. + # operation because we don't the need to track the details about + # how we parse this rule. + #/ + self.children = None + self.start = None + self.stop = None + # The exception that forced this rule to return. If the rule successfully + # completed, this is {@code null}. + self.exception = None + + #* COPY a ctx (I'm deliberately not using copy constructor)#/ + # + # This is used in the generated parser code to flip a generic XContext + # node for rule X to a YContext for alt label Y. In that sense, it is + # not really a generic copy function. + # + # If we do an error sync() at start of a rule, we might add error nodes + # to the generic XContext so this function must copy those nodes to + # the YContext as well else they are lost! + #/ + def copyFrom(self, ctx:ParserRuleContext): + # from RuleContext + self.parentCtx = ctx.parentCtx + self.invokingState = ctx.invokingState + self.children = None + self.start = ctx.start + self.stop = ctx.stop + + # copy any error nodes to alt label node + if ctx.children is not None: + self.children = [] + # reset parent pointer for any error nodes + for child in ctx.children: + if isinstance(child, ErrorNodeImpl): + self.children.append(child) + child.parentCtx = self + + # Double dispatch methods for listeners + def enterRule(self, listener:ParseTreeListener): + pass + + def exitRule(self, listener:ParseTreeListener): + pass + + #* Does not set parent link; other add methods do that#/ + def addChild(self, child:ParseTree): + if self.children is None: + self.children = [] + self.children.append(child) + return child + + #* Used by enterOuterAlt to toss out a RuleContext previously added as + # we entered a rule. If we have # label, we will need to remove + # generic ruleContext object. + #/ + def removeLastChild(self): + if self.children is not None: + del self.children[len(self.children)-1] + + def addTokenNode(self, token:Token): + node = TerminalNodeImpl(token) + self.addChild(node) + node.parentCtx = self + return node + + def addErrorNode(self, badToken:Token): + node = ErrorNodeImpl(badToken) + self.addChild(node) + node.parentCtx = self + return node + + def getChild(self, i:int, ttype:type = None): + if ttype is None: + return self.children[i] if len(self.children)>=i else None + else: + for child in self.getChildren(): + if not isinstance(child, ttype): + continue + if i==0: + return child + i -= 1 + return None + + def getChildren(self, predicate = None): + if self.children is not None: + for child in self.children: + if predicate is not None and not predicate(child): + continue + yield child + + def getToken(self, ttype:int, i:int): + for child in self.getChildren(): + if not isinstance(child, TerminalNode): + continue + if child.symbol.type != ttype: + continue + if i==0: + return child + i -= 1 + return None + + def getTokens(self, ttype:int ): + if self.getChildren() is None: + return [] + tokens = [] + for child in self.getChildren(): + if not isinstance(child, TerminalNode): + continue + if child.symbol.type != ttype: + continue + tokens.append(child) + return tokens + + def getTypedRuleContext(self, ctxType:type, i:int): + return self.getChild(i, ctxType) + + def getTypedRuleContexts(self, ctxType:type): + children = self.getChildren() + if children is None: + return [] + contexts = [] + for child in children: + if not isinstance(child, ctxType): + continue + contexts.append(child) + return contexts + + def getChildCount(self): + return len(self.children) if self.children else 0 + + def getSourceInterval(self): + if self.start is None or self.stop is None: + return INVALID_INTERVAL + else: + return (self.start.tokenIndex, self.stop.tokenIndex) + + +RuleContext.EMPTY = ParserRuleContext() + +class InterpreterRuleContext(ParserRuleContext): + + def __init__(self, parent:ParserRuleContext, invokingStateNumber:int, ruleIndex:int): + super().__init__(parent, invokingStateNumber) + self.ruleIndex = ruleIndex diff --git a/src/antlr4/PredictionContext.py b/src/antlr4/PredictionContext.py new file mode 100644 index 00000000..e3736ad2 --- /dev/null +++ b/src/antlr4/PredictionContext.py @@ -0,0 +1,623 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ +from io import StringIO + +from antlr4.error.Errors import IllegalStateException + +from antlr4.RuleContext import RuleContext +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNState import ATNState + + +class PredictionContext(object): + + # Represents {@code $} in local context prediction, which means wildcard. + # {@code#+x =#}. + #/ + EMPTY = None + + # Represents {@code $} in an array in full context mode, when {@code $} + # doesn't mean wildcard: {@code $ + x = [$,x]}. Here, + # {@code $} = {@link #EMPTY_RETURN_STATE}. + #/ + EMPTY_RETURN_STATE = 0x7FFFFFFF + + globalNodeCount = 1 + id = globalNodeCount + + # Stores the computed hash code of this {@link PredictionContext}. The hash + # code is computed in parts to match the following reference algorithm. + # + #
          +    #  private int referenceHashCode() {
          +    #      int hash = {@link MurmurHash#initialize MurmurHash.initialize}({@link #INITIAL_HASH});
          +    #
          +    #      for (int i = 0; i < {@link #size()}; i++) {
          +    #          hash = {@link MurmurHash#update MurmurHash.update}(hash, {@link #getParent getParent}(i));
          +    #      }
          +    #
          +    #      for (int i = 0; i < {@link #size()}; i++) {
          +    #          hash = {@link MurmurHash#update MurmurHash.update}(hash, {@link #getReturnState getReturnState}(i));
          +    #      }
          +    #
          +    #      hash = {@link MurmurHash#finish MurmurHash.finish}(hash, 2# {@link #size()});
          +    #      return hash;
          +    #  }
          +    # 
          + #/ + + def __init__(self, cachedHashCode:int): + self.cachedHashCode = cachedHashCode + + def __len__(self): + return 0 + + # This means only the {@link #EMPTY} context is in set. + def isEmpty(self): + return self is self.EMPTY + + def hasEmptyPath(self): + return self.getReturnState(len(self) - 1) == self.EMPTY_RETURN_STATE + + def getReturnState(self, index:int): + raise IllegalStateException("illegal!") + + def __hash__(self): + return self.cachedHashCode + +def calculateHashCode(parent:PredictionContext, returnState:int): + return hash("") if parent is None else hash((hash(parent), returnState)) + +def calculateListsHashCode(parents:[], returnStates:[] ): + h = 0 + for parent, returnState in zip(parents, returnStates): + h = hash((h, calculateHashCode(parent, returnState))) + return h + +# Used to cache {@link PredictionContext} objects. Its used for the shared +# context cash associated with contexts in DFA states. This cache +# can be used for both lexers and parsers. + +class PredictionContextCache(object): + + def __init__(self): + self.cache = dict() + + # Add a context to the cache and return it. If the context already exists, + # return that one instead and do not add a new context to the cache. + # Protect shared cache from unsafe thread access. + # + def add(self, ctx:PredictionContext): + if ctx==PredictionContext.EMPTY: + return PredictionContext.EMPTY + existing = self.cache.get(ctx, None) + if existing is not None: + return existing + self.cache[ctx] = ctx + return ctx + + def get(self, ctx:PredictionContext): + return self.cache.get(ctx, None) + + def __len__(self): + return len(self.cache) + + +class SingletonPredictionContext(PredictionContext): + + @staticmethod + def create(parent:PredictionContext , returnState:int ): + if returnState == PredictionContext.EMPTY_RETURN_STATE and parent is None: + # someone can pass in the bits of an array ctx that mean $ + return SingletonPredictionContext.EMPTY + else: + return SingletonPredictionContext(parent, returnState) + + def __init__(self, parent:PredictionContext, returnState:int): + hashCode = calculateHashCode(parent, returnState) + super().__init__(hashCode) + self.parentCtx = parent + self.returnState = returnState + + def __len__(self): + return 1 + + def getParent(self, index:int): + return self.parentCtx + + def getReturnState(self, index:int): + return self.returnState + + def __eq__(self, other): + if self is other: + return True + elif other is None: + return False + elif not isinstance(other, SingletonPredictionContext): + return False + else: + return self.returnState == other.returnState and self.parentCtx == other.parentCtx + + def __hash__(self): + return self.cachedHashCode + + def __str__(self): + up = "" if self.parentCtx is None else str(self.parentCtx) + if len(up)==0: + if self.returnState == self.EMPTY_RETURN_STATE: + return "$" + else: + return str(self.returnState) + else: + return str(self.returnState) + " " + up + + +class EmptyPredictionContext(SingletonPredictionContext): + + def __init__(self): + super().__init__(None, self.EMPTY_RETURN_STATE) + + def isEmpty(self): + return True + + def __eq__(self, other): + return self is other + + def __hash__(self): + return self.cachedHashCode + + def __str__(self): + return "$" + + +PredictionContext.EMPTY = EmptyPredictionContext() + +class ArrayPredictionContext(PredictionContext): + # Parent can be null only if full ctx mode and we make an array + # from {@link #EMPTY} and non-empty. We merge {@link #EMPTY} by using null parent and + # returnState == {@link #EMPTY_RETURN_STATE}. + + def __init__(self, parents:list, returnStates:list): + super().__init__(calculateListsHashCode(parents, returnStates)) + self.parents = parents + self.returnStates = returnStates + + def isEmpty(self): + # since EMPTY_RETURN_STATE can only appear in the last position, we + # don't need to verify that size==1 + return self.returnStates[0]==PredictionContext.EMPTY_RETURN_STATE + + def __len__(self): + return len(self.returnStates) + + def getParent(self, index:int): + return self.parents[index] + + def getReturnState(self, index:int): + return self.returnStates[index] + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, ArrayPredictionContext): + return False + elif hash(self) != hash(other): + return False # can't be same if hash is different + else: + return self.returnStates==other.returnStates and self.parents==other.parents + + def __str__(self): + if self.isEmpty(): + return "[]" + with StringIO() as buf: + buf.write("[") + for i in range(0,len(self.returnStates)): + if i>0: + buf.write(", ") + if self.returnStates[i]==PredictionContext.EMPTY_RETURN_STATE: + buf.write("$") + continue + buf.write(str(self.returnStates[i])) + if self.parents[i] is not None: + buf.write(' ') + buf.write(str(self.parents[i])) + else: + buf.write("null") + buf.write("]") + return buf.getvalue() + + def __hash__(self): + return self.cachedHashCode + + + +# Convert a {@link RuleContext} tree to a {@link PredictionContext} graph. +# Return {@link #EMPTY} if {@code outerContext} is empty or null. +#/ +def PredictionContextFromRuleContext(atn:ATN, outerContext:RuleContext=None): + if outerContext is None: + outerContext = RuleContext.EMPTY + + # if we are in RuleContext of start rule, s, then PredictionContext + # is EMPTY. Nobody called us. (if we are empty, return empty) + if outerContext.parentCtx is None or outerContext is RuleContext.EMPTY: + return PredictionContext.EMPTY + + # If we have a parent, convert it to a PredictionContext graph + parent = PredictionContextFromRuleContext(atn, outerContext.parentCtx) + state = atn.states[outerContext.invokingState] + transition = state.transitions[0] + return SingletonPredictionContext.create(parent, transition.followState.stateNumber) + + +def merge(a:PredictionContext, b:PredictionContext, rootIsWildcard:bool, mergeCache:dict): + + # share same graph if both same + if a==b: + return a + + if isinstance(a, SingletonPredictionContext) and isinstance(b, SingletonPredictionContext): + return mergeSingletons(a, b, rootIsWildcard, mergeCache) + + # At least one of a or b is array + # If one is $ and rootIsWildcard, return $ as# wildcard + if rootIsWildcard: + if isinstance( a, EmptyPredictionContext ): + return a + if isinstance( b, EmptyPredictionContext ): + return b + + # convert singleton so both are arrays to normalize + if isinstance( a, SingletonPredictionContext ): + a = ArrayPredictionContext([a.parentCtx], [a.returnState]) + if isinstance( b, SingletonPredictionContext): + b = ArrayPredictionContext([b.parentCtx], [b.returnState]) + return mergeArrays(a, b, rootIsWildcard, mergeCache) + + +# +# Merge two {@link SingletonPredictionContext} instances. +# +#

          Stack tops equal, parents merge is same; return left graph.
          +#

          +# +#

          Same stack top, parents differ; merge parents giving array node, then +# remainders of those graphs. A new root node is created to point to the +# merged parents.
          +#

          +# +#

          Different stack tops pointing to same parent. Make array node for the +# root where both element in the root point to the same (original) +# parent.
          +#

          +# +#

          Different stack tops pointing to different parents. Make array node for +# the root where each element points to the corresponding original +# parent.
          +#

          +# +# @param a the first {@link SingletonPredictionContext} +# @param b the second {@link SingletonPredictionContext} +# @param rootIsWildcard {@code true} if this is a local-context merge, +# otherwise false to indicate a full-context merge +# @param mergeCache +#/ +def mergeSingletons(a:SingletonPredictionContext, b:SingletonPredictionContext, rootIsWildcard:bool, mergeCache:dict): + if mergeCache is not None: + previous = mergeCache.get((a,b), None) + if previous is not None: + return previous + previous = mergeCache.get((b,a), None) + if previous is not None: + return previous + + merged = mergeRoot(a, b, rootIsWildcard) + if merged is not None: + if mergeCache is not None: + mergeCache[(a, b)] = merged + return merged + + if a.returnState==b.returnState: + parent = merge(a.parentCtx, b.parentCtx, rootIsWildcard, mergeCache) + # if parent is same as existing a or b parent or reduced to a parent, return it + if parent == a.parentCtx: + return a # ax + bx = ax, if a=b + if parent == b.parentCtx: + return b # ax + bx = bx, if a=b + # else: ax + ay = a'[x,y] + # merge parents x and y, giving array node with x,y then remainders + # of those graphs. dup a, a' points at merged array + # new joined parent so create new singleton pointing to it, a' + merged = SingletonPredictionContext.create(parent, a.returnState) + if mergeCache is not None: + mergeCache[(a, b)] = merged + return merged + else: # a != b payloads differ + # see if we can collapse parents due to $+x parents if local ctx + singleParent = None + if a is b or (a.parentCtx is not None and a.parentCtx==b.parentCtx): # ax + bx = [a,b]x + singleParent = a.parentCtx + if singleParent is not None: # parents are same + # sort payloads and use same parent + payloads = [ a.returnState, b.returnState ] + if a.returnState > b.returnState: + payloads = [ b.returnState, a.returnState ] + parents = [singleParent, singleParent] + merged = ArrayPredictionContext(parents, payloads) + if mergeCache is not None: + mergeCache[(a, b)] = merged + return merged + # parents differ and can't merge them. Just pack together + # into array; can't merge. + # ax + by = [ax,by] + payloads = [ a.returnState, b.returnState ] + parents = [ a.parentCtx, b.parentCtx ] + if a.returnState > b.returnState: # sort by payload + payloads = [ b.returnState, a.returnState ] + parents = [ b.parentCtx, a.parentCtx ] + merged = ArrayPredictionContext(parents, payloads) + if mergeCache is not None: + mergeCache[(a, b)] = merged + return merged + + +# +# Handle case where at least one of {@code a} or {@code b} is +# {@link #EMPTY}. In the following diagrams, the symbol {@code $} is used +# to represent {@link #EMPTY}. +# +#

          Local-Context Merges

          +# +#

          These local-context merge operations are used when {@code rootIsWildcard} +# is true.

          +# +#

          {@link #EMPTY} is superset of any graph; return {@link #EMPTY}.
          +#

          +# +#

          {@link #EMPTY} and anything is {@code #EMPTY}, so merged parent is +# {@code #EMPTY}; return left graph.
          +#

          +# +#

          Special case of last merge if local context.
          +#

          +# +#

          Full-Context Merges

          +# +#

          These full-context merge operations are used when {@code rootIsWildcard} +# is false.

          +# +#

          +# +#

          Must keep all contexts; {@link #EMPTY} in array is a special value (and +# null parent).
          +#

          +# +#

          +# +# @param a the first {@link SingletonPredictionContext} +# @param b the second {@link SingletonPredictionContext} +# @param rootIsWildcard {@code true} if this is a local-context merge, +# otherwise false to indicate a full-context merge +#/ +def mergeRoot(a:SingletonPredictionContext, b:SingletonPredictionContext, rootIsWildcard:bool): + if rootIsWildcard: + if a == PredictionContext.EMPTY: + return PredictionContext.EMPTY ## + b =# + if b == PredictionContext.EMPTY: + return PredictionContext.EMPTY # a +# =# + else: + if a == PredictionContext.EMPTY and b == PredictionContext.EMPTY: + return PredictionContext.EMPTY # $ + $ = $ + elif a == PredictionContext.EMPTY: # $ + x = [$,x] + payloads = [ b.returnState, PredictionContext.EMPTY_RETURN_STATE ] + parents = [ b.parentCtx, None ] + return ArrayPredictionContext(parents, payloads) + elif b == PredictionContext.EMPTY: # x + $ = [$,x] ($ is always first if present) + payloads = [ a.returnState, PredictionContext.EMPTY_RETURN_STATE ] + parents = [ a.parentCtx, None ] + return ArrayPredictionContext(parents, payloads) + return None + + +# +# Merge two {@link ArrayPredictionContext} instances. +# +#

          Different tops, different parents.
          +#

          +# +#

          Shared top, same parents.
          +#

          +# +#

          Shared top, different parents.
          +#

          +# +#

          Shared top, all shared parents.
          +#

          +# +#

          Equal tops, merge parents and reduce top to +# {@link SingletonPredictionContext}.
          +#

          +#/ +def mergeArrays(a:ArrayPredictionContext, b:ArrayPredictionContext, rootIsWildcard:bool, mergeCache:dict): + if mergeCache is not None: + previous = mergeCache.get((a,b), None) + if previous is not None: + return previous + previous = mergeCache.get((b,a), None) + if previous is not None: + return previous + + # merge sorted payloads a + b => M + i = 0 # walks a + j = 0 # walks b + k = 0 # walks target M array + + mergedReturnStates = [None] * (len(a.returnStates) + len( b.returnStates)) + mergedParents = [None] * len(mergedReturnStates) + # walk and merge to yield mergedParents, mergedReturnStates + while i ax + if bothDollars or ax_ax: + mergedParents[k] = a_parent # choose left + mergedReturnStates[k] = payload + else: # ax+ay -> a'[x,y] + mergedParent = merge(a_parent, b_parent, rootIsWildcard, mergeCache) + mergedParents[k] = mergedParent + mergedReturnStates[k] = payload + i += 1 # hop over left one as usual + j += 1 # but also skip one in right side since we merge + elif a.returnStates[i] a, copy b[j] to M + mergedParents[k] = b_parent + mergedReturnStates[k] = b.returnStates[j] + j += 1 + k += 1 + + # copy over any payloads remaining in either array + if i < len(a.returnStates): + for p in range(i, len(a.returnStates)): + mergedParents[k] = a.parents[p] + mergedReturnStates[k] = a.returnStates[p] + k += 1 + else: + for p in range(j, len(b.returnStates)): + mergedParents[k] = b.parents[p] + mergedReturnStates[k] = b.returnStates[p] + k += 1 + + # trim merged if we combined a few that had same stack tops + if k < len(mergedParents): # write index < last position; trim + if k == 1: # for just one merged element, return singleton top + merged = SingletonPredictionContext.create(mergedParents[0], mergedReturnStates[0]) + if mergeCache is not None: + mergeCache[(a,b)] = merged + return merged + mergedParents = mergedParents[0:k] + mergedReturnStates = mergedReturnStates[0:k] + + merged = ArrayPredictionContext(mergedParents, mergedReturnStates) + + # if we created same array as a or b, return that instead + # TODO: track whether this is possible above during merge sort for speed + if merged==a: + if mergeCache is not None: + mergeCache[(a,b)] = a + return a + if merged==b: + if mergeCache is not None: + mergeCache[(a,b)] = b + return b + combineCommonParents(mergedParents) + + if mergeCache is not None: + mergeCache[(a,b)] = merged + return merged + + +# +# Make pass over all M {@code parents}; merge any {@code equals()} +# ones. +#/ +def combineCommonParents(parents:list): + uniqueParents = dict() + + for p in range(0, len(parents)): + parent = parents[p] + if uniqueParents.get(parent, None) is None: + uniqueParents[parent] = parent + + for p in range(0, len(parents)): + parents[p] = uniqueParents[parents[p]] + +def getCachedPredictionContext(context:PredictionContext, contextCache:PredictionContextCache, visited:dict): + if context.isEmpty(): + return context + existing = visited.get(context) + if existing is not None: + return existing + existing = contextCache.get(context) + if existing is not None: + visited[context] = existing + return existing + changed = False + parents = [None] * len(context) + for i in range(0, len(parents)): + parent = getCachedPredictionContext(context.getParent(i), contextCache, visited) + if changed or parent is not context.getParent(i): + if not changed: + parents = [context.getParent(j) for j in range(len(context))] + changed = True + parents[i] = parent + if not changed: + contextCache.add(context) + visited[context] = context + return context + + updated = None + if len(parents) == 0: + updated = PredictionContext.EMPTY + elif len(parents) == 1: + updated = SingletonPredictionContext.create(parents[0], context.getReturnState(0)) + else: + updated = ArrayPredictionContext(parents, context.returnStates) + + contextCache.add(updated) + visited[updated] = updated + visited[context] = updated + + return updated + + +# # extra structures, but cut/paste/morphed works, so leave it. +# # seems to do a breadth-first walk +# public static List getAllNodes(PredictionContext context) { +# Map visited = +# new IdentityHashMap(); +# Deque workList = new ArrayDeque(); +# workList.add(context); +# visited.put(context, context); +# List nodes = new ArrayList(); +# while (!workList.isEmpty()) { +# PredictionContext current = workList.pop(); +# nodes.add(current); +# for (int i = 0; i < current.size(); i++) { +# PredictionContext parent = current.getParent(i); +# if ( parent!=null && visited.put(parent, parent) == null) { +# workList.push(parent); +# } +# } +# } +# return nodes; +# } + +# ter's recursive version of Sam's getAllNodes() +def getAllContextNodes(context:PredictionContext, nodes:list=None, visited:dict=None): + if nodes is None: + nodes = list() + return getAllContextNodes(context, nodes, visited) + elif visited is None: + visited = dict() + return getAllContextNodes(context, nodes, visited) + else: + if context is None or visited.get(context, None) is not None: + return nodes + visited.put(context, context) + nodes.add(context) + for i in range(0, len(context)): + getAllContextNodes(context.getParent(i), nodes, visited) + return nodes + diff --git a/src/antlr4/Recognizer.py b/src/antlr4/Recognizer.py new file mode 100644 index 00000000..01017351 --- /dev/null +++ b/src/antlr4/Recognizer.py @@ -0,0 +1,160 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# +from antlr4.RuleContext import RuleContext +from antlr4.Token import Token +from antlr4.error.ErrorListener import ProxyErrorListener, ConsoleErrorListener + +# need forward delcaration +RecognitionException = None + +class Recognizer(object): + + tokenTypeMapCache = dict() + ruleIndexMapCache = dict() + + def __init__(self): + self._listeners = [ ConsoleErrorListener.INSTANCE ] + self._interp = None + self._stateNumber = -1 + + def extractVersion(self, version): + pos = version.find(".") + major = version[0:pos] + version = version[pos+1:] + pos = version.find(".") + if pos==-1: + pos = version.find("-") + if pos==-1: + pos = len(version) + minor = version[0:pos] + return major, minor + + def checkVersion(self, toolVersion): + runtimeVersion = "4.7.2" + rvmajor, rvminor = self.extractVersion(runtimeVersion) + tvmajor, tvminor = self.extractVersion(toolVersion) + if rvmajor!=tvmajor or rvminor!=tvminor: + print("ANTLR runtime and generated code versions disagree: "+runtimeVersion+"!="+toolVersion) + + def addErrorListener(self, listener): + self._listeners.append(listener) + + def removeErrorListener(self, listener): + self._listeners.remove(listener) + + def removeErrorListeners(self): + self._listeners = [] + + def getTokenTypeMap(self): + tokenNames = self.getTokenNames() + if tokenNames is None: + from antlr4.error.Errors import UnsupportedOperationException + raise UnsupportedOperationException("The current recognizer does not provide a list of token names.") + result = self.tokenTypeMapCache.get(tokenNames, None) + if result is None: + result = zip( tokenNames, range(0, len(tokenNames))) + result["EOF"] = Token.EOF + self.tokenTypeMapCache[tokenNames] = result + return result + + # Get a map from rule names to rule indexes. + # + #

          Used for XPath and tree pattern compilation.

          + # + def getRuleIndexMap(self): + ruleNames = self.getRuleNames() + if ruleNames is None: + from antlr4.error.Errors import UnsupportedOperationException + raise UnsupportedOperationException("The current recognizer does not provide a list of rule names.") + result = self.ruleIndexMapCache.get(ruleNames, None) + if result is None: + result = zip( ruleNames, range(0, len(ruleNames))) + self.ruleIndexMapCache[ruleNames] = result + return result + + def getTokenType(self, tokenName:str): + ttype = self.getTokenTypeMap().get(tokenName, None) + if ttype is not None: + return ttype + else: + return Token.INVALID_TYPE + + + # What is the error header, normally line/character position information?# + def getErrorHeader(self, e:RecognitionException): + line = e.getOffendingToken().line + column = e.getOffendingToken().column + return "line "+line+":"+column + + + # How should a token be displayed in an error message? The default + # is to display just the text, but during development you might + # want to have a lot of information spit out. Override in that case + # to use t.toString() (which, for CommonToken, dumps everything about + # the token). This is better than forcing you to override a method in + # your token objects because you don't have to go modify your lexer + # so that it creates a new Java type. + # + # @deprecated This method is not called by the ANTLR 4 Runtime. Specific + # implementations of {@link ANTLRErrorStrategy} may provide a similar + # feature when necessary. For example, see + # {@link DefaultErrorStrategy#getTokenErrorDisplay}. + # + def getTokenErrorDisplay(self, t:Token): + if t is None: + return "" + s = t.text + if s is None: + if t.type==Token.EOF: + s = "" + else: + s = "<" + str(t.type) + ">" + s = s.replace("\n","\\n") + s = s.replace("\r","\\r") + s = s.replace("\t","\\t") + return "'" + s + "'" + + def getErrorListenerDispatch(self): + return ProxyErrorListener(self._listeners) + + # subclass needs to override these if there are sempreds or actions + # that the ATN interp needs to execute + def sempred(self, localctx:RuleContext, ruleIndex:int, actionIndex:int): + return True + + def precpred(self, localctx:RuleContext , precedence:int): + return True + + @property + def state(self): + return self._stateNumber + + # Indicate that the recognizer has changed internal state that is + # consistent with the ATN state passed in. This way we always know + # where we are in the ATN as the parser goes along. The rule + # context objects form a stack that lets us see the stack of + # invoking rules. Combine this and we have complete ATN + # configuration information. + + @state.setter + def state(self, atnState:int): + self._stateNumber = atnState + +del RecognitionException + +import unittest +class Test(unittest.TestCase): + + def testVersion(self): + major, minor = Recognizer().extractVersion("1.2") + self.assertEqual("1", major) + self.assertEqual("2", minor) + major, minor = Recognizer().extractVersion("1.2.3") + self.assertEqual("1", major) + self.assertEqual("2", minor) + major, minor = Recognizer().extractVersion("1.2-snapshot") + self.assertEqual("1", major) + self.assertEqual("2", minor) diff --git a/src/antlr4/RuleContext.py b/src/antlr4/RuleContext.py new file mode 100644 index 00000000..7f6dd914 --- /dev/null +++ b/src/antlr4/RuleContext.py @@ -0,0 +1,228 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + + +# A rule context is a record of a single rule invocation. It knows +# which context invoked it, if any. If there is no parent context, then +# naturally the invoking state is not valid. The parent link +# provides a chain upwards from the current rule invocation to the root +# of the invocation tree, forming a stack. We actually carry no +# information about the rule associated with this context (except +# when parsing). We keep only the state number of the invoking state from +# the ATN submachine that invoked this. Contrast this with the s +# pointer inside ParserRuleContext that tracks the current state +# being "executed" for the current rule. +# +# The parent contexts are useful for computing lookahead sets and +# getting error information. +# +# These objects are used during parsing and prediction. +# For the special case of parsers, we use the subclass +# ParserRuleContext. +# +# @see ParserRuleContext +#/ +from io import StringIO +from antlr4.tree.Tree import RuleNode, INVALID_INTERVAL, ParseTreeVisitor +from antlr4.tree.Trees import Trees + +# need forward declarations +RuleContext = None +Parser = None + +class RuleContext(RuleNode): + + EMPTY = None + + def __init__(self, parent:RuleContext=None, invokingState:int=-1): + super().__init__() + # What context invoked this rule? + self.parentCtx = parent + # What state invoked the rule associated with this context? + # The "return address" is the followState of invokingState + # If parent is null, this should be -1. + self.invokingState = invokingState + + + def depth(self): + n = 0 + p = self + while p is not None: + p = p.parentCtx + n += 1 + return n + + # A context is empty if there is no invoking state; meaning nobody call + # current context. + def isEmpty(self): + return self.invokingState == -1 + + # satisfy the ParseTree / SyntaxTree interface + + def getSourceInterval(self): + return INVALID_INTERVAL + + def getRuleContext(self): + return self + + def getPayload(self): + return self + + # Return the combined text of all child nodes. This method only considers + # tokens which have been added to the parse tree. + #

          + # Since tokens on hidden channels (e.g. whitespace or comments) are not + # added to the parse trees, they will not appear in the output of this + # method. + #/ + def getText(self): + if self.getChildCount() == 0: + return "" + with StringIO() as builder: + for child in self.getChildren(): + builder.write(child.getText()) + return builder.getvalue() + + def getRuleIndex(self): + return -1 + + # For rule associated with this parse tree internal node, return + # the outer alternative number used to match the input. Default + # implementation does not compute nor store this alt num. Create + # a subclass of ParserRuleContext with backing field and set + # option contextSuperClass. + # to set it. + def getAltNumber(self): + return 0 # should use ATN.INVALID_ALT_NUMBER but won't compile + + # Set the outer alternative number for this context node. Default + # implementation does nothing to avoid backing field overhead for + # trees that don't need it. Create + # a subclass of ParserRuleContext with backing field and set + # option contextSuperClass. + def setAltNumber(self, altNumber:int): + pass + + def getChild(self, i:int): + return None + + def getChildCount(self): + return 0 + + def getChildren(self): + for c in []: + yield c + + def accept(self, visitor:ParseTreeVisitor): + return visitor.visitChildren(self) + + # # Call this method to view a parse tree in a dialog box visually.#/ + # public Future inspect(@Nullable Parser parser) { + # List ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null; + # return inspect(ruleNames); + # } + # + # public Future inspect(@Nullable List ruleNames) { + # TreeViewer viewer = new TreeViewer(ruleNames, this); + # return viewer.open(); + # } + # + # # Save this tree in a postscript file#/ + # public void save(@Nullable Parser parser, String fileName) + # throws IOException, PrintException + # { + # List ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null; + # save(ruleNames, fileName); + # } + # + # # Save this tree in a postscript file using a particular font name and size#/ + # public void save(@Nullable Parser parser, String fileName, + # String fontName, int fontSize) + # throws IOException + # { + # List ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null; + # save(ruleNames, fileName, fontName, fontSize); + # } + # + # # Save this tree in a postscript file#/ + # public void save(@Nullable List ruleNames, String fileName) + # throws IOException, PrintException + # { + # Trees.writePS(this, ruleNames, fileName); + # } + # + # # Save this tree in a postscript file using a particular font name and size#/ + # public void save(@Nullable List ruleNames, String fileName, + # String fontName, int fontSize) + # throws IOException + # { + # Trees.writePS(this, ruleNames, fileName, fontName, fontSize); + # } + # + # # Print out a whole tree, not just a node, in LISP format + # # (root child1 .. childN). Print just a node if this is a leaf. + # # We have to know the recognizer so we can get rule names. + # #/ + # @Override + # public String toStringTree(@Nullable Parser recog) { + # return Trees.toStringTree(this, recog); + # } + # + # Print out a whole tree, not just a node, in LISP format + # (root child1 .. childN). Print just a node if this is a leaf. + # + def toStringTree(self, ruleNames:list=None, recog:Parser=None): + return Trees.toStringTree(self, ruleNames=ruleNames, recog=recog) + # } + # + # @Override + # public String toStringTree() { + # return toStringTree((List)null); + # } + # + def __str__(self): + return self.toString(None, None) + + # @Override + # public String toString() { + # return toString((List)null, (RuleContext)null); + # } + # + # public final String toString(@Nullable Recognizer recog) { + # return toString(recog, ParserRuleContext.EMPTY); + # } + # + # public final String toString(@Nullable List ruleNames) { + # return toString(ruleNames, null); + # } + # + # // recog null unless ParserRuleContext, in which case we use subclass toString(...) + # public String toString(@Nullable Recognizer recog, @Nullable RuleContext stop) { + # String[] ruleNames = recog != null ? recog.getRuleNames() : null; + # List ruleNamesList = ruleNames != null ? Arrays.asList(ruleNames) : null; + # return toString(ruleNamesList, stop); + # } + + def toString(self, ruleNames:list, stop:RuleContext)->str: + with StringIO() as buf: + p = self + buf.write("[") + while p is not None and p is not stop: + if ruleNames is None: + if not p.isEmpty(): + buf.write(str(p.invokingState)) + else: + ri = p.getRuleIndex() + ruleName = ruleNames[ri] if ri >= 0 and ri < len(ruleNames) else str(ri) + buf.write(ruleName) + + if p.parentCtx is not None and (ruleNames is not None or not p.parentCtx.isEmpty()): + buf.write(" ") + + p = p.parentCtx + + buf.write("]") + return buf.getvalue() + diff --git a/src/antlr4/StdinStream.py b/src/antlr4/StdinStream.py new file mode 100644 index 00000000..f044fc4d --- /dev/null +++ b/src/antlr4/StdinStream.py @@ -0,0 +1,11 @@ +import codecs +import sys + +from antlr4.InputStream import InputStream + + +class StdinStream(InputStream): + def __init__(self, encoding:str='ascii', errors:str='strict') -> None: + bytes = sys.stdin.buffer.read() + data = codecs.decode(bytes, encoding, errors) + super().__init__(data) diff --git a/src/antlr4/Token.py b/src/antlr4/Token.py new file mode 100644 index 00000000..6f4d5e26 --- /dev/null +++ b/src/antlr4/Token.py @@ -0,0 +1,155 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# A token has properties: text, type, line, character position in the line +# (so we can ignore tabs), token channel, index, and source from which +# we obtained this token. +from io import StringIO + + +class Token (object): + + INVALID_TYPE = 0 + + # During lookahead operations, this "token" signifies we hit rule end ATN state + # and did not follow it despite needing to. + EPSILON = -2 + + MIN_USER_TOKEN_TYPE = 1 + + EOF = -1 + + # All tokens go to the parser (unless skip() is called in that rule) + # on a particular "channel". The parser tunes to a particular channel + # so that whitespace etc... can go to the parser on a "hidden" channel. + + DEFAULT_CHANNEL = 0 + + # Anything on different channel than DEFAULT_CHANNEL is not parsed + # by parser. + + HIDDEN_CHANNEL = 1 + + def __init__(self): + self.source = None + self.type = None # token type of the token + self.channel = None # The parser ignores everything not on DEFAULT_CHANNEL + self.start = None # optional; return -1 if not implemented. + self.stop = None # optional; return -1 if not implemented. + self.tokenIndex = None # from 0..n-1 of the token object in the input stream + self.line = None # line=1..n of the 1st character + self.column = None # beginning of the line at which it occurs, 0..n-1 + self._text = None # text of the token. + + @property + def text(self): + return self._text + + # Explicitly set the text for this token. If {code text} is not + # {@code null}, then {@link #getText} will return this value rather than + # extracting the text from the input. + # + # @param text The explicit text of the token, or {@code null} if the text + # should be obtained from the input along with the start and stop indexes + # of the token. + + @text.setter + def text(self, text:str): + self._text = text + + + def getTokenSource(self): + return self.source[0] + + def getInputStream(self): + return self.source[1] + +class CommonToken(Token): + + + # An empty {@link Pair} which is used as the default value of + # {@link #source} for tokens that do not have a source. + EMPTY_SOURCE = (None, None) + + def __init__(self, source:tuple = EMPTY_SOURCE, type:int = None, channel:int=Token.DEFAULT_CHANNEL, start:int=-1, stop:int=-1): + super().__init__() + self.source = source + self.type = type + self.channel = channel + self.start = start + self.stop = stop + self.tokenIndex = -1 + if source[0] is not None: + self.line = source[0].line + self.column = source[0].column + else: + self.column = -1 + + # Constructs a new {@link CommonToken} as a copy of another {@link Token}. + # + #

          + # If {@code oldToken} is also a {@link CommonToken} instance, the newly + # constructed token will share a reference to the {@link #text} field and + # the {@link Pair} stored in {@link #source}. Otherwise, {@link #text} will + # be assigned the result of calling {@link #getText}, and {@link #source} + # will be constructed from the result of {@link Token#getTokenSource} and + # {@link Token#getInputStream}.

          + # + # @param oldToken The token to copy. + # + def clone(self): + t = CommonToken(self.source, self.type, self.channel, self.start, self.stop) + t.tokenIndex = self.tokenIndex + t.line = self.line + t.column = self.column + t.text = self.text + return t + + @property + def text(self): + if self._text is not None: + return self._text + input = self.getInputStream() + if input is None: + return None + n = input.size + if self.start < n and self.stop < n: + return input.getText(self.start, self.stop) + else: + return "" + + @text.setter + def text(self, text:str): + self._text = text + + def __str__(self): + with StringIO() as buf: + buf.write("[@") + buf.write(str(self.tokenIndex)) + buf.write(",") + buf.write(str(self.start)) + buf.write(":") + buf.write(str(self.stop)) + buf.write("='") + txt = self.text + if txt is not None: + txt = txt.replace("\n","\\n") + txt = txt.replace("\r","\\r") + txt = txt.replace("\t","\\t") + else: + txt = "" + buf.write(txt) + buf.write("',<") + buf.write(str(self.type)) + buf.write(">") + if self.channel > 0: + buf.write(",channel=") + buf.write(str(self.channel)) + buf.write(",") + buf.write(str(self.line)) + buf.write(":") + buf.write(str(self.column)) + buf.write("]") + return buf.getvalue() diff --git a/src/antlr4/TokenStreamRewriter.py b/src/antlr4/TokenStreamRewriter.py new file mode 100644 index 00000000..617fe620 --- /dev/null +++ b/src/antlr4/TokenStreamRewriter.py @@ -0,0 +1,237 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +from io import StringIO +from antlr4.Token import Token + +from antlr4.CommonTokenStream import CommonTokenStream + + +class TokenStreamRewriter(object): + DEFAULT_PROGRAM_NAME = "default" + PROGRAM_INIT_SIZE = 100 + MIN_TOKEN_INDEX = 0 + + def __init__(self, tokens): + """ + :type tokens: antlr4.BufferedTokenStream.BufferedTokenStream + :param tokens: + :return: + """ + super(TokenStreamRewriter, self).__init__() + self.tokens = tokens + self.programs = {self.DEFAULT_PROGRAM_NAME: []} + self.lastRewriteTokenIndexes = {} + + def getTokenStream(self): + return self.tokens + + def rollback(self, instruction_index, program_name): + ins = self.programs.get(program_name, None) + if ins: + self.programs[program_name] = ins[self.MIN_TOKEN_INDEX: instruction_index] + + def deleteProgram(self, program_name=DEFAULT_PROGRAM_NAME): + self.rollback(self.MIN_TOKEN_INDEX, program_name) + + def insertAfterToken(self, token, text, program_name=DEFAULT_PROGRAM_NAME): + self.insertAfter(token.tokenIndex, text, program_name) + + def insertAfter(self, index, text, program_name=DEFAULT_PROGRAM_NAME): + self.insertBefore(program_name, index + 1, text) + + def insertBeforeIndex(self, index, text): + self.insertBefore(self.DEFAULT_PROGRAM_NAME, index, text) + + def insertBeforeToken(self, token, text, program_name=DEFAULT_PROGRAM_NAME): + self.insertBefore(program_name, token.tokenIndex, text) + + def insertBefore(self, program_name, index, text): + op = self.InsertBeforeOp(self.tokens, index, text) + rewrites = self.getProgram(program_name) + op.instructionIndex = len(rewrites) + rewrites.append(op) + + def replaceIndex(self, index, text): + self.replace(self.DEFAULT_PROGRAM_NAME, index, index, text) + + def replaceRange(self, from_idx, to_idx, text): + self.replace(self.DEFAULT_PROGRAM_NAME, from_idx, to_idx, text) + + def replaceSingleToken(self, token, text): + self.replace(self.DEFAULT_PROGRAM_NAME, token.tokenIndex, token.tokenIndex, text) + + def replaceRangeTokens(self, from_token, to_token, text, program_name=DEFAULT_PROGRAM_NAME): + self.replace(program_name, from_token.tokenIndex, to_token.tokenIndex, text) + + def replace(self, program_name, from_idx, to_idx, text): + if any((from_idx > to_idx, from_idx < 0, to_idx < 0, to_idx >= len(self.tokens.tokens))): + raise ValueError( + 'replace: range invalid: {}..{}(size={})'.format(from_idx, to_idx, len(self.tokens.tokens))) + op = self.ReplaceOp(from_idx, to_idx, self.tokens, text) + rewrites = self.getProgram(program_name) + op.instructionIndex = len(rewrites) + rewrites.append(op) + + def deleteToken(self, token): + self.delete(self.DEFAULT_PROGRAM_NAME, token, token) + + def deleteIndex(self, index): + self.delete(self.DEFAULT_PROGRAM_NAME, index, index) + + def delete(self, program_name, from_idx, to_idx): + if isinstance(from_idx, Token): + self.replace(program_name, from_idx.tokenIndex, to_idx.tokenIndex, None) + self.replace(program_name, from_idx, to_idx, None) + + def lastRewriteTokenIndex(self, program_name=DEFAULT_PROGRAM_NAME): + return self.lastRewriteTokenIndexes.get(program_name, -1) + + def setLastRewriteTokenIndex(self, program_name, i): + self.lastRewriteTokenIndexes[program_name] = i + + def getProgram(self, program_name): + return self.programs.setdefault(program_name, []) + + def getText(self, program_name, interval): + """ + :type interval: Interval.Interval + :param program_name: + :param interval: + :return: + """ + rewrites = self.programs.get(program_name) + start = interval.start + stop = interval.stop + + # ensure start/end are in range + if stop > len(self.tokens.tokens) - 1: stop = len(self.tokens.tokens) - 1 + if start < 0: start = 0 + + # if no instructions to execute + if not rewrites: return self.tokens.getText(interval) + buf = StringIO() + indexToOp = self._reduceToSingleOperationPerIndex(rewrites) + i = start + while all((i <= stop, i < len(self.tokens.tokens))): + op = indexToOp.get(i) + token = self.tokens.get(i) + if op is None: + if token.type != Token.EOF: buf.write(token.text) + i += 1 + else: + i = op.execute(buf) + + if stop == len(self.tokens.tokens)-1: + for op in indexToOp.values(): + if op.index >= len(self.tokens.tokens)-1: buf.write(op.text) + + return buf.getvalue() + + def _reduceToSingleOperationPerIndex(self, rewrites): + # Walk replaces + for i, rop in enumerate(rewrites): + if any((rop is None, not isinstance(rop, TokenStreamRewriter.ReplaceOp))): + continue + # Wipe prior inserts within range + inserts = [op for op in rewrites[:i] if isinstance(rop, TokenStreamRewriter.InsertBeforeOp)] + for iop in inserts: + if iop.index == rop.index: + rewrites[iop.instructionIndex] = None + rop.text = '{}{}'.format(iop.text, rop.text) + elif all((iop.index > rop.index, iop.index <= rop.last_index)): + rewrites[iop.instructionIndex] = None + + # Drop any prior replaces contained within + prevReplaces = [op for op in rewrites[:i] if isinstance(op, TokenStreamRewriter.ReplaceOp)] + for prevRop in prevReplaces: + if all((prevRop.index >= rop.index, prevRop.last_index <= rop.last_index)): + rewrites[prevRop.instructioIndex] = None + continue + isDisjoint = any((prevRop.last_indexrop)) + isSame = all((prevRop.index == rop.index, prevRop.last_index == rop.last_index)) + if all((prevRop.text is None, rop.text is None, not isDisjoint)): + rewrites[prevRop.instructioIndex] = None + rop.index = min(prevRop.index, rop.index) + rop.last_index = min(prevRop.last_index, rop.last_index) + print('New rop {}'.format(rop)) + elif not all((isDisjoint, isSame)): + raise ValueError("replace op boundaries of {} overlap with previous {}".format(rop, prevRop)) + + # Walk inserts + for i, iop in enumerate(rewrites): + if any((iop is None, not isinstance(iop, TokenStreamRewriter.InsertBeforeOp))): + continue + prevInserts = [op for op in rewrites[:i] if isinstance(iop, TokenStreamRewriter.InsertBeforeOp)] + for prevIop in prevInserts: + if prevIop.index == iop.index: + iop.text += prevIop.text + rewrites[i] = None + # look for replaces where iop.index is in range; error + prevReplaces = [op for op in rewrites[:i] if isinstance(op, TokenStreamRewriter.ReplaceOp)] + for rop in prevReplaces: + if iop.index == rop.index: + rop.text = iop.text + rop.text + rewrites[i] = None + continue + if all((iop.index >= rop.index, iop.index <= rop.index)): + raise ValueError("insert op {} within boundaries of previous {}".format(iop, rop)) + + reduced = {} + for i, op in enumerate(rewrites): + if op is None: continue + if reduced.get(op.index): raise ValueError('should be only one op per index') + reduced[op.index] = op + + return reduced + + class RewriteOperation(object): + + def __init__(self, tokens, index, text=""): + """ + :type tokens: CommonTokenStream + :param tokens: + :param index: + :param text: + :return: + """ + self.tokens = tokens + self.index = index + self.text = text + self.instructionIndex = 0 + + def execute(self, buf): + """ + :type buf: StringIO.StringIO + :param buf: + :return: + """ + return self.index + + def __str__(self): + pass + + class InsertBeforeOp(RewriteOperation): + + def __init__(self, tokens, index, text=""): + super(TokenStreamRewriter.InsertBeforeOp, self).__init__(tokens, index, text) + + def execute(self, buf): + buf.write(self.text) + if self.tokens.get(self.index).type != Token.EOF: + buf.write(self.tokens.get(self.index).text) + return self.index + 1 + + class ReplaceOp(RewriteOperation): + + def __init__(self, from_idx, to_idx, tokens, text): + super(TokenStreamRewriter.ReplaceOp, self).__init__(tokens, from_idx, text) + self.last_index = to_idx + + def execute(self, buf): + if self.text: + buf.write(self.text) + return self.last_index + 1 \ No newline at end of file diff --git a/src/antlr4/Utils.py b/src/antlr4/Utils.py new file mode 100644 index 00000000..88c870da --- /dev/null +++ b/src/antlr4/Utils.py @@ -0,0 +1,33 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +from io import StringIO + +def str_list(val): + with StringIO() as buf: + buf.write('[') + first = True + for item in val: + if not first: + buf.write(', ') + buf.write(str(item)) + first = False + buf.write(']') + return buf.getvalue() + +def escapeWhitespace(s:str, escapeSpaces:bool): + with StringIO() as buf: + for c in s: + if c==' ' and escapeSpaces: + buf.write('\u00B7') + elif c=='\t': + buf.write("\\t") + elif c=='\n': + buf.write("\\n") + elif c=='\r': + buf.write("\\r") + else: + buf.write(c) + return buf.getvalue() diff --git a/src/antlr4/__init__.py b/src/antlr4/__init__.py new file mode 100644 index 00000000..42027289 --- /dev/null +++ b/src/antlr4/__init__.py @@ -0,0 +1,21 @@ +from antlr4.Token import Token +from antlr4.InputStream import InputStream +from antlr4.FileStream import FileStream +from antlr4.StdinStream import StdinStream +from antlr4.BufferedTokenStream import TokenStream +from antlr4.CommonTokenStream import CommonTokenStream +from antlr4.Lexer import Lexer +from antlr4.Parser import Parser +from antlr4.dfa.DFA import DFA +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNDeserializer import ATNDeserializer +from antlr4.atn.LexerATNSimulator import LexerATNSimulator +from antlr4.atn.ParserATNSimulator import ParserATNSimulator +from antlr4.atn.PredictionMode import PredictionMode +from antlr4.PredictionContext import PredictionContextCache +from antlr4.ParserRuleContext import RuleContext, ParserRuleContext +from antlr4.tree.Tree import ParseTreeListener, ParseTreeVisitor, ParseTreeWalker, TerminalNode, ErrorNode, RuleNode +from antlr4.error.Errors import RecognitionException, IllegalStateException, NoViableAltException +from antlr4.error.ErrorStrategy import BailErrorStrategy +from antlr4.error.DiagnosticErrorListener import DiagnosticErrorListener +from antlr4.Utils import str_list diff --git a/src/antlr4/atn/ATN.py b/src/antlr4/atn/ATN.py new file mode 100644 index 00000000..4ef5640b --- /dev/null +++ b/src/antlr4/atn/ATN.py @@ -0,0 +1,127 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ +from antlr4.IntervalSet import IntervalSet + +from antlr4.RuleContext import RuleContext + +from antlr4.Token import Token +from antlr4.atn.ATNType import ATNType +from antlr4.atn.ATNState import ATNState, DecisionState + + +class ATN(object): + + INVALID_ALT_NUMBER = 0 + + # Used for runtime deserialization of ATNs from strings#/ + def __init__(self, grammarType:ATNType , maxTokenType:int ): + # The type of the ATN. + self.grammarType = grammarType + # The maximum value for any symbol recognized by a transition in the ATN. + self.maxTokenType = maxTokenType + self.states = [] + # Each subrule/rule is a decision point and we must track them so we + # can go back later and build DFA predictors for them. This includes + # all the rules, subrules, optional blocks, ()+, ()* etc... + self.decisionToState = [] + # Maps from rule index to starting state number. + self.ruleToStartState = [] + # Maps from rule index to stop state number. + self.ruleToStopState = None + self.modeNameToStartState = dict() + # For lexer ATNs, this maps the rule index to the resulting token type. + # For parser ATNs, this maps the rule index to the generated bypass token + # type if the + # {@link ATNDeserializationOptions#isGenerateRuleBypassTransitions} + # deserialization option was specified; otherwise, this is {@code null}. + self.ruleToTokenType = None + # For lexer ATNs, this is an array of {@link LexerAction} objects which may + # be referenced by action transitions in the ATN. + self.lexerActions = None + self.modeToStartState = [] + + # Compute the set of valid tokens that can occur starting in state {@code s}. + # If {@code ctx} is null, the set of tokens will not include what can follow + # the rule surrounding {@code s}. In other words, the set will be + # restricted to tokens reachable staying within {@code s}'s rule. + def nextTokensInContext(self, s:ATNState, ctx:RuleContext): + from antlr4.LL1Analyzer import LL1Analyzer + anal = LL1Analyzer(self) + return anal.LOOK(s, ctx=ctx) + + # Compute the set of valid tokens that can occur starting in {@code s} and + # staying in same rule. {@link Token#EPSILON} is in set if we reach end of + # rule. + def nextTokensNoContext(self, s:ATNState): + if s.nextTokenWithinRule is not None: + return s.nextTokenWithinRule + s.nextTokenWithinRule = self.nextTokensInContext(s, None) + s.nextTokenWithinRule.readonly = True + return s.nextTokenWithinRule + + def nextTokens(self, s:ATNState, ctx:RuleContext = None): + if ctx==None: + return self.nextTokensNoContext(s) + else: + return self.nextTokensInContext(s, ctx) + + def addState(self, state:ATNState): + if state is not None: + state.atn = self + state.stateNumber = len(self.states) + self.states.append(state) + + def removeState(self, state:ATNState): + self.states[state.stateNumber] = None # just free mem, don't shift states in list + + def defineDecisionState(self, s:DecisionState): + self.decisionToState.append(s) + s.decision = len(self.decisionToState)-1 + return s.decision + + def getDecisionState(self, decision:int): + if len(self.decisionToState)==0: + return None + else: + return self.decisionToState[decision] + + # Computes the set of input symbols which could follow ATN state number + # {@code stateNumber} in the specified full {@code context}. This method + # considers the complete parser context, but does not evaluate semantic + # predicates (i.e. all predicates encountered during the calculation are + # assumed true). If a path in the ATN exists from the starting state to the + # {@link RuleStopState} of the outermost context without matching any + # symbols, {@link Token#EOF} is added to the returned set. + # + #

          If {@code context} is {@code null}, it is treated as + # {@link ParserRuleContext#EMPTY}.

          + # + # @param stateNumber the ATN state number + # @param context the full parse context + # @return The set of potentially valid input symbols which could follow the + # specified state in the specified context. + # @throws IllegalArgumentException if the ATN does not contain a state with + # number {@code stateNumber} + #/ + def getExpectedTokens(self, stateNumber:int, ctx:RuleContext ): + if stateNumber < 0 or stateNumber >= len(self.states): + raise Exception("Invalid state number.") + s = self.states[stateNumber] + following = self.nextTokens(s) + if Token.EPSILON not in following: + return following + expected = IntervalSet() + expected.addSet(following) + expected.removeOne(Token.EPSILON) + while (ctx != None and ctx.invokingState >= 0 and Token.EPSILON in following): + invokingState = self.states[ctx.invokingState] + rt = invokingState.transitions[0] + following = self.nextTokens(rt.followState) + expected.addSet(following) + expected.removeOne(Token.EPSILON) + ctx = ctx.parentCtx + if Token.EPSILON in following: + expected.addOne(Token.EOF) + return expected \ No newline at end of file diff --git a/src/antlr4/atn/ATNConfig.py b/src/antlr4/atn/ATNConfig.py new file mode 100644 index 00000000..e2d8b99c --- /dev/null +++ b/src/antlr4/atn/ATNConfig.py @@ -0,0 +1,154 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# A tuple: (ATN state, predicted alt, syntactic, semantic context). +# The syntactic context is a graph-structured stack node whose +# path(s) to the root is the rule invocation(s) +# chain used to arrive at the state. The semantic context is +# the tree of semantic predicates encountered before reaching +# an ATN state. +#/ +from io import StringIO +from antlr4.PredictionContext import PredictionContext +from antlr4.atn.ATNState import ATNState, DecisionState +from antlr4.atn.LexerActionExecutor import LexerActionExecutor +from antlr4.atn.SemanticContext import SemanticContext + +# need a forward declaration +ATNConfig = None + +class ATNConfig(object): + + def __init__(self, state:ATNState=None, alt:int=None, context:PredictionContext=None, semantic:SemanticContext=None, config:ATNConfig=None): + if config is not None: + if state is None: + state = config.state + if alt is None: + alt = config.alt + if context is None: + context = config.context + if semantic is None: + semantic = config.semanticContext + if semantic is None: + semantic = SemanticContext.NONE + # The ATN state associated with this configuration#/ + self.state = state + # What alt (or lexer rule) is predicted by this configuration#/ + self.alt = alt + # The stack of invoking states leading to the rule/states associated + # with this config. We track only those contexts pushed during + # execution of the ATN simulator. + self.context = context + self.semanticContext = semantic + # We cannot execute predicates dependent upon local context unless + # we know for sure we are in the correct context. Because there is + # no way to do this efficiently, we simply cannot evaluate + # dependent predicates unless we are in the rule that initially + # invokes the ATN simulator. + # + # closure() tracks the depth of how far we dip into the + # outer context: depth > 0. Note that it may not be totally + # accurate depth since I don't ever decrement. TODO: make it a boolean then + self.reachesIntoOuterContext = 0 if config is None else config.reachesIntoOuterContext + self.precedenceFilterSuppressed = False if config is None else config.precedenceFilterSuppressed + + # An ATN configuration is equal to another if both have + # the same state, they predict the same alternative, and + # syntactic/semantic contexts are the same. + #/ + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, ATNConfig): + return False + else: + return self.state.stateNumber==other.state.stateNumber \ + and self.alt==other.alt \ + and ((self.context is other.context) or (self.context==other.context)) \ + and self.semanticContext==other.semanticContext \ + and self.precedenceFilterSuppressed==other.precedenceFilterSuppressed + + def __hash__(self): + return hash((self.state.stateNumber, self.alt, self.context, self.semanticContext)) + + def hashCodeForConfigSet(self): + return hash((self.state.stateNumber, self.alt, hash(self.semanticContext))) + + def equalsForConfigSet(self, other): + if self is other: + return True + elif not isinstance(other, ATNConfig): + return False + else: + return self.state.stateNumber==other.state.stateNumber \ + and self.alt==other.alt \ + and self.semanticContext==other.semanticContext + + def __str__(self): + with StringIO() as buf: + buf.write('(') + buf.write(str(self.state)) + buf.write(",") + buf.write(str(self.alt)) + if self.context is not None: + buf.write(",[") + buf.write(str(self.context)) + buf.write("]") + if self.semanticContext is not None and self.semanticContext is not SemanticContext.NONE: + buf.write(",") + buf.write(str(self.semanticContext)) + if self.reachesIntoOuterContext>0: + buf.write(",up=") + buf.write(str(self.reachesIntoOuterContext)) + buf.write(')') + return buf.getvalue() + +# need a forward declaration +LexerATNConfig = None + +class LexerATNConfig(ATNConfig): + + def __init__(self, state:ATNState, alt:int=None, context:PredictionContext=None, semantic:SemanticContext=SemanticContext.NONE, + lexerActionExecutor:LexerActionExecutor=None, config:LexerATNConfig=None): + super().__init__(state=state, alt=alt, context=context, semantic=semantic, config=config) + if config is not None: + if lexerActionExecutor is None: + lexerActionExecutor = config.lexerActionExecutor + # This is the backing field for {@link #getLexerActionExecutor}. + self.lexerActionExecutor = lexerActionExecutor + self.passedThroughNonGreedyDecision = False if config is None else self.checkNonGreedyDecision(config, state) + + def __hash__(self): + return hash((self.state.stateNumber, self.alt, self.context, + self.semanticContext, self.passedThroughNonGreedyDecision, + self.lexerActionExecutor)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerATNConfig): + return False + if self.passedThroughNonGreedyDecision != other.passedThroughNonGreedyDecision: + return False + if not(self.lexerActionExecutor == other.lexerActionExecutor): + return False + return super().__eq__(other) + + + + def hashCodeForConfigSet(self): + return hash(self) + + + + def equalsForConfigSet(self, other): + return self==other + + + + def checkNonGreedyDecision(self, source:LexerATNConfig, target:ATNState): + return source.passedThroughNonGreedyDecision \ + or isinstance(target, DecisionState) and target.nonGreedy diff --git a/src/antlr4/atn/ATNConfigSet.py b/src/antlr4/atn/ATNConfigSet.py new file mode 100644 index 00000000..b240c25d --- /dev/null +++ b/src/antlr4/atn/ATNConfigSet.py @@ -0,0 +1,209 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. + +# +# Specialized {@link Set}{@code <}{@link ATNConfig}{@code >} that can track +# info about the set, with support for combining similar configurations using a +# graph-structured stack. +#/ +from io import StringIO +from functools import reduce +from antlr4.PredictionContext import PredictionContext, merge +from antlr4.Utils import str_list +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNConfig import ATNConfig +from antlr4.atn.SemanticContext import SemanticContext +from antlr4.error.Errors import UnsupportedOperationException, IllegalStateException + +ATNSimulator = None + +class ATNConfigSet(object): + # + # The reason that we need this is because we don't want the hash map to use + # the standard hash code and equals. We need all configurations with the same + # {@code (s,i,_,semctx)} to be equal. Unfortunately, this key effectively doubles + # the number of objects associated with ATNConfigs. The other solution is to + # use a hash table that lets us specify the equals/hashcode operation. + + def __init__(self, fullCtx:bool=True): + # All configs but hashed by (s, i, _, pi) not including context. Wiped out + # when we go readonly as this set becomes a DFA state. + self.configLookup = dict() + # Indicates that this configuration set is part of a full context + # LL prediction. It will be used to determine how to merge $. With SLL + # it's a wildcard whereas it is not for LL context merge. + self.fullCtx = fullCtx + # Indicates that the set of configurations is read-only. Do not + # allow any code to manipulate the set; DFA states will point at + # the sets and they must not change. This does not protect the other + # fields; in particular, conflictingAlts is set after + # we've made this readonly. + self.readonly = False + # Track the elements as they are added to the set; supports get(i)#/ + self.configs = [] + + # TODO: these fields make me pretty uncomfortable but nice to pack up info together, saves recomputation + # TODO: can we track conflicts as they are added to save scanning configs later? + self.uniqueAlt = 0 + self.conflictingAlts = None + + # Used in parser and lexer. In lexer, it indicates we hit a pred + # while computing a closure operation. Don't make a DFA state from this. + self.hasSemanticContext = False + self.dipsIntoOuterContext = False + + self.cachedHashCode = -1 + + def __iter__(self): + return self.configs.__iter__() + + # Adding a new config means merging contexts with existing configs for + # {@code (s, i, pi, _)}, where {@code s} is the + # {@link ATNConfig#state}, {@code i} is the {@link ATNConfig#alt}, and + # {@code pi} is the {@link ATNConfig#semanticContext}. We use + # {@code (s,i,pi)} as key. + # + #

          This method updates {@link #dipsIntoOuterContext} and + # {@link #hasSemanticContext} when necessary.

          + #/ + def add(self, config:ATNConfig, mergeCache=None): + if self.readonly: + raise Exception("This set is readonly") + if config.semanticContext is not SemanticContext.NONE: + self.hasSemanticContext = True + if config.reachesIntoOuterContext > 0: + self.dipsIntoOuterContext = True + existing = self.getOrAdd(config) + if existing is config: + self.cachedHashCode = -1 + self.configs.append(config) # track order here + return True + # a previous (s,i,pi,_), merge with it and save result + rootIsWildcard = not self.fullCtx + merged = merge(existing.context, config.context, rootIsWildcard, mergeCache) + # no need to check for existing.context, config.context in cache + # since only way to create new graphs is "call rule" and here. + # We cache at both places. + existing.reachesIntoOuterContext = max(existing.reachesIntoOuterContext, config.reachesIntoOuterContext) + # make sure to preserve the precedence filter suppression during the merge + if config.precedenceFilterSuppressed: + existing.precedenceFilterSuppressed = True + existing.context = merged # replace context; no need to alt mapping + return True + + def getOrAdd(self, config:ATNConfig): + h = config.hashCodeForConfigSet() + l = self.configLookup.get(h, None) + if l is not None: + r = next((cfg for cfg in l if config.equalsForConfigSet(cfg)), None) + if r is not None: + return r + if l is None: + l = [config] + self.configLookup[h] = l + else: + l.append(config) + return config + + def getStates(self): + return set(c.state for c in self.configs) + + def getPredicates(self): + return list(cfg.semanticContext for cfg in self.configs if cfg.semanticContext!=SemanticContext.NONE) + + def get(self, i:int): + return self.configs[i] + + def optimizeConfigs(self, interpreter:ATNSimulator): + if self.readonly: + raise IllegalStateException("This set is readonly") + if len(self.configs)==0: + return + for config in self.configs: + config.context = interpreter.getCachedContext(config.context) + + def addAll(self, coll:list): + for c in coll: + self.add(c) + return False + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, ATNConfigSet): + return False + + same = self.configs is not None and \ + self.configs==other.configs and \ + self.fullCtx == other.fullCtx and \ + self.uniqueAlt == other.uniqueAlt and \ + self.conflictingAlts == other.conflictingAlts and \ + self.hasSemanticContext == other.hasSemanticContext and \ + self.dipsIntoOuterContext == other.dipsIntoOuterContext + + return same + + def __hash__(self): + if self.readonly: + if self.cachedHashCode == -1: + self.cachedHashCode = self.hashConfigs() + return self.cachedHashCode + return self.hashConfigs() + + def hashConfigs(self): + return reduce(lambda h, cfg: hash((h, cfg)), self.configs, 0) + + def __len__(self): + return len(self.configs) + + def isEmpty(self): + return len(self.configs)==0 + + def __contains__(self, config): + if self.configLookup is None: + raise UnsupportedOperationException("This method is not implemented for readonly sets.") + h = config.hashCodeForConfigSet() + l = self.configLookup.get(h, None) + if l is not None: + for c in l: + if config.equalsForConfigSet(c): + return True + return False + + def clear(self): + if self.readonly: + raise IllegalStateException("This set is readonly") + self.configs.clear() + self.cachedHashCode = -1 + self.configLookup.clear() + + def setReadonly(self, readonly:bool): + self.readonly = readonly + self.configLookup = None # can't mod, no need for lookup cache + + def __str__(self): + with StringIO() as buf: + buf.write(str_list(self.configs)) + if self.hasSemanticContext: + buf.write(",hasSemanticContext=") + buf.write(str(self.hasSemanticContext)) + if self.uniqueAlt!=ATN.INVALID_ALT_NUMBER: + buf.write(",uniqueAlt=") + buf.write(str(self.uniqueAlt)) + if self.conflictingAlts is not None: + buf.write(",conflictingAlts=") + buf.write(str(self.conflictingAlts)) + if self.dipsIntoOuterContext: + buf.write(",dipsIntoOuterContext") + return buf.getvalue() + + +class OrderedATNConfigSet(ATNConfigSet): + + def __init__(self): + super().__init__() + + + diff --git a/src/antlr4/atn/ATNDeserializationOptions.py b/src/antlr4/atn/ATNDeserializationOptions.py new file mode 100644 index 00000000..9c4e23de --- /dev/null +++ b/src/antlr4/atn/ATNDeserializationOptions.py @@ -0,0 +1,24 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. + +# need a forward declaration +ATNDeserializationOptions = None + +class ATNDeserializationOptions(object): + + defaultOptions = None + + def __init__(self, copyFrom:ATNDeserializationOptions = None): + self.readOnly = False + self.verifyATN = True if copyFrom is None else copyFrom.verifyATN + self.generateRuleBypassTransitions = False if copyFrom is None else copyFrom.generateRuleBypassTransitions + + def __setattr__(self, key, value): + if key!="readOnly" and self.readOnly: + raise Exception("The object is read only.") + super(type(self), self).__setattr__(key,value) + +ATNDeserializationOptions.defaultOptions = ATNDeserializationOptions() +ATNDeserializationOptions.defaultOptions.readOnly = True + diff --git a/src/antlr4/atn/ATNDeserializer.py b/src/antlr4/atn/ATNDeserializer.py new file mode 100644 index 00000000..cd0bb661 --- /dev/null +++ b/src/antlr4/atn/ATNDeserializer.py @@ -0,0 +1,528 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ +from uuid import UUID +from io import StringIO +from typing import Callable +from antlr4.Token import Token +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNType import ATNType +from antlr4.atn.ATNState import * +from antlr4.atn.Transition import * +from antlr4.atn.LexerAction import * +from antlr4.atn.ATNDeserializationOptions import ATNDeserializationOptions + +# This is the earliest supported serialized UUID. +BASE_SERIALIZED_UUID = UUID("AADB8D7E-AEEF-4415-AD2B-8204D6CF042E") + +# This UUID indicates the serialized ATN contains two sets of +# IntervalSets, where the second set's values are encoded as +# 32-bit integers to support the full Unicode SMP range up to U+10FFFF. +ADDED_UNICODE_SMP = UUID("59627784-3BE5-417A-B9EB-8131A7286089") + +# This list contains all of the currently supported UUIDs, ordered by when +# the feature first appeared in this branch. +SUPPORTED_UUIDS = [ BASE_SERIALIZED_UUID, ADDED_UNICODE_SMP ] + +SERIALIZED_VERSION = 3 + +# This is the current serialized UUID. +SERIALIZED_UUID = ADDED_UNICODE_SMP + +class ATNDeserializer (object): + + def __init__(self, options : ATNDeserializationOptions = None): + if options is None: + options = ATNDeserializationOptions.defaultOptions + self.deserializationOptions = options + + # Determines if a particular serialized representation of an ATN supports + # a particular feature, identified by the {@link UUID} used for serializing + # the ATN at the time the feature was first introduced. + # + # @param feature The {@link UUID} marking the first time the feature was + # supported in the serialized ATN. + # @param actualUuid The {@link UUID} of the actual serialized ATN which is + # currently being deserialized. + # @return {@code true} if the {@code actualUuid} value represents a + # serialized ATN at or after the feature identified by {@code feature} was + # introduced; otherwise, {@code false}. + + def isFeatureSupported(self, feature : UUID , actualUuid : UUID ): + idx1 = SUPPORTED_UUIDS.index(feature) + if idx1<0: + return False + idx2 = SUPPORTED_UUIDS.index(actualUuid) + return idx2 >= idx1 + + def deserialize(self, data : str): + self.reset(data) + self.checkVersion() + self.checkUUID() + atn = self.readATN() + self.readStates(atn) + self.readRules(atn) + self.readModes(atn) + sets = [] + # First, read all sets with 16-bit Unicode code points <= U+FFFF. + self.readSets(atn, sets, self.readInt) + # Next, if the ATN was serialized with the Unicode SMP feature, + # deserialize sets with 32-bit arguments <= U+10FFFF. + if self.isFeatureSupported(ADDED_UNICODE_SMP, self.uuid): + self.readSets(atn, sets, self.readInt32) + self.readEdges(atn, sets) + self.readDecisions(atn) + self.readLexerActions(atn) + self.markPrecedenceDecisions(atn) + self.verifyATN(atn) + if self.deserializationOptions.generateRuleBypassTransitions \ + and atn.grammarType == ATNType.PARSER: + self.generateRuleBypassTransitions(atn) + # re-verify after modification + self.verifyATN(atn) + return atn + + def reset(self, data:str): + def adjust(c): + v = ord(c) + return v-2 if v>1 else v + 65533 + temp = [ adjust(c) for c in data ] + # don't adjust the first value since that's the version number + temp[0] = ord(data[0]) + self.data = temp + self.pos = 0 + + def checkVersion(self): + version = self.readInt() + if version != SERIALIZED_VERSION: + raise Exception("Could not deserialize ATN with version " + str(version) + " (expected " + str(SERIALIZED_VERSION) + ").") + + def checkUUID(self): + uuid = self.readUUID() + if not uuid in SUPPORTED_UUIDS: + raise Exception("Could not deserialize ATN with UUID: " + str(uuid) + \ + " (expected " + str(SERIALIZED_UUID) + " or a legacy UUID).", uuid, SERIALIZED_UUID) + self.uuid = uuid + + def readATN(self): + idx = self.readInt() + grammarType = ATNType.fromOrdinal(idx) + maxTokenType = self.readInt() + return ATN(grammarType, maxTokenType) + + def readStates(self, atn:ATN): + loopBackStateNumbers = [] + endStateNumbers = [] + nstates = self.readInt() + for i in range(0, nstates): + stype = self.readInt() + # ignore bad type of states + if stype==ATNState.INVALID_TYPE: + atn.addState(None) + continue + ruleIndex = self.readInt() + if ruleIndex == 0xFFFF: + ruleIndex = -1 + + s = self.stateFactory(stype, ruleIndex) + if stype == ATNState.LOOP_END: # special case + loopBackStateNumber = self.readInt() + loopBackStateNumbers.append((s, loopBackStateNumber)) + elif isinstance(s, BlockStartState): + endStateNumber = self.readInt() + endStateNumbers.append((s, endStateNumber)) + + atn.addState(s) + + # delay the assignment of loop back and end states until we know all the state instances have been initialized + for pair in loopBackStateNumbers: + pair[0].loopBackState = atn.states[pair[1]] + + for pair in endStateNumbers: + pair[0].endState = atn.states[pair[1]] + + numNonGreedyStates = self.readInt() + for i in range(0, numNonGreedyStates): + stateNumber = self.readInt() + atn.states[stateNumber].nonGreedy = True + + numPrecedenceStates = self.readInt() + for i in range(0, numPrecedenceStates): + stateNumber = self.readInt() + atn.states[stateNumber].isPrecedenceRule = True + + def readRules(self, atn:ATN): + nrules = self.readInt() + if atn.grammarType == ATNType.LEXER: + atn.ruleToTokenType = [0] * nrules + + atn.ruleToStartState = [0] * nrules + for i in range(0, nrules): + s = self.readInt() + startState = atn.states[s] + atn.ruleToStartState[i] = startState + if atn.grammarType == ATNType.LEXER: + tokenType = self.readInt() + if tokenType == 0xFFFF: + tokenType = Token.EOF + + atn.ruleToTokenType[i] = tokenType + + atn.ruleToStopState = [0] * nrules + for state in atn.states: + if not isinstance(state, RuleStopState): + continue + atn.ruleToStopState[state.ruleIndex] = state + atn.ruleToStartState[state.ruleIndex].stopState = state + + def readModes(self, atn:ATN): + nmodes = self.readInt() + for i in range(0, nmodes): + s = self.readInt() + atn.modeToStartState.append(atn.states[s]) + + def readSets(self, atn:ATN, sets:list, readUnicode:Callable[[], int]): + m = self.readInt() + for i in range(0, m): + iset = IntervalSet() + sets.append(iset) + n = self.readInt() + containsEof = self.readInt() + if containsEof!=0: + iset.addOne(-1) + for j in range(0, n): + i1 = readUnicode() + i2 = readUnicode() + iset.addRange(range(i1, i2 + 1)) # range upper limit is exclusive + + def readEdges(self, atn:ATN, sets:list): + nedges = self.readInt() + for i in range(0, nedges): + src = self.readInt() + trg = self.readInt() + ttype = self.readInt() + arg1 = self.readInt() + arg2 = self.readInt() + arg3 = self.readInt() + trans = self.edgeFactory(atn, ttype, src, trg, arg1, arg2, arg3, sets) + srcState = atn.states[src] + srcState.addTransition(trans) + + # edges for rule stop states can be derived, so they aren't serialized + for state in atn.states: + for i in range(0, len(state.transitions)): + t = state.transitions[i] + if not isinstance(t, RuleTransition): + continue + outermostPrecedenceReturn = -1 + if atn.ruleToStartState[t.target.ruleIndex].isPrecedenceRule: + if t.precedence == 0: + outermostPrecedenceReturn = t.target.ruleIndex + trans = EpsilonTransition(t.followState, outermostPrecedenceReturn) + atn.ruleToStopState[t.target.ruleIndex].addTransition(trans) + + for state in atn.states: + if isinstance(state, BlockStartState): + # we need to know the end state to set its start state + if state.endState is None: + raise Exception("IllegalState") + # block end states can only be associated to a single block start state + if state.endState.startState is not None: + raise Exception("IllegalState") + state.endState.startState = state + + if isinstance(state, PlusLoopbackState): + for i in range(0, len(state.transitions)): + target = state.transitions[i].target + if isinstance(target, PlusBlockStartState): + target.loopBackState = state + elif isinstance(state, StarLoopbackState): + for i in range(0, len(state.transitions)): + target = state.transitions[i].target + if isinstance(target, StarLoopEntryState): + target.loopBackState = state + + def readDecisions(self, atn:ATN): + ndecisions = self.readInt() + for i in range(0, ndecisions): + s = self.readInt() + decState = atn.states[s] + atn.decisionToState.append(decState) + decState.decision = i + + def readLexerActions(self, atn:ATN): + if atn.grammarType == ATNType.LEXER: + count = self.readInt() + atn.lexerActions = [ None ] * count + for i in range(0, count): + actionType = self.readInt() + data1 = self.readInt() + if data1 == 0xFFFF: + data1 = -1 + data2 = self.readInt() + if data2 == 0xFFFF: + data2 = -1 + lexerAction = self.lexerActionFactory(actionType, data1, data2) + atn.lexerActions[i] = lexerAction + + def generateRuleBypassTransitions(self, atn:ATN): + + count = len(atn.ruleToStartState) + atn.ruleToTokenType = [ 0 ] * count + for i in range(0, count): + atn.ruleToTokenType[i] = atn.maxTokenType + i + 1 + + for i in range(0, count): + self.generateRuleBypassTransition(atn, i) + + def generateRuleBypassTransition(self, atn:ATN, idx:int): + + bypassStart = BasicBlockStartState() + bypassStart.ruleIndex = idx + atn.addState(bypassStart) + + bypassStop = BlockEndState() + bypassStop.ruleIndex = idx + atn.addState(bypassStop) + + bypassStart.endState = bypassStop + atn.defineDecisionState(bypassStart) + + bypassStop.startState = bypassStart + + excludeTransition = None + + if atn.ruleToStartState[idx].isPrecedenceRule: + # wrap from the beginning of the rule to the StarLoopEntryState + endState = None + for state in atn.states: + if self.stateIsEndStateFor(state, idx): + endState = state + excludeTransition = state.loopBackState.transitions[0] + break + + if excludeTransition is None: + raise Exception("Couldn't identify final state of the precedence rule prefix section.") + + else: + + endState = atn.ruleToStopState[idx] + + # all non-excluded transitions that currently target end state need to target blockEnd instead + for state in atn.states: + for transition in state.transitions: + if transition == excludeTransition: + continue + if transition.target == endState: + transition.target = bypassStop + + # all transitions leaving the rule start state need to leave blockStart instead + ruleToStartState = atn.ruleToStartState[idx] + count = len(ruleToStartState.transitions) + while count > 0: + bypassStart.addTransition(ruleToStartState.transitions[count-1]) + del ruleToStartState.transitions[-1] + + # link the new states + atn.ruleToStartState[idx].addTransition(EpsilonTransition(bypassStart)) + bypassStop.addTransition(EpsilonTransition(endState)) + + matchState = BasicState() + atn.addState(matchState) + matchState.addTransition(AtomTransition(bypassStop, atn.ruleToTokenType[idx])) + bypassStart.addTransition(EpsilonTransition(matchState)) + + + def stateIsEndStateFor(self, state:ATNState, idx:int): + if state.ruleIndex != idx: + return None + if not isinstance(state, StarLoopEntryState): + return None + + maybeLoopEndState = state.transitions[len(state.transitions) - 1].target + if not isinstance(maybeLoopEndState, LoopEndState): + return None + + if maybeLoopEndState.epsilonOnlyTransitions and \ + isinstance(maybeLoopEndState.transitions[0].target, RuleStopState): + return state + else: + return None + + + # + # Analyze the {@link StarLoopEntryState} states in the specified ATN to set + # the {@link StarLoopEntryState#isPrecedenceDecision} field to the + # correct value. + # + # @param atn The ATN. + # + def markPrecedenceDecisions(self, atn:ATN): + for state in atn.states: + if not isinstance(state, StarLoopEntryState): + continue + + # We analyze the ATN to determine if this ATN decision state is the + # decision for the closure block that determines whether a + # precedence rule should continue or complete. + # + if atn.ruleToStartState[state.ruleIndex].isPrecedenceRule: + maybeLoopEndState = state.transitions[len(state.transitions) - 1].target + if isinstance(maybeLoopEndState, LoopEndState): + if maybeLoopEndState.epsilonOnlyTransitions and \ + isinstance(maybeLoopEndState.transitions[0].target, RuleStopState): + state.isPrecedenceDecision = True + + def verifyATN(self, atn:ATN): + if not self.deserializationOptions.verifyATN: + return + # verify assumptions + for state in atn.states: + if state is None: + continue + + self.checkCondition(state.epsilonOnlyTransitions or len(state.transitions) <= 1) + + if isinstance(state, PlusBlockStartState): + self.checkCondition(state.loopBackState is not None) + + if isinstance(state, StarLoopEntryState): + self.checkCondition(state.loopBackState is not None) + self.checkCondition(len(state.transitions) == 2) + + if isinstance(state.transitions[0].target, StarBlockStartState): + self.checkCondition(isinstance(state.transitions[1].target, LoopEndState)) + self.checkCondition(not state.nonGreedy) + elif isinstance(state.transitions[0].target, LoopEndState): + self.checkCondition(isinstance(state.transitions[1].target, StarBlockStartState)) + self.checkCondition(state.nonGreedy) + else: + raise Exception("IllegalState") + + if isinstance(state, StarLoopbackState): + self.checkCondition(len(state.transitions) == 1) + self.checkCondition(isinstance(state.transitions[0].target, StarLoopEntryState)) + + if isinstance(state, LoopEndState): + self.checkCondition(state.loopBackState is not None) + + if isinstance(state, RuleStartState): + self.checkCondition(state.stopState is not None) + + if isinstance(state, BlockStartState): + self.checkCondition(state.endState is not None) + + if isinstance(state, BlockEndState): + self.checkCondition(state.startState is not None) + + if isinstance(state, DecisionState): + self.checkCondition(len(state.transitions) <= 1 or state.decision >= 0) + else: + self.checkCondition(len(state.transitions) <= 1 or isinstance(state, RuleStopState)) + + def checkCondition(self, condition:bool, message=None): + if not condition: + if message is None: + message = "IllegalState" + raise Exception(message) + + def readInt(self): + i = self.data[self.pos] + self.pos += 1 + return i + + def readInt32(self): + low = self.readInt() + high = self.readInt() + return low | (high << 16) + + def readLong(self): + low = self.readInt32() + high = self.readInt32() + return (low & 0x00000000FFFFFFFF) | (high << 32) + + def readUUID(self): + low = self.readLong() + high = self.readLong() + allBits = (low & 0xFFFFFFFFFFFFFFFF) | (high << 64) + return UUID(int=allBits) + + edgeFactories = [ lambda args : None, + lambda atn, src, trg, arg1, arg2, arg3, sets, target : EpsilonTransition(target), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + RangeTransition(target, Token.EOF, arg2) if arg3 != 0 else RangeTransition(target, arg1, arg2), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + RuleTransition(atn.states[arg1], arg2, arg3, target), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + PredicateTransition(target, arg1, arg2, arg3 != 0), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + AtomTransition(target, Token.EOF) if arg3 != 0 else AtomTransition(target, arg1), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + ActionTransition(target, arg1, arg2, arg3 != 0), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + SetTransition(target, sets[arg1]), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + NotSetTransition(target, sets[arg1]), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + WildcardTransition(target), + lambda atn, src, trg, arg1, arg2, arg3, sets, target : \ + PrecedencePredicateTransition(target, arg1) + ] + + def edgeFactory(self, atn:ATN, type:int, src:int, trg:int, arg1:int, arg2:int, arg3:int, sets:list): + target = atn.states[trg] + if type > len(self.edgeFactories) or self.edgeFactories[type] is None: + raise Exception("The specified transition type: " + str(type) + " is not valid.") + else: + return self.edgeFactories[type](atn, src, trg, arg1, arg2, arg3, sets, target) + + stateFactories = [ lambda : None, + lambda : BasicState(), + lambda : RuleStartState(), + lambda : BasicBlockStartState(), + lambda : PlusBlockStartState(), + lambda : StarBlockStartState(), + lambda : TokensStartState(), + lambda : RuleStopState(), + lambda : BlockEndState(), + lambda : StarLoopbackState(), + lambda : StarLoopEntryState(), + lambda : PlusLoopbackState(), + lambda : LoopEndState() + ] + + def stateFactory(self, type:int, ruleIndex:int): + if type> len(self.stateFactories) or self.stateFactories[type] is None: + raise Exception("The specified state type " + str(type) + " is not valid.") + else: + s = self.stateFactories[type]() + if s is not None: + s.ruleIndex = ruleIndex + return s + + CHANNEL = 0 #The type of a {@link LexerChannelAction} action. + CUSTOM = 1 #The type of a {@link LexerCustomAction} action. + MODE = 2 #The type of a {@link LexerModeAction} action. + MORE = 3 #The type of a {@link LexerMoreAction} action. + POP_MODE = 4 #The type of a {@link LexerPopModeAction} action. + PUSH_MODE = 5 #The type of a {@link LexerPushModeAction} action. + SKIP = 6 #The type of a {@link LexerSkipAction} action. + TYPE = 7 #The type of a {@link LexerTypeAction} action. + + actionFactories = [ lambda data1, data2: LexerChannelAction(data1), + lambda data1, data2: LexerCustomAction(data1, data2), + lambda data1, data2: LexerModeAction(data1), + lambda data1, data2: LexerMoreAction.INSTANCE, + lambda data1, data2: LexerPopModeAction.INSTANCE, + lambda data1, data2: LexerPushModeAction(data1), + lambda data1, data2: LexerSkipAction.INSTANCE, + lambda data1, data2: LexerTypeAction(data1) + ] + + def lexerActionFactory(self, type:int, data1:int, data2:int): + + if type > len(self.actionFactories) or self.actionFactories[type] is None: + raise Exception("The specified lexer action type " + str(type) + " is not valid.") + else: + return self.actionFactories[type](data1, data2) diff --git a/src/antlr4/atn/ATNSimulator.py b/src/antlr4/atn/ATNSimulator.py new file mode 100644 index 00000000..26c0b94a --- /dev/null +++ b/src/antlr4/atn/ATNSimulator.py @@ -0,0 +1,47 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ +from antlr4.PredictionContext import PredictionContextCache, PredictionContext, getCachedPredictionContext +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNConfigSet import ATNConfigSet +from antlr4.dfa.DFAState import DFAState + + +class ATNSimulator(object): + + # Must distinguish between missing edge and edge we know leads nowhere#/ + ERROR = DFAState(configs=ATNConfigSet()) + ERROR.stateNumber = 0x7FFFFFFF + + # The context cache maps all PredictionContext objects that are == + # to a single cached copy. This cache is shared across all contexts + # in all ATNConfigs in all DFA states. We rebuild each ATNConfigSet + # to use only cached nodes/graphs in addDFAState(). We don't want to + # fill this during closure() since there are lots of contexts that + # pop up but are not used ever again. It also greatly slows down closure(). + # + #

          This cache makes a huge difference in memory and a little bit in speed. + # For the Java grammar on java.*, it dropped the memory requirements + # at the end from 25M to 16M. We don't store any of the full context + # graphs in the DFA because they are limited to local context only, + # but apparently there's a lot of repetition there as well. We optimize + # the config contexts before storing the config set in the DFA states + # by literally rebuilding them with cached subgraphs only.

          + # + #

          I tried a cache for use during closure operations, that was + # whacked after each adaptivePredict(). It cost a little bit + # more time I think and doesn't save on the overall footprint + # so it's not worth the complexity.

          + #/ + def __init__(self, atn:ATN, sharedContextCache:PredictionContextCache): + self.atn = atn + self.sharedContextCache = sharedContextCache + + def getCachedContext(self, context:PredictionContext): + if self.sharedContextCache is None: + return context + visited = dict() + return getCachedPredictionContext(context, self.sharedContextCache, visited) + diff --git a/src/antlr4/atn/ATNState.py b/src/antlr4/atn/ATNState.py new file mode 100644 index 00000000..97ade955 --- /dev/null +++ b/src/antlr4/atn/ATNState.py @@ -0,0 +1,254 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# The following images show the relation of states and +# {@link ATNState#transitions} for various grammar constructs. +# +#
            +# +#
          • Solid edges marked with an ε indicate a required +# {@link EpsilonTransition}.
          • +# +#
          • Dashed edges indicate locations where any transition derived from +# {@link Transition} might appear.
          • +# +#
          • Dashed nodes are place holders for either a sequence of linked +# {@link BasicState} states or the inclusion of a block representing a nested +# construct in one of the forms below.
          • +# +#
          • Nodes showing multiple outgoing alternatives with a {@code ...} support +# any number of alternatives (one or more). Nodes without the {@code ...} only +# support the exact number of alternatives shown in the diagram.
          • +# +#
          +# +#

          Basic Blocks

          +# +#

          Rule

          +# +# +# +#

          Block of 1 or more alternatives

          +# +# +# +#

          Greedy Loops

          +# +#

          Greedy Closure: {@code (...)*}

          +# +# +# +#

          Greedy Positive Closure: {@code (...)+}

          +# +# +# +#

          Greedy Optional: {@code (...)?}

          +# +# +# +#

          Non-Greedy Loops

          +# +#

          Non-Greedy Closure: {@code (...)*?}

          +# +# +# +#

          Non-Greedy Positive Closure: {@code (...)+?}

          +# +# +# +#

          Non-Greedy Optional: {@code (...)??}

          +# +# +# + +from antlr4.atn.Transition import Transition + +INITIAL_NUM_TRANSITIONS = 4 + +class ATNState(object): + + # constants for serialization + INVALID_TYPE = 0 + BASIC = 1 + RULE_START = 2 + BLOCK_START = 3 + PLUS_BLOCK_START = 4 + STAR_BLOCK_START = 5 + TOKEN_START = 6 + RULE_STOP = 7 + BLOCK_END = 8 + STAR_LOOP_BACK = 9 + STAR_LOOP_ENTRY = 10 + PLUS_LOOP_BACK = 11 + LOOP_END = 12 + + serializationNames = [ + "INVALID", + "BASIC", + "RULE_START", + "BLOCK_START", + "PLUS_BLOCK_START", + "STAR_BLOCK_START", + "TOKEN_START", + "RULE_STOP", + "BLOCK_END", + "STAR_LOOP_BACK", + "STAR_LOOP_ENTRY", + "PLUS_LOOP_BACK", + "LOOP_END" ] + + INVALID_STATE_NUMBER = -1 + + def __init__(self): + # Which ATN are we in? + self.atn = None + self.stateNumber = ATNState.INVALID_STATE_NUMBER + self.stateType = None + self.ruleIndex = 0 # at runtime, we don't have Rule objects + self.epsilonOnlyTransitions = False + # Track the transitions emanating from this ATN state. + self.transitions = [] + # Used to cache lookahead during parsing, not used during construction + self.nextTokenWithinRule = None + + def __hash__(self): + return self.stateNumber + + def __eq__(self, other): + return isinstance(other, ATNState) and self.stateNumber==other.stateNumber + + def onlyHasEpsilonTransitions(self): + return self.epsilonOnlyTransitions + + def isNonGreedyExitState(self): + return False + + def __str__(self): + return str(self.stateNumber) + + def addTransition(self, trans:Transition, index:int=-1): + if len(self.transitions)==0: + self.epsilonOnlyTransitions = trans.isEpsilon + elif self.epsilonOnlyTransitions != trans.isEpsilon: + self.epsilonOnlyTransitions = False + # TODO System.err.format(Locale.getDefault(), "ATN state %d has both epsilon and non-epsilon transitions.\n", stateNumber); + if index==-1: + self.transitions.append(trans) + else: + self.transitions.insert(index, trans) + +class BasicState(ATNState): + + def __init__(self): + super().__init__() + self.stateType = self.BASIC + + +class DecisionState(ATNState): + + def __init__(self): + super().__init__() + self.decision = -1 + self.nonGreedy = False + +# The start of a regular {@code (...)} block. +class BlockStartState(DecisionState): + + def __init__(self): + super().__init__() + self.endState = None + +class BasicBlockStartState(BlockStartState): + + def __init__(self): + super().__init__() + self.stateType = self.BLOCK_START + +# Terminal node of a simple {@code (a|b|c)} block. +class BlockEndState(ATNState): + + def __init__(self): + super().__init__() + self.stateType = self.BLOCK_END + self.startState = None + +# The last node in the ATN for a rule, unless that rule is the start symbol. +# In that case, there is one transition to EOF. Later, we might encode +# references to all calls to this rule to compute FOLLOW sets for +# error handling. +# +class RuleStopState(ATNState): + + def __init__(self): + super().__init__() + self.stateType = self.RULE_STOP + +class RuleStartState(ATNState): + + def __init__(self): + super().__init__() + self.stateType = self.RULE_START + self.stopState = None + self.isPrecedenceRule = False + +# Decision state for {@code A+} and {@code (A|B)+}. It has two transitions: +# one to the loop back to start of the block and one to exit. +# +class PlusLoopbackState(DecisionState): + + def __init__(self): + super().__init__() + self.stateType = self.PLUS_LOOP_BACK + +# Start of {@code (A|B|...)+} loop. Technically a decision state, but +# we don't use for code generation; somebody might need it, so I'm defining +# it for completeness. In reality, the {@link PlusLoopbackState} node is the +# real decision-making note for {@code A+}. +# +class PlusBlockStartState(BlockStartState): + + def __init__(self): + super().__init__() + self.stateType = self.PLUS_BLOCK_START + self.loopBackState = None + +# The block that begins a closure loop. +class StarBlockStartState(BlockStartState): + + def __init__(self): + super().__init__() + self.stateType = self.STAR_BLOCK_START + +class StarLoopbackState(ATNState): + + def __init__(self): + super().__init__() + self.stateType = self.STAR_LOOP_BACK + + +class StarLoopEntryState(DecisionState): + + def __init__(self): + super().__init__() + self.stateType = self.STAR_LOOP_ENTRY + self.loopBackState = None + # Indicates whether this state can benefit from a precedence DFA during SLL decision making. + self.isPrecedenceDecision = None + +# Mark the end of a * or + loop. +class LoopEndState(ATNState): + + def __init__(self): + super().__init__() + self.stateType = self.LOOP_END + self.loopBackState = None + +# The Tokens rule start state linking to each lexer rule start state */ +class TokensStartState(DecisionState): + + def __init__(self): + super().__init__() + self.stateType = self.TOKEN_START diff --git a/src/antlr4/atn/ATNType.py b/src/antlr4/atn/ATNType.py new file mode 100644 index 00000000..cc0d4d92 --- /dev/null +++ b/src/antlr4/atn/ATNType.py @@ -0,0 +1,17 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +from enum import IntEnum + +# Represents the type of recognizer an ATN applies to. + +class ATNType(IntEnum): + + LEXER = 0 + PARSER = 1 + + @classmethod + def fromOrdinal(cls, i:int): + return cls._value2member_map_[i] diff --git a/src/antlr4/atn/LexerATNSimulator.py b/src/antlr4/atn/LexerATNSimulator.py new file mode 100644 index 00000000..cc638c82 --- /dev/null +++ b/src/antlr4/atn/LexerATNSimulator.py @@ -0,0 +1,568 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# When we hit an accept state in either the DFA or the ATN, we +# have to notify the character stream to start buffering characters +# via {@link IntStream#mark} and record the current state. The current sim state +# includes the current index into the input, the current line, +# and current character position in that line. Note that the Lexer is +# tracking the starting line and characterization of the token. These +# variables track the "state" of the simulator when it hits an accept state. +# +#

          We track these variables separately for the DFA and ATN simulation +# because the DFA simulation often has to fail over to the ATN +# simulation. If the ATN simulation fails, we need the DFA to fall +# back to its previously accepted state, if any. If the ATN succeeds, +# then the ATN does the accept and the DFA simulator that invoked it +# can simply return the predicted token type.

          +#/ + +from antlr4.PredictionContext import PredictionContextCache, SingletonPredictionContext, PredictionContext +from antlr4.InputStream import InputStream +from antlr4.Token import Token +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNConfig import LexerATNConfig +from antlr4.atn.ATNSimulator import ATNSimulator +from antlr4.atn.ATNConfigSet import ATNConfigSet, OrderedATNConfigSet +from antlr4.atn.ATNState import RuleStopState, ATNState +from antlr4.atn.LexerActionExecutor import LexerActionExecutor +from antlr4.atn.Transition import Transition +from antlr4.dfa.DFAState import DFAState +from antlr4.error.Errors import LexerNoViableAltException, UnsupportedOperationException + +class SimState(object): + + def __init__(self): + self.reset() + + def reset(self): + self.index = -1 + self.line = 0 + self.column = -1 + self.dfaState = None + +# need forward declaration +Lexer = None +LexerATNSimulator = None + +class LexerATNSimulator(ATNSimulator): + + debug = False + dfa_debug = False + + MIN_DFA_EDGE = 0 + MAX_DFA_EDGE = 127 # forces unicode to stay in ATN + + ERROR = None + + match_calls = 0 + + def __init__(self, recog:Lexer, atn:ATN, decisionToDFA:list, sharedContextCache:PredictionContextCache): + super().__init__(atn, sharedContextCache) + self.decisionToDFA = decisionToDFA + self.recog = recog + # The current token's starting index into the character stream. + # Shared across DFA to ATN simulation in case the ATN fails and the + # DFA did not have a previous accept state. In this case, we use the + # ATN-generated exception object. + self.startIndex = -1 + # line number 1..n within the input#/ + self.line = 1 + # The index of the character relative to the beginning of the line 0..n-1#/ + self.column = 0 + from antlr4.Lexer import Lexer + self.mode = Lexer.DEFAULT_MODE + # Used during DFA/ATN exec to record the most recent accept configuration info + self.prevAccept = SimState() + + + def copyState(self, simulator:LexerATNSimulator ): + self.column = simulator.column + self.line = simulator.line + self.mode = simulator.mode + self.startIndex = simulator.startIndex + + def match(self, input:InputStream , mode:int): + self.match_calls += 1 + self.mode = mode + mark = input.mark() + try: + self.startIndex = input.index + self.prevAccept.reset() + dfa = self.decisionToDFA[mode] + if dfa.s0 is None: + return self.matchATN(input) + else: + return self.execATN(input, dfa.s0) + finally: + input.release(mark) + + def reset(self): + self.prevAccept.reset() + self.startIndex = -1 + self.line = 1 + self.column = 0 + from antlr4.Lexer import Lexer + self.mode = Lexer.DEFAULT_MODE + + def matchATN(self, input:InputStream): + startState = self.atn.modeToStartState[self.mode] + + if LexerATNSimulator.debug: + print("matchATN mode " + str(self.mode) + " start: " + str(startState)) + + old_mode = self.mode + s0_closure = self.computeStartState(input, startState) + suppressEdge = s0_closure.hasSemanticContext + s0_closure.hasSemanticContext = False + + next = self.addDFAState(s0_closure) + if not suppressEdge: + self.decisionToDFA[self.mode].s0 = next + + predict = self.execATN(input, next) + + if LexerATNSimulator.debug: + print("DFA after matchATN: " + str(self.decisionToDFA[old_mode].toLexerString())) + + return predict + + def execATN(self, input:InputStream, ds0:DFAState): + if LexerATNSimulator.debug: + print("start state closure=" + str(ds0.configs)) + + if ds0.isAcceptState: + # allow zero-length tokens + self.captureSimState(self.prevAccept, input, ds0) + + t = input.LA(1) + s = ds0 # s is current/from DFA state + + while True: # while more work + if LexerATNSimulator.debug: + print("execATN loop starting closure:", str(s.configs)) + + # As we move src->trg, src->trg, we keep track of the previous trg to + # avoid looking up the DFA state again, which is expensive. + # If the previous target was already part of the DFA, we might + # be able to avoid doing a reach operation upon t. If s!=null, + # it means that semantic predicates didn't prevent us from + # creating a DFA state. Once we know s!=null, we check to see if + # the DFA state has an edge already for t. If so, we can just reuse + # it's configuration set; there's no point in re-computing it. + # This is kind of like doing DFA simulation within the ATN + # simulation because DFA simulation is really just a way to avoid + # computing reach/closure sets. Technically, once we know that + # we have a previously added DFA state, we could jump over to + # the DFA simulator. But, that would mean popping back and forth + # a lot and making things more complicated algorithmically. + # This optimization makes a lot of sense for loops within DFA. + # A character will take us back to an existing DFA state + # that already has lots of edges out of it. e.g., .* in comments. + # print("Target for:" + str(s) + " and:" + str(t)) + target = self.getExistingTargetState(s, t) + # print("Existing:" + str(target)) + if target is None: + target = self.computeTargetState(input, s, t) + # print("Computed:" + str(target)) + + if target == self.ERROR: + break + + # If this is a consumable input element, make sure to consume before + # capturing the accept state so the input index, line, and char + # position accurately reflect the state of the interpreter at the + # end of the token. + if t != Token.EOF: + self.consume(input) + + if target.isAcceptState: + self.captureSimState(self.prevAccept, input, target) + if t == Token.EOF: + break + + t = input.LA(1) + + s = target # flip; current DFA target becomes new src/from state + + return self.failOrAccept(self.prevAccept, input, s.configs, t) + + # Get an existing target state for an edge in the DFA. If the target state + # for the edge has not yet been computed or is otherwise not available, + # this method returns {@code null}. + # + # @param s The current DFA state + # @param t The next input symbol + # @return The existing target DFA state for the given input symbol + # {@code t}, or {@code null} if the target state for this edge is not + # already cached + def getExistingTargetState(self, s:DFAState, t:int): + if s.edges is None or t < self.MIN_DFA_EDGE or t > self.MAX_DFA_EDGE: + return None + + target = s.edges[t - self.MIN_DFA_EDGE] + if LexerATNSimulator.debug and target is not None: + print("reuse state", str(s.stateNumber), "edge to", str(target.stateNumber)) + + return target + + # Compute a target state for an edge in the DFA, and attempt to add the + # computed state and corresponding edge to the DFA. + # + # @param input The input stream + # @param s The current DFA state + # @param t The next input symbol + # + # @return The computed target DFA state for the given input symbol + # {@code t}. If {@code t} does not lead to a valid DFA state, this method + # returns {@link #ERROR}. + def computeTargetState(self, input:InputStream, s:DFAState, t:int): + reach = OrderedATNConfigSet() + + # if we don't find an existing DFA state + # Fill reach starting from closure, following t transitions + self.getReachableConfigSet(input, s.configs, reach, t) + + if len(reach)==0: # we got nowhere on t from s + if not reach.hasSemanticContext: + # we got nowhere on t, don't throw out this knowledge; it'd + # cause a failover from DFA later. + self. addDFAEdge(s, t, self.ERROR) + + # stop when we can't match any more char + return self.ERROR + + # Add an edge from s to target DFA found/created for reach + return self.addDFAEdge(s, t, cfgs=reach) + + def failOrAccept(self, prevAccept:SimState , input:InputStream, reach:ATNConfigSet, t:int): + if self.prevAccept.dfaState is not None: + lexerActionExecutor = prevAccept.dfaState.lexerActionExecutor + self.accept(input, lexerActionExecutor, self.startIndex, prevAccept.index, prevAccept.line, prevAccept.column) + return prevAccept.dfaState.prediction + else: + # if no accept and EOF is first char, return EOF + if t==Token.EOF and input.index==self.startIndex: + return Token.EOF + raise LexerNoViableAltException(self.recog, input, self.startIndex, reach) + + # Given a starting configuration set, figure out all ATN configurations + # we can reach upon input {@code t}. Parameter {@code reach} is a return + # parameter. + def getReachableConfigSet(self, input:InputStream, closure:ATNConfigSet, reach:ATNConfigSet, t:int): + # this is used to skip processing for configs which have a lower priority + # than a config that already reached an accept state for the same rule + skipAlt = ATN.INVALID_ALT_NUMBER + for cfg in closure: + currentAltReachedAcceptState = ( cfg.alt == skipAlt ) + if currentAltReachedAcceptState and cfg.passedThroughNonGreedyDecision: + continue + + if LexerATNSimulator.debug: + print("testing", self.getTokenName(t), "at", str(cfg)) + + for trans in cfg.state.transitions: # for each transition + target = self.getReachableTarget(trans, t) + if target is not None: + lexerActionExecutor = cfg.lexerActionExecutor + if lexerActionExecutor is not None: + lexerActionExecutor = lexerActionExecutor.fixOffsetBeforeMatch(input.index - self.startIndex) + + treatEofAsEpsilon = (t == Token.EOF) + config = LexerATNConfig(state=target, lexerActionExecutor=lexerActionExecutor, config=cfg) + if self.closure(input, config, reach, currentAltReachedAcceptState, True, treatEofAsEpsilon): + # any remaining configs for this alt have a lower priority than + # the one that just reached an accept state. + skipAlt = cfg.alt + + def accept(self, input:InputStream, lexerActionExecutor:LexerActionExecutor, startIndex:int, index:int, line:int, charPos:int): + if LexerATNSimulator.debug: + print("ACTION", lexerActionExecutor) + + # seek to after last char in token + input.seek(index) + self.line = line + self.column = charPos + + if lexerActionExecutor is not None and self.recog is not None: + lexerActionExecutor.execute(self.recog, input, startIndex) + + def getReachableTarget(self, trans:Transition, t:int): + from antlr4.Lexer import Lexer + if trans.matches(t, 0, Lexer.MAX_CHAR_VALUE): + return trans.target + else: + return None + + def computeStartState(self, input:InputStream, p:ATNState): + initialContext = PredictionContext.EMPTY + configs = OrderedATNConfigSet() + for i in range(0,len(p.transitions)): + target = p.transitions[i].target + c = LexerATNConfig(state=target, alt=i+1, context=initialContext) + self.closure(input, c, configs, False, False, False) + return configs + + # Since the alternatives within any lexer decision are ordered by + # preference, this method stops pursuing the closure as soon as an accept + # state is reached. After the first accept state is reached by depth-first + # search from {@code config}, all other (potentially reachable) states for + # this rule would have a lower priority. + # + # @return {@code true} if an accept state is reached, otherwise + # {@code false}. + def closure(self, input:InputStream, config:LexerATNConfig, configs:ATNConfigSet, currentAltReachedAcceptState:bool, + speculative:bool, treatEofAsEpsilon:bool): + if LexerATNSimulator.debug: + print("closure(" + str(config) + ")") + + if isinstance( config.state, RuleStopState ): + if LexerATNSimulator.debug: + if self.recog is not None: + print("closure at", self.recog.symbolicNames[config.state.ruleIndex], "rule stop", str(config)) + else: + print("closure at rule stop", str(config)) + + if config.context is None or config.context.hasEmptyPath(): + if config.context is None or config.context.isEmpty(): + configs.add(config) + return True + else: + configs.add(LexerATNConfig(state=config.state, config=config, context=PredictionContext.EMPTY)) + currentAltReachedAcceptState = True + + if config.context is not None and not config.context.isEmpty(): + for i in range(0,len(config.context)): + if config.context.getReturnState(i) != PredictionContext.EMPTY_RETURN_STATE: + newContext = config.context.getParent(i) # "pop" return state + returnState = self.atn.states[config.context.getReturnState(i)] + c = LexerATNConfig(state=returnState, config=config, context=newContext) + currentAltReachedAcceptState = self.closure(input, c, configs, + currentAltReachedAcceptState, speculative, treatEofAsEpsilon) + + return currentAltReachedAcceptState + + # optimization + if not config.state.epsilonOnlyTransitions: + if not currentAltReachedAcceptState or not config.passedThroughNonGreedyDecision: + configs.add(config) + + for t in config.state.transitions: + c = self.getEpsilonTarget(input, config, t, configs, speculative, treatEofAsEpsilon) + if c is not None: + currentAltReachedAcceptState = self.closure(input, c, configs, currentAltReachedAcceptState, speculative, treatEofAsEpsilon) + + return currentAltReachedAcceptState + + # side-effect: can alter configs.hasSemanticContext + def getEpsilonTarget(self, input:InputStream, config:LexerATNConfig, t:Transition, configs:ATNConfigSet, + speculative:bool, treatEofAsEpsilon:bool): + c = None + if t.serializationType==Transition.RULE: + newContext = SingletonPredictionContext.create(config.context, t.followState.stateNumber) + c = LexerATNConfig(state=t.target, config=config, context=newContext) + + elif t.serializationType==Transition.PRECEDENCE: + raise UnsupportedOperationException("Precedence predicates are not supported in lexers.") + + elif t.serializationType==Transition.PREDICATE: + # Track traversing semantic predicates. If we traverse, + # we cannot add a DFA state for this "reach" computation + # because the DFA would not test the predicate again in the + # future. Rather than creating collections of semantic predicates + # like v3 and testing them on prediction, v4 will test them on the + # fly all the time using the ATN not the DFA. This is slower but + # semantically it's not used that often. One of the key elements to + # this predicate mechanism is not adding DFA states that see + # predicates immediately afterwards in the ATN. For example, + + # a : ID {p1}? | ID {p2}? ; + + # should create the start state for rule 'a' (to save start state + # competition), but should not create target of ID state. The + # collection of ATN states the following ID references includes + # states reached by traversing predicates. Since this is when we + # test them, we cannot cash the DFA state target of ID. + + if LexerATNSimulator.debug: + print("EVAL rule "+ str(t.ruleIndex) + ":" + str(t.predIndex)) + configs.hasSemanticContext = True + if self.evaluatePredicate(input, t.ruleIndex, t.predIndex, speculative): + c = LexerATNConfig(state=t.target, config=config) + + elif t.serializationType==Transition.ACTION: + if config.context is None or config.context.hasEmptyPath(): + # execute actions anywhere in the start rule for a token. + # + # TODO: if the entry rule is invoked recursively, some + # actions may be executed during the recursive call. The + # problem can appear when hasEmptyPath() is true but + # isEmpty() is false. In this case, the config needs to be + # split into two contexts - one with just the empty path + # and another with everything but the empty path. + # Unfortunately, the current algorithm does not allow + # getEpsilonTarget to return two configurations, so + # additional modifications are needed before we can support + # the split operation. + lexerActionExecutor = LexerActionExecutor.append(config.lexerActionExecutor, + self.atn.lexerActions[t.actionIndex]) + c = LexerATNConfig(state=t.target, config=config, lexerActionExecutor=lexerActionExecutor) + + else: + # ignore actions in referenced rules + c = LexerATNConfig(state=t.target, config=config) + + elif t.serializationType==Transition.EPSILON: + c = LexerATNConfig(state=t.target, config=config) + + elif t.serializationType in [ Transition.ATOM, Transition.RANGE, Transition.SET ]: + if treatEofAsEpsilon: + from antlr4.Lexer import Lexer + if t.matches(Token.EOF, 0, Lexer.MAX_CHAR_VALUE): + c = LexerATNConfig(state=t.target, config=config) + + return c + + # Evaluate a predicate specified in the lexer. + # + #

          If {@code speculative} is {@code true}, this method was called before + # {@link #consume} for the matched character. This method should call + # {@link #consume} before evaluating the predicate to ensure position + # sensitive values, including {@link Lexer#getText}, {@link Lexer#getLine}, + # and {@link Lexer#getcolumn}, properly reflect the current + # lexer state. This method should restore {@code input} and the simulator + # to the original state before returning (i.e. undo the actions made by the + # call to {@link #consume}.

          + # + # @param input The input stream. + # @param ruleIndex The rule containing the predicate. + # @param predIndex The index of the predicate within the rule. + # @param speculative {@code true} if the current index in {@code input} is + # one character before the predicate's location. + # + # @return {@code true} if the specified predicate evaluates to + # {@code true}. + #/ + def evaluatePredicate(self, input:InputStream, ruleIndex:int, predIndex:int, speculative:bool): + # assume true if no recognizer was provided + if self.recog is None: + return True + + if not speculative: + return self.recog.sempred(None, ruleIndex, predIndex) + + savedcolumn = self.column + savedLine = self.line + index = input.index + marker = input.mark() + try: + self.consume(input) + return self.recog.sempred(None, ruleIndex, predIndex) + finally: + self.column = savedcolumn + self.line = savedLine + input.seek(index) + input.release(marker) + + def captureSimState(self, settings:SimState, input:InputStream, dfaState:DFAState): + settings.index = input.index + settings.line = self.line + settings.column = self.column + settings.dfaState = dfaState + + def addDFAEdge(self, from_:DFAState, tk:int, to:DFAState=None, cfgs:ATNConfigSet=None) -> DFAState: + + if to is None and cfgs is not None: + # leading to this call, ATNConfigSet.hasSemanticContext is used as a + # marker indicating dynamic predicate evaluation makes this edge + # dependent on the specific input sequence, so the static edge in the + # DFA should be omitted. The target DFAState is still created since + # execATN has the ability to resynchronize with the DFA state cache + # following the predicate evaluation step. + # + # TJP notes: next time through the DFA, we see a pred again and eval. + # If that gets us to a previously created (but dangling) DFA + # state, we can continue in pure DFA mode from there. + #/ + suppressEdge = cfgs.hasSemanticContext + cfgs.hasSemanticContext = False + + to = self.addDFAState(cfgs) + + if suppressEdge: + return to + + # add the edge + if tk < self.MIN_DFA_EDGE or tk > self.MAX_DFA_EDGE: + # Only track edges within the DFA bounds + return to + + if LexerATNSimulator.debug: + print("EDGE " + str(from_) + " -> " + str(to) + " upon "+ chr(tk)) + + if from_.edges is None: + # make room for tokens 1..n and -1 masquerading as index 0 + from_.edges = [ None ] * (self.MAX_DFA_EDGE - self.MIN_DFA_EDGE + 1) + + from_.edges[tk - self.MIN_DFA_EDGE] = to # connect + + return to + + + # Add a new DFA state if there isn't one with this set of + # configurations already. This method also detects the first + # configuration containing an ATN rule stop state. Later, when + # traversing the DFA, we will know which rule to accept. + def addDFAState(self, configs:ATNConfigSet) -> DFAState: + + proposed = DFAState(configs=configs) + firstConfigWithRuleStopState = next((cfg for cfg in configs if isinstance(cfg.state, RuleStopState)), None) + + if firstConfigWithRuleStopState is not None: + proposed.isAcceptState = True + proposed.lexerActionExecutor = firstConfigWithRuleStopState.lexerActionExecutor + proposed.prediction = self.atn.ruleToTokenType[firstConfigWithRuleStopState.state.ruleIndex] + + dfa = self.decisionToDFA[self.mode] + existing = dfa.states.get(proposed, None) + if existing is not None: + return existing + + newState = proposed + + newState.stateNumber = len(dfa.states) + configs.setReadonly(True) + newState.configs = configs + dfa.states[newState] = newState + return newState + + def getDFA(self, mode:int): + return self.decisionToDFA[mode] + + # Get the text matched so far for the current token. + def getText(self, input:InputStream): + # index is first lookahead char, don't include. + return input.getText(self.startIndex, input.index-1) + + def consume(self, input:InputStream): + curChar = input.LA(1) + if curChar==ord('\n'): + self.line += 1 + self.column = 0 + else: + self.column += 1 + input.consume() + + def getTokenName(self, t:int): + if t==-1: + return "EOF" + else: + return "'" + chr(t) + "'" + + +LexerATNSimulator.ERROR = DFAState(0x7FFFFFFF, ATNConfigSet()) + +del Lexer \ No newline at end of file diff --git a/src/antlr4/atn/LexerAction.py b/src/antlr4/atn/LexerAction.py new file mode 100644 index 00000000..5d11f21a --- /dev/null +++ b/src/antlr4/atn/LexerAction.py @@ -0,0 +1,291 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. + # + +from enum import IntEnum + +# need forward declaration +Lexer = None + + +class LexerActionType(IntEnum): + + CHANNEL = 0 #The type of a {@link LexerChannelAction} action. + CUSTOM = 1 #The type of a {@link LexerCustomAction} action. + MODE = 2 #The type of a {@link LexerModeAction} action. + MORE = 3 #The type of a {@link LexerMoreAction} action. + POP_MODE = 4 #The type of a {@link LexerPopModeAction} action. + PUSH_MODE = 5 #The type of a {@link LexerPushModeAction} action. + SKIP = 6 #The type of a {@link LexerSkipAction} action. + TYPE = 7 #The type of a {@link LexerTypeAction} action. + +class LexerAction(object): + + def __init__(self, action:LexerActionType): + self.actionType = action + self.isPositionDependent = False + + def __hash__(self): + return hash(self.actionType) + + def __eq__(self, other): + return self is other + + +# +# Implements the {@code skip} lexer action by calling {@link Lexer#skip}. +# +#

          The {@code skip} command does not have any parameters, so this action is +# implemented as a singleton instance exposed by {@link #INSTANCE}.

          +class LexerSkipAction(LexerAction ): + + # Provides a singleton instance of this parameterless lexer action. + INSTANCE = None + + def __init__(self): + super().__init__(LexerActionType.SKIP) + + def execute(self, lexer:Lexer): + lexer.skip() + + def __str__(self): + return "skip" + +LexerSkipAction.INSTANCE = LexerSkipAction() + +# Implements the {@code type} lexer action by calling {@link Lexer#setType} +# with the assigned type. +class LexerTypeAction(LexerAction): + + def __init__(self, type:int): + super().__init__(LexerActionType.TYPE) + self.type = type + + def execute(self, lexer:Lexer): + lexer.type = self.type + + def __hash__(self): + return hash((self.actionType, self.type)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerTypeAction): + return False + else: + return self.type == other.type + + def __str__(self): + return "type(" + str(self.type) + ")" + + +# Implements the {@code pushMode} lexer action by calling +# {@link Lexer#pushMode} with the assigned mode. +class LexerPushModeAction(LexerAction): + + def __init__(self, mode:int): + super().__init__(LexerActionType.PUSH_MODE) + self.mode = mode + + #

          This action is implemented by calling {@link Lexer#pushMode} with the + # value provided by {@link #getMode}.

          + def execute(self, lexer:Lexer): + lexer.pushMode(self.mode) + + def __hash__(self): + return hash((self.actionType, self.mode)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerPushModeAction): + return False + else: + return self.mode == other.mode + + def __str__(self): + return "pushMode(" + str(self.mode) + ")" + + +# Implements the {@code popMode} lexer action by calling {@link Lexer#popMode}. +# +#

          The {@code popMode} command does not have any parameters, so this action is +# implemented as a singleton instance exposed by {@link #INSTANCE}.

          +class LexerPopModeAction(LexerAction): + + INSTANCE = None + + def __init__(self): + super().__init__(LexerActionType.POP_MODE) + + #

          This action is implemented by calling {@link Lexer#popMode}.

          + def execute(self, lexer:Lexer): + lexer.popMode() + + def __str__(self): + return "popMode" + +LexerPopModeAction.INSTANCE = LexerPopModeAction() + +# Implements the {@code more} lexer action by calling {@link Lexer#more}. +# +#

          The {@code more} command does not have any parameters, so this action is +# implemented as a singleton instance exposed by {@link #INSTANCE}.

          +class LexerMoreAction(LexerAction): + + INSTANCE = None + + def __init__(self): + super().__init__(LexerActionType.MORE) + + #

          This action is implemented by calling {@link Lexer#popMode}.

          + def execute(self, lexer:Lexer): + lexer.more() + + def __str__(self): + return "more" + +LexerMoreAction.INSTANCE = LexerMoreAction() + +# Implements the {@code mode} lexer action by calling {@link Lexer#mode} with +# the assigned mode. +class LexerModeAction(LexerAction): + + def __init__(self, mode:int): + super().__init__(LexerActionType.MODE) + self.mode = mode + + #

          This action is implemented by calling {@link Lexer#mode} with the + # value provided by {@link #getMode}.

          + def execute(self, lexer:Lexer): + lexer.mode(self.mode) + + def __hash__(self): + return hash((self.actionType, self.mode)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerModeAction): + return False + else: + return self.mode == other.mode + + def __str__(self): + return "mode(" + str(self.mode) + ")" + +# Executes a custom lexer action by calling {@link Recognizer#action} with the +# rule and action indexes assigned to the custom action. The implementation of +# a custom action is added to the generated code for the lexer in an override +# of {@link Recognizer#action} when the grammar is compiled. +# +#

          This class may represent embedded actions created with the {...} +# syntax in ANTLR 4, as well as actions created for lexer commands where the +# command argument could not be evaluated when the grammar was compiled.

          + +class LexerCustomAction(LexerAction): + + # Constructs a custom lexer action with the specified rule and action + # indexes. + # + # @param ruleIndex The rule index to use for calls to + # {@link Recognizer#action}. + # @param actionIndex The action index to use for calls to + # {@link Recognizer#action}. + #/ + def __init__(self, ruleIndex:int, actionIndex:int): + super().__init__(LexerActionType.CUSTOM) + self.ruleIndex = ruleIndex + self.actionIndex = actionIndex + self.isPositionDependent = True + + #

          Custom actions are implemented by calling {@link Lexer#action} with the + # appropriate rule and action indexes.

          + def execute(self, lexer:Lexer): + lexer.action(None, self.ruleIndex, self.actionIndex) + + def __hash__(self): + return hash((self.actionType, self.ruleIndex, self.actionIndex)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerCustomAction): + return False + else: + return self.ruleIndex == other.ruleIndex and self.actionIndex == other.actionIndex + +# Implements the {@code channel} lexer action by calling +# {@link Lexer#setChannel} with the assigned channel. +class LexerChannelAction(LexerAction): + + # Constructs a new {@code channel} action with the specified channel value. + # @param channel The channel value to pass to {@link Lexer#setChannel}. + def __init__(self, channel:int): + super().__init__(LexerActionType.CHANNEL) + self.channel = channel + + #

          This action is implemented by calling {@link Lexer#setChannel} with the + # value provided by {@link #getChannel}.

          + def execute(self, lexer:Lexer): + lexer._channel = self.channel + + def __hash__(self): + return hash((self.actionType, self.channel)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerChannelAction): + return False + else: + return self.channel == other.channel + + def __str__(self): + return "channel(" + str(self.channel) + ")" + +# This implementation of {@link LexerAction} is used for tracking input offsets +# for position-dependent actions within a {@link LexerActionExecutor}. +# +#

          This action is not serialized as part of the ATN, and is only required for +# position-dependent lexer actions which appear at a location other than the +# end of a rule. For more information about DFA optimizations employed for +# lexer actions, see {@link LexerActionExecutor#append} and +# {@link LexerActionExecutor#fixOffsetBeforeMatch}.

          +class LexerIndexedCustomAction(LexerAction): + + # Constructs a new indexed custom action by associating a character offset + # with a {@link LexerAction}. + # + #

          Note: This class is only required for lexer actions for which + # {@link LexerAction#isPositionDependent} returns {@code true}.

          + # + # @param offset The offset into the input {@link CharStream}, relative to + # the token start index, at which the specified lexer action should be + # executed. + # @param action The lexer action to execute at a particular offset in the + # input {@link CharStream}. + def __init__(self, offset:int, action:LexerAction): + super().__init__(action.actionType) + self.offset = offset + self.action = action + self.isPositionDependent = True + + #

          This method calls {@link #execute} on the result of {@link #getAction} + # using the provided {@code lexer}.

          + def execute(self, lexer:Lexer): + # assume the input stream position was properly set by the calling code + self.action.execute(lexer) + + def __hash__(self): + return hash((self.actionType, self.offset, self.action)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerIndexedCustomAction): + return False + else: + return self.offset == other.offset and self.action == other.action diff --git a/src/antlr4/atn/LexerActionExecutor.py b/src/antlr4/atn/LexerActionExecutor.py new file mode 100644 index 00000000..df125169 --- /dev/null +++ b/src/antlr4/atn/LexerActionExecutor.py @@ -0,0 +1,142 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# Represents an executor for a sequence of lexer actions which traversed during +# the matching operation of a lexer rule (token). +# +#

          The executor tracks position information for position-dependent lexer actions +# efficiently, ensuring that actions appearing only at the end of the rule do +# not cause bloating of the {@link DFA} created for the lexer.

          + + +from antlr4.InputStream import InputStream +from antlr4.atn.LexerAction import LexerAction, LexerIndexedCustomAction + +# need a forward declaration +Lexer = None +LexerActionExecutor = None + +class LexerActionExecutor(object): + + def __init__(self, lexerActions:list=list()): + self.lexerActions = lexerActions + # Caches the result of {@link #hashCode} since the hash code is an element + # of the performance-critical {@link LexerATNConfig#hashCode} operation. + self.hashCode = hash("".join([str(la) for la in lexerActions])) + + + # Creates a {@link LexerActionExecutor} which executes the actions for + # the input {@code lexerActionExecutor} followed by a specified + # {@code lexerAction}. + # + # @param lexerActionExecutor The executor for actions already traversed by + # the lexer while matching a token within a particular + # {@link LexerATNConfig}. If this is {@code null}, the method behaves as + # though it were an empty executor. + # @param lexerAction The lexer action to execute after the actions + # specified in {@code lexerActionExecutor}. + # + # @return A {@link LexerActionExecutor} for executing the combine actions + # of {@code lexerActionExecutor} and {@code lexerAction}. + @staticmethod + def append(lexerActionExecutor:LexerActionExecutor , lexerAction:LexerAction ): + if lexerActionExecutor is None: + return LexerActionExecutor([ lexerAction ]) + + lexerActions = lexerActionExecutor.lexerActions + [ lexerAction ] + return LexerActionExecutor(lexerActions) + + # Creates a {@link LexerActionExecutor} which encodes the current offset + # for position-dependent lexer actions. + # + #

          Normally, when the executor encounters lexer actions where + # {@link LexerAction#isPositionDependent} returns {@code true}, it calls + # {@link IntStream#seek} on the input {@link CharStream} to set the input + # position to the end of the current token. This behavior provides + # for efficient DFA representation of lexer actions which appear at the end + # of a lexer rule, even when the lexer rule matches a variable number of + # characters.

          + # + #

          Prior to traversing a match transition in the ATN, the current offset + # from the token start index is assigned to all position-dependent lexer + # actions which have not already been assigned a fixed offset. By storing + # the offsets relative to the token start index, the DFA representation of + # lexer actions which appear in the middle of tokens remains efficient due + # to sharing among tokens of the same length, regardless of their absolute + # position in the input stream.

          + # + #

          If the current executor already has offsets assigned to all + # position-dependent lexer actions, the method returns {@code this}.

          + # + # @param offset The current offset to assign to all position-dependent + # lexer actions which do not already have offsets assigned. + # + # @return A {@link LexerActionExecutor} which stores input stream offsets + # for all position-dependent lexer actions. + #/ + def fixOffsetBeforeMatch(self, offset:int): + updatedLexerActions = None + for i in range(0, len(self.lexerActions)): + if self.lexerActions[i].isPositionDependent and not isinstance(self.lexerActions[i], LexerIndexedCustomAction): + if updatedLexerActions is None: + updatedLexerActions = [ la for la in self.lexerActions ] + updatedLexerActions[i] = LexerIndexedCustomAction(offset, self.lexerActions[i]) + + if updatedLexerActions is None: + return self + else: + return LexerActionExecutor(updatedLexerActions) + + + # Execute the actions encapsulated by this executor within the context of a + # particular {@link Lexer}. + # + #

          This method calls {@link IntStream#seek} to set the position of the + # {@code input} {@link CharStream} prior to calling + # {@link LexerAction#execute} on a position-dependent action. Before the + # method returns, the input position will be restored to the same position + # it was in when the method was invoked.

          + # + # @param lexer The lexer instance. + # @param input The input stream which is the source for the current token. + # When this method is called, the current {@link IntStream#index} for + # {@code input} should be the start of the following token, i.e. 1 + # character past the end of the current token. + # @param startIndex The token start index. This value may be passed to + # {@link IntStream#seek} to set the {@code input} position to the beginning + # of the token. + #/ + def execute(self, lexer:Lexer, input:InputStream, startIndex:int): + requiresSeek = False + stopIndex = input.index + try: + for lexerAction in self.lexerActions: + if isinstance(lexerAction, LexerIndexedCustomAction): + offset = lexerAction.offset + input.seek(startIndex + offset) + lexerAction = lexerAction.action + requiresSeek = (startIndex + offset) != stopIndex + elif lexerAction.isPositionDependent: + input.seek(stopIndex) + requiresSeek = False + lexerAction.execute(lexer) + finally: + if requiresSeek: + input.seek(stopIndex) + + def __hash__(self): + return self.hashCode + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, LexerActionExecutor): + return False + else: + return self.hashCode == other.hashCode \ + and self.lexerActions == other.lexerActions + +del Lexer \ No newline at end of file diff --git a/src/antlr4/atn/ParserATNSimulator.py b/src/antlr4/atn/ParserATNSimulator.py new file mode 100644 index 00000000..5f932dbe --- /dev/null +++ b/src/antlr4/atn/ParserATNSimulator.py @@ -0,0 +1,1649 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# The embodiment of the adaptive LL(*), ALL(*), parsing strategy. +# +#

          +# The basic complexity of the adaptive strategy makes it harder to understand. +# We begin with ATN simulation to build paths in a DFA. Subsequent prediction +# requests go through the DFA first. If they reach a state without an edge for +# the current symbol, the algorithm fails over to the ATN simulation to +# complete the DFA path for the current input (until it finds a conflict state +# or uniquely predicting state).

          +# +#

          +# All of that is done without using the outer context because we want to create +# a DFA that is not dependent upon the rule invocation stack when we do a +# prediction. One DFA works in all contexts. We avoid using context not +# necessarily because it's slower, although it can be, but because of the DFA +# caching problem. The closure routine only considers the rule invocation stack +# created during prediction beginning in the decision rule. For example, if +# prediction occurs without invoking another rule's ATN, there are no context +# stacks in the configurations. When lack of context leads to a conflict, we +# don't know if it's an ambiguity or a weakness in the strong LL(*) parsing +# strategy (versus full LL(*)).

          +# +#

          +# When SLL yields a configuration set with conflict, we rewind the input and +# retry the ATN simulation, this time using full outer context without adding +# to the DFA. Configuration context stacks will be the full invocation stacks +# from the start rule. If we get a conflict using full context, then we can +# definitively say we have a true ambiguity for that input sequence. If we +# don't get a conflict, it implies that the decision is sensitive to the outer +# context. (It is not context-sensitive in the sense of context-sensitive +# grammars.)

          +# +#

          +# The next time we reach this DFA state with an SLL conflict, through DFA +# simulation, we will again retry the ATN simulation using full context mode. +# This is slow because we can't save the results and have to "interpret" the +# ATN each time we get that input.

          +# +#

          +# CACHING FULL CONTEXT PREDICTIONS

          +# +#

          +# We could cache results from full context to predicted alternative easily and +# that saves a lot of time but doesn't work in presence of predicates. The set +# of visible predicates from the ATN start state changes depending on the +# context, because closure can fall off the end of a rule. I tried to cache +# tuples (stack context, semantic context, predicted alt) but it was slower +# than interpreting and much more complicated. Also required a huge amount of +# memory. The goal is not to create the world's fastest parser anyway. I'd like +# to keep this algorithm simple. By launching multiple threads, we can improve +# the speed of parsing across a large number of files.

          +# +#

          +# There is no strict ordering between the amount of input used by SLL vs LL, +# which makes it really hard to build a cache for full context. Let's say that +# we have input A B C that leads to an SLL conflict with full context X. That +# implies that using X we might only use A B but we could also use A B C D to +# resolve conflict. Input A B C D could predict alternative 1 in one position +# in the input and A B C E could predict alternative 2 in another position in +# input. The conflicting SLL configurations could still be non-unique in the +# full context prediction, which would lead us to requiring more input than the +# original A B C. To make a prediction cache work, we have to track the exact +# input used during the previous prediction. That amounts to a cache that maps +# X to a specific DFA for that context.

          +# +#

          +# Something should be done for left-recursive expression predictions. They are +# likely LL(1) + pred eval. Easier to do the whole SLL unless error and retry +# with full LL thing Sam does.

          +# +#

          +# AVOIDING FULL CONTEXT PREDICTION

          +# +#

          +# We avoid doing full context retry when the outer context is empty, we did not +# dip into the outer context by falling off the end of the decision state rule, +# or when we force SLL mode.

          +# +#

          +# As an example of the not dip into outer context case, consider as super +# constructor calls versus function calls. One grammar might look like +# this:

          +# +#
          +# ctorBody
          +#   : '{' superCall? stat* '}'
          +#   ;
          +# 
          +# +#

          +# Or, you might see something like

          +# +#
          +# stat
          +#   : superCall ';'
          +#   | expression ';'
          +#   | ...
          +#   ;
          +# 
          +# +#

          +# In both cases I believe that no closure operations will dip into the outer +# context. In the first case ctorBody in the worst case will stop at the '}'. +# In the 2nd case it should stop at the ';'. Both cases should stay within the +# entry rule and not dip into the outer context.

          +# +#

          +# PREDICATES

          +# +#

          +# Predicates are always evaluated if present in either SLL or LL both. SLL and +# LL simulation deals with predicates differently. SLL collects predicates as +# it performs closure operations like ANTLR v3 did. It delays predicate +# evaluation until it reaches and accept state. This allows us to cache the SLL +# ATN simulation whereas, if we had evaluated predicates on-the-fly during +# closure, the DFA state configuration sets would be different and we couldn't +# build up a suitable DFA.

          +# +#

          +# When building a DFA accept state during ATN simulation, we evaluate any +# predicates and return the sole semantically valid alternative. If there is +# more than 1 alternative, we report an ambiguity. If there are 0 alternatives, +# we throw an exception. Alternatives without predicates act like they have +# true predicates. The simple way to think about it is to strip away all +# alternatives with false predicates and choose the minimum alternative that +# remains.

          +# +#

          +# When we start in the DFA and reach an accept state that's predicated, we test +# those and return the minimum semantically viable alternative. If no +# alternatives are viable, we throw an exception.

          +# +#

          +# During full LL ATN simulation, closure always evaluates predicates and +# on-the-fly. This is crucial to reducing the configuration set size during +# closure. It hits a landmine when parsing with the Java grammar, for example, +# without this on-the-fly evaluation.

          +# +#

          +# SHARING DFA

          +# +#

          +# All instances of the same parser share the same decision DFAs through a +# static field. Each instance gets its own ATN simulator but they share the +# same {@link #decisionToDFA} field. They also share a +# {@link PredictionContextCache} object that makes sure that all +# {@link PredictionContext} objects are shared among the DFA states. This makes +# a big size difference.

          +# +#

          +# THREAD SAFETY

          +# +#

          +# The {@link ParserATNSimulator} locks on the {@link #decisionToDFA} field when +# it adds a new DFA object to that array. {@link #addDFAEdge} +# locks on the DFA for the current decision when setting the +# {@link DFAState#edges} field. {@link #addDFAState} locks on +# the DFA for the current decision when looking up a DFA state to see if it +# already exists. We must make sure that all requests to add DFA states that +# are equivalent result in the same shared DFA object. This is because lots of +# threads will be trying to update the DFA at once. The +# {@link #addDFAState} method also locks inside the DFA lock +# but this time on the shared context cache when it rebuilds the +# configurations' {@link PredictionContext} objects using cached +# subgraphs/nodes. No other locking occurs, even during DFA simulation. This is +# safe as long as we can guarantee that all threads referencing +# {@code s.edge[t]} get the same physical target {@link DFAState}, or +# {@code null}. Once into the DFA, the DFA simulation does not reference the +# {@link DFA#states} map. It follows the {@link DFAState#edges} field to new +# targets. The DFA simulator will either find {@link DFAState#edges} to be +# {@code null}, to be non-{@code null} and {@code dfa.edges[t]} null, or +# {@code dfa.edges[t]} to be non-null. The +# {@link #addDFAEdge} method could be racing to set the field +# but in either case the DFA simulator works; if {@code null}, and requests ATN +# simulation. It could also race trying to get {@code dfa.edges[t]}, but either +# way it will work because it's not doing a test and set operation.

          +# +#

          +# Starting with SLL then failing to combined SLL/LL (Two-Stage +# Parsing)

          +# +#

          +# Sam pointed out that if SLL does not give a syntax error, then there is no +# point in doing full LL, which is slower. We only have to try LL if we get a +# syntax error. For maximum speed, Sam starts the parser set to pure SLL +# mode with the {@link BailErrorStrategy}:

          +# +#
          +# parser.{@link Parser#getInterpreter() getInterpreter()}.{@link #setPredictionMode setPredictionMode}{@code (}{@link PredictionMode#SLL}{@code )};
          +# parser.{@link Parser#setErrorHandler setErrorHandler}(new {@link BailErrorStrategy}());
          +# 
          +# +#

          +# If it does not get a syntax error, then we're done. If it does get a syntax +# error, we need to retry with the combined SLL/LL strategy.

          +# +#

          +# The reason this works is as follows. If there are no SLL conflicts, then the +# grammar is SLL (at least for that input set). If there is an SLL conflict, +# the full LL analysis must yield a set of viable alternatives which is a +# subset of the alternatives reported by SLL. If the LL set is a singleton, +# then the grammar is LL but not SLL. If the LL set is the same size as the SLL +# set, the decision is SLL. If the LL set has size > 1, then that decision +# is truly ambiguous on the current input. If the LL set is smaller, then the +# SLL conflict resolution might choose an alternative that the full LL would +# rule out as a possibility based upon better context information. If that's +# the case, then the SLL parse will definitely get an error because the full LL +# analysis says it's not viable. If SLL conflict resolution chooses an +# alternative within the LL set, them both SLL and LL would choose the same +# alternative because they both choose the minimum of multiple conflicting +# alternatives.

          +# +#

          +# Let's say we have a set of SLL conflicting alternatives {@code {1, 2, 3}} and +# a smaller LL set called s. If s is {@code {2, 3}}, then SLL +# parsing will get an error because SLL will pursue alternative 1. If +# s is {@code {1, 2}} or {@code {1, 3}} then both SLL and LL will +# choose the same alternative because alternative one is the minimum of either +# set. If s is {@code {2}} or {@code {3}} then SLL will get a syntax +# error. If s is {@code {1}} then SLL will succeed.

          +# +#

          +# Of course, if the input is invalid, then we will get an error for sure in +# both SLL and LL parsing. Erroneous input will therefore require 2 passes over +# the input.

          +# +import sys +from antlr4 import DFA +from antlr4.PredictionContext import PredictionContextCache, PredictionContext, SingletonPredictionContext, \ + PredictionContextFromRuleContext +from antlr4.BufferedTokenStream import TokenStream +from antlr4.Parser import Parser +from antlr4.ParserRuleContext import ParserRuleContext +from antlr4.RuleContext import RuleContext +from antlr4.Token import Token +from antlr4.Utils import str_list +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNConfig import ATNConfig +from antlr4.atn.ATNConfigSet import ATNConfigSet +from antlr4.atn.ATNSimulator import ATNSimulator +from antlr4.atn.ATNState import StarLoopEntryState, DecisionState, RuleStopState, ATNState +from antlr4.atn.PredictionMode import PredictionMode +from antlr4.atn.SemanticContext import SemanticContext, AND, andContext, orContext +from antlr4.atn.Transition import Transition, RuleTransition, ActionTransition, PrecedencePredicateTransition, \ + PredicateTransition, AtomTransition, SetTransition, NotSetTransition +from antlr4.dfa.DFAState import DFAState, PredPrediction +from antlr4.error.Errors import NoViableAltException + + +class ParserATNSimulator(ATNSimulator): + + debug = False + debug_list_atn_decisions = False + dfa_debug = False + retry_debug = False + + + def __init__(self, parser:Parser, atn:ATN, decisionToDFA:list, sharedContextCache:PredictionContextCache): + super().__init__(atn, sharedContextCache) + self.parser = parser + self.decisionToDFA = decisionToDFA + # SLL, LL, or LL + exact ambig detection?# + self.predictionMode = PredictionMode.LL + # LAME globals to avoid parameters!!!!! I need these down deep in predTransition + self._input = None + self._startIndex = 0 + self._outerContext = None + self._dfa = None + # Each prediction operation uses a cache for merge of prediction contexts. + # Don't keep around as it wastes huge amounts of memory. DoubleKeyMap + # isn't synchronized but we're ok since two threads shouldn't reuse same + # parser/atnsim object because it can only handle one input at a time. + # This maps graphs a and b to merged result c. (a,b)→c. We can avoid + # the merge if we ever see a and b again. Note that (b,a)→c should + # also be examined during cache lookup. + # + self.mergeCache = None + + + def reset(self): + pass + + def adaptivePredict(self, input:TokenStream, decision:int, outerContext:ParserRuleContext): + if ParserATNSimulator.debug or ParserATNSimulator.debug_list_atn_decisions: + print("adaptivePredict decision " + str(decision) + + " exec LA(1)==" + self.getLookaheadName(input) + + " line " + str(input.LT(1).line) + ":" + + str(input.LT(1).column)) + self._input = input + self._startIndex = input.index + self._outerContext = outerContext + + dfa = self.decisionToDFA[decision] + self._dfa = dfa + m = input.mark() + index = input.index + + # Now we are certain to have a specific decision's DFA + # But, do we still need an initial state? + try: + if dfa.precedenceDfa: + # the start state for a precedence DFA depends on the current + # parser precedence, and is provided by a DFA method. + s0 = dfa.getPrecedenceStartState(self.parser.getPrecedence()) + else: + # the start state for a "regular" DFA is just s0 + s0 = dfa.s0 + + if s0 is None: + if outerContext is None: + outerContext = ParserRuleContext.EMPTY + if ParserATNSimulator.debug or ParserATNSimulator.debug_list_atn_decisions: + print("predictATN decision " + str(dfa.decision) + + " exec LA(1)==" + self.getLookaheadName(input) + + ", outerContext=" + outerContext.toString(self.parser.literalNames, None)) + + fullCtx = False + s0_closure = self.computeStartState(dfa.atnStartState, ParserRuleContext.EMPTY, fullCtx) + + if dfa.precedenceDfa: + # If this is a precedence DFA, we use applyPrecedenceFilter + # to convert the computed start state to a precedence start + # state. We then use DFA.setPrecedenceStartState to set the + # appropriate start state for the precedence level rather + # than simply setting DFA.s0. + # + dfa.s0.configs = s0_closure # not used for prediction but useful to know start configs anyway + s0_closure = self.applyPrecedenceFilter(s0_closure) + s0 = self.addDFAState(dfa, DFAState(configs=s0_closure)) + dfa.setPrecedenceStartState(self.parser.getPrecedence(), s0) + else: + s0 = self.addDFAState(dfa, DFAState(configs=s0_closure)) + dfa.s0 = s0 + + alt = self.execATN(dfa, s0, input, index, outerContext) + if ParserATNSimulator.debug: + print("DFA after predictATN: " + dfa.toString(self.parser.literalNames)) + return alt + finally: + self._dfa = None + self.mergeCache = None # wack cache after each prediction + input.seek(index) + input.release(m) + + # Performs ATN simulation to compute a predicted alternative based + # upon the remaining input, but also updates the DFA cache to avoid + # having to traverse the ATN again for the same input sequence. + + # There are some key conditions we're looking for after computing a new + # set of ATN configs (proposed DFA state): + # if the set is empty, there is no viable alternative for current symbol + # does the state uniquely predict an alternative? + # does the state have a conflict that would prevent us from + # putting it on the work list? + + # We also have some key operations to do: + # add an edge from previous DFA state to potentially new DFA state, D, + # upon current symbol but only if adding to work list, which means in all + # cases except no viable alternative (and possibly non-greedy decisions?) + # collecting predicates and adding semantic context to DFA accept states + # adding rule context to context-sensitive DFA accept states + # consuming an input symbol + # reporting a conflict + # reporting an ambiguity + # reporting a context sensitivity + # reporting insufficient predicates + + # cover these cases: + # dead end + # single alt + # single alt + preds + # conflict + # conflict + preds + # + def execATN(self, dfa:DFA, s0:DFAState, input:TokenStream, startIndex:int, outerContext:ParserRuleContext ): + if ParserATNSimulator.debug or ParserATNSimulator.debug_list_atn_decisions: + print("execATN decision " + str(dfa.decision) + + " exec LA(1)==" + self.getLookaheadName(input) + + " line " + str(input.LT(1).line) + ":" + str(input.LT(1).column)) + + previousD = s0 + + if ParserATNSimulator.debug: + print("s0 = " + str(s0)) + + t = input.LA(1) + + while True: # while more work + D = self.getExistingTargetState(previousD, t) + if D is None: + D = self.computeTargetState(dfa, previousD, t) + if D is self.ERROR: + # if any configs in previous dipped into outer context, that + # means that input up to t actually finished entry rule + # at least for SLL decision. Full LL doesn't dip into outer + # so don't need special case. + # We will get an error no matter what so delay until after + # decision; better error message. Also, no reachable target + # ATN states in SLL implies LL will also get nowhere. + # If conflict in states that dip out, choose min since we + # will get error no matter what. + e = self.noViableAlt(input, outerContext, previousD.configs, startIndex) + input.seek(startIndex) + alt = self.getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule(previousD.configs, outerContext) + if alt!=ATN.INVALID_ALT_NUMBER: + return alt + raise e + + if D.requiresFullContext and self.predictionMode != PredictionMode.SLL: + # IF PREDS, MIGHT RESOLVE TO SINGLE ALT => SLL (or syntax error) + conflictingAlts = D.configs.conflictingAlts + if D.predicates is not None: + if ParserATNSimulator.debug: + print("DFA state has preds in DFA sim LL failover") + conflictIndex = input.index + if conflictIndex != startIndex: + input.seek(startIndex) + + conflictingAlts = self.evalSemanticContext(D.predicates, outerContext, True) + if len(conflictingAlts)==1: + if ParserATNSimulator.debug: + print("Full LL avoided") + return min(conflictingAlts) + + if conflictIndex != startIndex: + # restore the index so reporting the fallback to full + # context occurs with the index at the correct spot + input.seek(conflictIndex) + + if ParserATNSimulator.dfa_debug: + print("ctx sensitive state " + str(outerContext) +" in " + str(D)) + fullCtx = True + s0_closure = self.computeStartState(dfa.atnStartState, outerContext, fullCtx) + self.reportAttemptingFullContext(dfa, conflictingAlts, D.configs, startIndex, input.index) + alt = self.execATNWithFullContext(dfa, D, s0_closure, input, startIndex, outerContext) + return alt + + if D.isAcceptState: + if D.predicates is None: + return D.prediction + + stopIndex = input.index + input.seek(startIndex) + alts = self.evalSemanticContext(D.predicates, outerContext, True) + if len(alts)==0: + raise self.noViableAlt(input, outerContext, D.configs, startIndex) + elif len(alts)==1: + return min(alts) + else: + # report ambiguity after predicate evaluation to make sure the correct + # set of ambig alts is reported. + self.reportAmbiguity(dfa, D, startIndex, stopIndex, False, alts, D.configs) + return min(alts) + + previousD = D + + if t != Token.EOF: + input.consume() + t = input.LA(1) + + # + # Get an existing target state for an edge in the DFA. If the target state + # for the edge has not yet been computed or is otherwise not available, + # this method returns {@code null}. + # + # @param previousD The current DFA state + # @param t The next input symbol + # @return The existing target DFA state for the given input symbol + # {@code t}, or {@code null} if the target state for this edge is not + # already cached + # + def getExistingTargetState(self, previousD:DFAState, t:int): + edges = previousD.edges + if edges is None or t + 1 < 0 or t + 1 >= len(edges): + return None + else: + return edges[t + 1] + + # + # Compute a target state for an edge in the DFA, and attempt to add the + # computed state and corresponding edge to the DFA. + # + # @param dfa The DFA + # @param previousD The current DFA state + # @param t The next input symbol + # + # @return The computed target DFA state for the given input symbol + # {@code t}. If {@code t} does not lead to a valid DFA state, this method + # returns {@link #ERROR}. + # + def computeTargetState(self, dfa:DFA, previousD:DFAState, t:int): + reach = self.computeReachSet(previousD.configs, t, False) + if reach is None: + self.addDFAEdge(dfa, previousD, t, self.ERROR) + return self.ERROR + + # create new target state; we'll add to DFA after it's complete + D = DFAState(configs=reach) + + predictedAlt = self.getUniqueAlt(reach) + + if ParserATNSimulator.debug: + altSubSets = PredictionMode.getConflictingAltSubsets(reach) + print("SLL altSubSets=" + str(altSubSets) + ", configs=" + str(reach) + + ", predict=" + str(predictedAlt) + ", allSubsetsConflict=" + + str(PredictionMode.allSubsetsConflict(altSubSets)) + ", conflictingAlts=" + + str(self.getConflictingAlts(reach))) + + if predictedAlt!=ATN.INVALID_ALT_NUMBER: + # NO CONFLICT, UNIQUELY PREDICTED ALT + D.isAcceptState = True + D.configs.uniqueAlt = predictedAlt + D.prediction = predictedAlt + elif PredictionMode.hasSLLConflictTerminatingPrediction(self.predictionMode, reach): + # MORE THAN ONE VIABLE ALTERNATIVE + D.configs.conflictingAlts = self.getConflictingAlts(reach) + D.requiresFullContext = True + # in SLL-only mode, we will stop at this state and return the minimum alt + D.isAcceptState = True + D.prediction = min(D.configs.conflictingAlts) + + if D.isAcceptState and D.configs.hasSemanticContext: + self.predicateDFAState(D, self.atn.getDecisionState(dfa.decision)) + if D.predicates is not None: + D.prediction = ATN.INVALID_ALT_NUMBER + + # all adds to dfa are done after we've created full D state + D = self.addDFAEdge(dfa, previousD, t, D) + return D + + def predicateDFAState(self, dfaState:DFAState, decisionState:DecisionState): + # We need to test all predicates, even in DFA states that + # uniquely predict alternative. + nalts = len(decisionState.transitions) + # Update DFA so reach becomes accept state with (predicate,alt) + # pairs if preds found for conflicting alts + altsToCollectPredsFrom = self.getConflictingAltsOrUniqueAlt(dfaState.configs) + altToPred = self.getPredsForAmbigAlts(altsToCollectPredsFrom, dfaState.configs, nalts) + if altToPred is not None: + dfaState.predicates = self.getPredicatePredictions(altsToCollectPredsFrom, altToPred) + dfaState.prediction = ATN.INVALID_ALT_NUMBER # make sure we use preds + else: + # There are preds in configs but they might go away + # when OR'd together like {p}? || NONE == NONE. If neither + # alt has preds, resolve to min alt + dfaState.prediction = min(altsToCollectPredsFrom) + + # comes back with reach.uniqueAlt set to a valid alt + def execATNWithFullContext(self, dfa:DFA, D:DFAState, # how far we got before failing over + s0:ATNConfigSet, + input:TokenStream, + startIndex:int, + outerContext:ParserRuleContext): + if ParserATNSimulator.debug or ParserATNSimulator.debug_list_atn_decisions: + print("execATNWithFullContext", str(s0)) + fullCtx = True + foundExactAmbig = False + reach = None + previous = s0 + input.seek(startIndex) + t = input.LA(1) + predictedAlt = -1 + while (True): # while more work + reach = self.computeReachSet(previous, t, fullCtx) + if reach is None: + # if any configs in previous dipped into outer context, that + # means that input up to t actually finished entry rule + # at least for LL decision. Full LL doesn't dip into outer + # so don't need special case. + # We will get an error no matter what so delay until after + # decision; better error message. Also, no reachable target + # ATN states in SLL implies LL will also get nowhere. + # If conflict in states that dip out, choose min since we + # will get error no matter what. + e = self.noViableAlt(input, outerContext, previous, startIndex) + input.seek(startIndex) + alt = self.getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule(previous, outerContext) + if alt!=ATN.INVALID_ALT_NUMBER: + return alt + else: + raise e + + altSubSets = PredictionMode.getConflictingAltSubsets(reach) + if ParserATNSimulator.debug: + print("LL altSubSets=" + str(altSubSets) + ", predict=" + + str(PredictionMode.getUniqueAlt(altSubSets)) + ", resolvesToJustOneViableAlt=" + + str(PredictionMode.resolvesToJustOneViableAlt(altSubSets))) + + reach.uniqueAlt = self.getUniqueAlt(reach) + # unique prediction? + if reach.uniqueAlt!=ATN.INVALID_ALT_NUMBER: + predictedAlt = reach.uniqueAlt + break + elif self.predictionMode is not PredictionMode.LL_EXACT_AMBIG_DETECTION: + predictedAlt = PredictionMode.resolvesToJustOneViableAlt(altSubSets) + if predictedAlt != ATN.INVALID_ALT_NUMBER: + break + else: + # In exact ambiguity mode, we never try to terminate early. + # Just keeps scarfing until we know what the conflict is + if PredictionMode.allSubsetsConflict(altSubSets) and PredictionMode.allSubsetsEqual(altSubSets): + foundExactAmbig = True + predictedAlt = PredictionMode.getSingleViableAlt(altSubSets) + break + # else there are multiple non-conflicting subsets or + # we're not sure what the ambiguity is yet. + # So, keep going. + + previous = reach + if t != Token.EOF: + input.consume() + t = input.LA(1) + + # If the configuration set uniquely predicts an alternative, + # without conflict, then we know that it's a full LL decision + # not SLL. + if reach.uniqueAlt != ATN.INVALID_ALT_NUMBER : + self.reportContextSensitivity(dfa, predictedAlt, reach, startIndex, input.index) + return predictedAlt + + # We do not check predicates here because we have checked them + # on-the-fly when doing full context prediction. + + # + # In non-exact ambiguity detection mode, we might actually be able to + # detect an exact ambiguity, but I'm not going to spend the cycles + # needed to check. We only emit ambiguity warnings in exact ambiguity + # mode. + # + # For example, we might know that we have conflicting configurations. + # But, that does not mean that there is no way forward without a + # conflict. It's possible to have nonconflicting alt subsets as in: + + # altSubSets=[{1, 2}, {1, 2}, {1}, {1, 2}] + + # from + # + # [(17,1,[5 $]), (13,1,[5 10 $]), (21,1,[5 10 $]), (11,1,[$]), + # (13,2,[5 10 $]), (21,2,[5 10 $]), (11,2,[$])] + # + # In this case, (17,1,[5 $]) indicates there is some next sequence that + # would resolve this without conflict to alternative 1. Any other viable + # next sequence, however, is associated with a conflict. We stop + # looking for input because no amount of further lookahead will alter + # the fact that we should predict alternative 1. We just can't say for + # sure that there is an ambiguity without looking further. + + self.reportAmbiguity(dfa, D, startIndex, input.index, foundExactAmbig, None, reach) + + return predictedAlt + + def computeReachSet(self, closure:ATNConfigSet, t:int, fullCtx:bool): + if ParserATNSimulator.debug: + print("in computeReachSet, starting closure: " + str(closure)) + + if self.mergeCache is None: + self.mergeCache = dict() + + intermediate = ATNConfigSet(fullCtx) + + # Configurations already in a rule stop state indicate reaching the end + # of the decision rule (local context) or end of the start rule (full + # context). Once reached, these configurations are never updated by a + # closure operation, so they are handled separately for the performance + # advantage of having a smaller intermediate set when calling closure. + # + # For full-context reach operations, separate handling is required to + # ensure that the alternative matching the longest overall sequence is + # chosen when multiple such configurations can match the input. + + skippedStopStates = None + + # First figure out where we can reach on input t + for c in closure: + if ParserATNSimulator.debug: + print("testing " + self.getTokenName(t) + " at " + str(c)) + + if isinstance(c.state, RuleStopState): + if fullCtx or t == Token.EOF: + if skippedStopStates is None: + skippedStopStates = list() + skippedStopStates.append(c) + continue + + for trans in c.state.transitions: + target = self.getReachableTarget(trans, t) + if target is not None: + intermediate.add(ATNConfig(state=target, config=c), self.mergeCache) + + # Now figure out where the reach operation can take us... + + reach = None + + # This block optimizes the reach operation for intermediate sets which + # trivially indicate a termination state for the overall + # adaptivePredict operation. + # + # The conditions assume that intermediate + # contains all configurations relevant to the reach set, but this + # condition is not true when one or more configurations have been + # withheld in skippedStopStates, or when the current symbol is EOF. + # + if skippedStopStates is None and t!=Token.EOF: + if len(intermediate)==1: + # Don't pursue the closure if there is just one state. + # It can only have one alternative; just add to result + # Also don't pursue the closure if there is unique alternative + # among the configurations. + reach = intermediate + elif self.getUniqueAlt(intermediate)!=ATN.INVALID_ALT_NUMBER: + # Also don't pursue the closure if there is unique alternative + # among the configurations. + reach = intermediate + + # If the reach set could not be trivially determined, perform a closure + # operation on the intermediate set to compute its initial value. + # + if reach is None: + reach = ATNConfigSet(fullCtx) + closureBusy = set() + treatEofAsEpsilon = t == Token.EOF + for c in intermediate: + self.closure(c, reach, closureBusy, False, fullCtx, treatEofAsEpsilon) + + if t == Token.EOF: + # After consuming EOF no additional input is possible, so we are + # only interested in configurations which reached the end of the + # decision rule (local context) or end of the start rule (full + # context). Update reach to contain only these configurations. This + # handles both explicit EOF transitions in the grammar and implicit + # EOF transitions following the end of the decision or start rule. + # + # When reach==intermediate, no closure operation was performed. In + # this case, removeAllConfigsNotInRuleStopState needs to check for + # reachable rule stop states as well as configurations already in + # a rule stop state. + # + # This is handled before the configurations in skippedStopStates, + # because any configurations potentially added from that list are + # already guaranteed to meet this condition whether or not it's + # required. + # + reach = self.removeAllConfigsNotInRuleStopState(reach, reach is intermediate) + + # If skippedStopStates is not null, then it contains at least one + # configuration. For full-context reach operations, these + # configurations reached the end of the start rule, in which case we + # only add them back to reach if no configuration during the current + # closure operation reached such a state. This ensures adaptivePredict + # chooses an alternative matching the longest overall sequence when + # multiple alternatives are viable. + # + if skippedStopStates is not None and ( (not fullCtx) or (not PredictionMode.hasConfigInRuleStopState(reach))): + for c in skippedStopStates: + reach.add(c, self.mergeCache) + if len(reach)==0: + return None + else: + return reach + + # + # Return a configuration set containing only the configurations from + # {@code configs} which are in a {@link RuleStopState}. If all + # configurations in {@code configs} are already in a rule stop state, this + # method simply returns {@code configs}. + # + #

          When {@code lookToEndOfRule} is true, this method uses + # {@link ATN#nextTokens} for each configuration in {@code configs} which is + # not already in a rule stop state to see if a rule stop state is reachable + # from the configuration via epsilon-only transitions.

          + # + # @param configs the configuration set to update + # @param lookToEndOfRule when true, this method checks for rule stop states + # reachable by epsilon-only transitions from each configuration in + # {@code configs}. + # + # @return {@code configs} if all configurations in {@code configs} are in a + # rule stop state, otherwise return a new configuration set containing only + # the configurations from {@code configs} which are in a rule stop state + # + def removeAllConfigsNotInRuleStopState(self, configs:ATNConfigSet, lookToEndOfRule:bool): + if PredictionMode.allConfigsInRuleStopStates(configs): + return configs + result = ATNConfigSet(configs.fullCtx) + for config in configs: + if isinstance(config.state, RuleStopState): + result.add(config, self.mergeCache) + continue + if lookToEndOfRule and config.state.epsilonOnlyTransitions: + nextTokens = self.atn.nextTokens(config.state) + if Token.EPSILON in nextTokens: + endOfRuleState = self.atn.ruleToStopState[config.state.ruleIndex] + result.add(ATNConfig(state=endOfRuleState, config=config), self.mergeCache) + return result + + def computeStartState(self, p:ATNState, ctx:RuleContext, fullCtx:bool): + # always at least the implicit call to start rule + initialContext = PredictionContextFromRuleContext(self.atn, ctx) + configs = ATNConfigSet(fullCtx) + + for i in range(0, len(p.transitions)): + target = p.transitions[i].target + c = ATNConfig(target, i+1, initialContext) + closureBusy = set() + self.closure(c, configs, closureBusy, True, fullCtx, False) + return configs + + # + # This method transforms the start state computed by + # {@link #computeStartState} to the special start state used by a + # precedence DFA for a particular precedence value. The transformation + # process applies the following changes to the start state's configuration + # set. + # + #
            + #
          1. Evaluate the precedence predicates for each configuration using + # {@link SemanticContext#evalPrecedence}.
          2. + #
          3. Remove all configurations which predict an alternative greater than + # 1, for which another configuration that predicts alternative 1 is in the + # same ATN state with the same prediction context. This transformation is + # valid for the following reasons: + #
              + #
            • The closure block cannot contain any epsilon transitions which bypass + # the body of the closure, so all states reachable via alternative 1 are + # part of the precedence alternatives of the transformed left-recursive + # rule.
            • + #
            • The "primary" portion of a left recursive rule cannot contain an + # epsilon transition, so the only way an alternative other than 1 can exist + # in a state that is also reachable via alternative 1 is by nesting calls + # to the left-recursive rule, with the outer calls not being at the + # preferred precedence level.
            • + #
            + #
          4. + #
          + # + #

          + # The prediction context must be considered by this filter to address + # situations like the following. + #

          + # + #
          +    # grammar TA;
          +    # prog: statement* EOF;
          +    # statement: letterA | statement letterA 'b' ;
          +    # letterA: 'a';
          +    # 
          + #
          + #

          + # If the above grammar, the ATN state immediately before the token + # reference {@code 'a'} in {@code letterA} is reachable from the left edge + # of both the primary and closure blocks of the left-recursive rule + # {@code statement}. The prediction context associated with each of these + # configurations distinguishes between them, and prevents the alternative + # which stepped out to {@code prog} (and then back in to {@code statement} + # from being eliminated by the filter. + #

          + # + # @param configs The configuration set computed by + # {@link #computeStartState} as the start state for the DFA. + # @return The transformed configuration set representing the start state + # for a precedence DFA at a particular precedence level (determined by + # calling {@link Parser#getPrecedence}). + # + def applyPrecedenceFilter(self, configs:ATNConfigSet): + statesFromAlt1 = dict() + configSet = ATNConfigSet(configs.fullCtx) + for config in configs: + # handle alt 1 first + if config.alt != 1: + continue + updatedContext = config.semanticContext.evalPrecedence(self.parser, self._outerContext) + if updatedContext is None: + # the configuration was eliminated + continue + + statesFromAlt1[config.state.stateNumber] = config.context + if updatedContext is not config.semanticContext: + configSet.add(ATNConfig(config=config, semantic=updatedContext), self.mergeCache) + else: + configSet.add(config, self.mergeCache) + + for config in configs: + if config.alt == 1: + # already handled + continue + + # In the future, this elimination step could be updated to also + # filter the prediction context for alternatives predicting alt>1 + # (basically a graph subtraction algorithm). + # + if not config.precedenceFilterSuppressed: + context = statesFromAlt1.get(config.state.stateNumber, None) + if context==config.context: + # eliminated + continue + + configSet.add(config, self.mergeCache) + + return configSet + + def getReachableTarget(self, trans:Transition, ttype:int): + if trans.matches(ttype, 0, self.atn.maxTokenType): + return trans.target + else: + return None + + def getPredsForAmbigAlts(self, ambigAlts:set, configs:ATNConfigSet, nalts:int): + # REACH=[1|1|[]|0:0, 1|2|[]|0:1] + # altToPred starts as an array of all null contexts. The entry at index i + # corresponds to alternative i. altToPred[i] may have one of three values: + # 1. null: no ATNConfig c is found such that c.alt==i + # 2. SemanticContext.NONE: At least one ATNConfig c exists such that + # c.alt==i and c.semanticContext==SemanticContext.NONE. In other words, + # alt i has at least one unpredicated config. + # 3. Non-NONE Semantic Context: There exists at least one, and for all + # ATNConfig c such that c.alt==i, c.semanticContext!=SemanticContext.NONE. + # + # From this, it is clear that NONE||anything==NONE. + # + altToPred = [None] * (nalts + 1) + for c in configs: + if c.alt in ambigAlts: + altToPred[c.alt] = orContext(altToPred[c.alt], c.semanticContext) + + nPredAlts = 0 + for i in range(1, nalts+1): + if altToPred[i] is None: + altToPred[i] = SemanticContext.NONE + elif altToPred[i] is not SemanticContext.NONE: + nPredAlts += 1 + + # nonambig alts are null in altToPred + if nPredAlts==0: + altToPred = None + if ParserATNSimulator.debug: + print("getPredsForAmbigAlts result " + str_list(altToPred)) + return altToPred + + def getPredicatePredictions(self, ambigAlts:set, altToPred:list): + pairs = [] + containsPredicate = False + for i in range(1, len(altToPred)): + pred = altToPred[i] + # unpredicated is indicated by SemanticContext.NONE + if ambigAlts is not None and i in ambigAlts: + pairs.append(PredPrediction(pred, i)) + if pred is not SemanticContext.NONE: + containsPredicate = True + + if not containsPredicate: + return None + + return pairs + + # + # This method is used to improve the localization of error messages by + # choosing an alternative rather than throwing a + # {@link NoViableAltException} in particular prediction scenarios where the + # {@link #ERROR} state was reached during ATN simulation. + # + #

          + # The default implementation of this method uses the following + # algorithm to identify an ATN configuration which successfully parsed the + # decision entry rule. Choosing such an alternative ensures that the + # {@link ParserRuleContext} returned by the calling rule will be complete + # and valid, and the syntax error will be reported later at a more + # localized location.

          + # + #
            + #
          • If a syntactically valid path or paths reach the end of the decision rule and + # they are semantically valid if predicated, return the min associated alt.
          • + #
          • Else, if a semantically invalid but syntactically valid path exist + # or paths exist, return the minimum associated alt. + #
          • + #
          • Otherwise, return {@link ATN#INVALID_ALT_NUMBER}.
          • + #
          + # + #

          + # In some scenarios, the algorithm described above could predict an + # alternative which will result in a {@link FailedPredicateException} in + # the parser. Specifically, this could occur if the only configuration + # capable of successfully parsing to the end of the decision rule is + # blocked by a semantic predicate. By choosing this alternative within + # {@link #adaptivePredict} instead of throwing a + # {@link NoViableAltException}, the resulting + # {@link FailedPredicateException} in the parser will identify the specific + # predicate which is preventing the parser from successfully parsing the + # decision rule, which helps developers identify and correct logic errors + # in semantic predicates. + #

          + # + # @param configs The ATN configurations which were valid immediately before + # the {@link #ERROR} state was reached + # @param outerContext The is the \gamma_0 initial parser context from the paper + # or the parser stack at the instant before prediction commences. + # + # @return The value to return from {@link #adaptivePredict}, or + # {@link ATN#INVALID_ALT_NUMBER} if a suitable alternative was not + # identified and {@link #adaptivePredict} should report an error instead. + # + def getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule(self, configs:ATNConfigSet, outerContext:ParserRuleContext): + semValidConfigs, semInvalidConfigs = self.splitAccordingToSemanticValidity(configs, outerContext) + alt = self.getAltThatFinishedDecisionEntryRule(semValidConfigs) + if alt!=ATN.INVALID_ALT_NUMBER: # semantically/syntactically viable path exists + return alt + # Is there a syntactically valid path with a failed pred? + if len(semInvalidConfigs)>0: + alt = self.getAltThatFinishedDecisionEntryRule(semInvalidConfigs) + if alt!=ATN.INVALID_ALT_NUMBER: # syntactically viable path exists + return alt + return ATN.INVALID_ALT_NUMBER + + def getAltThatFinishedDecisionEntryRule(self, configs:ATNConfigSet): + alts = set() + for c in configs: + if c.reachesIntoOuterContext>0 or (isinstance(c.state, RuleStopState) and c.context.hasEmptyPath() ): + alts.add(c.alt) + if len(alts)==0: + return ATN.INVALID_ALT_NUMBER + else: + return min(alts) + + # Walk the list of configurations and split them according to + # those that have preds evaluating to true/false. If no pred, assume + # true pred and include in succeeded set. Returns Pair of sets. + # + # Create a new set so as not to alter the incoming parameter. + # + # Assumption: the input stream has been restored to the starting point + # prediction, which is where predicates need to evaluate. + # + def splitAccordingToSemanticValidity(self, configs:ATNConfigSet, outerContext:ParserRuleContext): + succeeded = ATNConfigSet(configs.fullCtx) + failed = ATNConfigSet(configs.fullCtx) + for c in configs: + if c.semanticContext is not SemanticContext.NONE: + predicateEvaluationResult = c.semanticContext.eval(self.parser, outerContext) + if predicateEvaluationResult: + succeeded.add(c) + else: + failed.add(c) + else: + succeeded.add(c) + return (succeeded,failed) + + # Look through a list of predicate/alt pairs, returning alts for the + # pairs that win. A {@code NONE} predicate indicates an alt containing an + # unpredicated config which behaves as "always true." If !complete + # then we stop at the first predicate that evaluates to true. This + # includes pairs with null predicates. + # + def evalSemanticContext(self, predPredictions:list, outerContext:ParserRuleContext, complete:bool): + predictions = set() + for pair in predPredictions: + if pair.pred is SemanticContext.NONE: + predictions.add(pair.alt) + if not complete: + break + continue + predicateEvaluationResult = pair.pred.eval(self.parser, outerContext) + if ParserATNSimulator.debug or ParserATNSimulator.dfa_debug: + print("eval pred " + str(pair) + "=" + str(predicateEvaluationResult)) + + if predicateEvaluationResult: + if ParserATNSimulator.debug or ParserATNSimulator.dfa_debug: + print("PREDICT " + str(pair.alt)) + predictions.add(pair.alt) + if not complete: + break + return predictions + + + # TODO: If we are doing predicates, there is no point in pursuing + # closure operations if we reach a DFA state that uniquely predicts + # alternative. We will not be caching that DFA state and it is a + # waste to pursue the closure. Might have to advance when we do + # ambig detection thought :( + # + + def closure(self, config:ATNConfig, configs:ATNConfigSet, closureBusy:set, collectPredicates:bool, fullCtx:bool, treatEofAsEpsilon:bool): + initialDepth = 0 + self.closureCheckingStopState(config, configs, closureBusy, collectPredicates, + fullCtx, initialDepth, treatEofAsEpsilon) + + + def closureCheckingStopState(self, config:ATNConfig, configs:ATNConfigSet, closureBusy:set, collectPredicates:bool, fullCtx:bool, depth:int, treatEofAsEpsilon:bool): + if ParserATNSimulator.debug: + print("closure(" + str(config) + ")") + + if isinstance(config.state, RuleStopState): + # We hit rule end. If we have context info, use it + # run thru all possible stack tops in ctx + if not config.context.isEmpty(): + for i in range(0, len(config.context)): + state = config.context.getReturnState(i) + if state is PredictionContext.EMPTY_RETURN_STATE: + if fullCtx: + configs.add(ATNConfig(state=config.state, context=PredictionContext.EMPTY, config=config), self.mergeCache) + continue + else: + # we have no context info, just chase follow links (if greedy) + if ParserATNSimulator.debug: + print("FALLING off rule " + self.getRuleName(config.state.ruleIndex)) + self.closure_(config, configs, closureBusy, collectPredicates, + fullCtx, depth, treatEofAsEpsilon) + continue + returnState = self.atn.states[state] + newContext = config.context.getParent(i) # "pop" return state + c = ATNConfig(state=returnState, alt=config.alt, context=newContext, semantic=config.semanticContext) + # While we have context to pop back from, we may have + # gotten that context AFTER having falling off a rule. + # Make sure we track that we are now out of context. + c.reachesIntoOuterContext = config.reachesIntoOuterContext + self.closureCheckingStopState(c, configs, closureBusy, collectPredicates, fullCtx, depth - 1, treatEofAsEpsilon) + return + elif fullCtx: + # reached end of start rule + configs.add(config, self.mergeCache) + return + else: + # else if we have no context info, just chase follow links (if greedy) + if ParserATNSimulator.debug: + print("FALLING off rule " + self.getRuleName(config.state.ruleIndex)) + + self.closure_(config, configs, closureBusy, collectPredicates, fullCtx, depth, treatEofAsEpsilon) + + # Do the actual work of walking epsilon edges# + def closure_(self, config:ATNConfig, configs:ATNConfigSet, closureBusy:set, collectPredicates:bool, fullCtx:bool, depth:int, treatEofAsEpsilon:bool): + p = config.state + # optimization + if not p.epsilonOnlyTransitions: + configs.add(config, self.mergeCache) + # make sure to not return here, because EOF transitions can act as + # both epsilon transitions and non-epsilon transitions. + + first = True + for t in p.transitions: + if first: + first = False + if self.canDropLoopEntryEdgeInLeftRecursiveRule(config): + continue + + continueCollecting = collectPredicates and not isinstance(t, ActionTransition) + c = self.getEpsilonTarget(config, t, continueCollecting, depth == 0, fullCtx, treatEofAsEpsilon) + if c is not None: + newDepth = depth + if isinstance( config.state, RuleStopState): + # target fell off end of rule; mark resulting c as having dipped into outer context + # We can't get here if incoming config was rule stop and we had context + # track how far we dip into outer context. Might + # come in handy and we avoid evaluating context dependent + # preds if this is > 0. + if self._dfa is not None and self._dfa.precedenceDfa: + if t.outermostPrecedenceReturn == self._dfa.atnStartState.ruleIndex: + c.precedenceFilterSuppressed = True + c.reachesIntoOuterContext += 1 + if c in closureBusy: + # avoid infinite recursion for right-recursive rules + continue + closureBusy.add(c) + configs.dipsIntoOuterContext = True # TODO: can remove? only care when we add to set per middle of this method + newDepth -= 1 + if ParserATNSimulator.debug: + print("dips into outer ctx: " + str(c)) + else: + if not t.isEpsilon: + if c in closureBusy: + # avoid infinite recursion for EOF* and EOF+ + continue + closureBusy.add(c) + if isinstance(t, RuleTransition): + # latch when newDepth goes negative - once we step out of the entry context we can't return + if newDepth >= 0: + newDepth += 1 + + self.closureCheckingStopState(c, configs, closureBusy, continueCollecting, fullCtx, newDepth, treatEofAsEpsilon) + + + + # Implements first-edge (loop entry) elimination as an optimization + # during closure operations. See antlr/antlr4#1398. + # + # The optimization is to avoid adding the loop entry config when + # the exit path can only lead back to the same + # StarLoopEntryState after popping context at the rule end state + # (traversing only epsilon edges, so we're still in closure, in + # this same rule). + # + # We need to detect any state that can reach loop entry on + # epsilon w/o exiting rule. We don't have to look at FOLLOW + # links, just ensure that all stack tops for config refer to key + # states in LR rule. + # + # To verify we are in the right situation we must first check + # closure is at a StarLoopEntryState generated during LR removal. + # Then we check that each stack top of context is a return state + # from one of these cases: + # + # 1. 'not' expr, '(' type ')' expr. The return state points at loop entry state + # 2. expr op expr. The return state is the block end of internal block of (...)* + # 3. 'between' expr 'and' expr. The return state of 2nd expr reference. + # That state points at block end of internal block of (...)*. + # 4. expr '?' expr ':' expr. The return state points at block end, + # which points at loop entry state. + # + # If any is true for each stack top, then closure does not add a + # config to the current config set for edge[0], the loop entry branch. + # + # Conditions fail if any context for the current config is: + # + # a. empty (we'd fall out of expr to do a global FOLLOW which could + # even be to some weird spot in expr) or, + # b. lies outside of expr or, + # c. lies within expr but at a state not the BlockEndState + # generated during LR removal + # + # Do we need to evaluate predicates ever in closure for this case? + # + # No. Predicates, including precedence predicates, are only + # evaluated when computing a DFA start state. I.e., only before + # the lookahead (but not parser) consumes a token. + # + # There are no epsilon edges allowed in LR rule alt blocks or in + # the "primary" part (ID here). If closure is in + # StarLoopEntryState any lookahead operation will have consumed a + # token as there are no epsilon-paths that lead to + # StarLoopEntryState. We do not have to evaluate predicates + # therefore if we are in the generated StarLoopEntryState of a LR + # rule. Note that when making a prediction starting at that + # decision point, decision d=2, compute-start-state performs + # closure starting at edges[0], edges[1] emanating from + # StarLoopEntryState. That means it is not performing closure on + # StarLoopEntryState during compute-start-state. + # + # How do we know this always gives same prediction answer? + # + # Without predicates, loop entry and exit paths are ambiguous + # upon remaining input +b (in, say, a+b). Either paths lead to + # valid parses. Closure can lead to consuming + immediately or by + # falling out of this call to expr back into expr and loop back + # again to StarLoopEntryState to match +b. In this special case, + # we choose the more efficient path, which is to take the bypass + # path. + # + # The lookahead language has not changed because closure chooses + # one path over the other. Both paths lead to consuming the same + # remaining input during a lookahead operation. If the next token + # is an operator, lookahead will enter the choice block with + # operators. If it is not, lookahead will exit expr. Same as if + # closure had chosen to enter the choice block immediately. + # + # Closure is examining one config (some loopentrystate, some alt, + # context) which means it is considering exactly one alt. Closure + # always copies the same alt to any derived configs. + # + # How do we know this optimization doesn't mess up precedence in + # our parse trees? + # + # Looking through expr from left edge of stat only has to confirm + # that an input, say, a+b+c; begins with any valid interpretation + # of an expression. The precedence actually doesn't matter when + # making a decision in stat seeing through expr. It is only when + # parsing rule expr that we must use the precedence to get the + # right interpretation and, hence, parse tree. + # + # @since 4.6 + # + def canDropLoopEntryEdgeInLeftRecursiveRule(self, config): + # return False + p = config.state + # First check to see if we are in StarLoopEntryState generated during + # left-recursion elimination. For efficiency, also check if + # the context has an empty stack case. If so, it would mean + # global FOLLOW so we can't perform optimization + # Are we the special loop entry/exit state? or SLL wildcard + if p.stateType != ATNState.STAR_LOOP_ENTRY \ + or not p.isPrecedenceDecision \ + or config.context.isEmpty() \ + or config.context.hasEmptyPath(): + return False + + # Require all return states to return back to the same rule + # that p is in. + numCtxs = len(config.context) + for i in range(0, numCtxs): # for each stack context + returnState = self.atn.states[config.context.getReturnState(i)] + if returnState.ruleIndex != p.ruleIndex: + return False + + decisionStartState = p.transitions[0].target + blockEndStateNum = decisionStartState.endState.stateNumber + blockEndState = self.atn.states[blockEndStateNum] + + # Verify that the top of each stack context leads to loop entry/exit + # state through epsilon edges and w/o leaving rule. + for i in range(0, numCtxs): # for each stack context + returnStateNumber = config.context.getReturnState(i) + returnState = self.atn.states[returnStateNumber] + # all states must have single outgoing epsilon edge + if len(returnState.transitions) != 1 or not returnState.transitions[0].isEpsilon: + return False + + # Look for prefix op case like 'not expr', (' type ')' expr + returnStateTarget = returnState.transitions[0].target + if returnState.stateType == ATNState.BLOCK_END and returnStateTarget is p: + continue + + # Look for 'expr op expr' or case where expr's return state is block end + # of (...)* internal block; the block end points to loop back + # which points to p but we don't need to check that + if returnState is blockEndState: + continue + + # Look for ternary expr ? expr : expr. The return state points at block end, + # which points at loop entry state + if returnStateTarget is blockEndState: + continue + + # Look for complex prefix 'between expr and expr' case where 2nd expr's + # return state points at block end state of (...)* internal block + if returnStateTarget.stateType == ATNState.BLOCK_END \ + and len(returnStateTarget.transitions) == 1 \ + and returnStateTarget.transitions[0].isEpsilon \ + and returnStateTarget.transitions[0].target is p: + continue + + # anything else ain't conforming + return False + + return True + + + def getRuleName(self, index:int): + if self.parser is not None and index>=0: + return self.parser.ruleNames[index] + else: + return "" + + epsilonTargetMethods = dict() + epsilonTargetMethods[Transition.RULE] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + sim.ruleTransition(config, t) + epsilonTargetMethods[Transition.PRECEDENCE] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + sim.precedenceTransition(config, t, collectPredicates, inContext, fullCtx) + epsilonTargetMethods[Transition.PREDICATE] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + sim.predTransition(config, t, collectPredicates, inContext, fullCtx) + epsilonTargetMethods[Transition.ACTION] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + sim.actionTransition(config, t) + epsilonTargetMethods[Transition.EPSILON] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + ATNConfig(state=t.target, config=config) + epsilonTargetMethods[Transition.ATOM] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + ATNConfig(state=t.target, config=config) if treatEofAsEpsilon and t.matches(Token.EOF, 0, 1) else None + epsilonTargetMethods[Transition.RANGE] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + ATNConfig(state=t.target, config=config) if treatEofAsEpsilon and t.matches(Token.EOF, 0, 1) else None + epsilonTargetMethods[Transition.SET] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \ + ATNConfig(state=t.target, config=config) if treatEofAsEpsilon and t.matches(Token.EOF, 0, 1) else None + + def getEpsilonTarget(self, config:ATNConfig, t:Transition, collectPredicates:bool, inContext:bool, fullCtx:bool, treatEofAsEpsilon:bool): + m = self.epsilonTargetMethods.get(t.serializationType, None) + if m is None: + return None + else: + return m(self, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon) + + def actionTransition(self, config:ATNConfig, t:ActionTransition): + if ParserATNSimulator.debug: + print("ACTION edge " + str(t.ruleIndex) + ":" + str(t.actionIndex)) + return ATNConfig(state=t.target, config=config) + + def precedenceTransition(self, config:ATNConfig, pt:PrecedencePredicateTransition, collectPredicates:bool, inContext:bool, fullCtx:bool): + if ParserATNSimulator.debug: + print("PRED (collectPredicates=" + str(collectPredicates) + ") " + + str(pt.precedence) + ">=_p, ctx dependent=true") + if self.parser is not None: + print("context surrounding pred is " + str(self.parser.getRuleInvocationStack())) + + c = None + if collectPredicates and inContext: + if fullCtx: + # In full context mode, we can evaluate predicates on-the-fly + # during closure, which dramatically reduces the size of + # the config sets. It also obviates the need to test predicates + # later during conflict resolution. + currentPosition = self._input.index + self._input.seek(self._startIndex) + predSucceeds = pt.getPredicate().eval(self.parser, self._outerContext) + self._input.seek(currentPosition) + if predSucceeds: + c = ATNConfig(state=pt.target, config=config) # no pred context + else: + newSemCtx = andContext(config.semanticContext, pt.getPredicate()) + c = ATNConfig(state=pt.target, semantic=newSemCtx, config=config) + else: + c = ATNConfig(state=pt.target, config=config) + + if ParserATNSimulator.debug: + print("config from pred transition=" + str(c)) + return c + + def predTransition(self, config:ATNConfig, pt:PredicateTransition, collectPredicates:bool, inContext:bool, fullCtx:bool): + if ParserATNSimulator.debug: + print("PRED (collectPredicates=" + str(collectPredicates) + ") " + str(pt.ruleIndex) + + ":" + str(pt.predIndex) + ", ctx dependent=" + str(pt.isCtxDependent)) + if self.parser is not None: + print("context surrounding pred is " + str(self.parser.getRuleInvocationStack())) + + c = None + if collectPredicates and (not pt.isCtxDependent or (pt.isCtxDependent and inContext)): + if fullCtx: + # In full context mode, we can evaluate predicates on-the-fly + # during closure, which dramatically reduces the size of + # the config sets. It also obviates the need to test predicates + # later during conflict resolution. + currentPosition = self._input.index + self._input.seek(self._startIndex) + predSucceeds = pt.getPredicate().eval(self.parser, self._outerContext) + self._input.seek(currentPosition) + if predSucceeds: + c = ATNConfig(state=pt.target, config=config) # no pred context + else: + newSemCtx = andContext(config.semanticContext, pt.getPredicate()) + c = ATNConfig(state=pt.target, semantic=newSemCtx, config=config) + else: + c = ATNConfig(state=pt.target, config=config) + + if ParserATNSimulator.debug: + print("config from pred transition=" + str(c)) + return c + + def ruleTransition(self, config:ATNConfig, t:RuleTransition): + if ParserATNSimulator.debug: + print("CALL rule " + self.getRuleName(t.target.ruleIndex) + ", ctx=" + str(config.context)) + returnState = t.followState + newContext = SingletonPredictionContext.create(config.context, returnState.stateNumber) + return ATNConfig(state=t.target, context=newContext, config=config ) + + def getConflictingAlts(self, configs:ATNConfigSet): + altsets = PredictionMode.getConflictingAltSubsets(configs) + return PredictionMode.getAlts(altsets) + + # Sam pointed out a problem with the previous definition, v3, of + # ambiguous states. If we have another state associated with conflicting + # alternatives, we should keep going. For example, the following grammar + # + # s : (ID | ID ID?) ';' ; + # + # When the ATN simulation reaches the state before ';', it has a DFA + # state that looks like: [12|1|[], 6|2|[], 12|2|[]]. Naturally + # 12|1|[] and 12|2|[] conflict, but we cannot stop processing this node + # because alternative to has another way to continue, via [6|2|[]]. + # The key is that we have a single state that has config's only associated + # with a single alternative, 2, and crucially the state transitions + # among the configurations are all non-epsilon transitions. That means + # we don't consider any conflicts that include alternative 2. So, we + # ignore the conflict between alts 1 and 2. We ignore a set of + # conflicting alts when there is an intersection with an alternative + # associated with a single alt state in the state→config-list map. + # + # It's also the case that we might have two conflicting configurations but + # also a 3rd nonconflicting configuration for a different alternative: + # [1|1|[], 1|2|[], 8|3|[]]. This can come about from grammar: + # + # a : A | A | A B ; + # + # After matching input A, we reach the stop state for rule A, state 1. + # State 8 is the state right before B. Clearly alternatives 1 and 2 + # conflict and no amount of further lookahead will separate the two. + # However, alternative 3 will be able to continue and so we do not + # stop working on this state. In the previous example, we're concerned + # with states associated with the conflicting alternatives. Here alt + # 3 is not associated with the conflicting configs, but since we can continue + # looking for input reasonably, I don't declare the state done. We + # ignore a set of conflicting alts when we have an alternative + # that we still need to pursue. + # + + def getConflictingAltsOrUniqueAlt(self, configs:ATNConfigSet): + conflictingAlts = None + if configs.uniqueAlt!= ATN.INVALID_ALT_NUMBER: + conflictingAlts = set() + conflictingAlts.add(configs.uniqueAlt) + else: + conflictingAlts = configs.conflictingAlts + return conflictingAlts + + def getTokenName(self, t:int): + if t==Token.EOF: + return "EOF" + if self.parser is not None and \ + self.parser.literalNames is not None and \ + t < len(self.parser.literalNames): + return self.parser.literalNames[t] + "<" + str(t) + ">" + else: + return str(t) + + def getLookaheadName(self, input:TokenStream): + return self.getTokenName(input.LA(1)) + + # Used for debugging in adaptivePredict around execATN but I cut + # it out for clarity now that alg. works well. We can leave this + # "dead" code for a bit. + # + def dumpDeadEndConfigs(self, nvae:NoViableAltException): + print("dead end configs: ") + for c in nvae.getDeadEndConfigs(): + trans = "no edges" + if len(c.state.transitions)>0: + t = c.state.transitions[0] + if isinstance(t, AtomTransition): + trans = "Atom "+ self.getTokenName(t.label) + elif isinstance(t, SetTransition): + neg = isinstance(t, NotSetTransition) + trans = ("~" if neg else "")+"Set "+ str(t.set) + print(c.toString(self.parser, True) + ":" + trans, file=sys.stderr) + + def noViableAlt(self, input:TokenStream, outerContext:ParserRuleContext, configs:ATNConfigSet, startIndex:int): + return NoViableAltException(self.parser, input, input.get(startIndex), input.LT(1), configs, outerContext) + + def getUniqueAlt(self, configs:ATNConfigSet): + alt = ATN.INVALID_ALT_NUMBER + for c in configs: + if alt == ATN.INVALID_ALT_NUMBER: + alt = c.alt # found first alt + elif c.alt!=alt: + return ATN.INVALID_ALT_NUMBER + return alt + + # + # Add an edge to the DFA, if possible. This method calls + # {@link #addDFAState} to ensure the {@code to} state is present in the + # DFA. If {@code from} is {@code null}, or if {@code t} is outside the + # range of edges that can be represented in the DFA tables, this method + # returns without adding the edge to the DFA. + # + #

          If {@code to} is {@code null}, this method returns {@code null}. + # Otherwise, this method returns the {@link DFAState} returned by calling + # {@link #addDFAState} for the {@code to} state.

          + # + # @param dfa The DFA + # @param from The source state for the edge + # @param t The input symbol + # @param to The target state for the edge + # + # @return If {@code to} is {@code null}, this method returns {@code null}; + # otherwise this method returns the result of calling {@link #addDFAState} + # on {@code to} + # + def addDFAEdge(self, dfa:DFA, from_:DFAState, t:int, to:DFAState): + if ParserATNSimulator.debug: + print("EDGE " + str(from_) + " -> " + str(to) + " upon " + self.getTokenName(t)) + + if to is None: + return None + + to = self.addDFAState(dfa, to) # used existing if possible not incoming + if from_ is None or t < -1 or t > self.atn.maxTokenType: + return to + + if from_.edges is None: + from_.edges = [None] * (self.atn.maxTokenType + 2) + from_.edges[t+1] = to # connect + + if ParserATNSimulator.debug: + names = None if self.parser is None else self.parser.literalNames + print("DFA=\n" + dfa.toString(names)) + + return to + + # + # Add state {@code D} to the DFA if it is not already present, and return + # the actual instance stored in the DFA. If a state equivalent to {@code D} + # is already in the DFA, the existing state is returned. Otherwise this + # method returns {@code D} after adding it to the DFA. + # + #

          If {@code D} is {@link #ERROR}, this method returns {@link #ERROR} and + # does not change the DFA.

          + # + # @param dfa The dfa + # @param D The DFA state to add + # @return The state stored in the DFA. This will be either the existing + # state if {@code D} is already in the DFA, or {@code D} itself if the + # state was not already present. + # + def addDFAState(self, dfa:DFA, D:DFAState): + if D is self.ERROR: + return D + + + existing = dfa.states.get(D, None) + if existing is not None: + return existing + + D.stateNumber = len(dfa.states) + if not D.configs.readonly: + D.configs.optimizeConfigs(self) + D.configs.setReadonly(True) + dfa.states[D] = D + if ParserATNSimulator.debug: + print("adding new DFA state: " + str(D)) + return D + + def reportAttemptingFullContext(self, dfa:DFA, conflictingAlts:set, configs:ATNConfigSet, startIndex:int, stopIndex:int): + if ParserATNSimulator.debug or ParserATNSimulator.retry_debug: + interval = (startIndex, stopIndex + 1) + print("reportAttemptingFullContext decision=" + str(dfa.decision) + ":" + str(configs) + + ", input=" + self.parser.getTokenStream().getText(interval)) + if self.parser is not None: + self.parser.getErrorListenerDispatch().reportAttemptingFullContext(self.parser, dfa, startIndex, stopIndex, conflictingAlts, configs) + + def reportContextSensitivity(self, dfa:DFA, prediction:int, configs:ATNConfigSet, startIndex:int, stopIndex:int): + if ParserATNSimulator.debug or ParserATNSimulator.retry_debug: + interval = (startIndex, stopIndex + 1) + print("reportContextSensitivity decision=" + str(dfa.decision) + ":" + str(configs) + + ", input=" + self.parser.getTokenStream().getText(interval)) + if self.parser is not None: + self.parser.getErrorListenerDispatch().reportContextSensitivity(self.parser, dfa, startIndex, stopIndex, prediction, configs) + + # If context sensitive parsing, we know it's ambiguity not conflict# + def reportAmbiguity(self, dfa:DFA, D:DFAState, startIndex:int, stopIndex:int, + exact:bool, ambigAlts:set, configs:ATNConfigSet ): + if ParserATNSimulator.debug or ParserATNSimulator.retry_debug: +# ParserATNPathFinder finder = new ParserATNPathFinder(parser, atn); +# int i = 1; +# for (Transition t : dfa.atnStartState.transitions) { +# print("ALT "+i+"="); +# print(startIndex+".."+stopIndex+", len(input)="+parser.getInputStream().size()); +# TraceTree path = finder.trace(t.target, parser.getContext(), (TokenStream)parser.getInputStream(), +# startIndex, stopIndex); +# if ( path!=null ) { +# print("path = "+path.toStringTree()); +# for (TraceTree leaf : path.leaves) { +# List states = path.getPathToNode(leaf); +# print("states="+states); +# } +# } +# i++; +# } + interval = (startIndex, stopIndex + 1) + print("reportAmbiguity " + str(ambigAlts) + ":" + str(configs) + + ", input=" + self.parser.getTokenStream().getText(interval)) + if self.parser is not None: + self.parser.getErrorListenerDispatch().reportAmbiguity(self.parser, dfa, startIndex, stopIndex, exact, ambigAlts, configs) + diff --git a/src/antlr4/atn/PredictionMode.py b/src/antlr4/atn/PredictionMode.py new file mode 100644 index 00000000..8e5c73bb --- /dev/null +++ b/src/antlr4/atn/PredictionMode.py @@ -0,0 +1,499 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# +# +# This enumeration defines the prediction modes available in ANTLR 4 along with +# utility methods for analyzing configuration sets for conflicts and/or +# ambiguities. + + +from enum import Enum +from antlr4.atn.ATN import ATN +from antlr4.atn.ATNConfig import ATNConfig +from antlr4.atn.ATNConfigSet import ATNConfigSet +from antlr4.atn.ATNState import RuleStopState +from antlr4.atn.SemanticContext import SemanticContext + +PredictionMode = None + +class PredictionMode(Enum): + # + # The SLL(*) prediction mode. This prediction mode ignores the current + # parser context when making predictions. This is the fastest prediction + # mode, and provides correct results for many grammars. This prediction + # mode is more powerful than the prediction mode provided by ANTLR 3, but + # may result in syntax errors for grammar and input combinations which are + # not SLL. + # + #

          + # When using this prediction mode, the parser will either return a correct + # parse tree (i.e. the same parse tree that would be returned with the + # {@link #LL} prediction mode), or it will report a syntax error. If a + # syntax error is encountered when using the {@link #SLL} prediction mode, + # it may be due to either an actual syntax error in the input or indicate + # that the particular combination of grammar and input requires the more + # powerful {@link #LL} prediction abilities to complete successfully.

          + # + #

          + # This prediction mode does not provide any guarantees for prediction + # behavior for syntactically-incorrect inputs.

          + # + SLL = 0 + # + # The LL(*) prediction mode. This prediction mode allows the current parser + # context to be used for resolving SLL conflicts that occur during + # prediction. This is the fastest prediction mode that guarantees correct + # parse results for all combinations of grammars with syntactically correct + # inputs. + # + #

          + # When using this prediction mode, the parser will make correct decisions + # for all syntactically-correct grammar and input combinations. However, in + # cases where the grammar is truly ambiguous this prediction mode might not + # report a precise answer for exactly which alternatives are + # ambiguous.

          + # + #

          + # This prediction mode does not provide any guarantees for prediction + # behavior for syntactically-incorrect inputs.

          + # + LL = 1 + # + # The LL(*) prediction mode with exact ambiguity detection. In addition to + # the correctness guarantees provided by the {@link #LL} prediction mode, + # this prediction mode instructs the prediction algorithm to determine the + # complete and exact set of ambiguous alternatives for every ambiguous + # decision encountered while parsing. + # + #

          + # This prediction mode may be used for diagnosing ambiguities during + # grammar development. Due to the performance overhead of calculating sets + # of ambiguous alternatives, this prediction mode should be avoided when + # the exact results are not necessary.

          + # + #

          + # This prediction mode does not provide any guarantees for prediction + # behavior for syntactically-incorrect inputs.

          + # + LL_EXACT_AMBIG_DETECTION = 2 + + + # + # Computes the SLL prediction termination condition. + # + #

          + # This method computes the SLL prediction termination condition for both of + # the following cases.

          + # + #
            + #
          • The usual SLL+LL fallback upon SLL conflict
          • + #
          • Pure SLL without LL fallback
          • + #
          + # + #

          COMBINED SLL+LL PARSING

          + # + #

          When LL-fallback is enabled upon SLL conflict, correct predictions are + # ensured regardless of how the termination condition is computed by this + # method. Due to the substantially higher cost of LL prediction, the + # prediction should only fall back to LL when the additional lookahead + # cannot lead to a unique SLL prediction.

          + # + #

          Assuming combined SLL+LL parsing, an SLL configuration set with only + # conflicting subsets should fall back to full LL, even if the + # configuration sets don't resolve to the same alternative (e.g. + # {@code {1,2}} and {@code {3,4}}. If there is at least one non-conflicting + # configuration, SLL could continue with the hopes that more lookahead will + # resolve via one of those non-conflicting configurations.

          + # + #

          Here's the prediction termination rule them: SLL (for SLL+LL parsing) + # stops when it sees only conflicting configuration subsets. In contrast, + # full LL keeps going when there is uncertainty.

          + # + #

          HEURISTIC

          + # + #

          As a heuristic, we stop prediction when we see any conflicting subset + # unless we see a state that only has one alternative associated with it. + # The single-alt-state thing lets prediction continue upon rules like + # (otherwise, it would admit defeat too soon):

          + # + #

          {@code [12|1|[], 6|2|[], 12|2|[]]. s : (ID | ID ID?) ';' ;}

          + # + #

          When the ATN simulation reaches the state before {@code ';'}, it has a + # DFA state that looks like: {@code [12|1|[], 6|2|[], 12|2|[]]}. Naturally + # {@code 12|1|[]} and {@code 12|2|[]} conflict, but we cannot stop + # processing this node because alternative to has another way to continue, + # via {@code [6|2|[]]}.

          + # + #

          It also let's us continue for this rule:

          + # + #

          {@code [1|1|[], 1|2|[], 8|3|[]] a : A | A | A B ;}

          + # + #

          After matching input A, we reach the stop state for rule A, state 1. + # State 8 is the state right before B. Clearly alternatives 1 and 2 + # conflict and no amount of further lookahead will separate the two. + # However, alternative 3 will be able to continue and so we do not stop + # working on this state. In the previous example, we're concerned with + # states associated with the conflicting alternatives. Here alt 3 is not + # associated with the conflicting configs, but since we can continue + # looking for input reasonably, don't declare the state done.

          + # + #

          PURE SLL PARSING

          + # + #

          To handle pure SLL parsing, all we have to do is make sure that we + # combine stack contexts for configurations that differ only by semantic + # predicate. From there, we can do the usual SLL termination heuristic.

          + # + #

          PREDICATES IN SLL+LL PARSING

          + # + #

          SLL decisions don't evaluate predicates until after they reach DFA stop + # states because they need to create the DFA cache that works in all + # semantic situations. In contrast, full LL evaluates predicates collected + # during start state computation so it can ignore predicates thereafter. + # This means that SLL termination detection can totally ignore semantic + # predicates.

          + # + #

          Implementation-wise, {@link ATNConfigSet} combines stack contexts but not + # semantic predicate contexts so we might see two configurations like the + # following.

          + # + #

          {@code (s, 1, x, {}), (s, 1, x', {p})}

          + # + #

          Before testing these configurations against others, we have to merge + # {@code x} and {@code x'} (without modifying the existing configurations). + # For example, we test {@code (x+x')==x''} when looking for conflicts in + # the following configurations.

          + # + #

          {@code (s, 1, x, {}), (s, 1, x', {p}), (s, 2, x'', {})}

          + # + #

          If the configuration set has predicates (as indicated by + # {@link ATNConfigSet#hasSemanticContext}), this algorithm makes a copy of + # the configurations to strip out all of the predicates so that a standard + # {@link ATNConfigSet} will merge everything ignoring predicates.

          + # + @classmethod + def hasSLLConflictTerminatingPrediction(cls, mode:PredictionMode, configs:ATNConfigSet): + # Configs in rule stop states indicate reaching the end of the decision + # rule (local context) or end of start rule (full context). If all + # configs meet this condition, then none of the configurations is able + # to match additional input so we terminate prediction. + # + if cls.allConfigsInRuleStopStates(configs): + return True + + # pure SLL mode parsing + if mode == PredictionMode.SLL: + # Don't bother with combining configs from different semantic + # contexts if we can fail over to full LL; costs more time + # since we'll often fail over anyway. + if configs.hasSemanticContext: + # dup configs, tossing out semantic predicates + dup = ATNConfigSet() + for c in configs: + c = ATNConfig(config=c, semantic=SemanticContext.NONE) + dup.add(c) + configs = dup + # now we have combined contexts for configs with dissimilar preds + + # pure SLL or combined SLL+LL mode parsing + altsets = cls.getConflictingAltSubsets(configs) + return cls.hasConflictingAltSet(altsets) and not cls.hasStateAssociatedWithOneAlt(configs) + + # Checks if any configuration in {@code configs} is in a + # {@link RuleStopState}. Configurations meeting this condition have reached + # the end of the decision rule (local context) or end of start rule (full + # context). + # + # @param configs the configuration set to test + # @return {@code true} if any configuration in {@code configs} is in a + # {@link RuleStopState}, otherwise {@code false} + @classmethod + def hasConfigInRuleStopState(cls, configs:ATNConfigSet): + return any(isinstance(cfg.state, RuleStopState) for cfg in configs) + + # Checks if all configurations in {@code configs} are in a + # {@link RuleStopState}. Configurations meeting this condition have reached + # the end of the decision rule (local context) or end of start rule (full + # context). + # + # @param configs the configuration set to test + # @return {@code true} if all configurations in {@code configs} are in a + # {@link RuleStopState}, otherwise {@code false} + @classmethod + def allConfigsInRuleStopStates(cls, configs:ATNConfigSet): + return all(isinstance(cfg.state, RuleStopState) for cfg in configs) + + # + # Full LL prediction termination. + # + #

          Can we stop looking ahead during ATN simulation or is there some + # uncertainty as to which alternative we will ultimately pick, after + # consuming more input? Even if there are partial conflicts, we might know + # that everything is going to resolve to the same minimum alternative. That + # means we can stop since no more lookahead will change that fact. On the + # other hand, there might be multiple conflicts that resolve to different + # minimums. That means we need more look ahead to decide which of those + # alternatives we should predict.

          + # + #

          The basic idea is to split the set of configurations {@code C}, into + # conflicting subsets {@code (s, _, ctx, _)} and singleton subsets with + # non-conflicting configurations. Two configurations conflict if they have + # identical {@link ATNConfig#state} and {@link ATNConfig#context} values + # but different {@link ATNConfig#alt} value, e.g. {@code (s, i, ctx, _)} + # and {@code (s, j, ctx, _)} for {@code i!=j}.

          + # + #

          Reduce these configuration subsets to the set of possible alternatives. + # You can compute the alternative subsets in one pass as follows:

          + # + #

          {@code A_s,ctx = {i | (s, i, ctx, _)}} for each configuration in + # {@code C} holding {@code s} and {@code ctx} fixed.

          + # + #

          Or in pseudo-code, for each configuration {@code c} in {@code C}:

          + # + #
          +    # map[c] U= c.{@link ATNConfig#alt alt} # map hash/equals uses s and x, not
          +    # alt and not pred
          +    # 
          + # + #

          The values in {@code map} are the set of {@code A_s,ctx} sets.

          + # + #

          If {@code |A_s,ctx|=1} then there is no conflict associated with + # {@code s} and {@code ctx}.

          + # + #

          Reduce the subsets to singletons by choosing a minimum of each subset. If + # the union of these alternative subsets is a singleton, then no amount of + # more lookahead will help us. We will always pick that alternative. If, + # however, there is more than one alternative, then we are uncertain which + # alternative to predict and must continue looking for resolution. We may + # or may not discover an ambiguity in the future, even if there are no + # conflicting subsets this round.

          + # + #

          The biggest sin is to terminate early because it means we've made a + # decision but were uncertain as to the eventual outcome. We haven't used + # enough lookahead. On the other hand, announcing a conflict too late is no + # big deal; you will still have the conflict. It's just inefficient. It + # might even look until the end of file.

          + # + #

          No special consideration for semantic predicates is required because + # predicates are evaluated on-the-fly for full LL prediction, ensuring that + # no configuration contains a semantic context during the termination + # check.

          + # + #

          CONFLICTING CONFIGS

          + # + #

          Two configurations {@code (s, i, x)} and {@code (s, j, x')}, conflict + # when {@code i!=j} but {@code x=x'}. Because we merge all + # {@code (s, i, _)} configurations together, that means that there are at + # most {@code n} configurations associated with state {@code s} for + # {@code n} possible alternatives in the decision. The merged stacks + # complicate the comparison of configuration contexts {@code x} and + # {@code x'}. Sam checks to see if one is a subset of the other by calling + # merge and checking to see if the merged result is either {@code x} or + # {@code x'}. If the {@code x} associated with lowest alternative {@code i} + # is the superset, then {@code i} is the only possible prediction since the + # others resolve to {@code min(i)} as well. However, if {@code x} is + # associated with {@code j>i} then at least one stack configuration for + # {@code j} is not in conflict with alternative {@code i}. The algorithm + # should keep going, looking for more lookahead due to the uncertainty.

          + # + #

          For simplicity, I'm doing a equality check between {@code x} and + # {@code x'} that lets the algorithm continue to consume lookahead longer + # than necessary. The reason I like the equality is of course the + # simplicity but also because that is the test you need to detect the + # alternatives that are actually in conflict.

          + # + #

          CONTINUE/STOP RULE

          + # + #

          Continue if union of resolved alternative sets from non-conflicting and + # conflicting alternative subsets has more than one alternative. We are + # uncertain about which alternative to predict.

          + # + #

          The complete set of alternatives, {@code [i for (_,i,_)]}, tells us which + # alternatives are still in the running for the amount of input we've + # consumed at this point. The conflicting sets let us to strip away + # configurations that won't lead to more states because we resolve + # conflicts to the configuration with a minimum alternate for the + # conflicting set.

          + # + #

          CASES

          + # + #
            + # + #
          • no conflicts and more than 1 alternative in set => continue
          • + # + #
          • {@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s, 3, z)}, + # {@code (s', 1, y)}, {@code (s', 2, y)} yields non-conflicting set + # {@code {3}} U conflicting sets {@code min({1,2})} U {@code min({1,2})} = + # {@code {1,3}} => continue + #
          • + # + #
          • {@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s', 1, y)}, + # {@code (s', 2, y)}, {@code (s'', 1, z)} yields non-conflicting set + # {@code {1}} U conflicting sets {@code min({1,2})} U {@code min({1,2})} = + # {@code {1}} => stop and predict 1
          • + # + #
          • {@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s', 1, y)}, + # {@code (s', 2, y)} yields conflicting, reduced sets {@code {1}} U + # {@code {1}} = {@code {1}} => stop and predict 1, can announce + # ambiguity {@code {1,2}}
          • + # + #
          • {@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s', 2, y)}, + # {@code (s', 3, y)} yields conflicting, reduced sets {@code {1}} U + # {@code {2}} = {@code {1,2}} => continue
          • + # + #
          • {@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s', 3, y)}, + # {@code (s', 4, y)} yields conflicting, reduced sets {@code {1}} U + # {@code {3}} = {@code {1,3}} => continue
          • + # + #
          + # + #

          EXACT AMBIGUITY DETECTION

          + # + #

          If all states report the same conflicting set of alternatives, then we + # know we have the exact ambiguity set.

          + # + #

          |A_i|>1 and + # A_i = A_j for all i, j.

          + # + #

          In other words, we continue examining lookahead until all {@code A_i} + # have more than one alternative and all {@code A_i} are the same. If + # {@code A={{1,2}, {1,3}}}, then regular LL prediction would terminate + # because the resolved set is {@code {1}}. To determine what the real + # ambiguity is, we have to know whether the ambiguity is between one and + # two or one and three so we keep going. We can only stop prediction when + # we need exact ambiguity detection when the sets look like + # {@code A={{1,2}}} or {@code {{1,2},{1,2}}}, etc...

          + # + @classmethod + def resolvesToJustOneViableAlt(cls, altsets:list): + return cls.getSingleViableAlt(altsets) + + # + # Determines if every alternative subset in {@code altsets} contains more + # than one alternative. + # + # @param altsets a collection of alternative subsets + # @return {@code true} if every {@link BitSet} in {@code altsets} has + # {@link BitSet#cardinality cardinality} > 1, otherwise {@code false} + # + @classmethod + def allSubsetsConflict(cls, altsets:list): + return not cls.hasNonConflictingAltSet(altsets) + + # + # Determines if any single alternative subset in {@code altsets} contains + # exactly one alternative. + # + # @param altsets a collection of alternative subsets + # @return {@code true} if {@code altsets} contains a {@link BitSet} with + # {@link BitSet#cardinality cardinality} 1, otherwise {@code false} + # + @classmethod + def hasNonConflictingAltSet(cls, altsets:list): + return any(len(alts) == 1 for alts in altsets) + + # + # Determines if any single alternative subset in {@code altsets} contains + # more than one alternative. + # + # @param altsets a collection of alternative subsets + # @return {@code true} if {@code altsets} contains a {@link BitSet} with + # {@link BitSet#cardinality cardinality} > 1, otherwise {@code false} + # + @classmethod + def hasConflictingAltSet(cls, altsets:list): + return any(len(alts) > 1 for alts in altsets) + + # + # Determines if every alternative subset in {@code altsets} is equivalent. + # + # @param altsets a collection of alternative subsets + # @return {@code true} if every member of {@code altsets} is equal to the + # others, otherwise {@code false} + # + @classmethod + def allSubsetsEqual(cls, altsets:list): + if not altsets: + return True + first = next(iter(altsets)) + return all(alts == first for alts in iter(altsets)) + + # + # Returns the unique alternative predicted by all alternative subsets in + # {@code altsets}. If no such alternative exists, this method returns + # {@link ATN#INVALID_ALT_NUMBER}. + # + # @param altsets a collection of alternative subsets + # + @classmethod + def getUniqueAlt(cls, altsets:list): + all = cls.getAlts(altsets) + if len(all)==1: + return next(iter(all)) + return ATN.INVALID_ALT_NUMBER + + # Gets the complete set of represented alternatives for a collection of + # alternative subsets. This method returns the union of each {@link BitSet} + # in {@code altsets}. + # + # @param altsets a collection of alternative subsets + # @return the set of represented alternatives in {@code altsets} + # + @classmethod + def getAlts(cls, altsets:list): + return set.union(*altsets) + + # + # This function gets the conflicting alt subsets from a configuration set. + # For each configuration {@code c} in {@code configs}: + # + #
          +    # map[c] U= c.{@link ATNConfig#alt alt} # map hash/equals uses s and x, not
          +    # alt and not pred
          +    # 
          + # + @classmethod + def getConflictingAltSubsets(cls, configs:ATNConfigSet): + configToAlts = dict() + for c in configs: + h = hash((c.state.stateNumber, c.context)) + alts = configToAlts.get(h, None) + if alts is None: + alts = set() + configToAlts[h] = alts + alts.add(c.alt) + return configToAlts.values() + + # + # Get a map from state to alt subset from a configuration set. For each + # configuration {@code c} in {@code configs}: + # + #
          +    # map[c.{@link ATNConfig#state state}] U= c.{@link ATNConfig#alt alt}
          +    # 
          + # + @classmethod + def getStateToAltMap(cls, configs:ATNConfigSet): + m = dict() + for c in configs: + alts = m.get(c.state, None) + if alts is None: + alts = set() + m[c.state] = alts + alts.add(c.alt) + return m + + @classmethod + def hasStateAssociatedWithOneAlt(cls, configs:ATNConfigSet): + return any(len(alts) == 1 for alts in cls.getStateToAltMap(configs).values()) + + @classmethod + def getSingleViableAlt(cls, altsets:list): + viableAlts = set() + for alts in altsets: + minAlt = min(alts) + viableAlts.add(minAlt) + if len(viableAlts)>1 : # more than 1 viable alt + return ATN.INVALID_ALT_NUMBER + return min(viableAlts) diff --git a/src/antlr4/atn/SemanticContext.py b/src/antlr4/atn/SemanticContext.py new file mode 100644 index 00000000..d4593195 --- /dev/null +++ b/src/antlr4/atn/SemanticContext.py @@ -0,0 +1,320 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# A tree structure used to record the semantic context in which +# an ATN configuration is valid. It's either a single predicate, +# a conjunction {@code p1&&p2}, or a sum of products {@code p1||p2}. +# +#

          I have scoped the {@link AND}, {@link OR}, and {@link Predicate} subclasses of +# {@link SemanticContext} within the scope of this outer class.

          +# +from antlr4.Recognizer import Recognizer +from antlr4.RuleContext import RuleContext +from io import StringIO + + +class SemanticContext(object): + # + # The default {@link SemanticContext}, which is semantically equivalent to + # a predicate of the form {@code {true}?}. + # + NONE = None + + # + # For context independent predicates, we evaluate them without a local + # context (i.e., null context). That way, we can evaluate them without + # having to create proper rule-specific context during prediction (as + # opposed to the parser, which creates them naturally). In a practical + # sense, this avoids a cast exception from RuleContext to myruleContext. + # + #

          For context dependent predicates, we must pass in a local context so that + # references such as $arg evaluate properly as _localctx.arg. We only + # capture context dependent predicates in the context in which we begin + # prediction, so we passed in the outer context here in case of context + # dependent predicate evaluation.

          + # + def eval(self, parser:Recognizer , outerContext:RuleContext ): + pass + + # + # Evaluate the precedence predicates for the context and reduce the result. + # + # @param parser The parser instance. + # @param outerContext The current parser context object. + # @return The simplified semantic context after precedence predicates are + # evaluated, which will be one of the following values. + #
            + #
          • {@link #NONE}: if the predicate simplifies to {@code true} after + # precedence predicates are evaluated.
          • + #
          • {@code null}: if the predicate simplifies to {@code false} after + # precedence predicates are evaluated.
          • + #
          • {@code this}: if the semantic context is not changed as a result of + # precedence predicate evaluation.
          • + #
          • A non-{@code null} {@link SemanticContext}: the new simplified + # semantic context after precedence predicates are evaluated.
          • + #
          + # + def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext): + return self + +# need forward declaration +AND = None + +def andContext(a:SemanticContext, b:SemanticContext): + if a is None or a is SemanticContext.NONE: + return b + if b is None or b is SemanticContext.NONE: + return a + result = AND(a, b) + if len(result.opnds) == 1: + return result.opnds[0] + else: + return result + +# need forward declaration +OR = None + +def orContext(a:SemanticContext, b:SemanticContext): + if a is None: + return b + if b is None: + return a + if a is SemanticContext.NONE or b is SemanticContext.NONE: + return SemanticContext.NONE + result = OR(a, b) + if len(result.opnds) == 1: + return result.opnds[0] + else: + return result + +def filterPrecedencePredicates(collection:set): + return [context for context in collection if isinstance(context, PrecedencePredicate)] + + +class Predicate(SemanticContext): + + def __init__(self, ruleIndex:int=-1, predIndex:int=-1, isCtxDependent:bool=False): + self.ruleIndex = ruleIndex + self.predIndex = predIndex + self.isCtxDependent = isCtxDependent # e.g., $i ref in pred + + def eval(self, parser:Recognizer , outerContext:RuleContext ): + localctx = outerContext if self.isCtxDependent else None + return parser.sempred(localctx, self.ruleIndex, self.predIndex) + + def __hash__(self): + return hash((self.ruleIndex, self.predIndex, self.isCtxDependent)) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, Predicate): + return False + return self.ruleIndex == other.ruleIndex and \ + self.predIndex == other.predIndex and \ + self.isCtxDependent == other.isCtxDependent + + def __str__(self): + return "{" + str(self.ruleIndex) + ":" + str(self.predIndex) + "}?" + + +class PrecedencePredicate(SemanticContext): + + def __init__(self, precedence:int=0): + self.precedence = precedence + + def eval(self, parser:Recognizer , outerContext:RuleContext ): + return parser.precpred(outerContext, self.precedence) + + def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext): + if parser.precpred(outerContext, self.precedence): + return SemanticContext.NONE + else: + return None + + def __lt__(self, other): + return self.precedence < other.precedence + + def __hash__(self): + return 31 + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, PrecedencePredicate): + return False + else: + return self.precedence == other.precedence + +# A semantic context which is true whenever none of the contained contexts +# is false. +del AND +class AND(SemanticContext): + + def __init__(self, a:SemanticContext, b:SemanticContext): + operands = set() + if isinstance( a, AND ): + operands.update(a.opnds) + else: + operands.add(a) + if isinstance( b, AND ): + operands.update(b.opnds) + else: + operands.add(b) + + precedencePredicates = filterPrecedencePredicates(operands) + if len(precedencePredicates)>0: + # interested in the transition with the lowest precedence + reduced = min(precedencePredicates) + operands.add(reduced) + + self.opnds = list(operands) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, AND): + return False + else: + return self.opnds == other.opnds + + def __hash__(self): + h = 0 + for o in self.opnds: + h = hash((h, o)) + return hash((h, "AND")) + + # + # {@inheritDoc} + # + #

          + # The evaluation of predicates by this context is short-circuiting, but + # unordered.

          + # + def eval(self, parser:Recognizer, outerContext:RuleContext): + return all(opnd.eval(parser, outerContext) for opnd in self.opnds) + + def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext): + differs = False + operands = [] + for context in self.opnds: + evaluated = context.evalPrecedence(parser, outerContext) + differs |= evaluated is not context + if evaluated is None: + # The AND context is false if any element is false + return None + elif evaluated is not SemanticContext.NONE: + # Reduce the result by skipping true elements + operands.append(evaluated) + + if not differs: + return self + + if len(operands)==0: + # all elements were true, so the AND context is true + return SemanticContext.NONE + + result = None + for o in operands: + result = o if result is None else andContext(result, o) + + return result + + def __str__(self): + with StringIO() as buf: + first = True + for o in self.opnds: + if not first: + buf.write("&&") + buf.write(str(o)) + first = False + return buf.getvalue() + +# +# A semantic context which is true whenever at least one of the contained +# contexts is true. +del OR +class OR (SemanticContext): + + def __init__(self, a:SemanticContext, b:SemanticContext): + operands = set() + if isinstance( a, OR ): + operands.update(a.opnds) + else: + operands.add(a) + if isinstance( b, OR ): + operands.update(b.opnds) + else: + operands.add(b) + + precedencePredicates = filterPrecedencePredicates(operands) + if len(precedencePredicates)>0: + # interested in the transition with the highest precedence + s = sorted(precedencePredicates) + reduced = s[-1] + operands.add(reduced) + + self.opnds = list(operands) + + def __eq__(self, other): + if self is other: + return True + elif not isinstance(other, OR): + return False + else: + return self.opnds == other.opnds + + def __hash__(self): + h = 0 + for o in self.opnds: + h = hash((h, o)) + return hash((h, "OR")) + + #

          + # The evaluation of predicates by this context is short-circuiting, but + # unordered.

          + # + def eval(self, parser:Recognizer, outerContext:RuleContext): + return any(opnd.eval(parser, outerContext) for opnd in self.opnds) + + def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext): + differs = False + operands = [] + for context in self.opnds: + evaluated = context.evalPrecedence(parser, outerContext) + differs |= evaluated is not context + if evaluated is SemanticContext.NONE: + # The OR context is true if any element is true + return SemanticContext.NONE + elif evaluated is not None: + # Reduce the result by skipping false elements + operands.append(evaluated) + + if not differs: + return self + + if len(operands)==0: + # all elements were false, so the OR context is false + return None + + result = None + for o in operands: + result = o if result is None else orContext(result, o) + + return result + + def __str__(self): + with StringIO() as buf: + first = True + for o in self.opnds: + if not first: + buf.write("||") + buf.write(str(o)) + first = False + return buf.getvalue() + + +SemanticContext.NONE = Predicate() \ No newline at end of file diff --git a/src/antlr4/atn/Transition.py b/src/antlr4/atn/Transition.py new file mode 100644 index 00000000..0ed042cd --- /dev/null +++ b/src/antlr4/atn/Transition.py @@ -0,0 +1,257 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# An ATN transition between any two ATN states. Subclasses define +# atom, set, epsilon, action, predicate, rule transitions. +# +#

          This is a one way link. It emanates from a state (usually via a list of +# transitions) and has a target state.

          +# +#

          Since we never have to change the ATN transitions once we construct it, +# we can fix these transitions as specific classes. The DFA transitions +# on the other hand need to update the labels as it adds transitions to +# the states. We'll use the term Edge for the DFA to distinguish them from +# ATN transitions.

          +# +from antlr4.IntervalSet import IntervalSet +from antlr4.Token import Token + +# need forward declarations +from antlr4.atn.SemanticContext import Predicate, PrecedencePredicate + +ATNState = None +RuleStartState = None + +class Transition (object): + # constants for serialization + EPSILON = 1 + RANGE = 2 + RULE = 3 + PREDICATE = 4 # e.g., {isType(input.LT(1))}? + ATOM = 5 + ACTION = 6 + SET = 7 # ~(A|B) or ~atom, wildcard, which convert to next 2 + NOT_SET = 8 + WILDCARD = 9 + PRECEDENCE = 10 + + serializationNames = [ + "INVALID", + "EPSILON", + "RANGE", + "RULE", + "PREDICATE", + "ATOM", + "ACTION", + "SET", + "NOT_SET", + "WILDCARD", + "PRECEDENCE" + ] + + serializationTypes = dict() + + def __init__(self, target:ATNState): + # The target of this transition. + if target is None: + raise Exception("target cannot be null.") + self.target = target + # Are we epsilon, action, sempred? + self.isEpsilon = False + self.label = None + + +# TODO: make all transitions sets? no, should remove set edges +class AtomTransition(Transition): + + def __init__(self, target:ATNState, label:int): + super().__init__(target) + self.label_ = label # The token type or character value; or, signifies special label. + self.label = self.makeLabel() + self.serializationType = self.ATOM + + def makeLabel(self): + s = IntervalSet() + s.addOne(self.label_) + return s + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return self.label_ == symbol + + def __str__(self): + return str(self.label_) + +class RuleTransition(Transition): + + def __init__(self, ruleStart:RuleStartState, ruleIndex:int, precedence:int, followState:ATNState): + super().__init__(ruleStart) + self.ruleIndex = ruleIndex # ptr to the rule definition object for this rule ref + self.precedence = precedence + self.followState = followState # what node to begin computations following ref to rule + self.serializationType = self.RULE + self.isEpsilon = True + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return False + + +class EpsilonTransition(Transition): + + def __init__(self, target, outermostPrecedenceReturn=-1): + super(EpsilonTransition, self).__init__(target) + self.serializationType = self.EPSILON + self.isEpsilon = True + self.outermostPrecedenceReturn = outermostPrecedenceReturn + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return False + + def __str__(self): + return "epsilon" + +class RangeTransition(Transition): + + def __init__(self, target:ATNState, start:int, stop:int): + super().__init__(target) + self.serializationType = self.RANGE + self.start = start + self.stop = stop + self.label = self.makeLabel() + + def makeLabel(self): + s = IntervalSet() + s.addRange(range(self.start, self.stop + 1)) + return s + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return symbol >= self.start and symbol <= self.stop + + def __str__(self): + return "'" + chr(self.start) + "'..'" + chr(self.stop) + "'" + +class AbstractPredicateTransition(Transition): + + def __init__(self, target:ATNState): + super().__init__(target) + + +class PredicateTransition(AbstractPredicateTransition): + + def __init__(self, target:ATNState, ruleIndex:int, predIndex:int, isCtxDependent:bool): + super().__init__(target) + self.serializationType = self.PREDICATE + self.ruleIndex = ruleIndex + self.predIndex = predIndex + self.isCtxDependent = isCtxDependent # e.g., $i ref in pred + self.isEpsilon = True + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return False + + def getPredicate(self): + return Predicate(self.ruleIndex, self.predIndex, self.isCtxDependent) + + def __str__(self): + return "pred_" + str(self.ruleIndex) + ":" + str(self.predIndex) + +class ActionTransition(Transition): + + def __init__(self, target:ATNState, ruleIndex:int, actionIndex:int=-1, isCtxDependent:bool=False): + super().__init__(target) + self.serializationType = self.ACTION + self.ruleIndex = ruleIndex + self.actionIndex = actionIndex + self.isCtxDependent = isCtxDependent # e.g., $i ref in pred + self.isEpsilon = True + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return False + + def __str__(self): + return "action_"+self.ruleIndex+":"+self.actionIndex + +# A transition containing a set of values. +class SetTransition(Transition): + + def __init__(self, target:ATNState, set:IntervalSet): + super().__init__(target) + self.serializationType = self.SET + if set is not None: + self.label = set + else: + self.label = IntervalSet() + self.label.addRange(range(Token.INVALID_TYPE, Token.INVALID_TYPE + 1)) + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return symbol in self.label + + def __str__(self): + return str(self.label) + +class NotSetTransition(SetTransition): + + def __init__(self, target:ATNState, set:IntervalSet): + super().__init__(target, set) + self.serializationType = self.NOT_SET + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return symbol >= minVocabSymbol \ + and symbol <= maxVocabSymbol \ + and not super(type(self), self).matches(symbol, minVocabSymbol, maxVocabSymbol) + + def __str__(self): + return '~' + super(type(self), self).__str__() + + +class WildcardTransition(Transition): + + def __init__(self, target:ATNState): + super().__init__(target) + self.serializationType = self.WILDCARD + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return symbol >= minVocabSymbol and symbol <= maxVocabSymbol + + def __str__(self): + return "." + + +class PrecedencePredicateTransition(AbstractPredicateTransition): + + def __init__(self, target:ATNState, precedence:int): + super().__init__(target) + self.serializationType = self.PRECEDENCE + self.precedence = precedence + self.isEpsilon = True + + def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int): + return False + + + def getPredicate(self): + return PrecedencePredicate(self.precedence) + + def __str__(self): + return self.precedence + " >= _p" + + +Transition.serializationTypes = { + EpsilonTransition: Transition.EPSILON, + RangeTransition: Transition.RANGE, + RuleTransition: Transition.RULE, + PredicateTransition: Transition.PREDICATE, + AtomTransition: Transition.ATOM, + ActionTransition: Transition.ACTION, + SetTransition: Transition.SET, + NotSetTransition: Transition.NOT_SET, + WildcardTransition: Transition.WILDCARD, + PrecedencePredicateTransition: Transition.PRECEDENCE + } + +del ATNState +del RuleStartState + +from antlr4.atn.ATNState import * \ No newline at end of file diff --git a/src/antlr4/atn/__init__.py b/src/antlr4/atn/__init__.py new file mode 100644 index 00000000..216c000d --- /dev/null +++ b/src/antlr4/atn/__init__.py @@ -0,0 +1 @@ +__author__ = 'ericvergnaud' diff --git a/src/antlr4/dfa/DFA.py b/src/antlr4/dfa/DFA.py new file mode 100644 index 00000000..af6839ca --- /dev/null +++ b/src/antlr4/dfa/DFA.py @@ -0,0 +1,133 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +from antlr4.atn.ATNState import StarLoopEntryState + +from antlr4.atn.ATNConfigSet import ATNConfigSet +from antlr4.atn.ATNState import DecisionState +from antlr4.dfa.DFAState import DFAState +from antlr4.error.Errors import IllegalStateException + + +class DFA(object): + + def __init__(self, atnStartState:DecisionState, decision:int=0): + # From which ATN state did we create this DFA? + self.atnStartState = atnStartState + self.decision = decision + # A set of all DFA states. Use {@link Map} so we can get old state back + # ({@link Set} only allows you to see if it's there). + self._states = dict() + self.s0 = None + # {@code true} if this DFA is for a precedence decision; otherwise, + # {@code false}. This is the backing field for {@link #isPrecedenceDfa}, + # {@link #setPrecedenceDfa}. + self.precedenceDfa = False + + if isinstance(atnStartState, StarLoopEntryState): + if atnStartState.isPrecedenceDecision: + self.precedenceDfa = True + precedenceState = DFAState(configs=ATNConfigSet()) + precedenceState.edges = [] + precedenceState.isAcceptState = False + precedenceState.requiresFullContext = False + self.s0 = precedenceState + + + # Get the start state for a specific precedence value. + # + # @param precedence The current precedence. + # @return The start state corresponding to the specified precedence, or + # {@code null} if no start state exists for the specified precedence. + # + # @throws IllegalStateException if this is not a precedence DFA. + # @see #isPrecedenceDfa() + + def getPrecedenceStartState(self, precedence:int): + if not self.precedenceDfa: + raise IllegalStateException("Only precedence DFAs may contain a precedence start state.") + + # s0.edges is never null for a precedence DFA + if precedence < 0 or precedence >= len(self.s0.edges): + return None + return self.s0.edges[precedence] + + # Set the start state for a specific precedence value. + # + # @param precedence The current precedence. + # @param startState The start state corresponding to the specified + # precedence. + # + # @throws IllegalStateException if this is not a precedence DFA. + # @see #isPrecedenceDfa() + # + def setPrecedenceStartState(self, precedence:int, startState:DFAState): + if not self.precedenceDfa: + raise IllegalStateException("Only precedence DFAs may contain a precedence start state.") + + if precedence < 0: + return + + # synchronization on s0 here is ok. when the DFA is turned into a + # precedence DFA, s0 will be initialized once and not updated again + # s0.edges is never null for a precedence DFA + if precedence >= len(self.s0.edges): + ext = [None] * (precedence + 1 - len(self.s0.edges)) + self.s0.edges.extend(ext) + self.s0.edges[precedence] = startState + # + # Sets whether this is a precedence DFA. If the specified value differs + # from the current DFA configuration, the following actions are taken; + # otherwise no changes are made to the current DFA. + # + #
            + #
          • The {@link #states} map is cleared
          • + #
          • If {@code precedenceDfa} is {@code false}, the initial state + # {@link #s0} is set to {@code null}; otherwise, it is initialized to a new + # {@link DFAState} with an empty outgoing {@link DFAState#edges} array to + # store the start states for individual precedence values.
          • + #
          • The {@link #precedenceDfa} field is updated
          • + #
          + # + # @param precedenceDfa {@code true} if this is a precedence DFA; otherwise, + # {@code false} + + def setPrecedenceDfa(self, precedenceDfa:bool): + if self.precedenceDfa != precedenceDfa: + self._states = dict() + if precedenceDfa: + precedenceState = DFAState(configs=ATNConfigSet()) + precedenceState.edges = [] + precedenceState.isAcceptState = False + precedenceState.requiresFullContext = False + self.s0 = precedenceState + else: + self.s0 = None + self.precedenceDfa = precedenceDfa + + @property + def states(self): + return self._states + + # Return a list of all states in this DFA, ordered by state number. + def sortedStates(self): + return sorted(self._states.keys(), key=lambda state: state.stateNumber) + + def __str__(self): + return self.toString(None) + + def toString(self, literalNames:list=None, symbolicNames:list=None): + if self.s0 is None: + return "" + from antlr4.dfa.DFASerializer import DFASerializer + serializer = DFASerializer(self,literalNames,symbolicNames) + return str(serializer) + + def toLexerString(self): + if self.s0 is None: + return "" + from antlr4.dfa.DFASerializer import LexerDFASerializer + serializer = LexerDFASerializer(self) + return str(serializer) + diff --git a/src/antlr4/dfa/DFASerializer.py b/src/antlr4/dfa/DFASerializer.py new file mode 100644 index 00000000..eeb6e366 --- /dev/null +++ b/src/antlr4/dfa/DFASerializer.py @@ -0,0 +1,72 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# A DFA walker that knows how to dump them to serialized strings.#/ +from io import StringIO +from antlr4 import DFA +from antlr4.Utils import str_list +from antlr4.dfa.DFAState import DFAState + + +class DFASerializer(object): + + def __init__(self, dfa:DFA, literalNames:list=None, symbolicNames:list=None): + self.dfa = dfa + self.literalNames = literalNames + self.symbolicNames = symbolicNames + + def __str__(self): + if self.dfa.s0 is None: + return None + with StringIO() as buf: + for s in self.dfa.sortedStates(): + n = 0 + if s.edges is not None: + n = len(s.edges) + for i in range(0, n): + t = s.edges[i] + if t is not None and t.stateNumber != 0x7FFFFFFF: + buf.write(self.getStateString(s)) + label = self.getEdgeLabel(i) + buf.write("-") + buf.write(label) + buf.write("->") + buf.write(self.getStateString(t)) + buf.write('\n') + output = buf.getvalue() + if len(output)==0: + return None + else: + return output + + def getEdgeLabel(self, i:int): + if i==0: + return "EOF" + if self.literalNames is not None and i<=len(self.literalNames): + return self.literalNames[i-1] + elif self.symbolicNames is not None and i<=len(self.symbolicNames): + return self.symbolicNames[i-1] + else: + return str(i-1) + + def getStateString(self, s:DFAState): + n = s.stateNumber + baseStateStr = ( ":" if s.isAcceptState else "") + "s" + str(n) + ( "^" if s.requiresFullContext else "") + if s.isAcceptState: + if s.predicates is not None: + return baseStateStr + "=>" + str_list(s.predicates) + else: + return baseStateStr + "=>" + str(s.prediction) + else: + return baseStateStr + +class LexerDFASerializer(DFASerializer): + + def __init__(self, dfa:DFA): + super().__init__(dfa, None) + + def getEdgeLabel(self, i:int): + return "'" + chr(i) + "'" diff --git a/src/antlr4/dfa/DFAState.py b/src/antlr4/dfa/DFAState.py new file mode 100644 index 00000000..d7af5a17 --- /dev/null +++ b/src/antlr4/dfa/DFAState.py @@ -0,0 +1,120 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + +# Map a predicate to a predicted alternative.#/ +from io import StringIO +from antlr4.atn.ATNConfigSet import ATNConfigSet +from antlr4.atn.SemanticContext import SemanticContext + + +class PredPrediction(object): + def __init__(self, pred:SemanticContext, alt:int): + self.alt = alt + self.pred = pred + + def __str__(self): + return "(" + str(self.pred) + ", " + str(self.alt) + ")" + +# A DFA state represents a set of possible ATN configurations. +# As Aho, Sethi, Ullman p. 117 says "The DFA uses its state +# to keep track of all possible states the ATN can be in after +# reading each input symbol. That is to say, after reading +# input a1a2..an, the DFA is in a state that represents the +# subset T of the states of the ATN that are reachable from the +# ATN's start state along some path labeled a1a2..an." +# In conventional NFA→DFA conversion, therefore, the subset T +# would be a bitset representing the set of states the +# ATN could be in. We need to track the alt predicted by each +# state as well, however. More importantly, we need to maintain +# a stack of states, tracking the closure operations as they +# jump from rule to rule, emulating rule invocations (method calls). +# I have to add a stack to simulate the proper lookahead sequences for +# the underlying LL grammar from which the ATN was derived. +# +#

          I use a set of ATNConfig objects not simple states. An ATNConfig +# is both a state (ala normal conversion) and a RuleContext describing +# the chain of rules (if any) followed to arrive at that state.

          +# +#

          A DFA state may have multiple references to a particular state, +# but with different ATN contexts (with same or different alts) +# meaning that state was reached via a different set of rule invocations.

          +#/ +class DFAState(object): + + def __init__(self, stateNumber:int=-1, configs:ATNConfigSet=ATNConfigSet()): + self.stateNumber = stateNumber + self.configs = configs + # {@code edges[symbol]} points to target of symbol. Shift up by 1 so (-1) + # {@link Token#EOF} maps to {@code edges[0]}. + self.edges = None + self.isAcceptState = False + # if accept state, what ttype do we match or alt do we predict? + # This is set to {@link ATN#INVALID_ALT_NUMBER} when {@link #predicates}{@code !=null} or + # {@link #requiresFullContext}. + self.prediction = 0 + self.lexerActionExecutor = None + # Indicates that this state was created during SLL prediction that + # discovered a conflict between the configurations in the state. Future + # {@link ParserATNSimulator#execATN} invocations immediately jumped doing + # full context prediction if this field is true. + self.requiresFullContext = False + # During SLL parsing, this is a list of predicates associated with the + # ATN configurations of the DFA state. When we have predicates, + # {@link #requiresFullContext} is {@code false} since full context prediction evaluates predicates + # on-the-fly. If this is not null, then {@link #prediction} is + # {@link ATN#INVALID_ALT_NUMBER}. + # + #

          We only use these for non-{@link #requiresFullContext} but conflicting states. That + # means we know from the context (it's $ or we don't dip into outer + # context) that it's an ambiguity not a conflict.

          + # + #

          This list is computed by {@link ParserATNSimulator#predicateDFAState}.

          + self.predicates = None + + + + # Get the set of all alts mentioned by all ATN configurations in this + # DFA state. + def getAltSet(self): + if self.configs is not None: + return set(cfg.alt for cfg in self.configs) or None + return None + + def __hash__(self): + return hash(self.configs) + + # Two {@link DFAState} instances are equal if their ATN configuration sets + # are the same. This method is used to see if a state already exists. + # + #

          Because the number of alternatives and number of ATN configurations are + # finite, there is a finite number of DFA states that can be processed. + # This is necessary to show that the algorithm terminates.

          + # + #

          Cannot test the DFA state numbers here because in + # {@link ParserATNSimulator#addDFAState} we need to know if any other state + # exists that has this exact set of ATN configurations. The + # {@link #stateNumber} is irrelevant.

          + def __eq__(self, other): + # compare set of ATN configurations in this set with other + if self is other: + return True + elif not isinstance(other, DFAState): + return False + else: + return self.configs==other.configs + + def __str__(self): + with StringIO() as buf: + buf.write(str(self.stateNumber)) + buf.write(":") + buf.write(str(self.configs)) + if self.isAcceptState: + buf.write("=>") + if self.predicates is not None: + buf.write(str(self.predicates)) + else: + buf.write(str(self.prediction)) + return buf.getvalue() diff --git a/src/antlr4/dfa/__init__.py b/src/antlr4/dfa/__init__.py new file mode 100644 index 00000000..216c000d --- /dev/null +++ b/src/antlr4/dfa/__init__.py @@ -0,0 +1 @@ +__author__ = 'ericvergnaud' diff --git a/src/antlr4/error/DiagnosticErrorListener.py b/src/antlr4/error/DiagnosticErrorListener.py new file mode 100644 index 00000000..7f983deb --- /dev/null +++ b/src/antlr4/error/DiagnosticErrorListener.py @@ -0,0 +1,107 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + + +# +# This implementation of {@link ANTLRErrorListener} can be used to identify +# certain potential correctness and performance problems in grammars. "Reports" +# are made by calling {@link Parser#notifyErrorListeners} with the appropriate +# message. +# +#
            +#
          • Ambiguities: These are cases where more than one path through the +# grammar can match the input.
          • +#
          • Weak context sensitivity: These are cases where full-context +# prediction resolved an SLL conflict to a unique alternative which equaled the +# minimum alternative of the SLL conflict.
          • +#
          • Strong (forced) context sensitivity: These are cases where the +# full-context prediction resolved an SLL conflict to a unique alternative, +# and the minimum alternative of the SLL conflict was found to not be +# a truly viable alternative. Two-stage parsing cannot be used for inputs where +# this situation occurs.
          • +#
          + +from io import StringIO +from antlr4 import Parser, DFA +from antlr4.atn.ATNConfigSet import ATNConfigSet +from antlr4.error.ErrorListener import ErrorListener + +class DiagnosticErrorListener(ErrorListener): + + def __init__(self, exactOnly:bool=True): + # whether all ambiguities or only exact ambiguities are reported. + self.exactOnly = exactOnly + + def reportAmbiguity(self, recognizer:Parser, dfa:DFA, startIndex:int, + stopIndex:int, exact:bool, ambigAlts:set, configs:ATNConfigSet): + if self.exactOnly and not exact: + return + + with StringIO() as buf: + buf.write("reportAmbiguity d=") + buf.write(self.getDecisionDescription(recognizer, dfa)) + buf.write(": ambigAlts=") + buf.write(str(self.getConflictingAlts(ambigAlts, configs))) + buf.write(", input='") + buf.write(recognizer.getTokenStream().getText((startIndex, stopIndex))) + buf.write("'") + recognizer.notifyErrorListeners(buf.getvalue()) + + + def reportAttemptingFullContext(self, recognizer:Parser, dfa:DFA, startIndex:int, + stopIndex:int, conflictingAlts:set, configs:ATNConfigSet): + with StringIO() as buf: + buf.write("reportAttemptingFullContext d=") + buf.write(self.getDecisionDescription(recognizer, dfa)) + buf.write(", input='") + buf.write(recognizer.getTokenStream().getText((startIndex, stopIndex))) + buf.write("'") + recognizer.notifyErrorListeners(buf.getvalue()) + + def reportContextSensitivity(self, recognizer:Parser, dfa:DFA, startIndex:int, + stopIndex:int, prediction:int, configs:ATNConfigSet): + with StringIO() as buf: + buf.write("reportContextSensitivity d=") + buf.write(self.getDecisionDescription(recognizer, dfa)) + buf.write(", input='") + buf.write(recognizer.getTokenStream().getText((startIndex, stopIndex))) + buf.write("'") + recognizer.notifyErrorListeners(buf.getvalue()) + + def getDecisionDescription(self, recognizer:Parser, dfa:DFA): + decision = dfa.decision + ruleIndex = dfa.atnStartState.ruleIndex + + ruleNames = recognizer.ruleNames + if ruleIndex < 0 or ruleIndex >= len(ruleNames): + return str(decision) + + ruleName = ruleNames[ruleIndex] + if ruleName is None or len(ruleName)==0: + return str(decision) + + return str(decision) + " (" + ruleName + ")" + + # + # Computes the set of conflicting or ambiguous alternatives from a + # configuration set, if that information was not already provided by the + # parser. + # + # @param reportedAlts The set of conflicting or ambiguous alternatives, as + # reported by the parser. + # @param configs The conflicting or ambiguous configuration set. + # @return Returns {@code reportedAlts} if it is not {@code null}, otherwise + # returns the set of alternatives represented in {@code configs}. + # + def getConflictingAlts(self, reportedAlts:set, configs:ATNConfigSet): + if reportedAlts is not None: + return reportedAlts + + result = set() + for config in configs: + result.add(config.alt) + + return result diff --git a/src/antlr4/error/ErrorListener.py b/src/antlr4/error/ErrorListener.py new file mode 100644 index 00000000..c8614beb --- /dev/null +++ b/src/antlr4/error/ErrorListener.py @@ -0,0 +1,73 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. + +# Provides an empty default implementation of {@link ANTLRErrorListener}. The +# default implementation of each method does nothing, but can be overridden as +# necessary. + + +import sys + +class ErrorListener(object): + + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): + pass + + def reportAmbiguity(self, recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs): + pass + + def reportAttemptingFullContext(self, recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs): + pass + + def reportContextSensitivity(self, recognizer, dfa, startIndex, stopIndex, prediction, configs): + pass + +class ConsoleErrorListener(ErrorListener): + # + # Provides a default instance of {@link ConsoleErrorListener}. + # + INSTANCE = None + + # + # {@inheritDoc} + # + #

          + # This implementation prints messages to {@link System#err} containing the + # values of {@code line}, {@code charPositionInLine}, and {@code msg} using + # the following format.

          + # + #
          +    # line line:charPositionInLine msg
          +    # 
          + # + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): + #file=sys.stderr + print("(" + str(line) + ", " + str(column) + ")"+ " - " + msg + ":", file=sys.stderr) + +ConsoleErrorListener.INSTANCE = ConsoleErrorListener() + +class ProxyErrorListener(ErrorListener): + + def __init__(self, delegates): + super().__init__() + if delegates is None: + raise ReferenceError("delegates") + self.delegates = delegates + + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): + for delegate in self.delegates: + delegate.syntaxError(recognizer, offendingSymbol, line, column, msg, e) + + def reportAmbiguity(self, recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs): + for delegate in self.delegates: + delegate.reportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs) + + def reportAttemptingFullContext(self, recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs): + for delegate in self.delegates: + delegate.reportAttemptingFullContext(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs) + + def reportContextSensitivity(self, recognizer, dfa, startIndex, stopIndex, prediction, configs): + for delegate in self.delegates: + delegate.reportContextSensitivity(recognizer, dfa, startIndex, stopIndex, prediction, configs) diff --git a/src/antlr4/error/ErrorStrategy.py b/src/antlr4/error/ErrorStrategy.py new file mode 100644 index 00000000..4c6d89d7 --- /dev/null +++ b/src/antlr4/error/ErrorStrategy.py @@ -0,0 +1,698 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# +import sys +from antlr4.IntervalSet import IntervalSet + +from antlr4.Token import Token +from antlr4.atn.ATNState import ATNState +from antlr4.error.Errors import RecognitionException, NoViableAltException, InputMismatchException, \ + FailedPredicateException, ParseCancellationException + +# need forward declaration +Parser = None + +class ErrorStrategy(object): + + def reset(self, recognizer:Parser): + pass + + def recoverInline(self, recognizer:Parser): + pass + + def recover(self, recognizer:Parser, e:RecognitionException): + pass + + def sync(self, recognizer:Parser): + pass + + def inErrorRecoveryMode(self, recognizer:Parser): + pass + + def reportError(self, recognizer:Parser, e:RecognitionException): + pass + + +# This is the default implementation of {@link ANTLRErrorStrategy} used for +# error reporting and recovery in ANTLR parsers. +# +class DefaultErrorStrategy(ErrorStrategy): + + def __init__(self): + super().__init__() + # Indicates whether the error strategy is currently "recovering from an + # error". This is used to suppress reporting multiple error messages while + # attempting to recover from a detected syntax error. + # + # @see #inErrorRecoveryMode + # + self.errorRecoveryMode = False + + # The index into the input stream where the last error occurred. + # This is used to prevent infinite loops where an error is found + # but no token is consumed during recovery...another error is found, + # ad nauseum. This is a failsafe mechanism to guarantee that at least + # one token/tree node is consumed for two errors. + # + self.lastErrorIndex = -1 + self.lastErrorStates = None + + #

          The default implementation simply calls {@link #endErrorCondition} to + # ensure that the handler is not in error recovery mode.

          + def reset(self, recognizer:Parser): + self.endErrorCondition(recognizer) + + # + # This method is called to enter error recovery mode when a recognition + # exception is reported. + # + # @param recognizer the parser instance + # + def beginErrorCondition(self, recognizer:Parser): + self.errorRecoveryMode = True + + def inErrorRecoveryMode(self, recognizer:Parser): + return self.errorRecoveryMode + + # + # This method is called to leave error recovery mode after recovering from + # a recognition exception. + # + # @param recognizer + # + def endErrorCondition(self, recognizer:Parser): + self.errorRecoveryMode = False + self.lastErrorStates = None + self.lastErrorIndex = -1 + + # + # {@inheritDoc} + # + #

          The default implementation simply calls {@link #endErrorCondition}.

          + # + def reportMatch(self, recognizer:Parser): + self.endErrorCondition(recognizer) + + # + # {@inheritDoc} + # + #

          The default implementation returns immediately if the handler is already + # in error recovery mode. Otherwise, it calls {@link #beginErrorCondition} + # and dispatches the reporting task based on the runtime type of {@code e} + # according to the following table.

          + # + #
            + #
          • {@link NoViableAltException}: Dispatches the call to + # {@link #reportNoViableAlternative}
          • + #
          • {@link InputMismatchException}: Dispatches the call to + # {@link #reportInputMismatch}
          • + #
          • {@link FailedPredicateException}: Dispatches the call to + # {@link #reportFailedPredicate}
          • + #
          • All other types: calls {@link Parser#notifyErrorListeners} to report + # the exception
          • + #
          + # + def reportError(self, recognizer:Parser, e:RecognitionException): + # if we've already reported an error and have not matched a token + # yet successfully, don't report any errors. + if self.inErrorRecoveryMode(recognizer): + return # don't report spurious errors + self.beginErrorCondition(recognizer) + if isinstance( e, NoViableAltException ): + self.reportNoViableAlternative(recognizer, e) + elif isinstance( e, InputMismatchException ): + self.reportInputMismatch(recognizer, e) + elif isinstance( e, FailedPredicateException ): + self.reportFailedPredicate(recognizer, e) + else: + print("unknown recognition error type: " + type(e).__name__) + recognizer.notifyErrorListeners(e.message, e.offendingToken, e) + + # + # {@inheritDoc} + # + #

          The default implementation resynchronizes the parser by consuming tokens + # until we find one in the resynchronization set--loosely the set of tokens + # that can follow the current rule.

          + # + def recover(self, recognizer:Parser, e:RecognitionException): + if self.lastErrorIndex==recognizer.getInputStream().index \ + and self.lastErrorStates is not None \ + and recognizer.state in self.lastErrorStates: + # uh oh, another error at same token index and previously-visited + # state in ATN; must be a case where LT(1) is in the recovery + # token set so nothing got consumed. Consume a single token + # at least to prevent an infinite loop; this is a failsafe. + recognizer.consume() + + self.lastErrorIndex = recognizer._input.index + if self.lastErrorStates is None: + self.lastErrorStates = [] + self.lastErrorStates.append(recognizer.state) + followSet = self.getErrorRecoverySet(recognizer) + self.consumeUntil(recognizer, followSet) + + # The default implementation of {@link ANTLRErrorStrategy#sync} makes sure + # that the current lookahead symbol is consistent with what were expecting + # at this point in the ATN. You can call this anytime but ANTLR only + # generates code to check before subrules/loops and each iteration. + # + #

          Implements Jim Idle's magic sync mechanism in closures and optional + # subrules. E.g.,

          + # + #
          +    # a : sync ( stuff sync )* ;
          +    # sync : {consume to what can follow sync} ;
          +    # 
          + # + # At the start of a sub rule upon error, {@link #sync} performs single + # token deletion, if possible. If it can't do that, it bails on the current + # rule and uses the default error recovery, which consumes until the + # resynchronization set of the current rule. + # + #

          If the sub rule is optional ({@code (...)?}, {@code (...)*}, or block + # with an empty alternative), then the expected set includes what follows + # the subrule.

          + # + #

          During loop iteration, it consumes until it sees a token that can start a + # sub rule or what follows loop. Yes, that is pretty aggressive. We opt to + # stay in the loop as long as possible.

          + # + #

          ORIGINS

          + # + #

          Previous versions of ANTLR did a poor job of their recovery within loops. + # A single mismatch token or missing token would force the parser to bail + # out of the entire rules surrounding the loop. So, for rule

          + # + #
          +    # classDef : 'class' ID '{' member* '}'
          +    # 
          + # + # input with an extra token between members would force the parser to + # consume until it found the next class definition rather than the next + # member definition of the current class. + # + #

          This functionality cost a little bit of effort because the parser has to + # compare token set at the start of the loop and at each iteration. If for + # some reason speed is suffering for you, you can turn off this + # functionality by simply overriding this method as a blank { }.

          + # + def sync(self, recognizer:Parser): + # If already recovering, don't try to sync + if self.inErrorRecoveryMode(recognizer): + return + + s = recognizer._interp.atn.states[recognizer.state] + la = recognizer.getTokenStream().LA(1) + # try cheaper subset first; might get lucky. seems to shave a wee bit off + nextTokens = recognizer.atn.nextTokens(s) + if Token.EPSILON in nextTokens or la in nextTokens: + return + + if s.stateType in [ATNState.BLOCK_START, ATNState.STAR_BLOCK_START, + ATNState.PLUS_BLOCK_START, ATNState.STAR_LOOP_ENTRY]: + # report error and recover if possible + if self.singleTokenDeletion(recognizer)is not None: + return + else: + raise InputMismatchException(recognizer) + + elif s.stateType in [ATNState.PLUS_LOOP_BACK, ATNState.STAR_LOOP_BACK]: + self.reportUnwantedToken(recognizer) + expecting = recognizer.getExpectedTokens() + whatFollowsLoopIterationOrRule = expecting.addSet(self.getErrorRecoverySet(recognizer)) + self.consumeUntil(recognizer, whatFollowsLoopIterationOrRule) + + else: + # do nothing if we can't identify the exact kind of ATN state + pass + + # This is called by {@link #reportError} when the exception is a + # {@link NoViableAltException}. + # + # @see #reportError + # + # @param recognizer the parser instance + # @param e the recognition exception + # + def reportNoViableAlternative(self, recognizer:Parser, e:NoViableAltException): + tokens = recognizer.getTokenStream() + if tokens is not None: + if e.startToken.type==Token.EOF: + input = "" + else: + input = tokens.getText((e.startToken, e.offendingToken)) + else: + input = "" + msg = "no viable alternative at input " + self.escapeWSAndQuote(input) + recognizer.notifyErrorListeners(msg, e.offendingToken, e) + + # + # This is called by {@link #reportError} when the exception is an + # {@link InputMismatchException}. + # + # @see #reportError + # + # @param recognizer the parser instance + # @param e the recognition exception + # + def reportInputMismatch(self, recognizer:Parser, e:InputMismatchException): + msg = "SyntacticError" + #self.getTokenErrorDisplay(e.offendingToken) \ + " expecting " + e.getExpectedTokens().toString(recognizer.literalNames, recognizer.symbolicNames) + recognizer.notifyErrorListeners(msg, e.offendingToken, e) + + # + # This is called by {@link #reportError} when the exception is a + # {@link FailedPredicateException}. + # + # @see #reportError + # + # @param recognizer the parser instance + # @param e the recognition exception + # + def reportFailedPredicate(self, recognizer, e): + ruleName = recognizer.ruleNames[recognizer._ctx.getRuleIndex()] + msg = "rule " + ruleName + " " + e.message + recognizer.notifyErrorListeners(msg, e.offendingToken, e) + + # This method is called to report a syntax error which requires the removal + # of a token from the input stream. At the time this method is called, the + # erroneous symbol is current {@code LT(1)} symbol and has not yet been + # removed from the input stream. When this method returns, + # {@code recognizer} is in error recovery mode. + # + #

          This method is called when {@link #singleTokenDeletion} identifies + # single-token deletion as a viable recovery strategy for a mismatched + # input error.

          + # + #

          The default implementation simply returns if the handler is already in + # error recovery mode. Otherwise, it calls {@link #beginErrorCondition} to + # enter error recovery mode, followed by calling + # {@link Parser#notifyErrorListeners}.

          + # + # @param recognizer the parser instance + # + def reportUnwantedToken(self, recognizer:Parser): + if self.inErrorRecoveryMode(recognizer): + return + + self.beginErrorCondition(recognizer) + t = recognizer.getCurrentToken() + tokenName = self.getTokenErrorDisplay(t) + expecting = self.getExpectedTokens(recognizer) + msg = "SyntacticError" + #+ tokenName + " expecting "+expecting.toString(recognizer.literalNames, recognizer.symbolicNames) + recognizer.notifyErrorListeners(msg, t, None) + + # This method is called to report a syntax error which requires the + # insertion of a missing token into the input stream. At the time this + # method is called, the missing token has not yet been inserted. When this + # method returns, {@code recognizer} is in error recovery mode. + # + #

          This method is called when {@link #singleTokenInsertion} identifies + # single-token insertion as a viable recovery strategy for a mismatched + # input error.

          + # + #

          The default implementation simply returns if the handler is already in + # error recovery mode. Otherwise, it calls {@link #beginErrorCondition} to + # enter error recovery mode, followed by calling + # {@link Parser#notifyErrorListeners}.

          + # + # @param recognizer the parser instance + # + def reportMissingToken(self, recognizer:Parser): + if self.inErrorRecoveryMode(recognizer): + return + self.beginErrorCondition(recognizer) + t = recognizer.getCurrentToken() + expecting = self.getExpectedTokens(recognizer) + msg = "missing " + expecting.toString(recognizer.literalNames, recognizer.symbolicNames) \ + + " at " + self.getTokenErrorDisplay(t) + recognizer.notifyErrorListeners(msg, t, None) + + #

          The default implementation attempts to recover from the mismatched input + # by using single token insertion and deletion as described below. If the + # recovery attempt fails, this method throws an + # {@link InputMismatchException}.

          + # + #

          EXTRA TOKEN (single token deletion)

          + # + #

          {@code LA(1)} is not what we are looking for. If {@code LA(2)} has the + # right token, however, then assume {@code LA(1)} is some extra spurious + # token and delete it. Then consume and return the next token (which was + # the {@code LA(2)} token) as the successful result of the match operation.

          + # + #

          This recovery strategy is implemented by {@link #singleTokenDeletion}.

          + # + #

          MISSING TOKEN (single token insertion)

          + # + #

          If current token (at {@code LA(1)}) is consistent with what could come + # after the expected {@code LA(1)} token, then assume the token is missing + # and use the parser's {@link TokenFactory} to create it on the fly. The + # "insertion" is performed by returning the created token as the successful + # result of the match operation.

          + # + #

          This recovery strategy is implemented by {@link #singleTokenInsertion}.

          + # + #

          EXAMPLE

          + # + #

          For example, Input {@code i=(3;} is clearly missing the {@code ')'}. When + # the parser returns from the nested call to {@code expr}, it will have + # call chain:

          + # + #
          +    # stat → expr → atom
          +    # 
          + # + # and it will be trying to match the {@code ')'} at this point in the + # derivation: + # + #
          +    # => ID '=' '(' INT ')' ('+' atom)* ';'
          +    #                    ^
          +    # 
          + # + # The attempt to match {@code ')'} will fail when it sees {@code ';'} and + # call {@link #recoverInline}. To recover, it sees that {@code LA(1)==';'} + # is in the set of tokens that can follow the {@code ')'} token reference + # in rule {@code atom}. It can assume that you forgot the {@code ')'}. + # + def recoverInline(self, recognizer:Parser): + # SINGLE TOKEN DELETION + matchedSymbol = self.singleTokenDeletion(recognizer) + if matchedSymbol is not None: + # we have deleted the extra token. + # now, move past ttype token as if all were ok + recognizer.consume() + return matchedSymbol + + # SINGLE TOKEN INSERTION + if self.singleTokenInsertion(recognizer): + return self.getMissingSymbol(recognizer) + + # even that didn't work; must throw the exception + raise InputMismatchException(recognizer) + + # + # This method implements the single-token insertion inline error recovery + # strategy. It is called by {@link #recoverInline} if the single-token + # deletion strategy fails to recover from the mismatched input. If this + # method returns {@code true}, {@code recognizer} will be in error recovery + # mode. + # + #

          This method determines whether or not single-token insertion is viable by + # checking if the {@code LA(1)} input symbol could be successfully matched + # if it were instead the {@code LA(2)} symbol. If this method returns + # {@code true}, the caller is responsible for creating and inserting a + # token with the correct type to produce this behavior.

          + # + # @param recognizer the parser instance + # @return {@code true} if single-token insertion is a viable recovery + # strategy for the current mismatched input, otherwise {@code false} + # + def singleTokenInsertion(self, recognizer:Parser): + currentSymbolType = recognizer.getTokenStream().LA(1) + # if current token is consistent with what could come after current + # ATN state, then we know we're missing a token; error recovery + # is free to conjure up and insert the missing token + atn = recognizer._interp.atn + currentState = atn.states[recognizer.state] + next = currentState.transitions[0].target + expectingAtLL2 = atn.nextTokens(next, recognizer._ctx) + if currentSymbolType in expectingAtLL2: + self.reportMissingToken(recognizer) + return True + else: + return False + + # This method implements the single-token deletion inline error recovery + # strategy. It is called by {@link #recoverInline} to attempt to recover + # from mismatched input. If this method returns null, the parser and error + # handler state will not have changed. If this method returns non-null, + # {@code recognizer} will not be in error recovery mode since the + # returned token was a successful match. + # + #

          If the single-token deletion is successful, this method calls + # {@link #reportUnwantedToken} to report the error, followed by + # {@link Parser#consume} to actually "delete" the extraneous token. Then, + # before returning {@link #reportMatch} is called to signal a successful + # match.

          + # + # @param recognizer the parser instance + # @return the successfully matched {@link Token} instance if single-token + # deletion successfully recovers from the mismatched input, otherwise + # {@code null} + # + def singleTokenDeletion(self, recognizer:Parser): + nextTokenType = recognizer.getTokenStream().LA(2) + expecting = self.getExpectedTokens(recognizer) + if nextTokenType in expecting: + self.reportUnwantedToken(recognizer) + # print("recoverFromMismatchedToken deleting " \ + # + str(recognizer.getTokenStream().LT(1)) \ + # + " since " + str(recognizer.getTokenStream().LT(2)) \ + # + " is what we want", file=sys.stderr) + recognizer.consume() # simply delete extra token + # we want to return the token we're actually matching + matchedSymbol = recognizer.getCurrentToken() + self.reportMatch(recognizer) # we know current token is correct + return matchedSymbol + else: + return None + + # Conjure up a missing token during error recovery. + # + # The recognizer attempts to recover from single missing + # symbols. But, actions might refer to that missing symbol. + # For example, x=ID {f($x);}. The action clearly assumes + # that there has been an identifier matched previously and that + # $x points at that token. If that token is missing, but + # the next token in the stream is what we want we assume that + # this token is missing and we keep going. Because we + # have to return some token to replace the missing token, + # we have to conjure one up. This method gives the user control + # over the tokens returned for missing tokens. Mostly, + # you will want to create something special for identifier + # tokens. For literals such as '{' and ',', the default + # action in the parser or tree parser works. It simply creates + # a CommonToken of the appropriate type. The text will be the token. + # If you change what tokens must be created by the lexer, + # override this method to create the appropriate tokens. + # + def getMissingSymbol(self, recognizer:Parser): + currentSymbol = recognizer.getCurrentToken() + expecting = self.getExpectedTokens(recognizer) + expectedTokenType = expecting[0] # get any element + if expectedTokenType==Token.EOF: + tokenText = "" + else: + name = None + if expectedTokenType < len(recognizer.literalNames): + name = recognizer.literalNames[expectedTokenType] + if name is None and expectedTokenType < len(recognizer.symbolicNames): + name = recognizer.symbolicNames[expectedTokenType] + tokenText = "" + current = currentSymbol + lookback = recognizer.getTokenStream().LT(-1) + if current.type==Token.EOF and lookback is not None: + current = lookback + return recognizer.getTokenFactory().create(current.source, + expectedTokenType, tokenText, Token.DEFAULT_CHANNEL, + -1, -1, current.line, current.column) + + def getExpectedTokens(self, recognizer:Parser): + return recognizer.getExpectedTokens() + + # How should a token be displayed in an error message? The default + # is to display just the text, but during development you might + # want to have a lot of information spit out. Override in that case + # to use t.toString() (which, for CommonToken, dumps everything about + # the token). This is better than forcing you to override a method in + # your token objects because you don't have to go modify your lexer + # so that it creates a new Java type. + # + def getTokenErrorDisplay(self, t:Token): + if t is None: + return "" + s = t.text + if s is None: + if t.type==Token.EOF: + s = "" + else: + s = "<" + str(t.type) + ">" + return self.escapeWSAndQuote(s) + + def escapeWSAndQuote(self, s:str): + s = s.replace("\n","\\n") + s = s.replace("\r","\\r") + s = s.replace("\t","\\t") + return "'" + s + "'" + + # Compute the error recovery set for the current rule. During + # rule invocation, the parser pushes the set of tokens that can + # follow that rule reference on the stack; this amounts to + # computing FIRST of what follows the rule reference in the + # enclosing rule. See LinearApproximator.FIRST(). + # This local follow set only includes tokens + # from within the rule; i.e., the FIRST computation done by + # ANTLR stops at the end of a rule. + # + # EXAMPLE + # + # When you find a "no viable alt exception", the input is not + # consistent with any of the alternatives for rule r. The best + # thing to do is to consume tokens until you see something that + # can legally follow a call to r#or* any rule that called r. + # You don't want the exact set of viable next tokens because the + # input might just be missing a token--you might consume the + # rest of the input looking for one of the missing tokens. + # + # Consider grammar: + # + # a : '[' b ']' + # | '(' b ')' + # ; + # b : c '^' INT ; + # c : ID + # | INT + # ; + # + # At each rule invocation, the set of tokens that could follow + # that rule is pushed on a stack. Here are the various + # context-sensitive follow sets: + # + # FOLLOW(b1_in_a) = FIRST(']') = ']' + # FOLLOW(b2_in_a) = FIRST(')') = ')' + # FOLLOW(c_in_b) = FIRST('^') = '^' + # + # Upon erroneous input "[]", the call chain is + # + # a -> b -> c + # + # and, hence, the follow context stack is: + # + # depth follow set start of rule execution + # 0 a (from main()) + # 1 ']' b + # 2 '^' c + # + # Notice that ')' is not included, because b would have to have + # been called from a different context in rule a for ')' to be + # included. + # + # For error recovery, we cannot consider FOLLOW(c) + # (context-sensitive or otherwise). We need the combined set of + # all context-sensitive FOLLOW sets--the set of all tokens that + # could follow any reference in the call chain. We need to + # resync to one of those tokens. Note that FOLLOW(c)='^' and if + # we resync'd to that token, we'd consume until EOF. We need to + # sync to context-sensitive FOLLOWs for a, b, and c: {']','^'}. + # In this case, for input "[]", LA(1) is ']' and in the set, so we would + # not consume anything. After printing an error, rule c would + # return normally. Rule b would not find the required '^' though. + # At this point, it gets a mismatched token error and throws an + # exception (since LA(1) is not in the viable following token + # set). The rule exception handler tries to recover, but finds + # the same recovery set and doesn't consume anything. Rule b + # exits normally returning to rule a. Now it finds the ']' (and + # with the successful match exits errorRecovery mode). + # + # So, you can see that the parser walks up the call chain looking + # for the token that was a member of the recovery set. + # + # Errors are not generated in errorRecovery mode. + # + # ANTLR's error recovery mechanism is based upon original ideas: + # + # "Algorithms + Data Structures = Programs" by Niklaus Wirth + # + # and + # + # "A note on error recovery in recursive descent parsers": + # http:#portal.acm.org/citation.cfm?id=947902.947905 + # + # Later, Josef Grosch had some good ideas: + # + # "Efficient and Comfortable Error Recovery in Recursive Descent + # Parsers": + # ftp:#www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip + # + # Like Grosch I implement context-sensitive FOLLOW sets that are combined + # at run-time upon error to avoid overhead during parsing. + # + def getErrorRecoverySet(self, recognizer:Parser): + atn = recognizer._interp.atn + ctx = recognizer._ctx + recoverSet = IntervalSet() + while ctx is not None and ctx.invokingState>=0: + # compute what follows who invoked us + invokingState = atn.states[ctx.invokingState] + rt = invokingState.transitions[0] + follow = atn.nextTokens(rt.followState) + recoverSet.addSet(follow) + ctx = ctx.parentCtx + recoverSet.removeOne(Token.EPSILON) + return recoverSet + + # Consume tokens until one matches the given token set.# + def consumeUntil(self, recognizer:Parser, set_:set): + ttype = recognizer.getTokenStream().LA(1) + while ttype != Token.EOF and not ttype in set_: + recognizer.consume() + ttype = recognizer.getTokenStream().LA(1) + + +# +# This implementation of {@link ANTLRErrorStrategy} responds to syntax errors +# by immediately canceling the parse operation with a +# {@link ParseCancellationException}. The implementation ensures that the +# {@link ParserRuleContext#exception} field is set for all parse tree nodes +# that were not completed prior to encountering the error. +# +#

          +# This error strategy is useful in the following scenarios.

          +# +#
            +#
          • Two-stage parsing: This error strategy allows the first +# stage of two-stage parsing to immediately terminate if an error is +# encountered, and immediately fall back to the second stage. In addition to +# avoiding wasted work by attempting to recover from errors here, the empty +# implementation of {@link BailErrorStrategy#sync} improves the performance of +# the first stage.
          • +#
          • Silent validation: When syntax errors are not being +# reported or logged, and the parse result is simply ignored if errors occur, +# the {@link BailErrorStrategy} avoids wasting work on recovering from errors +# when the result will be ignored either way.
          • +#
          +# +#

          +# {@code myparser.setErrorHandler(new BailErrorStrategy());}

          +# +# @see Parser#setErrorHandler(ANTLRErrorStrategy) +# +class BailErrorStrategy(DefaultErrorStrategy): + # Instead of recovering from exception {@code e}, re-throw it wrapped + # in a {@link ParseCancellationException} so it is not caught by the + # rule function catches. Use {@link Exception#getCause()} to get the + # original {@link RecognitionException}. + # + def recover(self, recognizer:Parser, e:RecognitionException): + context = recognizer._ctx + while context is not None: + context.exception = e + context = context.parentCtx + raise ParseCancellationException(e) + + # Make sure we don't attempt to recover inline; if the parser + # successfully recovers, it won't throw an exception. + # + def recoverInline(self, recognizer:Parser): + self.recover(recognizer, InputMismatchException(recognizer)) + + # Make sure we don't attempt to recover from problems in subrules.# + def sync(self, recognizer:Parser): + pass + +del Parser \ No newline at end of file diff --git a/src/antlr4/error/Errors.py b/src/antlr4/error/Errors.py new file mode 100644 index 00000000..e78ac059 --- /dev/null +++ b/src/antlr4/error/Errors.py @@ -0,0 +1,172 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# need forward declaration +Token = None +Lexer = None +Parser = None +TokenStream = None +ATNConfigSet = None +ParserRulecontext = None +PredicateTransition = None +BufferedTokenStream = None + +class UnsupportedOperationException(Exception): + + def __init__(self, msg:str): + super().__init__(msg) + +class IllegalStateException(Exception): + + def __init__(self, msg:str): + super().__init__(msg) + +class CancellationException(IllegalStateException): + + def __init__(self, msg:str): + super().__init__(msg) + +# The root of the ANTLR exception hierarchy. In general, ANTLR tracks just +# 3 kinds of errors: prediction errors, failed predicate errors, and +# mismatched input errors. In each case, the parser knows where it is +# in the input, where it is in the ATN, the rule invocation stack, +# and what kind of problem occurred. + +from antlr4.InputStream import InputStream +from antlr4.ParserRuleContext import ParserRuleContext +from antlr4.Recognizer import Recognizer + +class RecognitionException(Exception): + + + def __init__(self, message:str=None, recognizer:Recognizer=None, input:InputStream=None, ctx:ParserRulecontext=None): + super().__init__(message) + self.message = message + self.recognizer = recognizer + self.input = input + self.ctx = ctx + # The current {@link Token} when an error occurred. Since not all streams + # support accessing symbols by index, we have to track the {@link Token} + # instance itself. + self.offendingToken = None + # Get the ATN state number the parser was in at the time the error + # occurred. For {@link NoViableAltException} and + # {@link LexerNoViableAltException} exceptions, this is the + # {@link DecisionState} number. For others, it is the state whose outgoing + # edge we couldn't match. + self.offendingState = -1 + if recognizer is not None: + self.offendingState = recognizer.state + + #

          If the state number is not known, this method returns -1.

          + + # + # Gets the set of input symbols which could potentially follow the + # previously matched symbol at the time this exception was thrown. + # + #

          If the set of expected tokens is not known and could not be computed, + # this method returns {@code null}.

          + # + # @return The set of token types that could potentially follow the current + # state in the ATN, or {@code null} if the information is not available. + #/ + def getExpectedTokens(self): + if self.recognizer is not None: + return self.recognizer.atn.getExpectedTokens(self.offendingState, self.ctx) + else: + return None + + +class LexerNoViableAltException(RecognitionException): + + def __init__(self, lexer:Lexer, input:InputStream, startIndex:int, deadEndConfigs:ATNConfigSet): + super().__init__(message=None, recognizer=lexer, input=input, ctx=None) + self.startIndex = startIndex + self.deadEndConfigs = deadEndConfigs + + def __str__(self): + symbol = "" + if self.startIndex >= 0 and self.startIndex < self.input.size: + symbol = self.input.getText(self.startIndex, self.startIndex) + # TODO symbol = Utils.escapeWhitespace(symbol, false); + return "LexerNoViableAltException('" + symbol + "')" + +# Indicates that the parser could not decide which of two or more paths +# to take based upon the remaining input. It tracks the starting token +# of the offending input and also knows where the parser was +# in the various paths when the error. Reported by reportNoViableAlternative() +# +class NoViableAltException(RecognitionException): + + def __init__(self, recognizer:Parser, input:TokenStream=None, startToken:Token=None, + offendingToken:Token=None, deadEndConfigs:ATNConfigSet=None, ctx:ParserRuleContext=None): + if ctx is None: + ctx = recognizer._ctx + if offendingToken is None: + offendingToken = recognizer.getCurrentToken() + if startToken is None: + startToken = recognizer.getCurrentToken() + if input is None: + input = recognizer.getInputStream() + super().__init__(recognizer=recognizer, input=input, ctx=ctx) + # Which configurations did we try at input.index() that couldn't match input.LT(1)?# + self.deadEndConfigs = deadEndConfigs + # The token object at the start index; the input stream might + # not be buffering tokens so get a reference to it. (At the + # time the error occurred, of course the stream needs to keep a + # buffer all of the tokens but later we might not have access to those.) + self.startToken = startToken + self.offendingToken = offendingToken + +# This signifies any kind of mismatched input exceptions such as +# when the current input does not match the expected token. +# +class InputMismatchException(RecognitionException): + + def __init__(self, recognizer:Parser): + super().__init__(recognizer=recognizer, input=recognizer.getInputStream(), ctx=recognizer._ctx) + self.offendingToken = recognizer.getCurrentToken() + + +# A semantic predicate failed during validation. Validation of predicates +# occurs when normally parsing the alternative just like matching a token. +# Disambiguating predicate evaluation occurs when we test a predicate during +# prediction. + +class FailedPredicateException(RecognitionException): + + def __init__(self, recognizer:Parser, predicate:str=None, message:str=None): + super().__init__(message=self.formatMessage(predicate,message), recognizer=recognizer, + input=recognizer.getInputStream(), ctx=recognizer._ctx) + s = recognizer._interp.atn.states[recognizer.state] + trans = s.transitions[0] + from antlr4.atn.Transition import PredicateTransition + if isinstance(trans, PredicateTransition): + self.ruleIndex = trans.ruleIndex + self.predicateIndex = trans.predIndex + else: + self.ruleIndex = 0 + self.predicateIndex = 0 + self.predicate = predicate + self.offendingToken = recognizer.getCurrentToken() + + def formatMessage(self, predicate:str, message:str): + if message is not None: + return message + else: + return "failed predicate: {" + predicate + "}?" + +class ParseCancellationException(CancellationException): + + pass + +del Token +del Lexer +del Parser +del TokenStream +del ATNConfigSet +del ParserRulecontext +del PredicateTransition +del BufferedTokenStream diff --git a/src/antlr4/error/__init__.py b/src/antlr4/error/__init__.py new file mode 100644 index 00000000..216c000d --- /dev/null +++ b/src/antlr4/error/__init__.py @@ -0,0 +1 @@ +__author__ = 'ericvergnaud' diff --git a/src/antlr4/tree/Chunk.py b/src/antlr4/tree/Chunk.py new file mode 100644 index 00000000..a2fd16c9 --- /dev/null +++ b/src/antlr4/tree/Chunk.py @@ -0,0 +1,29 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +class Chunk(object): + pass + +class TagChunk(Chunk): + + def __init__(self, tag:str, label:str=None): + self.tag = tag + self.label = label + + def __str__(self): + if self.label is None: + return self.tag + else: + return self.label + ":" + self.tag + +class TextChunk(Chunk): + + def __init__(self, text:str): + self.text = text + + def __str__(self): + return "'" + self.text + "'" + diff --git a/src/antlr4/tree/ParseTreeMatch.py b/src/antlr4/tree/ParseTreeMatch.py new file mode 100644 index 00000000..bbda73e8 --- /dev/null +++ b/src/antlr4/tree/ParseTreeMatch.py @@ -0,0 +1,118 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + + +# +# Represents the result of matching a {@link ParseTree} against a tree pattern. +# +from io import StringIO +from antlr4.tree.ParseTreePattern import ParseTreePattern +from antlr4.tree.Tree import ParseTree + + +class ParseTreeMatch(object): + + # + # Constructs a new instance of {@link ParseTreeMatch} from the specified + # parse tree and pattern. + # + # @param tree The parse tree to match against the pattern. + # @param pattern The parse tree pattern. + # @param labels A mapping from label names to collections of + # {@link ParseTree} objects located by the tree pattern matching process. + # @param mismatchedNode The first node which failed to match the tree + # pattern during the matching process. + # + # @exception IllegalArgumentException if {@code tree} is {@code null} + # @exception IllegalArgumentException if {@code pattern} is {@code null} + # @exception IllegalArgumentException if {@code labels} is {@code null} + # + def __init__(self, tree:ParseTree, pattern:ParseTreePattern, labels:dict, mismatchedNode:ParseTree): + if tree is None: + raise Exception("tree cannot be null") + if pattern is None: + raise Exception("pattern cannot be null") + if labels is None: + raise Exception("labels cannot be null") + self.tree = tree + self.pattern = pattern + self.labels = labels + self.mismatchedNode = mismatchedNode + + # + # Get the last node associated with a specific {@code label}. + # + #

          For example, for pattern {@code }, {@code get("id")} returns the + # node matched for that {@code ID}. If more than one node + # matched the specified label, only the last is returned. If there is + # no node associated with the label, this returns {@code null}.

          + # + #

          Pattern tags like {@code } and {@code } without labels are + # considered to be labeled with {@code ID} and {@code expr}, respectively.

          + # + # @param label The label to check. + # + # @return The last {@link ParseTree} to match a tag with the specified + # label, or {@code null} if no parse tree matched a tag with the label. + # + def get(self, label:str): + parseTrees = self.labels.get(label, None) + if parseTrees is None or len(parseTrees)==0: + return None + else: + return parseTrees[len(parseTrees)-1] + + # + # Return all nodes matching a rule or token tag with the specified label. + # + #

          If the {@code label} is the name of a parser rule or token in the + # grammar, the resulting list will contain both the parse trees matching + # rule or tags explicitly labeled with the label and the complete set of + # parse trees matching the labeled and unlabeled tags in the pattern for + # the parser rule or token. For example, if {@code label} is {@code "foo"}, + # the result will contain all of the following.

          + # + #
            + #
          • Parse tree nodes matching tags of the form {@code } and + # {@code }.
          • + #
          • Parse tree nodes matching tags of the form {@code }.
          • + #
          • Parse tree nodes matching tags of the form {@code }.
          • + #
          + # + # @param label The label. + # + # @return A collection of all {@link ParseTree} nodes matching tags with + # the specified {@code label}. If no nodes matched the label, an empty list + # is returned. + # + def getAll(self, label:str): + nodes = self.labels.get(label, None) + if nodes is None: + return list() + else: + return nodes + + + # + # Gets a value indicating whether the match operation succeeded. + # + # @return {@code true} if the match operation succeeded; otherwise, + # {@code false}. + # + def succeeded(self): + return self.mismatchedNode is None + + # + # {@inheritDoc} + # + def __str__(self): + with StringIO() as buf: + buf.write("Match ") + buf.write("succeeded" if self.succeeded() else "failed") + buf.write("; found ") + buf.write(str(len(self.labels))) + buf.write(" labels") + return buf.getvalue() diff --git a/src/antlr4/tree/ParseTreePattern.py b/src/antlr4/tree/ParseTreePattern.py new file mode 100644 index 00000000..1abb880d --- /dev/null +++ b/src/antlr4/tree/ParseTreePattern.py @@ -0,0 +1,71 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# A pattern like {@code = ;} converted to a {@link ParseTree} by +# {@link ParseTreePatternMatcher#compile(String, int)}. +# +from antlr4.tree.ParseTreePatternMatcher import ParseTreePatternMatcher +from antlr4.tree.Tree import ParseTree +from antlr4.xpath.XPath import XPath + + +class ParseTreePattern(object): + + # Construct a new instance of the {@link ParseTreePattern} class. + # + # @param matcher The {@link ParseTreePatternMatcher} which created this + # tree pattern. + # @param pattern The tree pattern in concrete syntax form. + # @param patternRuleIndex The parser rule which serves as the root of the + # tree pattern. + # @param patternTree The tree pattern in {@link ParseTree} form. + # + def __init__(self, matcher:ParseTreePatternMatcher, pattern:str, patternRuleIndex:int , patternTree:ParseTree): + self.matcher = matcher + self.patternRuleIndex = patternRuleIndex + self.pattern = pattern + self.patternTree = patternTree + + # + # Match a specific parse tree against this tree pattern. + # + # @param tree The parse tree to match against this tree pattern. + # @return A {@link ParseTreeMatch} object describing the result of the + # match operation. The {@link ParseTreeMatch#succeeded()} method can be + # used to determine whether or not the match was successful. + # + def match(self, tree:ParseTree): + return self.matcher.match(tree, self) + + # + # Determine whether or not a parse tree matches this tree pattern. + # + # @param tree The parse tree to match against this tree pattern. + # @return {@code true} if {@code tree} is a match for the current tree + # pattern; otherwise, {@code false}. + # + def matches(self, tree:ParseTree): + return self.matcher.match(tree, self).succeeded() + + # Find all nodes using XPath and then try to match those subtrees against + # this tree pattern. + # + # @param tree The {@link ParseTree} to match against this pattern. + # @param xpath An expression matching the nodes + # + # @return A collection of {@link ParseTreeMatch} objects describing the + # successful matches. Unsuccessful matches are omitted from the result, + # regardless of the reason for the failure. + # + def findAll(self, tree:ParseTree, xpath:str): + subtrees = XPath.findAll(tree, xpath, self.matcher.parser) + matches = list() + for t in subtrees: + match = self.match(t) + if match.succeeded(): + matches.append(match) + return matches diff --git a/src/antlr4/tree/ParseTreePatternMatcher.py b/src/antlr4/tree/ParseTreePatternMatcher.py new file mode 100644 index 00000000..07b96408 --- /dev/null +++ b/src/antlr4/tree/ParseTreePatternMatcher.py @@ -0,0 +1,373 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# A tree pattern matching mechanism for ANTLR {@link ParseTree}s. +# +#

          Patterns are strings of source input text with special tags representing +# token or rule references such as:

          +# +#

          {@code = ;}

          +# +#

          Given a pattern start rule such as {@code statement}, this object constructs +# a {@link ParseTree} with placeholders for the {@code ID} and {@code expr} +# subtree. Then the {@link #match} routines can compare an actual +# {@link ParseTree} from a parse with this pattern. Tag {@code } matches +# any {@code ID} token and tag {@code } references the result of the +# {@code expr} rule (generally an instance of {@code ExprContext}.

          +# +#

          Pattern {@code x = 0;} is a similar pattern that matches the same pattern +# except that it requires the identifier to be {@code x} and the expression to +# be {@code 0}.

          +# +#

          The {@link #matches} routines return {@code true} or {@code false} based +# upon a match for the tree rooted at the parameter sent in. The +# {@link #match} routines return a {@link ParseTreeMatch} object that +# contains the parse tree, the parse tree pattern, and a map from tag name to +# matched nodes (more below). A subtree that fails to match, returns with +# {@link ParseTreeMatch#mismatchedNode} set to the first tree node that did not +# match.

          +# +#

          For efficiency, you can compile a tree pattern in string form to a +# {@link ParseTreePattern} object.

          +# +#

          See {@code TestParseTreeMatcher} for lots of examples. +# {@link ParseTreePattern} has two static helper methods: +# {@link ParseTreePattern#findAll} and {@link ParseTreePattern#match} that +# are easy to use but not super efficient because they create new +# {@link ParseTreePatternMatcher} objects each time and have to compile the +# pattern in string form before using it.

          +# +#

          The lexer and parser that you pass into the {@link ParseTreePatternMatcher} +# constructor are used to parse the pattern in string form. The lexer converts +# the {@code = ;} into a sequence of four tokens (assuming lexer +# throws out whitespace or puts it on a hidden channel). Be aware that the +# input stream is reset for the lexer (but not the parser; a +# {@link ParserInterpreter} is created to parse the input.). Any user-defined +# fields you have put into the lexer might get changed when this mechanism asks +# it to scan the pattern string.

          +# +#

          Normally a parser does not accept token {@code } as a valid +# {@code expr} but, from the parser passed in, we create a special version of +# the underlying grammar representation (an {@link ATN}) that allows imaginary +# tokens representing rules ({@code }) to match entire rules. We call +# these bypass alternatives.

          +# +#

          Delimiters are {@code <} and {@code >}, with {@code \} as the escape string +# by default, but you can set them to whatever you want using +# {@link #setDelimiters}. You must escape both start and stop strings +# {@code \<} and {@code \>}.

          +# +from antlr4.CommonTokenStream import CommonTokenStream +from antlr4.InputStream import InputStream +from antlr4.ParserRuleContext import ParserRuleContext +from antlr4.Lexer import Lexer +from antlr4.ListTokenSource import ListTokenSource +from antlr4.Token import Token +from antlr4.error.ErrorStrategy import BailErrorStrategy +from antlr4.error.Errors import RecognitionException, ParseCancellationException +from antlr4.tree.Chunk import TagChunk, TextChunk +from antlr4.tree.RuleTagToken import RuleTagToken +from antlr4.tree.TokenTagToken import TokenTagToken +from antlr4.tree.Tree import ParseTree, TerminalNode, RuleNode + +# need forward declaration +Parser = None +ParseTreePattern = None + +class CannotInvokeStartRule(Exception): + + def __init__(self, e:Exception): + super().__init__(e) + +class StartRuleDoesNotConsumeFullPattern(Exception): + + pass + + +class ParseTreePatternMatcher(object): + + # Constructs a {@link ParseTreePatternMatcher} or from a {@link Lexer} and + # {@link Parser} object. The lexer input stream is altered for tokenizing + # the tree patterns. The parser is used as a convenient mechanism to get + # the grammar name, plus token, rule names. + def __init__(self, lexer:Lexer, parser:Parser): + self.lexer = lexer + self.parser = parser + self.start = "<" + self.stop = ">" + self.escape = "\\" # e.g., \< and \> must escape BOTH! + + # Set the delimiters used for marking rule and token tags within concrete + # syntax used by the tree pattern parser. + # + # @param start The start delimiter. + # @param stop The stop delimiter. + # @param escapeLeft The escape sequence to use for escaping a start or stop delimiter. + # + # @exception IllegalArgumentException if {@code start} is {@code null} or empty. + # @exception IllegalArgumentException if {@code stop} is {@code null} or empty. + # + def setDelimiters(self, start:str, stop:str, escapeLeft:str): + if start is None or len(start)==0: + raise Exception("start cannot be null or empty") + if stop is None or len(stop)==0: + raise Exception("stop cannot be null or empty") + self.start = start + self.stop = stop + self.escape = escapeLeft + + # Does {@code pattern} matched as rule {@code patternRuleIndex} match {@code tree}?# + def matchesRuleIndex(self, tree:ParseTree, pattern:str, patternRuleIndex:int): + p = self.compileTreePattern(pattern, patternRuleIndex) + return self.matches(tree, p) + + # Does {@code pattern} matched as rule patternRuleIndex match tree? Pass in a + # compiled pattern instead of a string representation of a tree pattern. + # + def matchesPattern(self, tree:ParseTree, pattern:ParseTreePattern): + mismatchedNode = self.matchImpl(tree, pattern.patternTree, dict()) + return mismatchedNode is None + + # + # Compare {@code pattern} matched as rule {@code patternRuleIndex} against + # {@code tree} and return a {@link ParseTreeMatch} object that contains the + # matched elements, or the node at which the match failed. + # + def matchRuleIndex(self, tree:ParseTree, pattern:str, patternRuleIndex:int): + p = self.compileTreePattern(pattern, patternRuleIndex) + return self.matchPattern(tree, p) + + # + # Compare {@code pattern} matched against {@code tree} and return a + # {@link ParseTreeMatch} object that contains the matched elements, or the + # node at which the match failed. Pass in a compiled pattern instead of a + # string representation of a tree pattern. + # + def matchPattern(self, tree:ParseTree, pattern:ParseTreePattern): + labels = dict() + mismatchedNode = self.matchImpl(tree, pattern.patternTree, labels) + from antlr4.tree.ParseTreeMatch import ParseTreeMatch + return ParseTreeMatch(tree, pattern, labels, mismatchedNode) + + # + # For repeated use of a tree pattern, compile it to a + # {@link ParseTreePattern} using this method. + # + def compileTreePattern(self, pattern:str, patternRuleIndex:int): + tokenList = self.tokenize(pattern) + tokenSrc = ListTokenSource(tokenList) + tokens = CommonTokenStream(tokenSrc) + from antlr4.ParserInterpreter import ParserInterpreter + parserInterp = ParserInterpreter(self.parser.grammarFileName, self.parser.tokenNames, + self.parser.ruleNames, self.parser.getATNWithBypassAlts(),tokens) + tree = None + try: + parserInterp.setErrorHandler(BailErrorStrategy()) + tree = parserInterp.parse(patternRuleIndex) + except ParseCancellationException as e: + raise e.cause + except RecognitionException as e: + raise e + except Exception as e: + raise CannotInvokeStartRule(e) + + # Make sure tree pattern compilation checks for a complete parse + if tokens.LA(1)!=Token.EOF: + raise StartRuleDoesNotConsumeFullPattern() + + from antlr4.tree.ParseTreePattern import ParseTreePattern + return ParseTreePattern(self, pattern, patternRuleIndex, tree) + + # + # Recursively walk {@code tree} against {@code patternTree}, filling + # {@code match.}{@link ParseTreeMatch#labels labels}. + # + # @return the first node encountered in {@code tree} which does not match + # a corresponding node in {@code patternTree}, or {@code null} if the match + # was successful. The specific node returned depends on the matching + # algorithm used by the implementation, and may be overridden. + # + def matchImpl(self, tree:ParseTree, patternTree:ParseTree, labels:dict): + if tree is None: + raise Exception("tree cannot be null") + if patternTree is None: + raise Exception("patternTree cannot be null") + + # x and , x and y, or x and x; or could be mismatched types + if isinstance(tree, TerminalNode) and isinstance(patternTree, TerminalNode ): + mismatchedNode = None + # both are tokens and they have same type + if tree.symbol.type == patternTree.symbol.type: + if isinstance( patternTree.symbol, TokenTagToken ): # x and + tokenTagToken = patternTree.symbol + # track label->list-of-nodes for both token name and label (if any) + self.map(labels, tokenTagToken.tokenName, tree) + if tokenTagToken.label is not None: + self.map(labels, tokenTagToken.label, tree) + elif tree.getText()==patternTree.getText(): + # x and x + pass + else: + # x and y + if mismatchedNode is None: + mismatchedNode = tree + else: + if mismatchedNode is None: + mismatchedNode = tree + + return mismatchedNode + + if isinstance(tree, ParserRuleContext) and isinstance(patternTree, ParserRuleContext): + mismatchedNode = None + # (expr ...) and + ruleTagToken = self.getRuleTagToken(patternTree) + if ruleTagToken is not None: + m = None + if tree.ruleContext.ruleIndex == patternTree.ruleContext.ruleIndex: + # track label->list-of-nodes for both rule name and label (if any) + self.map(labels, ruleTagToken.ruleName, tree) + if ruleTagToken.label is not None: + self.map(labels, ruleTagToken.label, tree) + else: + if mismatchedNode is None: + mismatchedNode = tree + + return mismatchedNode + + # (expr ...) and (expr ...) + if tree.getChildCount()!=patternTree.getChildCount(): + if mismatchedNode is None: + mismatchedNode = tree + return mismatchedNode + + n = tree.getChildCount() + for i in range(0, n): + childMatch = self.matchImpl(tree.getChild(i), patternTree.getChild(i), labels) + if childMatch is not None: + return childMatch + + return mismatchedNode + + # if nodes aren't both tokens or both rule nodes, can't match + return tree + + def map(self, labels, label, tree): + v = labels.get(label, None) + if v is None: + v = list() + labels[label] = v + v.append(tree) + + # Is {@code t} {@code (expr )} subtree?# + def getRuleTagToken(self, tree:ParseTree): + if isinstance( tree, RuleNode ): + if tree.getChildCount()==1 and isinstance(tree.getChild(0), TerminalNode ): + c = tree.getChild(0) + if isinstance( c.symbol, RuleTagToken ): + return c.symbol + return None + + def tokenize(self, pattern:str): + # split pattern into chunks: sea (raw input) and islands (, ) + chunks = self.split(pattern) + + # create token stream from text and tags + tokens = list() + for chunk in chunks: + if isinstance( chunk, TagChunk ): + # add special rule token or conjure up new token from name + if chunk.tag[0].isupper(): + ttype = self.parser.getTokenType(chunk.tag) + if ttype==Token.INVALID_TYPE: + raise Exception("Unknown token " + str(chunk.tag) + " in pattern: " + pattern) + tokens.append(TokenTagToken(chunk.tag, ttype, chunk.label)) + elif chunk.tag[0].islower(): + ruleIndex = self.parser.getRuleIndex(chunk.tag) + if ruleIndex==-1: + raise Exception("Unknown rule " + str(chunk.tag) + " in pattern: " + pattern) + ruleImaginaryTokenType = self.parser.getATNWithBypassAlts().ruleToTokenType[ruleIndex] + tokens.append(RuleTagToken(chunk.tag, ruleImaginaryTokenType, chunk.label)) + else: + raise Exception("invalid tag: " + str(chunk.tag) + " in pattern: " + pattern) + else: + self.lexer.setInputStream(InputStream(chunk.text)) + t = self.lexer.nextToken() + while t.type!=Token.EOF: + tokens.append(t) + t = self.lexer.nextToken() + return tokens + + # Split {@code = ;} into 4 chunks for tokenizing by {@link #tokenize}.# + def split(self, pattern:str): + p = 0 + n = len(pattern) + chunks = list() + # find all start and stop indexes first, then collect + starts = list() + stops = list() + while p < n : + if p == pattern.find(self.escape + self.start, p): + p += len(self.escape) + len(self.start) + elif p == pattern.find(self.escape + self.stop, p): + p += len(self.escape) + len(self.stop) + elif p == pattern.find(self.start, p): + starts.append(p) + p += len(self.start) + elif p == pattern.find(self.stop, p): + stops.append(p) + p += len(self.stop) + else: + p += 1 + + nt = len(starts) + + if nt > len(stops): + raise Exception("unterminated tag in pattern: " + pattern) + if nt < len(stops): + raise Exception("missing start tag in pattern: " + pattern) + + for i in range(0, nt): + if starts[i] >= stops[i]: + raise Exception("tag delimiters out of order in pattern: " + pattern) + + # collect into chunks now + if nt==0: + chunks.append(TextChunk(pattern)) + + if nt>0 and starts[0]>0: # copy text up to first tag into chunks + text = pattern[0:starts[0]] + chunks.add(TextChunk(text)) + + for i in range(0, nt): + # copy inside of + tag = pattern[starts[i] + len(self.start) : stops[i]] + ruleOrToken = tag + label = None + colon = tag.find(':') + if colon >= 0: + label = tag[0:colon] + ruleOrToken = tag[colon+1 : len(tag)] + chunks.append(TagChunk(label, ruleOrToken)) + if i+1 < len(starts): + # copy from end of to start of next + text = pattern[stops[i] + len(self.stop) : starts[i + 1]] + chunks.append(TextChunk(text)) + + if nt > 0 : + afterLastTag = stops[nt - 1] + len(self.stop) + if afterLastTag < n : # copy text from end of last tag to end + text = pattern[afterLastTag : n] + chunks.append(TextChunk(text)) + + # strip out the escape sequences from text chunks but not tags + for i in range(0, len(chunks)): + c = chunks[i] + if isinstance( c, TextChunk ): + unescaped = c.text.replace(self.escape, "") + if len(unescaped) < len(c.text): + chunks[i] = TextChunk(unescaped) + return chunks diff --git a/src/antlr4/tree/RuleTagToken.py b/src/antlr4/tree/RuleTagToken.py new file mode 100644 index 00000000..7b2018fe --- /dev/null +++ b/src/antlr4/tree/RuleTagToken.py @@ -0,0 +1,49 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# A {@link Token} object representing an entire subtree matched by a parser +# rule; e.g., {@code }. These tokens are created for {@link TagChunk} +# chunks where the tag corresponds to a parser rule. +# +from antlr4.Token import Token + + +class RuleTagToken(Token): + # + # Constructs a new instance of {@link RuleTagToken} with the specified rule + # name, bypass token type, and label. + # + # @param ruleName The name of the parser rule this rule tag matches. + # @param bypassTokenType The bypass token type assigned to the parser rule. + # @param label The label associated with the rule tag, or {@code null} if + # the rule tag is unlabeled. + # + # @exception IllegalArgumentException if {@code ruleName} is {@code null} + # or empty. + + def __init__(self, ruleName:str, bypassTokenType:int, label:str=None): + if ruleName is None or len(ruleName)==0: + raise Exception("ruleName cannot be null or empty.") + self.source = None + self.type = bypassTokenType # token type of the token + self.channel = Token.DEFAULT_CHANNEL # The parser ignores everything not on DEFAULT_CHANNEL + self.start = -1 # optional; return -1 if not implemented. + self.stop = -1 # optional; return -1 if not implemented. + self.tokenIndex = -1 # from 0..n-1 of the token object in the input stream + self.line = 0 # line=1..n of the 1st character + self.column = -1 # beginning of the line at which it occurs, 0..n-1 + self.label = label + self._text = self.getText() # text of the token. + + self.ruleName = ruleName + + + def getText(self): + if self.label is None: + return "<" + self.ruleName + ">" + else: + return "<" + self.label + ":" + self.ruleName + ">" diff --git a/src/antlr4/tree/TokenTagToken.py b/src/antlr4/tree/TokenTagToken.py new file mode 100644 index 00000000..d00327ae --- /dev/null +++ b/src/antlr4/tree/TokenTagToken.py @@ -0,0 +1,47 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# A {@link Token} object representing a token of a particular type; e.g., +# {@code }. These tokens are created for {@link TagChunk} chunks where the +# tag corresponds to a lexer rule or token type. +# +from antlr4.Token import CommonToken + + +class TokenTagToken(CommonToken): + + # Constructs a new instance of {@link TokenTagToken} with the specified + # token name, type, and label. + # + # @param tokenName The token name. + # @param type The token type. + # @param label The label associated with the token tag, or {@code null} if + # the token tag is unlabeled. + # + def __init__(self, tokenName:str, type:int, label:str=None): + super().__init__(type=type) + self.tokenName = tokenName + self.label = label + self._text = self.getText() + + # + # {@inheritDoc} + # + #

          The implementation for {@link TokenTagToken} returns the token tag + # formatted with {@code <} and {@code >} delimiters.

          + # + def getText(self): + if self.label is None: + return "<" + self.tokenName + ">" + else: + return "<" + self.label + ":" + self.tokenName + ">" + + #

          The implementation for {@link TokenTagToken} returns a string of the form + # {@code tokenName:type}.

          + # + def __str__(self): + return self.tokenName + ":" + str(self.type) diff --git a/src/antlr4/tree/Tree.py b/src/antlr4/tree/Tree.py new file mode 100644 index 00000000..2b9db2d1 --- /dev/null +++ b/src/antlr4/tree/Tree.py @@ -0,0 +1,170 @@ +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +#/ + + +# The basic notion of a tree has a parent, a payload, and a list of children. +# It is the most abstract interface for all the trees used by ANTLR. +#/ +from antlr4.Token import Token + +INVALID_INTERVAL = (-1, -2) + +class Tree(object): + pass + +class SyntaxTree(Tree): + pass + +class ParseTree(SyntaxTree): + pass + +class RuleNode(ParseTree): + pass + +class TerminalNode(ParseTree): + pass + +class ErrorNode(TerminalNode): + pass + +class ParseTreeVisitor(object): + def visit(self, tree): + return tree.accept(self) + + def visitChildren(self, node): + result = self.defaultResult() + n = node.getChildCount() + for i in range(n): + if not self.shouldVisitNextChild(node, result): + return result + + c = node.getChild(i) + childResult = c.accept(self) + result = self.aggregateResult(result, childResult) + + return result + + def visitTerminal(self, node): + return self.defaultResult() + + def visitErrorNode(self, node): + return self.defaultResult() + + def defaultResult(self): + return None + + def aggregateResult(self, aggregate, nextResult): + return nextResult + + def shouldVisitNextChild(self, node, currentResult): + return True + +ParserRuleContext = None + +class ParseTreeListener(object): + + def visitTerminal(self, node:TerminalNode): + pass + + def visitErrorNode(self, node:ErrorNode): + pass + + def enterEveryRule(self, ctx:ParserRuleContext): + pass + + def exitEveryRule(self, ctx:ParserRuleContext): + pass + +del ParserRuleContext + +class TerminalNodeImpl(TerminalNode): + + def __init__(self, symbol:Token): + self.parentCtx = None + self.symbol = symbol + def __setattr__(self, key, value): + super().__setattr__(key, value) + + def getChild(self, i:int): + return None + + def getSymbol(self): + return self.symbol + + def getParent(self): + return self.parentCtx + + def getPayload(self): + return self.symbol + + def getSourceInterval(self): + if self.symbol is None: + return INVALID_INTERVAL + tokenIndex = self.symbol.tokenIndex + return (tokenIndex, tokenIndex) + + def getChildCount(self): + return 0 + + def accept(self, visitor:ParseTreeVisitor): + return visitor.visitTerminal(self) + + def getText(self): + return self.symbol.text + + def __str__(self): + if self.symbol.type == Token.EOF: + return "" + else: + return self.symbol.text + +# Represents a token that was consumed during resynchronization +# rather than during a valid match operation. For example, +# we will create this kind of a node during single token insertion +# and deletion as well as during "consume until error recovery set" +# upon no viable alternative exceptions. + +class ErrorNodeImpl(TerminalNodeImpl,ErrorNode): + + def __init__(self, token:Token): + super().__init__(token) + + def accept(self, visitor:ParseTreeVisitor): + return visitor.visitErrorNode(self) + + +class ParseTreeWalker(object): + + DEFAULT = None + + def walk(self, listener:ParseTreeListener, t:ParseTree): + if isinstance(t, ErrorNode): + listener.visitErrorNode(t) + return + elif isinstance(t, TerminalNode): + listener.visitTerminal(t) + return + self.enterRule(listener, t) + for child in t.getChildren(): + self.walk(listener, child) + self.exitRule(listener, t) + + # + # The discovery of a rule node, involves sending two events: the generic + # {@link ParseTreeListener#enterEveryRule} and a + # {@link RuleContext}-specific event. First we trigger the generic and then + # the rule specific. We to them in reverse order upon finishing the node. + # + def enterRule(self, listener:ParseTreeListener, r:RuleNode): + ctx = r.getRuleContext() + listener.enterEveryRule(ctx) + ctx.enterRule(listener) + + def exitRule(self, listener:ParseTreeListener, r:RuleNode): + ctx = r.getRuleContext() + ctx.exitRule(listener) + listener.exitEveryRule(ctx) + +ParseTreeWalker.DEFAULT = ParseTreeWalker() \ No newline at end of file diff --git a/src/antlr4/tree/Trees.py b/src/antlr4/tree/Trees.py new file mode 100644 index 00000000..686b8cb2 --- /dev/null +++ b/src/antlr4/tree/Trees.py @@ -0,0 +1,111 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + + +# A set of utility routines useful for all kinds of ANTLR trees.# +from io import StringIO +from antlr4.Token import Token +from antlr4.Utils import escapeWhitespace +from antlr4.tree.Tree import RuleNode, ErrorNode, TerminalNode, Tree, ParseTree + +# need forward declaration +Parser = None + +class Trees(object): + + # Print out a whole tree in LISP form. {@link #getNodeText} is used on the + # node payloads to get the text for the nodes. Detect + # parse trees and extract data appropriately. + @classmethod + def toStringTree(cls, t:Tree, ruleNames:list=None, recog:Parser=None): + if recog is not None: + ruleNames = recog.ruleNames + s = escapeWhitespace(cls.getNodeText(t, ruleNames), False) + if t.getChildCount()==0: + return s + with StringIO() as buf: + buf.write("(") + buf.write(s) + buf.write(' ') + for i in range(0, t.getChildCount()): + if i > 0: + buf.write(' ') + buf.write(cls.toStringTree(t.getChild(i), ruleNames)) + buf.write(")") + return buf.getvalue() + + @classmethod + def getNodeText(cls, t:Tree, ruleNames:list=None, recog:Parser=None): + if recog is not None: + ruleNames = recog.ruleNames + if ruleNames is not None: + if isinstance(t, RuleNode): + if t.getAltNumber()!=0: # should use ATN.INVALID_ALT_NUMBER but won't compile + return ruleNames[t.getRuleIndex()]+":"+str(t.getAltNumber()) + return ruleNames[t.getRuleIndex()] + elif isinstance( t, ErrorNode): + return str(t) + elif isinstance(t, TerminalNode): + if t.symbol is not None: + return t.symbol.text + # no recog for rule names + payload = t.getPayload() + if isinstance(payload, Token ): + return payload.text + return str(t.getPayload()) + + + # Return ordered list of all children of this node + @classmethod + def getChildren(cls, t:Tree): + return [ t.getChild(i) for i in range(0, t.getChildCount()) ] + + # Return a list of all ancestors of this node. The first node of + # list is the root and the last is the parent of this node. + # + @classmethod + def getAncestors(cls, t:Tree): + ancestors = [] + t = t.getParent() + while t is not None: + ancestors.insert(0, t) # insert at start + t = t.getParent() + return ancestors + + @classmethod + def findAllTokenNodes(cls, t:ParseTree, ttype:int): + return cls.findAllNodes(t, ttype, True) + + @classmethod + def findAllRuleNodes(cls, t:ParseTree, ruleIndex:int): + return cls.findAllNodes(t, ruleIndex, False) + + @classmethod + def findAllNodes(cls, t:ParseTree, index:int, findTokens:bool): + nodes = [] + cls._findAllNodes(t, index, findTokens, nodes) + return nodes + + @classmethod + def _findAllNodes(cls, t:ParseTree, index:int, findTokens:bool, nodes:list): + from antlr4.ParserRuleContext import ParserRuleContext + # check this node (the root) first + if findTokens and isinstance(t, TerminalNode): + if t.symbol.type==index: + nodes.append(t) + elif not findTokens and isinstance(t, ParserRuleContext): + if t.ruleIndex == index: + nodes.append(t) + # check children + for i in range(0, t.getChildCount()): + cls._findAllNodes(t.getChild(i), index, findTokens, nodes) + + @classmethod + def descendants(cls, t:ParseTree): + nodes = [t] + for i in range(0, t.getChildCount()): + nodes.extend(cls.descendants(t.getChild(i))) + return nodes diff --git a/src/antlr4/tree/__init__.py b/src/antlr4/tree/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/antlr4/xpath/XPath.py b/src/antlr4/xpath/XPath.py new file mode 100644 index 00000000..c49e3ba9 --- /dev/null +++ b/src/antlr4/xpath/XPath.py @@ -0,0 +1,343 @@ +# +# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. +# Use of this file is governed by the BSD 3-clause license that +# can be found in the LICENSE.txt file in the project root. +# + +# +# Represent a subset of XPath XML path syntax for use in identifying nodes in +# parse trees. +# +#

          +# Split path into words and separators {@code /} and {@code //} via ANTLR +# itself then walk path elements from left to right. At each separator-word +# pair, find set of nodes. Next stage uses those as work list.

          +# +#

          +# The basic interface is +# {@link XPath#findAll ParseTree.findAll}{@code (tree, pathString, parser)}. +# But that is just shorthand for:

          +# +#
          +# {@link XPath} p = new {@link XPath#XPath XPath}(parser, pathString);
          +# return p.{@link #evaluate evaluate}(tree);
          +# 
          +# +#

          +# See {@code org.antlr.v4.test.TestXPath} for descriptions. In short, this +# allows operators:

          +# +#
          +#
          /
          root
          +#
          //
          anywhere
          +#
          !
          invert; this must appear directly after root or anywhere +# operator
          +#
          +# +#

          +# and path elements:

          +# +#
          +#
          ID
          token name
          +#
          'string'
          any string literal token from the grammar
          +#
          expr
          rule name
          +#
          *
          wildcard matching any node
          +#
          +# +#

          +# Whitespace is not allowed.

          +# +from antlr4 import CommonTokenStream, DFA, PredictionContextCache, Lexer, LexerATNSimulator +from antlr4.InputStream import InputStream +from antlr4.Parser import Parser +from antlr4.RuleContext import RuleContext +from antlr4.Token import Token +from antlr4.atn.ATNDeserializer import ATNDeserializer +from antlr4.error.ErrorListener import ErrorListener +from antlr4.error.Errors import LexerNoViableAltException +from antlr4.tree.Tree import ParseTree +from antlr4.tree.Trees import Trees +from io import StringIO + + +def serializedATN(): + with StringIO() as buf: + buf.write("\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2\n") + buf.write("\64\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t") + buf.write("\7\4\b\t\b\4\t\t\t\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5") + buf.write("\3\6\3\6\7\6\37\n\6\f\6\16\6\"\13\6\3\6\3\6\3\7\3\7\5") + buf.write("\7(\n\7\3\b\3\b\3\t\3\t\7\t.\n\t\f\t\16\t\61\13\t\3\t") + buf.write("\3\t\3/\2\n\3\5\5\6\7\7\t\b\13\t\r\2\17\2\21\n\3\2\4\7") + buf.write("\2\62;aa\u00b9\u00b9\u0302\u0371\u2041\u2042\17\2C\\c") + buf.write("|\u00c2\u00d8\u00da\u00f8\u00fa\u0301\u0372\u037f\u0381") + buf.write("\u2001\u200e\u200f\u2072\u2191\u2c02\u2ff1\u3003\ud801") + buf.write("\uf902\ufdd1\ufdf2\uffff\64\2\3\3\2\2\2\2\5\3\2\2\2\2") + buf.write("\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\21\3\2\2\2\3\23") + buf.write("\3\2\2\2\5\26\3\2\2\2\7\30\3\2\2\2\t\32\3\2\2\2\13\34") + buf.write("\3\2\2\2\r\'\3\2\2\2\17)\3\2\2\2\21+\3\2\2\2\23\24\7\61") + buf.write("\2\2\24\25\7\61\2\2\25\4\3\2\2\2\26\27\7\61\2\2\27\6\3") + buf.write("\2\2\2\30\31\7,\2\2\31\b\3\2\2\2\32\33\7#\2\2\33\n\3\2") + buf.write("\2\2\34 \5\17\b\2\35\37\5\r\7\2\36\35\3\2\2\2\37\"\3\2") + buf.write("\2\2 \36\3\2\2\2 !\3\2\2\2!#\3\2\2\2\" \3\2\2\2#$\b\6") + buf.write("\2\2$\f\3\2\2\2%(\5\17\b\2&(\t\2\2\2\'%\3\2\2\2\'&\3\2") + buf.write("\2\2(\16\3\2\2\2)*\t\3\2\2*\20\3\2\2\2+/\7)\2\2,.\13\2") + buf.write("\2\2-,\3\2\2\2.\61\3\2\2\2/\60\3\2\2\2/-\3\2\2\2\60\62") + buf.write("\3\2\2\2\61/\3\2\2\2\62\63\7)\2\2\63\22\3\2\2\2\6\2 \'") + buf.write("/\3\3\6\2") + return buf.getvalue() + + +class XPathLexer(Lexer): + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] + + + TOKEN_REF = 1 + RULE_REF = 2 + ANYWHERE = 3 + ROOT = 4 + WILDCARD = 5 + BANG = 6 + ID = 7 + STRING = 8 + + modeNames = [ "DEFAULT_MODE" ] + + literalNames = [ "", + "'//'", "'/'", "'*'", "'!'" ] + + symbolicNames = [ "", + "TOKEN_REF", "RULE_REF", "ANYWHERE", "ROOT", "WILDCARD", "BANG", + "ID", "STRING" ] + + ruleNames = [ "ANYWHERE", "ROOT", "WILDCARD", "BANG", "ID", "NameChar", + "NameStartChar", "STRING" ] + + grammarFileName = "XPathLexer.g4" + + def __init__(self, input=None): + super().__init__(input) + self.checkVersion("4.7.2") + self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) + self._actions = None + self._predicates = None + + + def action(self, localctx:RuleContext, ruleIndex:int, actionIndex:int): + if self._actions is None: + actions = dict() + actions[4] = self.ID_action + self._actions = actions + _action = self._actions.get(ruleIndex, None) + if _action is not None: + _action(localctx, actionIndex) + else: + raise Exception("No registered action for:" + str(ruleIndex)) + + def ID_action(self, localctx:RuleContext , actionIndex:int): + if actionIndex == 0: + char = self.text[0] + if char.isupper(): + self.type = XPathLexer.TOKEN_REF + else: + self.type = XPathLexer.RULE_REF + +class XPath(object): + + WILDCARD = "*" # word not operator/separator + NOT = "!" # word for invert operator + + def __init__(self, parser:Parser, path:str): + self.parser = parser + self.path = path + self.elements = self.split(path) + + def split(self, path:str): + input = InputStream(path) + lexer = XPathLexer(input) + def recover(self, e): + raise e + lexer.recover = recover + lexer.removeErrorListeners() + lexer.addErrorListener(ErrorListener()) # XPathErrorListener does no more + tokenStream = CommonTokenStream(lexer) + try: + tokenStream.fill() + except LexerNoViableAltException as e: + pos = lexer.getColumn() + msg = "Invalid tokens or characters at index " + str(pos) + " in path '" + path + "'" + raise Exception(msg, e) + + tokens = tokenStream.getTokens() + elements = list() + n = len(tokens) + i=0 + while i < n : + el = tokens[i] + next = None + if el.type in [XPathLexer.ROOT, XPathLexer.ANYWHERE]: + anywhere = el.type == XPathLexer.ANYWHERE + i += 1 + next = tokens[i] + invert = next.type==XPathLexer.BANG + if invert: + i += 1 + next = tokens[i] + pathElement = self.getXPathElement(next, anywhere) + pathElement.invert = invert + elements.append(pathElement) + i += 1 + + elif el.type in [XPathLexer.TOKEN_REF, XPathLexer.RULE_REF, XPathLexer.WILDCARD] : + elements.append( self.getXPathElement(el, False) ) + i += 1 + + elif el.type==Token.EOF : + break + + else: + raise Exception("Unknown path element " + str(el)) + + return elements + + # + # Convert word like {@code#} or {@code ID} or {@code expr} to a path + # element. {@code anywhere} is {@code true} if {@code //} precedes the + # word. + # + def getXPathElement(self, wordToken:Token, anywhere:bool): + if wordToken.type==Token.EOF: + raise Exception("Missing path element at end of path") + word = wordToken.text + ttype = self.parser.getTokenType(word) + ruleIndex = self.parser.getRuleIndex(word) + + if wordToken.type==XPathLexer.WILDCARD : + + return XPathWildcardAnywhereElement() if anywhere else XPathWildcardElement() + + elif wordToken.type in [XPathLexer.TOKEN_REF, XPathLexer.STRING]: + + if ttype==Token.INVALID_TYPE: + raise Exception( word + " at index " + str(wordToken.startIndex) + " isn't a valid token name") + return XPathTokenAnywhereElement(word, ttype) if anywhere else XPathTokenElement(word, ttype) + + else: + + if ruleIndex==-1: + raise Exception( word + " at index " + str(wordToken.getStartIndex()) + " isn't a valid rule name") + return XPathRuleAnywhereElement(word, ruleIndex) if anywhere else XPathRuleElement(word, ruleIndex) + + + @staticmethod + def findAll(tree:ParseTree, xpath:str, parser:Parser): + p = XPath(parser, xpath) + return p.evaluate(tree) + + # + # Return a list of all nodes starting at {@code t} as root that satisfy the + # path. The root {@code /} is relative to the node passed to + # {@link #evaluate}. + # + def evaluate(self, t:ParseTree): + dummyRoot = ParserRuleContext() + dummyRoot.children = [t] # don't set t's parent. + + work = [dummyRoot] + + for i in range(0, len(self.elements)): + next = set() + for node in work: + if len( node.children) > 0 : + # only try to match next element if it has children + # e.g., //func/*/stat might have a token node for which + # we can't go looking for stat nodes. + matching = self.elements[i].evaluate(node) + next |= matching + i += 1 + work = next + + return work + + +class XPathElement(object): + + def __init__(self, nodeName:str): + self.nodeName = nodeName + self.invert = False + + def __str__(self): + return type(self).__name__ + "[" + ("!" if self.invert else "") + self.nodeName + "]" + + + +# +# Either {@code ID} at start of path or {@code ...//ID} in middle of path. +# +class XPathRuleAnywhereElement(XPathElement): + + def __init__(self, ruleName:str, ruleIndex:int): + super().__init__(ruleName) + self.ruleIndex = ruleIndex + + def evaluate(self, t:ParseTree): + return Trees.findAllRuleNodes(t, self.ruleIndex) + + +class XPathRuleElement(XPathElement): + + def __init__(self, ruleName:str, ruleIndex:int): + super().__init__(ruleName) + self.ruleIndex = ruleIndex + + def evaluate(self, t:ParseTree): + # return all children of t that match nodeName + return [c for c in Trees.getChildren(t) if isinstance(c, ParserRuleContext) and (c.ruleIndex == self.ruleIndex) == (not self.invert)] + + +class XPathTokenAnywhereElement(XPathElement): + + def __init__(self, ruleName:str, tokenType:int): + super().__init__(ruleName) + self.tokenType = tokenType + + def evaluate(self, t:ParseTree): + return Trees.findAllTokenNodes(t, self.tokenType) + + +class XPathTokenElement(XPathElement): + + def __init__(self, ruleName:str, tokenType:int): + super().__init__(ruleName) + self.tokenType = tokenType + + def evaluate(self, t:ParseTree): + # return all children of t that match nodeName + return [c for c in Trees.getChildren(t) if isinstance(c, TerminalNode) and (c.symbol.type == self.tokenType) == (not self.invert)] + + +class XPathWildcardAnywhereElement(XPathElement): + + def __init__(self): + super().__init__(XPath.WILDCARD) + + def evaluate(self, t:ParseTree): + if self.invert: + return list() # !* is weird but valid (empty) + else: + return Trees.descendants(t) + + +class XPathWildcardElement(XPathElement): + + def __init__(self): + super().__init__(XPath.WILDCARD) + + + def evaluate(self, t:ParseTree): + if self.invert: + return list() # !* is weird but valid (empty) + else: + return Trees.getChildren(t) diff --git a/src/antlr4/xpath/__init__.py b/src/antlr4/xpath/__init__.py new file mode 100644 index 00000000..216c000d --- /dev/null +++ b/src/antlr4/xpath/__init__.py @@ -0,0 +1 @@ +__author__ = 'ericvergnaud' diff --git a/src/coolc.sh b/src/coolc.sh index 3088de4f..32158b64 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -5,7 +5,8 @@ OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas -echo "Copyright (c) 2019: Nombre1, Nombre2, Nombre3" # TODO: líneas a los valores correctos +echo "Copyright (c) 2019: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" # TODO: líneas a los valores correctos # Llamar al compilador -echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +#echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +python COOLCompiler.py INPUT_FILE OUTPUT_FILE From 8d3d764c2a84e13b79accb675d6d0d3d95920ce8 Mon Sep 17 00:00:00 2001 From: LSilvaO Date: Sat, 29 Feb 2020 14:17:50 -0500 Subject: [PATCH 24/77] cambio --- doc/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Readme.md b/doc/Readme.md index 59c61e34..a2f68fed 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -4,7 +4,7 @@ **Nombre** | **Grupo** | **Github** --|--|-- -Liset Silva Oropesa | C411 | [@github_user](https://github.com/) +Liset Silva Oropesa | C411 | [@github_user](https://github.com/Liset97) Pablo Antonio de Armas Suarez | C411 | [@github_user](https://github.com/) Yenli Gil Machado | C412 | [@github_user](https://github.com/) From 2b502be562be756a8c9871af5899edc15896e314 Mon Sep 17 00:00:00 2001 From: LSilvaO Date: Sat, 29 Feb 2020 14:27:19 -0500 Subject: [PATCH 25/77] modifica --- doc/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Readme.md b/doc/Readme.md index a2f68fed..b953665a 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -4,7 +4,7 @@ **Nombre** | **Grupo** | **Github** --|--|-- -Liset Silva Oropesa | C411 | [@github_user](https://github.com/Liset97) +Liset Silva Oropesa | C411 | [@Liset97](https://github.com/Liset97) Pablo Antonio de Armas Suarez | C411 | [@github_user](https://github.com/) Yenli Gil Machado | C412 | [@github_user](https://github.com/) From ebf8679b69f02078f46272793d0e12d8aa7f6af1 Mon Sep 17 00:00:00 2001 From: LSilvaO Date: Sat, 29 Feb 2020 20:00:50 -0500 Subject: [PATCH 26/77] dos nombres --- doc/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Readme.md b/doc/Readme.md index b953665a..e32260f4 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -6,7 +6,7 @@ --|--|-- Liset Silva Oropesa | C411 | [@Liset97](https://github.com/Liset97) Pablo Antonio de Armas Suarez | C411 | [@github_user](https://github.com/) -Yenli Gil Machado | C412 | [@github_user](https://github.com/) +Yenli Gil Machado | C412 | [@YenGM](https://github.com/YenGM) ## Readme From b330fdf348d86f0a6533d7206bb1666d70673eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sat, 29 Feb 2020 23:40:55 -0500 Subject: [PATCH 27/77] Se agregaron las clases para el lexer y el parser Se agregaron clases para el procesamiento de los errores Se agregaron algunos tests que faltaban --- COOL.interp | 113 ++ COOL.py | 1828 ++++++++++++++++++++++++++++++++ COOL.tokens | 69 ++ COOLCompiler.py | 36 + COOLLexer.py | 34 + COOLLexerErrorListener.py | 7 + COOLListener.py | 289 +++++ COOLParser.py | 24 + COOLParserErrorListener.py | 12 + COOL_LEX.interp | 182 ++++ COOL_LEX.py | 284 +++++ COOL_LEX.tokens | 69 ++ tests/lexer/test1.cl | 9 + tests/lexer/test1_error.txt | 3 + tests/lexer/test3.cl | 46 + tests/lexer/test3_error.txt | 1 + tests/lexer/test5.cl | 4 + tests/lexer/test5_error.txt | 1 + tests/lexer/test6.cl | 6 + tests/lexer/test6_error.txt | 5 + tests/parser/err2.cl | 14 + tests/parser/err2_error.txt | 2 + tests/parser/isprime.cl | 40 + tests/parser/isprime_error.txt | 1 + tests/parser/prod.cl | 21 + tests/parser/prod_error.txt | 1 + tests/parser/test2.cl | 20 + tests/parser/test2_error.txt | 4 + tests/parser/test4.cl | 5 + tests/parser/test4_error.txt | 1 + 30 files changed, 3131 insertions(+) create mode 100644 COOL.interp create mode 100644 COOL.py create mode 100644 COOL.tokens create mode 100644 COOLCompiler.py create mode 100644 COOLLexer.py create mode 100644 COOLLexerErrorListener.py create mode 100644 COOLListener.py create mode 100644 COOLParser.py create mode 100644 COOLParserErrorListener.py create mode 100644 COOL_LEX.interp create mode 100644 COOL_LEX.py create mode 100644 COOL_LEX.tokens create mode 100644 tests/lexer/test1.cl create mode 100644 tests/lexer/test1_error.txt create mode 100644 tests/lexer/test3.cl create mode 100644 tests/lexer/test3_error.txt create mode 100644 tests/lexer/test5.cl create mode 100644 tests/lexer/test5_error.txt create mode 100644 tests/lexer/test6.cl create mode 100644 tests/lexer/test6_error.txt create mode 100644 tests/parser/err2.cl create mode 100644 tests/parser/err2_error.txt create mode 100644 tests/parser/isprime.cl create mode 100644 tests/parser/isprime_error.txt create mode 100644 tests/parser/prod.cl create mode 100644 tests/parser/prod_error.txt create mode 100644 tests/parser/test2.cl create mode 100644 tests/parser/test2_error.txt create mode 100644 tests/parser/test4.cl create mode 100644 tests/parser/test4_error.txt diff --git a/COOL.interp b/COOL.interp new file mode 100644 index 00000000..bba307e6 --- /dev/null +++ b/COOL.interp @@ -0,0 +1,113 @@ +token literal names: +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +'<-' +'=>' +'+' +'-' +'*' +'/' +'<' +'<=' +'=' +'~' +'(' +')' +'{' +'}' +'@' +'.' +',' +':' +';' +null +null +'(*' +null +'*)' + +token symbolic names: +null +CLASS +ELSE +FALSE +FI +IF +IN +INHERITS +ISVOID +LET +LOOP +POOL +THEN +WHILE +CASE +ESAC +NEW +OF +NOT +TRUE +STRING +BREAK_STRING +INT +TYPEID +OBJECTID +ASSIGNMENT +CASE_ARROW +ADD +MINUS +MULTIPLY +DIVISION +LESS_THAN +LESS_EQUAL +EQUAL +INTEGER_NEGATIVE +OPEN_ROUND +CLOSE_ROUND +OPEN_CURLY +CLOSE_CURLY +AT +DOT +COMMA +COLON +SEMICOLON +WHITESPACE +ONE_LINE_COMMENT +OPEN_COMMENT +COMMENT +CLOSE_COMMENT + +rule names: +program +programBlocks +classDefine +feature +formal +expression + + +atn: +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 50, 225, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 7, 7, 86, 10, 7, 12, 7, 14, 7, 89, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 110, 10, 7, 13, 7, 14, 7, 111, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 122, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 130, 10, 7, 7, 7, 132, 10, 7, 12, 7, 14, 7, 135, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 149, 10, 7, 13, 7, 14, 7, 150, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 175, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 201, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 209, 10, 7, 12, 7, 14, 7, 212, 11, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 7, 7, 220, 10, 7, 12, 7, 14, 7, 223, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 259, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 174, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 45, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 25, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 25, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 39, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 45, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 40, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 26, 2, 2, 40, 51, 7, 37, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 43, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 38, 2, 2, 55, 56, 7, 44, 2, 2, 56, 57, 7, 25, 2, 2, 57, 58, 7, 39, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 40, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 26, 2, 2, 62, 63, 7, 44, 2, 2, 63, 66, 7, 25, 2, 2, 64, 65, 7, 27, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 26, 2, 2, 71, 72, 7, 44, 2, 2, 72, 73, 7, 25, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 26, 2, 2, 76, 87, 7, 37, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 43, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 90, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 175, 7, 38, 2, 2, 91, 92, 7, 7, 2, 2, 92, 93, 5, 12, 7, 2, 93, 94, 7, 14, 2, 2, 94, 95, 5, 12, 7, 2, 95, 96, 7, 4, 2, 2, 96, 97, 5, 12, 7, 2, 97, 98, 7, 6, 2, 2, 98, 175, 3, 2, 2, 2, 99, 100, 7, 15, 2, 2, 100, 101, 5, 12, 7, 2, 101, 102, 7, 12, 2, 2, 102, 103, 5, 12, 7, 2, 103, 104, 7, 13, 2, 2, 104, 175, 3, 2, 2, 2, 105, 109, 7, 39, 2, 2, 106, 107, 5, 12, 7, 2, 107, 108, 7, 45, 2, 2, 108, 110, 3, 2, 2, 2, 109, 106, 3, 2, 2, 2, 110, 111, 3, 2, 2, 2, 111, 109, 3, 2, 2, 2, 111, 112, 3, 2, 2, 2, 112, 113, 3, 2, 2, 2, 113, 114, 7, 40, 2, 2, 114, 175, 3, 2, 2, 2, 115, 116, 7, 11, 2, 2, 116, 117, 7, 26, 2, 2, 117, 118, 7, 44, 2, 2, 118, 121, 7, 25, 2, 2, 119, 120, 7, 27, 2, 2, 120, 122, 5, 12, 7, 2, 121, 119, 3, 2, 2, 2, 121, 122, 3, 2, 2, 2, 122, 133, 3, 2, 2, 2, 123, 124, 7, 43, 2, 2, 124, 125, 7, 26, 2, 2, 125, 126, 7, 44, 2, 2, 126, 129, 7, 25, 2, 2, 127, 128, 7, 27, 2, 2, 128, 130, 5, 12, 7, 2, 129, 127, 3, 2, 2, 2, 129, 130, 3, 2, 2, 2, 130, 132, 3, 2, 2, 2, 131, 123, 3, 2, 2, 2, 132, 135, 3, 2, 2, 2, 133, 131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 136, 3, 2, 2, 2, 135, 133, 3, 2, 2, 2, 136, 137, 7, 8, 2, 2, 137, 175, 5, 12, 7, 22, 138, 139, 7, 16, 2, 2, 139, 140, 5, 12, 7, 2, 140, 148, 7, 19, 2, 2, 141, 142, 7, 26, 2, 2, 142, 143, 7, 44, 2, 2, 143, 144, 7, 25, 2, 2, 144, 145, 7, 28, 2, 2, 145, 146, 5, 12, 7, 2, 146, 147, 7, 45, 2, 2, 147, 149, 3, 2, 2, 2, 148, 141, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 150, 148, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 7, 17, 2, 2, 153, 175, 3, 2, 2, 2, 154, 155, 7, 18, 2, 2, 155, 175, 7, 25, 2, 2, 156, 157, 7, 36, 2, 2, 157, 175, 5, 12, 7, 19, 158, 159, 7, 10, 2, 2, 159, 175, 5, 12, 7, 18, 160, 161, 7, 20, 2, 2, 161, 175, 5, 12, 7, 10, 162, 163, 7, 37, 2, 2, 163, 164, 5, 12, 7, 2, 164, 165, 7, 38, 2, 2, 165, 175, 3, 2, 2, 2, 166, 175, 7, 26, 2, 2, 167, 175, 7, 24, 2, 2, 168, 175, 7, 22, 2, 2, 169, 175, 7, 21, 2, 2, 170, 175, 7, 5, 2, 2, 171, 172, 7, 26, 2, 2, 172, 173, 7, 27, 2, 2, 173, 175, 5, 12, 7, 3, 174, 74, 3, 2, 2, 2, 174, 91, 3, 2, 2, 2, 174, 99, 3, 2, 2, 2, 174, 105, 3, 2, 2, 2, 174, 115, 3, 2, 2, 2, 174, 138, 3, 2, 2, 2, 174, 154, 3, 2, 2, 2, 174, 156, 3, 2, 2, 2, 174, 158, 3, 2, 2, 2, 174, 160, 3, 2, 2, 2, 174, 162, 3, 2, 2, 2, 174, 166, 3, 2, 2, 2, 174, 167, 3, 2, 2, 2, 174, 168, 3, 2, 2, 2, 174, 169, 3, 2, 2, 2, 174, 170, 3, 2, 2, 2, 174, 171, 3, 2, 2, 2, 175, 221, 3, 2, 2, 2, 176, 177, 12, 17, 2, 2, 177, 178, 7, 31, 2, 2, 178, 220, 5, 12, 7, 18, 179, 180, 12, 16, 2, 2, 180, 181, 7, 32, 2, 2, 181, 220, 5, 12, 7, 17, 182, 183, 12, 15, 2, 2, 183, 184, 7, 29, 2, 2, 184, 220, 5, 12, 7, 16, 185, 186, 12, 14, 2, 2, 186, 187, 7, 30, 2, 2, 187, 220, 5, 12, 7, 15, 188, 189, 12, 13, 2, 2, 189, 190, 7, 33, 2, 2, 190, 220, 5, 12, 7, 14, 191, 192, 12, 12, 2, 2, 192, 193, 7, 34, 2, 2, 193, 220, 5, 12, 7, 13, 194, 195, 12, 11, 2, 2, 195, 196, 7, 35, 2, 2, 196, 220, 5, 12, 7, 12, 197, 200, 12, 27, 2, 2, 198, 199, 7, 41, 2, 2, 199, 201, 7, 25, 2, 2, 200, 198, 3, 2, 2, 2, 200, 201, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 7, 42, 2, 2, 203, 204, 7, 26, 2, 2, 204, 215, 7, 37, 2, 2, 205, 210, 5, 12, 7, 2, 206, 207, 7, 43, 2, 2, 207, 209, 5, 12, 7, 2, 208, 206, 3, 2, 2, 2, 209, 212, 3, 2, 2, 2, 210, 208, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 214, 3, 2, 2, 2, 212, 210, 3, 2, 2, 2, 213, 205, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 218, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 218, 220, 7, 38, 2, 2, 219, 176, 3, 2, 2, 2, 219, 179, 3, 2, 2, 2, 219, 182, 3, 2, 2, 2, 219, 185, 3, 2, 2, 2, 219, 188, 3, 2, 2, 2, 219, 191, 3, 2, 2, 2, 219, 194, 3, 2, 2, 2, 219, 197, 3, 2, 2, 2, 220, 223, 3, 2, 2, 2, 221, 219, 3, 2, 2, 2, 221, 222, 3, 2, 2, 2, 222, 13, 3, 2, 2, 2, 223, 221, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 87, 111, 121, 129, 133, 150, 174, 200, 210, 215, 219, 221] \ No newline at end of file diff --git a/COOL.py b/COOL.py new file mode 100644 index 00000000..7fca203d --- /dev/null +++ b/COOL.py @@ -0,0 +1,1828 @@ +# Generated from COOL.g4 by ANTLR 4.7.2 +# encoding: utf-8 +from antlr4 import * +from io import StringIO +from typing.io import TextIO +import sys + + +def serializedATN(): + with StringIO() as buf: + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\62") + buf.write("\u00e1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") + buf.write("\3\2\3\2\3\2\3\3\3\3\3\3\5\3\25\n\3\3\4\3\4\3\4\3\4\5") + buf.write("\4\33\n\4\3\4\3\4\3\4\3\4\7\4!\n\4\f\4\16\4$\13\4\3\4") + buf.write("\3\4\3\5\3\5\3\5\3\5\3\5\7\5-\n\5\f\5\16\5\60\13\5\7\5") + buf.write("\62\n\5\f\5\16\5\65\13\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3") + buf.write("\5\3\5\3\5\3\5\3\5\5\5C\n\5\5\5E\n\5\3\6\3\6\3\6\3\6\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\7\7Q\n\7\f\7\16\7T\13\7\7\7V\n") + buf.write("\7\f\7\16\7Y\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\6\7n\n\7\r\7") + buf.write("\16\7o\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\5\7z\n\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\5\7\u0082\n\7\7\7\u0084\n\7\f\7\16") + buf.write("\7\u0087\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\6\7\u0095\n\7\r\7\16\7\u0096\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\5\7\u00af\n\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\5\7\u00c9\n\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\7\7\u00d1\n\7\f\7\16\7\u00d4\13\7\7\7\u00d6\n\7\f") + buf.write("\7\16\7\u00d9\13\7\3\7\7\7\u00dc\n\7\f\7\16\7\u00df\13") + buf.write("\7\3\7\2\3\f\b\2\4\6\b\n\f\2\2\2\u0103\2\16\3\2\2\2\4") + buf.write("\21\3\2\2\2\6\26\3\2\2\2\bD\3\2\2\2\nF\3\2\2\2\f\u00ae") + buf.write("\3\2\2\2\16\17\5\4\3\2\17\20\7\2\2\3\20\3\3\2\2\2\21\22") + buf.write("\5\6\4\2\22\24\7-\2\2\23\25\5\4\3\2\24\23\3\2\2\2\24\25") + buf.write("\3\2\2\2\25\5\3\2\2\2\26\27\7\3\2\2\27\32\7\31\2\2\30") + buf.write("\31\7\t\2\2\31\33\7\31\2\2\32\30\3\2\2\2\32\33\3\2\2\2") + buf.write("\33\34\3\2\2\2\34\"\7\'\2\2\35\36\5\b\5\2\36\37\7-\2\2") + buf.write("\37!\3\2\2\2 \35\3\2\2\2!$\3\2\2\2\" \3\2\2\2\"#\3\2\2") + buf.write("\2#%\3\2\2\2$\"\3\2\2\2%&\7(\2\2&\7\3\2\2\2\'(\7\32\2") + buf.write("\2(\63\7%\2\2).\5\n\6\2*+\7+\2\2+-\5\n\6\2,*\3\2\2\2-") + buf.write("\60\3\2\2\2.,\3\2\2\2./\3\2\2\2/\62\3\2\2\2\60.\3\2\2") + buf.write("\2\61)\3\2\2\2\62\65\3\2\2\2\63\61\3\2\2\2\63\64\3\2\2") + buf.write("\2\64\66\3\2\2\2\65\63\3\2\2\2\66\67\7&\2\2\678\7,\2\2") + buf.write("89\7\31\2\29:\7\'\2\2:;\5\f\7\2;<\7(\2\2\7") + buf.write("\32\2\2>?\7,\2\2?B\7\31\2\2@A\7\33\2\2AC\5\f\7\2B@\3\2") + buf.write("\2\2BC\3\2\2\2CE\3\2\2\2D\'\3\2\2\2D=\3\2\2\2E\t\3\2\2") + buf.write("\2FG\7\32\2\2GH\7,\2\2HI\7\31\2\2I\13\3\2\2\2JK\b\7\1") + buf.write("\2KL\7\32\2\2LW\7%\2\2MR\5\f\7\2NO\7+\2\2OQ\5\f\7\2PN") + buf.write("\3\2\2\2QT\3\2\2\2RP\3\2\2\2RS\3\2\2\2SV\3\2\2\2TR\3\2") + buf.write("\2\2UM\3\2\2\2VY\3\2\2\2WU\3\2\2\2WX\3\2\2\2XZ\3\2\2\2") + buf.write("YW\3\2\2\2Z\u00af\7&\2\2[\\\7\7\2\2\\]\5\f\7\2]^\7\16") + buf.write("\2\2^_\5\f\7\2_`\7\4\2\2`a\5\f\7\2ab\7\6\2\2b\u00af\3") + buf.write("\2\2\2cd\7\17\2\2de\5\f\7\2ef\7\f\2\2fg\5\f\7\2gh\7\r") + buf.write("\2\2h\u00af\3\2\2\2im\7\'\2\2jk\5\f\7\2kl\7-\2\2ln\3\2") + buf.write("\2\2mj\3\2\2\2no\3\2\2\2om\3\2\2\2op\3\2\2\2pq\3\2\2\2") + buf.write("qr\7(\2\2r\u00af\3\2\2\2st\7\13\2\2tu\7\32\2\2uv\7,\2") + buf.write("\2vy\7\31\2\2wx\7\33\2\2xz\5\f\7\2yw\3\2\2\2yz\3\2\2\2") + buf.write("z\u0085\3\2\2\2{|\7+\2\2|}\7\32\2\2}~\7,\2\2~\u0081\7") + buf.write("\31\2\2\177\u0080\7\33\2\2\u0080\u0082\5\f\7\2\u0081\177") + buf.write("\3\2\2\2\u0081\u0082\3\2\2\2\u0082\u0084\3\2\2\2\u0083") + buf.write("{\3\2\2\2\u0084\u0087\3\2\2\2\u0085\u0083\3\2\2\2\u0085") + buf.write("\u0086\3\2\2\2\u0086\u0088\3\2\2\2\u0087\u0085\3\2\2\2") + buf.write("\u0088\u0089\7\b\2\2\u0089\u00af\5\f\7\26\u008a\u008b") + buf.write("\7\20\2\2\u008b\u008c\5\f\7\2\u008c\u0094\7\23\2\2\u008d") + buf.write("\u008e\7\32\2\2\u008e\u008f\7,\2\2\u008f\u0090\7\31\2") + buf.write("\2\u0090\u0091\7\34\2\2\u0091\u0092\5\f\7\2\u0092\u0093") + buf.write("\7-\2\2\u0093\u0095\3\2\2\2\u0094\u008d\3\2\2\2\u0095") + buf.write("\u0096\3\2\2\2\u0096\u0094\3\2\2\2\u0096\u0097\3\2\2\2") + buf.write("\u0097\u0098\3\2\2\2\u0098\u0099\7\21\2\2\u0099\u00af") + buf.write("\3\2\2\2\u009a\u009b\7\22\2\2\u009b\u00af\7\31\2\2\u009c") + buf.write("\u009d\7$\2\2\u009d\u00af\5\f\7\23\u009e\u009f\7\n\2\2") + buf.write("\u009f\u00af\5\f\7\22\u00a0\u00a1\7\24\2\2\u00a1\u00af") + buf.write("\5\f\7\n\u00a2\u00a3\7%\2\2\u00a3\u00a4\5\f\7\2\u00a4") + buf.write("\u00a5\7&\2\2\u00a5\u00af\3\2\2\2\u00a6\u00af\7\32\2\2") + buf.write("\u00a7\u00af\7\30\2\2\u00a8\u00af\7\26\2\2\u00a9\u00af") + buf.write("\7\25\2\2\u00aa\u00af\7\5\2\2\u00ab\u00ac\7\32\2\2\u00ac") + buf.write("\u00ad\7\33\2\2\u00ad\u00af\5\f\7\3\u00aeJ\3\2\2\2\u00ae") + buf.write("[\3\2\2\2\u00aec\3\2\2\2\u00aei\3\2\2\2\u00aes\3\2\2\2") + buf.write("\u00ae\u008a\3\2\2\2\u00ae\u009a\3\2\2\2\u00ae\u009c\3") + buf.write("\2\2\2\u00ae\u009e\3\2\2\2\u00ae\u00a0\3\2\2\2\u00ae\u00a2") + buf.write("\3\2\2\2\u00ae\u00a6\3\2\2\2\u00ae\u00a7\3\2\2\2\u00ae") + buf.write("\u00a8\3\2\2\2\u00ae\u00a9\3\2\2\2\u00ae\u00aa\3\2\2\2") + buf.write("\u00ae\u00ab\3\2\2\2\u00af\u00dd\3\2\2\2\u00b0\u00b1\f") + buf.write("\21\2\2\u00b1\u00b2\7\37\2\2\u00b2\u00dc\5\f\7\22\u00b3") + buf.write("\u00b4\f\20\2\2\u00b4\u00b5\7 \2\2\u00b5\u00dc\5\f\7\21") + buf.write("\u00b6\u00b7\f\17\2\2\u00b7\u00b8\7\35\2\2\u00b8\u00dc") + buf.write("\5\f\7\20\u00b9\u00ba\f\16\2\2\u00ba\u00bb\7\36\2\2\u00bb") + buf.write("\u00dc\5\f\7\17\u00bc\u00bd\f\r\2\2\u00bd\u00be\7!\2\2") + buf.write("\u00be\u00dc\5\f\7\16\u00bf\u00c0\f\f\2\2\u00c0\u00c1") + buf.write("\7\"\2\2\u00c1\u00dc\5\f\7\r\u00c2\u00c3\f\13\2\2\u00c3") + buf.write("\u00c4\7#\2\2\u00c4\u00dc\5\f\7\f\u00c5\u00c8\f\33\2\2") + buf.write("\u00c6\u00c7\7)\2\2\u00c7\u00c9\7\31\2\2\u00c8\u00c6\3") + buf.write("\2\2\2\u00c8\u00c9\3\2\2\2\u00c9\u00ca\3\2\2\2\u00ca\u00cb") + buf.write("\7*\2\2\u00cb\u00cc\7\32\2\2\u00cc\u00d7\7%\2\2\u00cd") + buf.write("\u00d2\5\f\7\2\u00ce\u00cf\7+\2\2\u00cf\u00d1\5\f\7\2") + buf.write("\u00d0\u00ce\3\2\2\2\u00d1\u00d4\3\2\2\2\u00d2\u00d0\3") + buf.write("\2\2\2\u00d2\u00d3\3\2\2\2\u00d3\u00d6\3\2\2\2\u00d4\u00d2") + buf.write("\3\2\2\2\u00d5\u00cd\3\2\2\2\u00d6\u00d9\3\2\2\2\u00d7") + buf.write("\u00d5\3\2\2\2\u00d7\u00d8\3\2\2\2\u00d8\u00da\3\2\2\2") + buf.write("\u00d9\u00d7\3\2\2\2\u00da\u00dc\7&\2\2\u00db\u00b0\3") + buf.write("\2\2\2\u00db\u00b3\3\2\2\2\u00db\u00b6\3\2\2\2\u00db\u00b9") + buf.write("\3\2\2\2\u00db\u00bc\3\2\2\2\u00db\u00bf\3\2\2\2\u00db") + buf.write("\u00c2\3\2\2\2\u00db\u00c5\3\2\2\2\u00dc\u00df\3\2\2\2") + buf.write("\u00dd\u00db\3\2\2\2\u00dd\u00de\3\2\2\2\u00de\r\3\2\2") + buf.write("\2\u00df\u00dd\3\2\2\2\26\24\32\".\63BDRWoy\u0081\u0085") + buf.write("\u0096\u00ae\u00c8\u00d2\u00d7\u00db\u00dd") + return buf.getvalue() + + +class COOL ( Parser ): + + grammarFileName = "COOL.g4" + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] + + sharedContextCache = PredictionContextCache() + + literalNames = [ "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", + "'<'", "'<='", "'='", "'~'", "'('", "')'", "'{'", "'}'", + "'@'", "'.'", "','", "':'", "';'", "", "", + "'(*'", "", "'*)'" ] + + symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", + "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", + "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", + "TRUE", "STRING", "BREAK_STRING", "INT", "TYPEID", + "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", + "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", + "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", + "OPEN_CURLY", "CLOSE_CURLY", "AT", "DOT", "COMMA", + "COLON", "SEMICOLON", "WHITESPACE", "ONE_LINE_COMMENT", + "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT" ] + + RULE_program = 0 + RULE_programBlocks = 1 + RULE_classDefine = 2 + RULE_feature = 3 + RULE_formal = 4 + RULE_expression = 5 + + ruleNames = [ "program", "programBlocks", "classDefine", "feature", + "formal", "expression" ] + + EOF = Token.EOF + CLASS=1 + ELSE=2 + FALSE=3 + FI=4 + IF=5 + IN=6 + INHERITS=7 + ISVOID=8 + LET=9 + LOOP=10 + POOL=11 + THEN=12 + WHILE=13 + CASE=14 + ESAC=15 + NEW=16 + OF=17 + NOT=18 + TRUE=19 + STRING=20 + BREAK_STRING=21 + INT=22 + TYPEID=23 + OBJECTID=24 + ASSIGNMENT=25 + CASE_ARROW=26 + ADD=27 + MINUS=28 + MULTIPLY=29 + DIVISION=30 + LESS_THAN=31 + LESS_EQUAL=32 + EQUAL=33 + INTEGER_NEGATIVE=34 + OPEN_ROUND=35 + CLOSE_ROUND=36 + OPEN_CURLY=37 + CLOSE_CURLY=38 + AT=39 + DOT=40 + COMMA=41 + COLON=42 + SEMICOLON=43 + WHITESPACE=44 + ONE_LINE_COMMENT=45 + OPEN_COMMENT=46 + COMMENT=47 + CLOSE_COMMENT=48 + + def __init__(self, input:TokenStream, output:TextIO = sys.stdout): + super().__init__(input, output) + self.checkVersion("4.7.2") + self._interp = ParserATNSimulator(self, self.atn, self.decisionsToDFA, self.sharedContextCache) + self._predicates = None + + + + + class ProgramContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def programBlocks(self): + return self.getTypedRuleContext(COOL.ProgramBlocksContext,0) + + + def EOF(self): + return self.getToken(COOL.EOF, 0) + + def getRuleIndex(self): + return COOL.RULE_program + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterProgram" ): + listener.enterProgram(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitProgram" ): + listener.exitProgram(self) + + + + + def program(self): + + localctx = COOL.ProgramContext(self, self._ctx, self.state) + self.enterRule(localctx, 0, self.RULE_program) + try: + self.enterOuterAlt(localctx, 1) + self.state = 12 + self.programBlocks() + self.state = 13 + self.match(COOL.EOF) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class ProgramBlocksContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return COOL.RULE_programBlocks + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) + + + + class ClassesContext(ProgramBlocksContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ProgramBlocksContext + super().__init__(parser) + self.copyFrom(ctx) + + def classDefine(self): + return self.getTypedRuleContext(COOL.ClassDefineContext,0) + + def SEMICOLON(self): + return self.getToken(COOL.SEMICOLON, 0) + def programBlocks(self): + return self.getTypedRuleContext(COOL.ProgramBlocksContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterClasses" ): + listener.enterClasses(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitClasses" ): + listener.exitClasses(self) + + + + def programBlocks(self): + + localctx = COOL.ProgramBlocksContext(self, self._ctx, self.state) + self.enterRule(localctx, 2, self.RULE_programBlocks) + self._la = 0 # Token type + try: + localctx = COOL.ClassesContext(self, localctx) + self.enterOuterAlt(localctx, 1) + self.state = 15 + self.classDefine() + self.state = 16 + self.match(COOL.SEMICOLON) + self.state = 18 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOL.CLASS: + self.state = 17 + self.programBlocks() + + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class ClassDefineContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def CLASS(self): + return self.getToken(COOL.CLASS, 0) + + def TYPEID(self, i:int=None): + if i is None: + return self.getTokens(COOL.TYPEID) + else: + return self.getToken(COOL.TYPEID, i) + + def OPEN_CURLY(self): + return self.getToken(COOL.OPEN_CURLY, 0) + + def CLOSE_CURLY(self): + return self.getToken(COOL.CLOSE_CURLY, 0) + + def INHERITS(self): + return self.getToken(COOL.INHERITS, 0) + + def feature(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.FeatureContext) + else: + return self.getTypedRuleContext(COOL.FeatureContext,i) + + + def SEMICOLON(self, i:int=None): + if i is None: + return self.getTokens(COOL.SEMICOLON) + else: + return self.getToken(COOL.SEMICOLON, i) + + def getRuleIndex(self): + return COOL.RULE_classDefine + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterClassDefine" ): + listener.enterClassDefine(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitClassDefine" ): + listener.exitClassDefine(self) + + + + + def classDefine(self): + + localctx = COOL.ClassDefineContext(self, self._ctx, self.state) + self.enterRule(localctx, 4, self.RULE_classDefine) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 20 + self.match(COOL.CLASS) + self.state = 21 + self.match(COOL.TYPEID) + self.state = 24 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOL.INHERITS: + self.state = 22 + self.match(COOL.INHERITS) + self.state = 23 + self.match(COOL.TYPEID) + + + self.state = 26 + self.match(COOL.OPEN_CURLY) + self.state = 32 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOL.OBJECTID: + self.state = 27 + self.feature() + self.state = 28 + self.match(COOL.SEMICOLON) + self.state = 34 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 35 + self.match(COOL.CLOSE_CURLY) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class FeatureContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return COOL.RULE_feature + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) + + + + class MethodContext(FeatureContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.FeatureContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + def OPEN_ROUND(self): + return self.getToken(COOL.OPEN_ROUND, 0) + def CLOSE_ROUND(self): + return self.getToken(COOL.CLOSE_ROUND, 0) + def COLON(self): + return self.getToken(COOL.COLON, 0) + def TYPEID(self): + return self.getToken(COOL.TYPEID, 0) + def OPEN_CURLY(self): + return self.getToken(COOL.OPEN_CURLY, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + def CLOSE_CURLY(self): + return self.getToken(COOL.CLOSE_CURLY, 0) + def formal(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.FormalContext) + else: + return self.getTypedRuleContext(COOL.FormalContext,i) + + def COMMA(self, i:int=None): + if i is None: + return self.getTokens(COOL.COMMA) + else: + return self.getToken(COOL.COMMA, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMethod" ): + listener.enterMethod(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMethod" ): + listener.exitMethod(self) + + + class PropertyContext(FeatureContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.FeatureContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + def COLON(self): + return self.getToken(COOL.COLON, 0) + def TYPEID(self): + return self.getToken(COOL.TYPEID, 0) + def ASSIGNMENT(self): + return self.getToken(COOL.ASSIGNMENT, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterProperty" ): + listener.enterProperty(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitProperty" ): + listener.exitProperty(self) + + + + def feature(self): + + localctx = COOL.FeatureContext(self, self._ctx, self.state) + self.enterRule(localctx, 6, self.RULE_feature) + self._la = 0 # Token type + try: + self.state = 66 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input,6,self._ctx) + if la_ == 1: + localctx = COOL.MethodContext(self, localctx) + self.enterOuterAlt(localctx, 1) + self.state = 37 + self.match(COOL.OBJECTID) + self.state = 38 + self.match(COOL.OPEN_ROUND) + self.state = 49 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOL.OBJECTID: + self.state = 39 + self.formal() + self.state = 44 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOL.COMMA: + self.state = 40 + self.match(COOL.COMMA) + self.state = 41 + self.formal() + self.state = 46 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 51 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 52 + self.match(COOL.CLOSE_ROUND) + self.state = 53 + self.match(COOL.COLON) + self.state = 54 + self.match(COOL.TYPEID) + self.state = 55 + self.match(COOL.OPEN_CURLY) + self.state = 56 + self.expression(0) + self.state = 57 + self.match(COOL.CLOSE_CURLY) + pass + + elif la_ == 2: + localctx = COOL.PropertyContext(self, localctx) + self.enterOuterAlt(localctx, 2) + self.state = 59 + self.match(COOL.OBJECTID) + self.state = 60 + self.match(COOL.COLON) + self.state = 61 + self.match(COOL.TYPEID) + self.state = 64 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOL.ASSIGNMENT: + self.state = 62 + self.match(COOL.ASSIGNMENT) + self.state = 63 + self.expression(0) + + + pass + + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class FormalContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + + def COLON(self): + return self.getToken(COOL.COLON, 0) + + def TYPEID(self): + return self.getToken(COOL.TYPEID, 0) + + def getRuleIndex(self): + return COOL.RULE_formal + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterFormal" ): + listener.enterFormal(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitFormal" ): + listener.exitFormal(self) + + + + + def formal(self): + + localctx = COOL.FormalContext(self, self._ctx, self.state) + self.enterRule(localctx, 8, self.RULE_formal) + try: + self.enterOuterAlt(localctx, 1) + self.state = 68 + self.match(COOL.OBJECTID) + self.state = 69 + self.match(COOL.COLON) + self.state = 70 + self.match(COOL.TYPEID) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class ExpressionContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return COOL.RULE_expression + + + def copyFrom(self, ctx:ParserRuleContext): + super().copyFrom(ctx) + + + class LetInContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def LET(self): + return self.getToken(COOL.LET, 0) + def OBJECTID(self, i:int=None): + if i is None: + return self.getTokens(COOL.OBJECTID) + else: + return self.getToken(COOL.OBJECTID, i) + def COLON(self, i:int=None): + if i is None: + return self.getTokens(COOL.COLON) + else: + return self.getToken(COOL.COLON, i) + def TYPEID(self, i:int=None): + if i is None: + return self.getTokens(COOL.TYPEID) + else: + return self.getToken(COOL.TYPEID, i) + def IN(self): + return self.getToken(COOL.IN, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def ASSIGNMENT(self, i:int=None): + if i is None: + return self.getTokens(COOL.ASSIGNMENT) + else: + return self.getToken(COOL.ASSIGNMENT, i) + def COMMA(self, i:int=None): + if i is None: + return self.getTokens(COOL.COMMA) + else: + return self.getToken(COOL.COMMA, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterLetIn" ): + listener.enterLetIn(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitLetIn" ): + listener.exitLetIn(self) + + + class MinusContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def MINUS(self): + return self.getToken(COOL.MINUS, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMinus" ): + listener.enterMinus(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMinus" ): + listener.exitMinus(self) + + + class StringContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def STRING(self): + return self.getToken(COOL.STRING, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterString" ): + listener.enterString(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitString" ): + listener.exitString(self) + + + class IsvoidContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def ISVOID(self): + return self.getToken(COOL.ISVOID, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterIsvoid" ): + listener.enterIsvoid(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitIsvoid" ): + listener.exitIsvoid(self) + + + class WhileContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def WHILE(self): + return self.getToken(COOL.WHILE, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def LOOP(self): + return self.getToken(COOL.LOOP, 0) + def POOL(self): + return self.getToken(COOL.POOL, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterWhile" ): + listener.enterWhile(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitWhile" ): + listener.exitWhile(self) + + + class DivisionContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def DIVISION(self): + return self.getToken(COOL.DIVISION, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterDivision" ): + listener.enterDivision(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitDivision" ): + listener.exitDivision(self) + + + class NegativeContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def INTEGER_NEGATIVE(self): + return self.getToken(COOL.INTEGER_NEGATIVE, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterNegative" ): + listener.enterNegative(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitNegative" ): + listener.exitNegative(self) + + + class BoolNotContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def NOT(self): + return self.getToken(COOL.NOT, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterBoolNot" ): + listener.enterBoolNot(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitBoolNot" ): + listener.exitBoolNot(self) + + + class LessThanContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def LESS_THAN(self): + return self.getToken(COOL.LESS_THAN, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterLessThan" ): + listener.enterLessThan(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitLessThan" ): + listener.exitLessThan(self) + + + class BlockContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OPEN_CURLY(self): + return self.getToken(COOL.OPEN_CURLY, 0) + def CLOSE_CURLY(self): + return self.getToken(COOL.CLOSE_CURLY, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def SEMICOLON(self, i:int=None): + if i is None: + return self.getTokens(COOL.SEMICOLON) + else: + return self.getToken(COOL.SEMICOLON, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterBlock" ): + listener.enterBlock(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitBlock" ): + listener.exitBlock(self) + + + class IdContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterId" ): + listener.enterId(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitId" ): + listener.exitId(self) + + + class MultiplyContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def MULTIPLY(self): + return self.getToken(COOL.MULTIPLY, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMultiply" ): + listener.enterMultiply(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMultiply" ): + listener.exitMultiply(self) + + + class IfContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def IF(self): + return self.getToken(COOL.IF, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def THEN(self): + return self.getToken(COOL.THEN, 0) + def ELSE(self): + return self.getToken(COOL.ELSE, 0) + def FI(self): + return self.getToken(COOL.FI, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterIf" ): + listener.enterIf(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitIf" ): + listener.exitIf(self) + + + class CaseContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def CASE(self): + return self.getToken(COOL.CASE, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def OF(self): + return self.getToken(COOL.OF, 0) + def ESAC(self): + return self.getToken(COOL.ESAC, 0) + def OBJECTID(self, i:int=None): + if i is None: + return self.getTokens(COOL.OBJECTID) + else: + return self.getToken(COOL.OBJECTID, i) + def COLON(self, i:int=None): + if i is None: + return self.getTokens(COOL.COLON) + else: + return self.getToken(COOL.COLON, i) + def TYPEID(self, i:int=None): + if i is None: + return self.getTokens(COOL.TYPEID) + else: + return self.getToken(COOL.TYPEID, i) + def CASE_ARROW(self, i:int=None): + if i is None: + return self.getTokens(COOL.CASE_ARROW) + else: + return self.getToken(COOL.CASE_ARROW, i) + def SEMICOLON(self, i:int=None): + if i is None: + return self.getTokens(COOL.SEMICOLON) + else: + return self.getToken(COOL.SEMICOLON, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterCase" ): + listener.enterCase(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitCase" ): + listener.exitCase(self) + + + class OwnMethodCallContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + def OPEN_ROUND(self): + return self.getToken(COOL.OPEN_ROUND, 0) + def CLOSE_ROUND(self): + return self.getToken(COOL.CLOSE_ROUND, 0) + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def COMMA(self, i:int=None): + if i is None: + return self.getTokens(COOL.COMMA) + else: + return self.getToken(COOL.COMMA, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterOwnMethodCall" ): + listener.enterOwnMethodCall(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitOwnMethodCall" ): + listener.exitOwnMethodCall(self) + + + class AddContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def ADD(self): + return self.getToken(COOL.ADD, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterAdd" ): + listener.enterAdd(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitAdd" ): + listener.exitAdd(self) + + + class NewContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def NEW(self): + return self.getToken(COOL.NEW, 0) + def TYPEID(self): + return self.getToken(COOL.TYPEID, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterNew" ): + listener.enterNew(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitNew" ): + listener.exitNew(self) + + + class ParenthesesContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OPEN_ROUND(self): + return self.getToken(COOL.OPEN_ROUND, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + def CLOSE_ROUND(self): + return self.getToken(COOL.CLOSE_ROUND, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterParentheses" ): + listener.enterParentheses(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitParentheses" ): + listener.exitParentheses(self) + + + class AssignmentContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + def ASSIGNMENT(self): + return self.getToken(COOL.ASSIGNMENT, 0) + def expression(self): + return self.getTypedRuleContext(COOL.ExpressionContext,0) + + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterAssignment" ): + listener.enterAssignment(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitAssignment" ): + listener.exitAssignment(self) + + + class FalseContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def FALSE(self): + return self.getToken(COOL.FALSE, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterFalse" ): + listener.enterFalse(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitFalse" ): + listener.exitFalse(self) + + + class IntContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def INT(self): + return self.getToken(COOL.INT, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterInt" ): + listener.enterInt(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitInt" ): + listener.exitInt(self) + + + class EqualContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def EQUAL(self): + return self.getToken(COOL.EQUAL, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterEqual" ): + listener.enterEqual(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitEqual" ): + listener.exitEqual(self) + + + class TrueContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def TRUE(self): + return self.getToken(COOL.TRUE, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterTrue" ): + listener.enterTrue(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitTrue" ): + listener.exitTrue(self) + + + class LessEqualContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def LESS_EQUAL(self): + return self.getToken(COOL.LESS_EQUAL, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterLessEqual" ): + listener.enterLessEqual(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitLessEqual" ): + listener.exitLessEqual(self) + + + class MethodCallContext(ExpressionContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a COOL.ExpressionContext + super().__init__(parser) + self.copyFrom(ctx) + + def expression(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(COOL.ExpressionContext) + else: + return self.getTypedRuleContext(COOL.ExpressionContext,i) + + def DOT(self): + return self.getToken(COOL.DOT, 0) + def OBJECTID(self): + return self.getToken(COOL.OBJECTID, 0) + def OPEN_ROUND(self): + return self.getToken(COOL.OPEN_ROUND, 0) + def CLOSE_ROUND(self): + return self.getToken(COOL.CLOSE_ROUND, 0) + def AT(self): + return self.getToken(COOL.AT, 0) + def TYPEID(self): + return self.getToken(COOL.TYPEID, 0) + def COMMA(self, i:int=None): + if i is None: + return self.getTokens(COOL.COMMA) + else: + return self.getToken(COOL.COMMA, i) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterMethodCall" ): + listener.enterMethodCall(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitMethodCall" ): + listener.exitMethodCall(self) + + + + def expression(self, _p:int=0): + _parentctx = self._ctx + _parentState = self.state + localctx = COOL.ExpressionContext(self, self._ctx, _parentState) + _prevctx = localctx + _startState = 10 + self.enterRecursionRule(localctx, 10, self.RULE_expression, _p) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 172 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input,14,self._ctx) + if la_ == 1: + localctx = COOL.OwnMethodCallContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + + self.state = 73 + self.match(COOL.OBJECTID) + self.state = 74 + self.match(COOL.OPEN_ROUND) + self.state = 85 + self._errHandler.sync(self) + _la = self._input.LA(1) + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0): + self.state = 75 + self.expression(0) + self.state = 80 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOL.COMMA: + self.state = 76 + self.match(COOL.COMMA) + self.state = 77 + self.expression(0) + self.state = 82 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 87 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 88 + self.match(COOL.CLOSE_ROUND) + pass + + elif la_ == 2: + localctx = COOL.IfContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 89 + self.match(COOL.IF) + self.state = 90 + self.expression(0) + self.state = 91 + self.match(COOL.THEN) + self.state = 92 + self.expression(0) + self.state = 93 + self.match(COOL.ELSE) + self.state = 94 + self.expression(0) + self.state = 95 + self.match(COOL.FI) + pass + + elif la_ == 3: + localctx = COOL.WhileContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 97 + self.match(COOL.WHILE) + self.state = 98 + self.expression(0) + self.state = 99 + self.match(COOL.LOOP) + self.state = 100 + self.expression(0) + self.state = 101 + self.match(COOL.POOL) + pass + + elif la_ == 4: + localctx = COOL.BlockContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 103 + self.match(COOL.OPEN_CURLY) + self.state = 107 + self._errHandler.sync(self) + _la = self._input.LA(1) + while True: + self.state = 104 + self.expression(0) + self.state = 105 + self.match(COOL.SEMICOLON) + self.state = 109 + self._errHandler.sync(self) + _la = self._input.LA(1) + if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0)): + break + + self.state = 111 + self.match(COOL.CLOSE_CURLY) + pass + + elif la_ == 5: + localctx = COOL.LetInContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 113 + self.match(COOL.LET) + self.state = 114 + self.match(COOL.OBJECTID) + self.state = 115 + self.match(COOL.COLON) + self.state = 116 + self.match(COOL.TYPEID) + self.state = 119 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOL.ASSIGNMENT: + self.state = 117 + self.match(COOL.ASSIGNMENT) + self.state = 118 + self.expression(0) + + + self.state = 131 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOL.COMMA: + self.state = 121 + self.match(COOL.COMMA) + self.state = 122 + self.match(COOL.OBJECTID) + self.state = 123 + self.match(COOL.COLON) + self.state = 124 + self.match(COOL.TYPEID) + self.state = 127 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOL.ASSIGNMENT: + self.state = 125 + self.match(COOL.ASSIGNMENT) + self.state = 126 + self.expression(0) + + + self.state = 133 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 134 + self.match(COOL.IN) + self.state = 135 + self.expression(20) + pass + + elif la_ == 6: + localctx = COOL.CaseContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 136 + self.match(COOL.CASE) + self.state = 137 + self.expression(0) + self.state = 138 + self.match(COOL.OF) + self.state = 146 + self._errHandler.sync(self) + _la = self._input.LA(1) + while True: + self.state = 139 + self.match(COOL.OBJECTID) + self.state = 140 + self.match(COOL.COLON) + self.state = 141 + self.match(COOL.TYPEID) + self.state = 142 + self.match(COOL.CASE_ARROW) + self.state = 143 + self.expression(0) + self.state = 144 + self.match(COOL.SEMICOLON) + self.state = 148 + self._errHandler.sync(self) + _la = self._input.LA(1) + if not (_la==COOL.OBJECTID): + break + + self.state = 150 + self.match(COOL.ESAC) + pass + + elif la_ == 7: + localctx = COOL.NewContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 152 + self.match(COOL.NEW) + self.state = 153 + self.match(COOL.TYPEID) + pass + + elif la_ == 8: + localctx = COOL.NegativeContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 154 + self.match(COOL.INTEGER_NEGATIVE) + self.state = 155 + self.expression(17) + pass + + elif la_ == 9: + localctx = COOL.IsvoidContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 156 + self.match(COOL.ISVOID) + self.state = 157 + self.expression(16) + pass + + elif la_ == 10: + localctx = COOL.BoolNotContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 158 + self.match(COOL.NOT) + self.state = 159 + self.expression(8) + pass + + elif la_ == 11: + localctx = COOL.ParenthesesContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 160 + self.match(COOL.OPEN_ROUND) + self.state = 161 + self.expression(0) + self.state = 162 + self.match(COOL.CLOSE_ROUND) + pass + + elif la_ == 12: + localctx = COOL.IdContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 164 + self.match(COOL.OBJECTID) + pass + + elif la_ == 13: + localctx = COOL.IntContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 165 + self.match(COOL.INT) + pass + + elif la_ == 14: + localctx = COOL.StringContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 166 + self.match(COOL.STRING) + pass + + elif la_ == 15: + localctx = COOL.TrueContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 167 + self.match(COOL.TRUE) + pass + + elif la_ == 16: + localctx = COOL.FalseContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 168 + self.match(COOL.FALSE) + pass + + elif la_ == 17: + localctx = COOL.AssignmentContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 169 + self.match(COOL.OBJECTID) + self.state = 170 + self.match(COOL.ASSIGNMENT) + self.state = 171 + self.expression(1) + pass + + + self._ctx.stop = self._input.LT(-1) + self.state = 219 + self._errHandler.sync(self) + _alt = self._interp.adaptivePredict(self._input,19,self._ctx) + while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: + if _alt==1: + if self._parseListeners is not None: + self.triggerExitRuleEvent() + _prevctx = localctx + self.state = 217 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input,18,self._ctx) + if la_ == 1: + localctx = COOL.MultiplyContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 174 + if not self.precpred(self._ctx, 15): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 15)") + self.state = 175 + self.match(COOL.MULTIPLY) + self.state = 176 + self.expression(16) + pass + + elif la_ == 2: + localctx = COOL.DivisionContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 177 + if not self.precpred(self._ctx, 14): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 14)") + self.state = 178 + self.match(COOL.DIVISION) + self.state = 179 + self.expression(15) + pass + + elif la_ == 3: + localctx = COOL.AddContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 180 + if not self.precpred(self._ctx, 13): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 13)") + self.state = 181 + self.match(COOL.ADD) + self.state = 182 + self.expression(14) + pass + + elif la_ == 4: + localctx = COOL.MinusContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 183 + if not self.precpred(self._ctx, 12): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 12)") + self.state = 184 + self.match(COOL.MINUS) + self.state = 185 + self.expression(13) + pass + + elif la_ == 5: + localctx = COOL.LessThanContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 186 + if not self.precpred(self._ctx, 11): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 11)") + self.state = 187 + self.match(COOL.LESS_THAN) + self.state = 188 + self.expression(12) + pass + + elif la_ == 6: + localctx = COOL.LessEqualContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 189 + if not self.precpred(self._ctx, 10): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 10)") + self.state = 190 + self.match(COOL.LESS_EQUAL) + self.state = 191 + self.expression(11) + pass + + elif la_ == 7: + localctx = COOL.EqualContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 192 + if not self.precpred(self._ctx, 9): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 9)") + self.state = 193 + self.match(COOL.EQUAL) + self.state = 194 + self.expression(10) + pass + + elif la_ == 8: + localctx = COOL.MethodCallContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) + self.state = 195 + if not self.precpred(self._ctx, 25): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 25)") + self.state = 198 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==COOL.AT: + self.state = 196 + self.match(COOL.AT) + self.state = 197 + self.match(COOL.TYPEID) + + + self.state = 200 + self.match(COOL.DOT) + self.state = 201 + self.match(COOL.OBJECTID) + self.state = 202 + self.match(COOL.OPEN_ROUND) + self.state = 213 + self._errHandler.sync(self) + _la = self._input.LA(1) + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0): + self.state = 203 + self.expression(0) + self.state = 208 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==COOL.COMMA: + self.state = 204 + self.match(COOL.COMMA) + self.state = 205 + self.expression(0) + self.state = 210 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 215 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 216 + self.match(COOL.CLOSE_ROUND) + pass + + + self.state = 221 + self._errHandler.sync(self) + _alt = self._interp.adaptivePredict(self._input,19,self._ctx) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.unrollRecursionContexts(_parentctx) + return localctx + + + + def sempred(self, localctx:RuleContext, ruleIndex:int, predIndex:int): + if self._predicates == None: + self._predicates = dict() + self._predicates[5] = self.expression_sempred + pred = self._predicates.get(ruleIndex, None) + if pred is None: + raise Exception("No predicate with index:" + str(ruleIndex)) + else: + return pred(localctx, predIndex) + + def expression_sempred(self, localctx:ExpressionContext, predIndex:int): + if predIndex == 0: + return self.precpred(self._ctx, 15) + + + if predIndex == 1: + return self.precpred(self._ctx, 14) + + + if predIndex == 2: + return self.precpred(self._ctx, 13) + + + if predIndex == 3: + return self.precpred(self._ctx, 12) + + + if predIndex == 4: + return self.precpred(self._ctx, 11) + + + if predIndex == 5: + return self.precpred(self._ctx, 10) + + + if predIndex == 6: + return self.precpred(self._ctx, 9) + + + if predIndex == 7: + return self.precpred(self._ctx, 25) + + + + + diff --git a/COOL.tokens b/COOL.tokens new file mode 100644 index 00000000..bbdda836 --- /dev/null +++ b/COOL.tokens @@ -0,0 +1,69 @@ +CLASS=1 +ELSE=2 +FALSE=3 +FI=4 +IF=5 +IN=6 +INHERITS=7 +ISVOID=8 +LET=9 +LOOP=10 +POOL=11 +THEN=12 +WHILE=13 +CASE=14 +ESAC=15 +NEW=16 +OF=17 +NOT=18 +TRUE=19 +STRING=20 +BREAK_STRING=21 +INT=22 +TYPEID=23 +OBJECTID=24 +ASSIGNMENT=25 +CASE_ARROW=26 +ADD=27 +MINUS=28 +MULTIPLY=29 +DIVISION=30 +LESS_THAN=31 +LESS_EQUAL=32 +EQUAL=33 +INTEGER_NEGATIVE=34 +OPEN_ROUND=35 +CLOSE_ROUND=36 +OPEN_CURLY=37 +CLOSE_CURLY=38 +AT=39 +DOT=40 +COMMA=41 +COLON=42 +SEMICOLON=43 +WHITESPACE=44 +ONE_LINE_COMMENT=45 +OPEN_COMMENT=46 +COMMENT=47 +CLOSE_COMMENT=48 +'<-'=25 +'=>'=26 +'+'=27 +'-'=28 +'*'=29 +'/'=30 +'<'=31 +'<='=32 +'='=33 +'~'=34 +'('=35 +')'=36 +'{'=37 +'}'=38 +'@'=39 +'.'=40 +','=41 +':'=42 +';'=43 +'(*'=46 +'*)'=48 diff --git a/COOLCompiler.py b/COOLCompiler.py new file mode 100644 index 00000000..5a9b2584 --- /dev/null +++ b/COOLCompiler.py @@ -0,0 +1,36 @@ +import sys +import os.path +from antlr4 import * +from COOLLexer import COOLLexer +from COOLLexerErrorListener import COOLLexerErrorListener +from COOLParser import COOLParser +from COOLParserErrorListener import COOLParserErrorListener +from COOLListener import COOLListener + +def main(argv): + if not os.path.isfile(argv[1]): + print("invalid input filename") + return + + input = FileStream(argv[1]) + + lexer = COOLLexer(input) + lexer.removeErrorListeners() + lexer.addErrorListener(COOLLexerErrorListener()) + token = lexer.nextToken() + while token.type != Token.EOF: + token = lexer.nextToken() + + if lexer.hasErrors: + return + + lexer.reset(); + stream = CommonTokenStream(lexer) + parser = COOLParser(stream) + parser.removeErrorListeners() + parser.addErrorListener(COOLParserErrorListener()) + + tree = parser.program() + +if __name__ == '__main__': + main(sys.argv) diff --git a/COOLLexer.py b/COOLLexer.py new file mode 100644 index 00000000..bcb2349c --- /dev/null +++ b/COOLLexer.py @@ -0,0 +1,34 @@ +import sys +from io import StringIO +from typing.io import TextIO +from antlr4 import * +from COOL_LEX import COOL_LEX +from antlr4.CommonTokenFactory import CommonTokenFactory +from antlr4.atn.LexerATNSimulator import LexerATNSimulator +from antlr4.InputStream import InputStream +from antlr4.Recognizer import Recognizer +from antlr4.Token import Token +from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException + +class COOLLexer(COOL_LEX): + def __init__(self, input=None, output:TextIO = sys.stdout): + super().__init__(input, output) + self._hasErrors = False + + def notifyListeners(self, e:LexerNoViableAltException): + self._hasErrors = True + + start = self._tokenStartCharIndex + stop = self._input.index + text = self._input.getText(start, stop) + msg = "'" + self.getErrorDisplay(text) + "'" + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, self._token, self._tokenStartLine, self._tokenStartColumn, msg, e) + + def reset(self): + super().reset() + self._hasErrors = False + + @property + def hasErrors(self): + return self._hasErrors \ No newline at end of file diff --git a/COOLLexerErrorListener.py b/COOLLexerErrorListener.py new file mode 100644 index 00000000..451cdba7 --- /dev/null +++ b/COOLLexerErrorListener.py @@ -0,0 +1,7 @@ +import sys +from antlr4 import * +from antlr4.error.ErrorListener import ErrorListener + +class COOLLexerErrorListener(ErrorListener): + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): + print("(" + str(line) + ", " + str(column+1) + ") - LexicographicError: " + msg, file=sys.stderr) \ No newline at end of file diff --git a/COOLListener.py b/COOLListener.py new file mode 100644 index 00000000..e5e5d915 --- /dev/null +++ b/COOLListener.py @@ -0,0 +1,289 @@ +# Generated from COOL.g4 by ANTLR 4.7.2 +from antlr4 import * +if __name__ is not None and "." in __name__: + from .COOL import COOL +else: + from COOL import COOL + +# This class defines a complete listener for a parse tree produced by COOL. +class COOLListener(ParseTreeListener): + + # Enter a parse tree produced by COOL#program. + def enterProgram(self, ctx:COOL.ProgramContext): + pass + + # Exit a parse tree produced by COOL#program. + def exitProgram(self, ctx:COOL.ProgramContext): + pass + + + # Enter a parse tree produced by COOL#classes. + def enterClasses(self, ctx:COOL.ClassesContext): + pass + + # Exit a parse tree produced by COOL#classes. + def exitClasses(self, ctx:COOL.ClassesContext): + pass + + + # Enter a parse tree produced by COOL#classDefine. + def enterClassDefine(self, ctx:COOL.ClassDefineContext): + pass + + # Exit a parse tree produced by COOL#classDefine. + def exitClassDefine(self, ctx:COOL.ClassDefineContext): + pass + + + # Enter a parse tree produced by COOL#method. + def enterMethod(self, ctx:COOL.MethodContext): + pass + + # Exit a parse tree produced by COOL#method. + def exitMethod(self, ctx:COOL.MethodContext): + pass + + + # Enter a parse tree produced by COOL#property. + def enterProperty(self, ctx:COOL.PropertyContext): + pass + + # Exit a parse tree produced by COOL#property. + def exitProperty(self, ctx:COOL.PropertyContext): + pass + + + # Enter a parse tree produced by COOL#formal. + def enterFormal(self, ctx:COOL.FormalContext): + pass + + # Exit a parse tree produced by COOL#formal. + def exitFormal(self, ctx:COOL.FormalContext): + pass + + + # Enter a parse tree produced by COOL#letIn. + def enterLetIn(self, ctx:COOL.LetInContext): + pass + + # Exit a parse tree produced by COOL#letIn. + def exitLetIn(self, ctx:COOL.LetInContext): + pass + + + # Enter a parse tree produced by COOL#minus. + def enterMinus(self, ctx:COOL.MinusContext): + pass + + # Exit a parse tree produced by COOL#minus. + def exitMinus(self, ctx:COOL.MinusContext): + pass + + + # Enter a parse tree produced by COOL#string. + def enterString(self, ctx:COOL.StringContext): + pass + + # Exit a parse tree produced by COOL#string. + def exitString(self, ctx:COOL.StringContext): + pass + + + # Enter a parse tree produced by COOL#isvoid. + def enterIsvoid(self, ctx:COOL.IsvoidContext): + pass + + # Exit a parse tree produced by COOL#isvoid. + def exitIsvoid(self, ctx:COOL.IsvoidContext): + pass + + + # Enter a parse tree produced by COOL#while. + def enterWhile(self, ctx:COOL.WhileContext): + pass + + # Exit a parse tree produced by COOL#while. + def exitWhile(self, ctx:COOL.WhileContext): + pass + + + # Enter a parse tree produced by COOL#division. + def enterDivision(self, ctx:COOL.DivisionContext): + pass + + # Exit a parse tree produced by COOL#division. + def exitDivision(self, ctx:COOL.DivisionContext): + pass + + + # Enter a parse tree produced by COOL#negative. + def enterNegative(self, ctx:COOL.NegativeContext): + pass + + # Exit a parse tree produced by COOL#negative. + def exitNegative(self, ctx:COOL.NegativeContext): + pass + + + # Enter a parse tree produced by COOL#boolNot. + def enterBoolNot(self, ctx:COOL.BoolNotContext): + pass + + # Exit a parse tree produced by COOL#boolNot. + def exitBoolNot(self, ctx:COOL.BoolNotContext): + pass + + + # Enter a parse tree produced by COOL#lessThan. + def enterLessThan(self, ctx:COOL.LessThanContext): + pass + + # Exit a parse tree produced by COOL#lessThan. + def exitLessThan(self, ctx:COOL.LessThanContext): + pass + + + # Enter a parse tree produced by COOL#block. + def enterBlock(self, ctx:COOL.BlockContext): + pass + + # Exit a parse tree produced by COOL#block. + def exitBlock(self, ctx:COOL.BlockContext): + pass + + + # Enter a parse tree produced by COOL#id. + def enterId(self, ctx:COOL.IdContext): + pass + + # Exit a parse tree produced by COOL#id. + def exitId(self, ctx:COOL.IdContext): + pass + + + # Enter a parse tree produced by COOL#multiply. + def enterMultiply(self, ctx:COOL.MultiplyContext): + pass + + # Exit a parse tree produced by COOL#multiply. + def exitMultiply(self, ctx:COOL.MultiplyContext): + pass + + + # Enter a parse tree produced by COOL#if. + def enterIf(self, ctx:COOL.IfContext): + pass + + # Exit a parse tree produced by COOL#if. + def exitIf(self, ctx:COOL.IfContext): + pass + + + # Enter a parse tree produced by COOL#case. + def enterCase(self, ctx:COOL.CaseContext): + pass + + # Exit a parse tree produced by COOL#case. + def exitCase(self, ctx:COOL.CaseContext): + pass + + + # Enter a parse tree produced by COOL#ownMethodCall. + def enterOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): + pass + + # Exit a parse tree produced by COOL#ownMethodCall. + def exitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): + pass + + + # Enter a parse tree produced by COOL#add. + def enterAdd(self, ctx:COOL.AddContext): + pass + + # Exit a parse tree produced by COOL#add. + def exitAdd(self, ctx:COOL.AddContext): + pass + + + # Enter a parse tree produced by COOL#new. + def enterNew(self, ctx:COOL.NewContext): + pass + + # Exit a parse tree produced by COOL#new. + def exitNew(self, ctx:COOL.NewContext): + pass + + + # Enter a parse tree produced by COOL#parentheses. + def enterParentheses(self, ctx:COOL.ParenthesesContext): + pass + + # Exit a parse tree produced by COOL#parentheses. + def exitParentheses(self, ctx:COOL.ParenthesesContext): + pass + + + # Enter a parse tree produced by COOL#assignment. + def enterAssignment(self, ctx:COOL.AssignmentContext): + pass + + # Exit a parse tree produced by COOL#assignment. + def exitAssignment(self, ctx:COOL.AssignmentContext): + pass + + + # Enter a parse tree produced by COOL#false. + def enterFalse(self, ctx:COOL.FalseContext): + pass + + # Exit a parse tree produced by COOL#false. + def exitFalse(self, ctx:COOL.FalseContext): + pass + + + # Enter a parse tree produced by COOL#int. + def enterInt(self, ctx:COOL.IntContext): + pass + + # Exit a parse tree produced by COOL#int. + def exitInt(self, ctx:COOL.IntContext): + pass + + + # Enter a parse tree produced by COOL#equal. + def enterEqual(self, ctx:COOL.EqualContext): + pass + + # Exit a parse tree produced by COOL#equal. + def exitEqual(self, ctx:COOL.EqualContext): + pass + + + # Enter a parse tree produced by COOL#true. + def enterTrue(self, ctx:COOL.TrueContext): + pass + + # Exit a parse tree produced by COOL#true. + def exitTrue(self, ctx:COOL.TrueContext): + pass + + + # Enter a parse tree produced by COOL#lessEqual. + def enterLessEqual(self, ctx:COOL.LessEqualContext): + pass + + # Exit a parse tree produced by COOL#lessEqual. + def exitLessEqual(self, ctx:COOL.LessEqualContext): + pass + + + # Enter a parse tree produced by COOL#methodCall. + def enterMethodCall(self, ctx:COOL.MethodCallContext): + pass + + # Exit a parse tree produced by COOL#methodCall. + def exitMethodCall(self, ctx:COOL.MethodCallContext): + pass + + diff --git a/COOLParser.py b/COOLParser.py new file mode 100644 index 00000000..7f3ad8ac --- /dev/null +++ b/COOLParser.py @@ -0,0 +1,24 @@ +import sys +from io import StringIO +from typing.io import TextIO +from antlr4 import * +from COOL import COOL +from antlr4.CommonTokenFactory import CommonTokenFactory +from antlr4.atn.LexerATNSimulator import LexerATNSimulator +from antlr4.InputStream import InputStream +from antlr4.Recognizer import Recognizer +from antlr4.Token import Token +from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException + +class COOLParser(COOL): + def __init__(self, input=None, output:TextIO = sys.stdout): + super().__init__(input, output) + + def notifyErrorListeners(self, msg:str, offendingToken:Token = None, e:RecognitionException = None): + if offendingToken is None: + offendingToken = self.getCurrentToken() + self._syntaxErrors += 1 + line = offendingToken.line + column = offendingToken.column + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, offendingToken, line, column, msg, e) \ No newline at end of file diff --git a/COOLParserErrorListener.py b/COOLParserErrorListener.py new file mode 100644 index 00000000..5bae5069 --- /dev/null +++ b/COOLParserErrorListener.py @@ -0,0 +1,12 @@ +import sys +from antlr4 import * +from antlr4.error.ErrorListener import ErrorListener + +class COOLParserErrorListener(ErrorListener): + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): + msg = offendingSymbol.text + if msg == "": + msg = "EOF" + else: + msg = "\"" + msg + "\"" + print("(" + str(line) + ", " + str(column+1) + ") - SyntacticError: ERROR at or near " +msg, file=sys.stderr) \ No newline at end of file diff --git a/COOL_LEX.interp b/COOL_LEX.interp new file mode 100644 index 00000000..5e362562 --- /dev/null +++ b/COOL_LEX.interp @@ -0,0 +1,182 @@ +token literal names: +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +'<-' +'=>' +'+' +'-' +'*' +'/' +'<' +'<=' +'=' +'~' +'(' +')' +'{' +'}' +'@' +'.' +',' +':' +';' +null +null +'(*' +null +'*)' + +token symbolic names: +null +CLASS +ELSE +FALSE +FI +IF +IN +INHERITS +ISVOID +LET +LOOP +POOL +THEN +WHILE +CASE +ESAC +NEW +OF +NOT +TRUE +STRING +BREAK_STRING +INT +TYPEID +OBJECTID +ASSIGNMENT +CASE_ARROW +ADD +MINUS +MULTIPLY +DIVISION +LESS_THAN +LESS_EQUAL +EQUAL +INTEGER_NEGATIVE +OPEN_ROUND +CLOSE_ROUND +OPEN_CURLY +CLOSE_CURLY +AT +DOT +COMMA +COLON +SEMICOLON +WHITESPACE +ONE_LINE_COMMENT +OPEN_COMMENT +COMMENT +CLOSE_COMMENT + +rule names: +CLASS +ELSE +FALSE +FI +IF +IN +INHERITS +ISVOID +LET +LOOP +POOL +THEN +WHILE +CASE +ESAC +NEW +OF +NOT +TRUE +STRING +BREAK_STRING +INT +TYPEID +OBJECTID +ASSIGNMENT +CASE_ARROW +ADD +MINUS +MULTIPLY +DIVISION +LESS_THAN +LESS_EQUAL +EQUAL +INTEGER_NEGATIVE +OPEN_ROUND +CLOSE_ROUND +OPEN_CURLY +CLOSE_CURLY +AT +DOT +COMMA +COLON +SEMICOLON +A +C +D +E +F +H +I +L +N +O +P +R +S +T +U +V +W +ESC +UNICODE +HEX +WHITESPACE +ONE_LINE_COMMENT +OPEN_COMMENT +COMMENT +CLOSE_COMMENT + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN + +mode names: +DEFAULT_MODE +MULTILINE_COMMENT + +atn: +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 50, 406, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 7, 21, 238, 10, 21, 12, 21, 14, 21, 241, 11, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 5, 22, 252, 10, 22, 3, 23, 6, 23, 255, 10, 23, 13, 23, 14, 23, 256, 3, 24, 3, 24, 7, 24, 261, 10, 24, 12, 24, 14, 24, 264, 11, 24, 3, 25, 3, 25, 7, 25, 268, 10, 25, 12, 25, 14, 25, 271, 11, 25, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 62, 5, 62, 351, 10, 62, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 6, 65, 362, 10, 65, 13, 65, 14, 65, 363, 3, 65, 3, 65, 3, 66, 3, 66, 3, 66, 3, 66, 7, 66, 372, 10, 66, 12, 66, 14, 66, 375, 11, 66, 3, 66, 5, 66, 378, 10, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 6, 68, 393, 10, 68, 13, 68, 14, 68, 394, 5, 68, 397, 10, 68, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 394, 2, 70, 4, 3, 6, 4, 8, 5, 10, 6, 12, 7, 14, 8, 16, 9, 18, 10, 20, 11, 22, 12, 24, 13, 26, 14, 28, 15, 30, 16, 32, 17, 34, 18, 36, 19, 38, 20, 40, 21, 42, 22, 44, 23, 46, 24, 48, 25, 50, 26, 52, 27, 54, 28, 56, 29, 58, 30, 60, 31, 62, 32, 64, 33, 66, 34, 68, 35, 70, 36, 72, 37, 74, 38, 76, 39, 78, 40, 80, 41, 82, 42, 84, 43, 86, 44, 88, 45, 90, 2, 92, 2, 94, 2, 96, 2, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 46, 132, 47, 134, 48, 136, 49, 138, 50, 4, 2, 3, 28, 6, 2, 12, 12, 15, 15, 36, 36, 94, 94, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 398, 2, 4, 3, 2, 2, 2, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 50, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 130, 3, 2, 2, 2, 2, 132, 3, 2, 2, 2, 2, 134, 3, 2, 2, 2, 3, 136, 3, 2, 2, 2, 3, 138, 3, 2, 2, 2, 4, 140, 3, 2, 2, 2, 6, 146, 3, 2, 2, 2, 8, 151, 3, 2, 2, 2, 10, 157, 3, 2, 2, 2, 12, 160, 3, 2, 2, 2, 14, 163, 3, 2, 2, 2, 16, 166, 3, 2, 2, 2, 18, 175, 3, 2, 2, 2, 20, 182, 3, 2, 2, 2, 22, 186, 3, 2, 2, 2, 24, 191, 3, 2, 2, 2, 26, 196, 3, 2, 2, 2, 28, 201, 3, 2, 2, 2, 30, 207, 3, 2, 2, 2, 32, 212, 3, 2, 2, 2, 34, 217, 3, 2, 2, 2, 36, 221, 3, 2, 2, 2, 38, 224, 3, 2, 2, 2, 40, 228, 3, 2, 2, 2, 42, 233, 3, 2, 2, 2, 44, 251, 3, 2, 2, 2, 46, 254, 3, 2, 2, 2, 48, 258, 3, 2, 2, 2, 50, 265, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 275, 3, 2, 2, 2, 56, 278, 3, 2, 2, 2, 58, 280, 3, 2, 2, 2, 60, 282, 3, 2, 2, 2, 62, 284, 3, 2, 2, 2, 64, 286, 3, 2, 2, 2, 66, 288, 3, 2, 2, 2, 68, 291, 3, 2, 2, 2, 70, 293, 3, 2, 2, 2, 72, 295, 3, 2, 2, 2, 74, 297, 3, 2, 2, 2, 76, 299, 3, 2, 2, 2, 78, 301, 3, 2, 2, 2, 80, 303, 3, 2, 2, 2, 82, 305, 3, 2, 2, 2, 84, 307, 3, 2, 2, 2, 86, 309, 3, 2, 2, 2, 88, 311, 3, 2, 2, 2, 90, 313, 3, 2, 2, 2, 92, 315, 3, 2, 2, 2, 94, 317, 3, 2, 2, 2, 96, 319, 3, 2, 2, 2, 98, 321, 3, 2, 2, 2, 100, 323, 3, 2, 2, 2, 102, 325, 3, 2, 2, 2, 104, 327, 3, 2, 2, 2, 106, 329, 3, 2, 2, 2, 108, 331, 3, 2, 2, 2, 110, 333, 3, 2, 2, 2, 112, 335, 3, 2, 2, 2, 114, 337, 3, 2, 2, 2, 116, 339, 3, 2, 2, 2, 118, 341, 3, 2, 2, 2, 120, 343, 3, 2, 2, 2, 122, 345, 3, 2, 2, 2, 124, 347, 3, 2, 2, 2, 126, 352, 3, 2, 2, 2, 128, 358, 3, 2, 2, 2, 130, 361, 3, 2, 2, 2, 132, 367, 3, 2, 2, 2, 134, 381, 3, 2, 2, 2, 136, 396, 3, 2, 2, 2, 138, 400, 3, 2, 2, 2, 140, 141, 5, 92, 46, 2, 141, 142, 5, 104, 52, 2, 142, 143, 5, 90, 45, 2, 143, 144, 5, 114, 57, 2, 144, 145, 5, 114, 57, 2, 145, 5, 3, 2, 2, 2, 146, 147, 5, 96, 48, 2, 147, 148, 5, 104, 52, 2, 148, 149, 5, 114, 57, 2, 149, 150, 5, 96, 48, 2, 150, 7, 3, 2, 2, 2, 151, 152, 7, 104, 2, 2, 152, 153, 5, 90, 45, 2, 153, 154, 5, 104, 52, 2, 154, 155, 5, 114, 57, 2, 155, 156, 5, 96, 48, 2, 156, 9, 3, 2, 2, 2, 157, 158, 5, 98, 49, 2, 158, 159, 5, 102, 51, 2, 159, 11, 3, 2, 2, 2, 160, 161, 5, 102, 51, 2, 161, 162, 5, 98, 49, 2, 162, 13, 3, 2, 2, 2, 163, 164, 5, 102, 51, 2, 164, 165, 5, 106, 53, 2, 165, 15, 3, 2, 2, 2, 166, 167, 5, 102, 51, 2, 167, 168, 5, 106, 53, 2, 168, 169, 5, 100, 50, 2, 169, 170, 5, 96, 48, 2, 170, 171, 5, 112, 56, 2, 171, 172, 5, 102, 51, 2, 172, 173, 5, 116, 58, 2, 173, 174, 5, 114, 57, 2, 174, 17, 3, 2, 2, 2, 175, 176, 5, 102, 51, 2, 176, 177, 5, 114, 57, 2, 177, 178, 5, 120, 60, 2, 178, 179, 5, 108, 54, 2, 179, 180, 5, 102, 51, 2, 180, 181, 5, 94, 47, 2, 181, 19, 3, 2, 2, 2, 182, 183, 5, 104, 52, 2, 183, 184, 5, 96, 48, 2, 184, 185, 5, 116, 58, 2, 185, 21, 3, 2, 2, 2, 186, 187, 5, 104, 52, 2, 187, 188, 5, 108, 54, 2, 188, 189, 5, 108, 54, 2, 189, 190, 5, 110, 55, 2, 190, 23, 3, 2, 2, 2, 191, 192, 5, 110, 55, 2, 192, 193, 5, 108, 54, 2, 193, 194, 5, 108, 54, 2, 194, 195, 5, 104, 52, 2, 195, 25, 3, 2, 2, 2, 196, 197, 5, 116, 58, 2, 197, 198, 5, 100, 50, 2, 198, 199, 5, 96, 48, 2, 199, 200, 5, 106, 53, 2, 200, 27, 3, 2, 2, 2, 201, 202, 5, 122, 61, 2, 202, 203, 5, 100, 50, 2, 203, 204, 5, 102, 51, 2, 204, 205, 5, 104, 52, 2, 205, 206, 5, 96, 48, 2, 206, 29, 3, 2, 2, 2, 207, 208, 5, 92, 46, 2, 208, 209, 5, 90, 45, 2, 209, 210, 5, 114, 57, 2, 210, 211, 5, 96, 48, 2, 211, 31, 3, 2, 2, 2, 212, 213, 5, 96, 48, 2, 213, 214, 5, 114, 57, 2, 214, 215, 5, 90, 45, 2, 215, 216, 5, 92, 46, 2, 216, 33, 3, 2, 2, 2, 217, 218, 5, 106, 53, 2, 218, 219, 5, 96, 48, 2, 219, 220, 5, 122, 61, 2, 220, 35, 3, 2, 2, 2, 221, 222, 5, 108, 54, 2, 222, 223, 5, 98, 49, 2, 223, 37, 3, 2, 2, 2, 224, 225, 5, 106, 53, 2, 225, 226, 5, 108, 54, 2, 226, 227, 5, 116, 58, 2, 227, 39, 3, 2, 2, 2, 228, 229, 7, 118, 2, 2, 229, 230, 5, 112, 56, 2, 230, 231, 5, 118, 59, 2, 231, 232, 5, 96, 48, 2, 232, 41, 3, 2, 2, 2, 233, 239, 7, 36, 2, 2, 234, 238, 5, 124, 62, 2, 235, 238, 5, 44, 22, 2, 236, 238, 10, 2, 2, 2, 237, 234, 3, 2, 2, 2, 237, 235, 3, 2, 2, 2, 237, 236, 3, 2, 2, 2, 238, 241, 3, 2, 2, 2, 239, 237, 3, 2, 2, 2, 239, 240, 3, 2, 2, 2, 240, 242, 3, 2, 2, 2, 241, 239, 3, 2, 2, 2, 242, 243, 7, 36, 2, 2, 243, 43, 3, 2, 2, 2, 244, 245, 7, 94, 2, 2, 245, 246, 7, 15, 2, 2, 246, 252, 7, 12, 2, 2, 247, 248, 7, 94, 2, 2, 248, 252, 7, 15, 2, 2, 249, 250, 7, 94, 2, 2, 250, 252, 7, 12, 2, 2, 251, 244, 3, 2, 2, 2, 251, 247, 3, 2, 2, 2, 251, 249, 3, 2, 2, 2, 252, 45, 3, 2, 2, 2, 253, 255, 9, 3, 2, 2, 254, 253, 3, 2, 2, 2, 255, 256, 3, 2, 2, 2, 256, 254, 3, 2, 2, 2, 256, 257, 3, 2, 2, 2, 257, 47, 3, 2, 2, 2, 258, 262, 9, 4, 2, 2, 259, 261, 9, 5, 2, 2, 260, 259, 3, 2, 2, 2, 261, 264, 3, 2, 2, 2, 262, 260, 3, 2, 2, 2, 262, 263, 3, 2, 2, 2, 263, 49, 3, 2, 2, 2, 264, 262, 3, 2, 2, 2, 265, 269, 9, 6, 2, 2, 266, 268, 9, 5, 2, 2, 267, 266, 3, 2, 2, 2, 268, 271, 3, 2, 2, 2, 269, 267, 3, 2, 2, 2, 269, 270, 3, 2, 2, 2, 270, 51, 3, 2, 2, 2, 271, 269, 3, 2, 2, 2, 272, 273, 7, 62, 2, 2, 273, 274, 7, 47, 2, 2, 274, 53, 3, 2, 2, 2, 275, 276, 7, 63, 2, 2, 276, 277, 7, 64, 2, 2, 277, 55, 3, 2, 2, 2, 278, 279, 7, 45, 2, 2, 279, 57, 3, 2, 2, 2, 280, 281, 7, 47, 2, 2, 281, 59, 3, 2, 2, 2, 282, 283, 7, 44, 2, 2, 283, 61, 3, 2, 2, 2, 284, 285, 7, 49, 2, 2, 285, 63, 3, 2, 2, 2, 286, 287, 7, 62, 2, 2, 287, 65, 3, 2, 2, 2, 288, 289, 7, 62, 2, 2, 289, 290, 7, 63, 2, 2, 290, 67, 3, 2, 2, 2, 291, 292, 7, 63, 2, 2, 292, 69, 3, 2, 2, 2, 293, 294, 7, 128, 2, 2, 294, 71, 3, 2, 2, 2, 295, 296, 7, 42, 2, 2, 296, 73, 3, 2, 2, 2, 297, 298, 7, 43, 2, 2, 298, 75, 3, 2, 2, 2, 299, 300, 7, 125, 2, 2, 300, 77, 3, 2, 2, 2, 301, 302, 7, 127, 2, 2, 302, 79, 3, 2, 2, 2, 303, 304, 7, 66, 2, 2, 304, 81, 3, 2, 2, 2, 305, 306, 7, 48, 2, 2, 306, 83, 3, 2, 2, 2, 307, 308, 7, 46, 2, 2, 308, 85, 3, 2, 2, 2, 309, 310, 7, 60, 2, 2, 310, 87, 3, 2, 2, 2, 311, 312, 7, 61, 2, 2, 312, 89, 3, 2, 2, 2, 313, 314, 9, 7, 2, 2, 314, 91, 3, 2, 2, 2, 315, 316, 9, 8, 2, 2, 316, 93, 3, 2, 2, 2, 317, 318, 9, 9, 2, 2, 318, 95, 3, 2, 2, 2, 319, 320, 9, 10, 2, 2, 320, 97, 3, 2, 2, 2, 321, 322, 9, 11, 2, 2, 322, 99, 3, 2, 2, 2, 323, 324, 9, 12, 2, 2, 324, 101, 3, 2, 2, 2, 325, 326, 9, 13, 2, 2, 326, 103, 3, 2, 2, 2, 327, 328, 9, 14, 2, 2, 328, 105, 3, 2, 2, 2, 329, 330, 9, 15, 2, 2, 330, 107, 3, 2, 2, 2, 331, 332, 9, 16, 2, 2, 332, 109, 3, 2, 2, 2, 333, 334, 9, 17, 2, 2, 334, 111, 3, 2, 2, 2, 335, 336, 9, 18, 2, 2, 336, 113, 3, 2, 2, 2, 337, 338, 9, 19, 2, 2, 338, 115, 3, 2, 2, 2, 339, 340, 9, 20, 2, 2, 340, 117, 3, 2, 2, 2, 341, 342, 9, 21, 2, 2, 342, 119, 3, 2, 2, 2, 343, 344, 9, 22, 2, 2, 344, 121, 3, 2, 2, 2, 345, 346, 9, 23, 2, 2, 346, 123, 3, 2, 2, 2, 347, 350, 7, 94, 2, 2, 348, 351, 9, 24, 2, 2, 349, 351, 5, 126, 63, 2, 350, 348, 3, 2, 2, 2, 350, 349, 3, 2, 2, 2, 351, 125, 3, 2, 2, 2, 352, 353, 7, 119, 2, 2, 353, 354, 5, 128, 64, 2, 354, 355, 5, 128, 64, 2, 355, 356, 5, 128, 64, 2, 356, 357, 5, 128, 64, 2, 357, 127, 3, 2, 2, 2, 358, 359, 9, 25, 2, 2, 359, 129, 3, 2, 2, 2, 360, 362, 9, 26, 2, 2, 361, 360, 3, 2, 2, 2, 362, 363, 3, 2, 2, 2, 363, 361, 3, 2, 2, 2, 363, 364, 3, 2, 2, 2, 364, 365, 3, 2, 2, 2, 365, 366, 8, 65, 2, 2, 366, 131, 3, 2, 2, 2, 367, 368, 7, 47, 2, 2, 368, 369, 7, 47, 2, 2, 369, 373, 3, 2, 2, 2, 370, 372, 10, 27, 2, 2, 371, 370, 3, 2, 2, 2, 372, 375, 3, 2, 2, 2, 373, 371, 3, 2, 2, 2, 373, 374, 3, 2, 2, 2, 374, 377, 3, 2, 2, 2, 375, 373, 3, 2, 2, 2, 376, 378, 7, 12, 2, 2, 377, 376, 3, 2, 2, 2, 377, 378, 3, 2, 2, 2, 378, 379, 3, 2, 2, 2, 379, 380, 8, 66, 2, 2, 380, 133, 3, 2, 2, 2, 381, 382, 7, 42, 2, 2, 382, 383, 7, 44, 2, 2, 383, 384, 3, 2, 2, 2, 384, 385, 8, 67, 2, 2, 385, 386, 8, 67, 3, 2, 386, 135, 3, 2, 2, 2, 387, 388, 5, 134, 67, 2, 388, 389, 5, 136, 68, 2, 389, 390, 5, 138, 69, 2, 390, 397, 3, 2, 2, 2, 391, 393, 11, 2, 2, 2, 392, 391, 3, 2, 2, 2, 393, 394, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 394, 392, 3, 2, 2, 2, 395, 397, 3, 2, 2, 2, 396, 387, 3, 2, 2, 2, 396, 392, 3, 2, 2, 2, 397, 398, 3, 2, 2, 2, 398, 399, 8, 68, 2, 2, 399, 137, 3, 2, 2, 2, 400, 401, 7, 44, 2, 2, 401, 402, 7, 43, 2, 2, 402, 403, 3, 2, 2, 2, 403, 404, 8, 69, 2, 2, 404, 405, 8, 69, 4, 2, 405, 139, 3, 2, 2, 2, 16, 2, 3, 237, 239, 251, 256, 262, 269, 350, 363, 373, 377, 394, 396, 5, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file diff --git a/COOL_LEX.py b/COOL_LEX.py new file mode 100644 index 00000000..b5bb708c --- /dev/null +++ b/COOL_LEX.py @@ -0,0 +1,284 @@ +# Generated from COOL_LEX.g4 by ANTLR 4.7.2 +from antlr4 import * +from io import StringIO +from typing.io import TextIO +import sys + + + +def serializedATN(): + with StringIO() as buf: + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\62") + buf.write("\u0196\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6") + buf.write("\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r") + buf.write("\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22") + buf.write("\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30") + buf.write("\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35") + buf.write("\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\4") + buf.write("%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t,\4-\t") + buf.write("-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63") + buf.write("\4\64\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4") + buf.write(":\t:\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4") + buf.write("C\tC\4D\tD\4E\tE\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3") + buf.write("\3\3\3\3\4\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\6\3\6\3\6") + buf.write("\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3") + buf.write("\t\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\13") + buf.write("\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\16") + buf.write("\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20") + buf.write("\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\22\3\22\3\22") + buf.write("\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\25\3\25") + buf.write("\3\25\3\25\7\25\u00ee\n\25\f\25\16\25\u00f1\13\25\3\25") + buf.write("\3\25\3\26\3\26\3\26\3\26\3\26\3\26\3\26\5\26\u00fc\n") + buf.write("\26\3\27\6\27\u00ff\n\27\r\27\16\27\u0100\3\30\3\30\7") + buf.write("\30\u0105\n\30\f\30\16\30\u0108\13\30\3\31\3\31\7\31\u010c") + buf.write("\n\31\f\31\16\31\u010f\13\31\3\32\3\32\3\32\3\33\3\33") + buf.write("\3\33\3\34\3\34\3\35\3\35\3\36\3\36\3\37\3\37\3 \3 \3") + buf.write("!\3!\3!\3\"\3\"\3#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(") + buf.write("\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3\60\3") + buf.write("\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65\3\66") + buf.write("\3\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<\3<\3=\3=\3") + buf.write(">\3>\3>\5>\u015f\n>\3?\3?\3?\3?\3?\3?\3@\3@\3A\6A\u016a") + buf.write("\nA\rA\16A\u016b\3A\3A\3B\3B\3B\3B\7B\u0174\nB\fB\16B") + buf.write("\u0177\13B\3B\5B\u017a\nB\3B\3B\3C\3C\3C\3C\3C\3C\3D\3") + buf.write("D\3D\3D\3D\6D\u0189\nD\rD\16D\u018a\5D\u018d\nD\3D\3D") + buf.write("\3E\3E\3E\3E\3E\3E\3\u018a\2F\4\3\6\4\b\5\n\6\f\7\16\b") + buf.write("\20\t\22\n\24\13\26\f\30\r\32\16\34\17\36\20 \21\"\22") + buf.write("$\23&\24(\25*\26,\27.\30\60\31\62\32\64\33\66\348\35:") + buf.write("\36<\37> @!B\"D#F$H%J&L\'N(P)R*T+V,X-Z\2\\\2^\2`\2b\2") + buf.write("d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2|\2~\2\u0080\2\u0082") + buf.write(".\u0084/\u0086\60\u0088\61\u008a\62\4\2\3\34\6\2\f\f\17") + buf.write("\17$$^^\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4") + buf.write("\2EEee\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNn") + buf.write("n\4\2PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2") + buf.write("WWww\4\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;C") + buf.write("Hch\5\2\13\f\16\17\"\"\3\2\f\f\2\u018e\2\4\3\2\2\2\2\6") + buf.write("\3\2\2\2\2\b\3\2\2\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16\3\2") + buf.write("\2\2\2\20\3\2\2\2\2\22\3\2\2\2\2\24\3\2\2\2\2\26\3\2\2") + buf.write("\2\2\30\3\2\2\2\2\32\3\2\2\2\2\34\3\2\2\2\2\36\3\2\2\2") + buf.write("\2 \3\2\2\2\2\"\3\2\2\2\2$\3\2\2\2\2&\3\2\2\2\2(\3\2\2") + buf.write("\2\2*\3\2\2\2\2,\3\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2\62") + buf.write("\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\28\3\2\2\2\2:\3\2\2") + buf.write("\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2\2\2\2B\3\2\2\2\2D\3\2") + buf.write("\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3\2\2\2\2L\3\2\2\2\2N\3") + buf.write("\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2\2\2\2V\3\2\2\2\2X") + buf.write("\3\2\2\2\2\u0082\3\2\2\2\2\u0084\3\2\2\2\2\u0086\3\2\2") + buf.write("\2\3\u0088\3\2\2\2\3\u008a\3\2\2\2\4\u008c\3\2\2\2\6\u0092") + buf.write("\3\2\2\2\b\u0097\3\2\2\2\n\u009d\3\2\2\2\f\u00a0\3\2\2") + buf.write("\2\16\u00a3\3\2\2\2\20\u00a6\3\2\2\2\22\u00af\3\2\2\2") + buf.write("\24\u00b6\3\2\2\2\26\u00ba\3\2\2\2\30\u00bf\3\2\2\2\32") + buf.write("\u00c4\3\2\2\2\34\u00c9\3\2\2\2\36\u00cf\3\2\2\2 \u00d4") + buf.write("\3\2\2\2\"\u00d9\3\2\2\2$\u00dd\3\2\2\2&\u00e0\3\2\2\2") + buf.write("(\u00e4\3\2\2\2*\u00e9\3\2\2\2,\u00fb\3\2\2\2.\u00fe\3") + buf.write("\2\2\2\60\u0102\3\2\2\2\62\u0109\3\2\2\2\64\u0110\3\2") + buf.write("\2\2\66\u0113\3\2\2\28\u0116\3\2\2\2:\u0118\3\2\2\2<\u011a") + buf.write("\3\2\2\2>\u011c\3\2\2\2@\u011e\3\2\2\2B\u0120\3\2\2\2") + buf.write("D\u0123\3\2\2\2F\u0125\3\2\2\2H\u0127\3\2\2\2J\u0129\3") + buf.write("\2\2\2L\u012b\3\2\2\2N\u012d\3\2\2\2P\u012f\3\2\2\2R\u0131") + buf.write("\3\2\2\2T\u0133\3\2\2\2V\u0135\3\2\2\2X\u0137\3\2\2\2") + buf.write("Z\u0139\3\2\2\2\\\u013b\3\2\2\2^\u013d\3\2\2\2`\u013f") + buf.write("\3\2\2\2b\u0141\3\2\2\2d\u0143\3\2\2\2f\u0145\3\2\2\2") + buf.write("h\u0147\3\2\2\2j\u0149\3\2\2\2l\u014b\3\2\2\2n\u014d\3") + buf.write("\2\2\2p\u014f\3\2\2\2r\u0151\3\2\2\2t\u0153\3\2\2\2v\u0155") + buf.write("\3\2\2\2x\u0157\3\2\2\2z\u0159\3\2\2\2|\u015b\3\2\2\2") + buf.write("~\u0160\3\2\2\2\u0080\u0166\3\2\2\2\u0082\u0169\3\2\2") + buf.write("\2\u0084\u016f\3\2\2\2\u0086\u017d\3\2\2\2\u0088\u018c") + buf.write("\3\2\2\2\u008a\u0190\3\2\2\2\u008c\u008d\5\\.\2\u008d") + buf.write("\u008e\5h\64\2\u008e\u008f\5Z-\2\u008f\u0090\5r9\2\u0090") + buf.write("\u0091\5r9\2\u0091\5\3\2\2\2\u0092\u0093\5`\60\2\u0093") + buf.write("\u0094\5h\64\2\u0094\u0095\5r9\2\u0095\u0096\5`\60\2\u0096") + buf.write("\7\3\2\2\2\u0097\u0098\7h\2\2\u0098\u0099\5Z-\2\u0099") + buf.write("\u009a\5h\64\2\u009a\u009b\5r9\2\u009b\u009c\5`\60\2\u009c") + buf.write("\t\3\2\2\2\u009d\u009e\5b\61\2\u009e\u009f\5f\63\2\u009f") + buf.write("\13\3\2\2\2\u00a0\u00a1\5f\63\2\u00a1\u00a2\5b\61\2\u00a2") + buf.write("\r\3\2\2\2\u00a3\u00a4\5f\63\2\u00a4\u00a5\5j\65\2\u00a5") + buf.write("\17\3\2\2\2\u00a6\u00a7\5f\63\2\u00a7\u00a8\5j\65\2\u00a8") + buf.write("\u00a9\5d\62\2\u00a9\u00aa\5`\60\2\u00aa\u00ab\5p8\2\u00ab") + buf.write("\u00ac\5f\63\2\u00ac\u00ad\5t:\2\u00ad\u00ae\5r9\2\u00ae") + buf.write("\21\3\2\2\2\u00af\u00b0\5f\63\2\u00b0\u00b1\5r9\2\u00b1") + buf.write("\u00b2\5x<\2\u00b2\u00b3\5l\66\2\u00b3\u00b4\5f\63\2\u00b4") + buf.write("\u00b5\5^/\2\u00b5\23\3\2\2\2\u00b6\u00b7\5h\64\2\u00b7") + buf.write("\u00b8\5`\60\2\u00b8\u00b9\5t:\2\u00b9\25\3\2\2\2\u00ba") + buf.write("\u00bb\5h\64\2\u00bb\u00bc\5l\66\2\u00bc\u00bd\5l\66\2") + buf.write("\u00bd\u00be\5n\67\2\u00be\27\3\2\2\2\u00bf\u00c0\5n\67") + buf.write("\2\u00c0\u00c1\5l\66\2\u00c1\u00c2\5l\66\2\u00c2\u00c3") + buf.write("\5h\64\2\u00c3\31\3\2\2\2\u00c4\u00c5\5t:\2\u00c5\u00c6") + buf.write("\5d\62\2\u00c6\u00c7\5`\60\2\u00c7\u00c8\5j\65\2\u00c8") + buf.write("\33\3\2\2\2\u00c9\u00ca\5z=\2\u00ca\u00cb\5d\62\2\u00cb") + buf.write("\u00cc\5f\63\2\u00cc\u00cd\5h\64\2\u00cd\u00ce\5`\60\2") + buf.write("\u00ce\35\3\2\2\2\u00cf\u00d0\5\\.\2\u00d0\u00d1\5Z-\2") + buf.write("\u00d1\u00d2\5r9\2\u00d2\u00d3\5`\60\2\u00d3\37\3\2\2") + buf.write("\2\u00d4\u00d5\5`\60\2\u00d5\u00d6\5r9\2\u00d6\u00d7\5") + buf.write("Z-\2\u00d7\u00d8\5\\.\2\u00d8!\3\2\2\2\u00d9\u00da\5j") + buf.write("\65\2\u00da\u00db\5`\60\2\u00db\u00dc\5z=\2\u00dc#\3\2") + buf.write("\2\2\u00dd\u00de\5l\66\2\u00de\u00df\5b\61\2\u00df%\3") + buf.write("\2\2\2\u00e0\u00e1\5j\65\2\u00e1\u00e2\5l\66\2\u00e2\u00e3") + buf.write("\5t:\2\u00e3\'\3\2\2\2\u00e4\u00e5\7v\2\2\u00e5\u00e6") + buf.write("\5p8\2\u00e6\u00e7\5v;\2\u00e7\u00e8\5`\60\2\u00e8)\3") + buf.write("\2\2\2\u00e9\u00ef\7$\2\2\u00ea\u00ee\5|>\2\u00eb\u00ee") + buf.write("\5,\26\2\u00ec\u00ee\n\2\2\2\u00ed\u00ea\3\2\2\2\u00ed") + buf.write("\u00eb\3\2\2\2\u00ed\u00ec\3\2\2\2\u00ee\u00f1\3\2\2\2") + buf.write("\u00ef\u00ed\3\2\2\2\u00ef\u00f0\3\2\2\2\u00f0\u00f2\3") + buf.write("\2\2\2\u00f1\u00ef\3\2\2\2\u00f2\u00f3\7$\2\2\u00f3+\3") + buf.write("\2\2\2\u00f4\u00f5\7^\2\2\u00f5\u00f6\7\17\2\2\u00f6\u00fc") + buf.write("\7\f\2\2\u00f7\u00f8\7^\2\2\u00f8\u00fc\7\17\2\2\u00f9") + buf.write("\u00fa\7^\2\2\u00fa\u00fc\7\f\2\2\u00fb\u00f4\3\2\2\2") + buf.write("\u00fb\u00f7\3\2\2\2\u00fb\u00f9\3\2\2\2\u00fc-\3\2\2") + buf.write("\2\u00fd\u00ff\t\3\2\2\u00fe\u00fd\3\2\2\2\u00ff\u0100") + buf.write("\3\2\2\2\u0100\u00fe\3\2\2\2\u0100\u0101\3\2\2\2\u0101") + buf.write("/\3\2\2\2\u0102\u0106\t\4\2\2\u0103\u0105\t\5\2\2\u0104") + buf.write("\u0103\3\2\2\2\u0105\u0108\3\2\2\2\u0106\u0104\3\2\2\2") + buf.write("\u0106\u0107\3\2\2\2\u0107\61\3\2\2\2\u0108\u0106\3\2") + buf.write("\2\2\u0109\u010d\t\6\2\2\u010a\u010c\t\5\2\2\u010b\u010a") + buf.write("\3\2\2\2\u010c\u010f\3\2\2\2\u010d\u010b\3\2\2\2\u010d") + buf.write("\u010e\3\2\2\2\u010e\63\3\2\2\2\u010f\u010d\3\2\2\2\u0110") + buf.write("\u0111\7>\2\2\u0111\u0112\7/\2\2\u0112\65\3\2\2\2\u0113") + buf.write("\u0114\7?\2\2\u0114\u0115\7@\2\2\u0115\67\3\2\2\2\u0116") + buf.write("\u0117\7-\2\2\u01179\3\2\2\2\u0118\u0119\7/\2\2\u0119") + buf.write(";\3\2\2\2\u011a\u011b\7,\2\2\u011b=\3\2\2\2\u011c\u011d") + buf.write("\7\61\2\2\u011d?\3\2\2\2\u011e\u011f\7>\2\2\u011fA\3\2") + buf.write("\2\2\u0120\u0121\7>\2\2\u0121\u0122\7?\2\2\u0122C\3\2") + buf.write("\2\2\u0123\u0124\7?\2\2\u0124E\3\2\2\2\u0125\u0126\7\u0080") + buf.write("\2\2\u0126G\3\2\2\2\u0127\u0128\7*\2\2\u0128I\3\2\2\2") + buf.write("\u0129\u012a\7+\2\2\u012aK\3\2\2\2\u012b\u012c\7}\2\2") + buf.write("\u012cM\3\2\2\2\u012d\u012e\7\177\2\2\u012eO\3\2\2\2\u012f") + buf.write("\u0130\7B\2\2\u0130Q\3\2\2\2\u0131\u0132\7\60\2\2\u0132") + buf.write("S\3\2\2\2\u0133\u0134\7.\2\2\u0134U\3\2\2\2\u0135\u0136") + buf.write("\7<\2\2\u0136W\3\2\2\2\u0137\u0138\7=\2\2\u0138Y\3\2\2") + buf.write("\2\u0139\u013a\t\7\2\2\u013a[\3\2\2\2\u013b\u013c\t\b") + buf.write("\2\2\u013c]\3\2\2\2\u013d\u013e\t\t\2\2\u013e_\3\2\2\2") + buf.write("\u013f\u0140\t\n\2\2\u0140a\3\2\2\2\u0141\u0142\t\13\2") + buf.write("\2\u0142c\3\2\2\2\u0143\u0144\t\f\2\2\u0144e\3\2\2\2\u0145") + buf.write("\u0146\t\r\2\2\u0146g\3\2\2\2\u0147\u0148\t\16\2\2\u0148") + buf.write("i\3\2\2\2\u0149\u014a\t\17\2\2\u014ak\3\2\2\2\u014b\u014c") + buf.write("\t\20\2\2\u014cm\3\2\2\2\u014d\u014e\t\21\2\2\u014eo\3") + buf.write("\2\2\2\u014f\u0150\t\22\2\2\u0150q\3\2\2\2\u0151\u0152") + buf.write("\t\23\2\2\u0152s\3\2\2\2\u0153\u0154\t\24\2\2\u0154u\3") + buf.write("\2\2\2\u0155\u0156\t\25\2\2\u0156w\3\2\2\2\u0157\u0158") + buf.write("\t\26\2\2\u0158y\3\2\2\2\u0159\u015a\t\27\2\2\u015a{\3") + buf.write("\2\2\2\u015b\u015e\7^\2\2\u015c\u015f\t\30\2\2\u015d\u015f") + buf.write("\5~?\2\u015e\u015c\3\2\2\2\u015e\u015d\3\2\2\2\u015f}") + buf.write("\3\2\2\2\u0160\u0161\7w\2\2\u0161\u0162\5\u0080@\2\u0162") + buf.write("\u0163\5\u0080@\2\u0163\u0164\5\u0080@\2\u0164\u0165\5") + buf.write("\u0080@\2\u0165\177\3\2\2\2\u0166\u0167\t\31\2\2\u0167") + buf.write("\u0081\3\2\2\2\u0168\u016a\t\32\2\2\u0169\u0168\3\2\2") + buf.write("\2\u016a\u016b\3\2\2\2\u016b\u0169\3\2\2\2\u016b\u016c") + buf.write("\3\2\2\2\u016c\u016d\3\2\2\2\u016d\u016e\bA\2\2\u016e") + buf.write("\u0083\3\2\2\2\u016f\u0170\7/\2\2\u0170\u0171\7/\2\2\u0171") + buf.write("\u0175\3\2\2\2\u0172\u0174\n\33\2\2\u0173\u0172\3\2\2") + buf.write("\2\u0174\u0177\3\2\2\2\u0175\u0173\3\2\2\2\u0175\u0176") + buf.write("\3\2\2\2\u0176\u0179\3\2\2\2\u0177\u0175\3\2\2\2\u0178") + buf.write("\u017a\7\f\2\2\u0179\u0178\3\2\2\2\u0179\u017a\3\2\2\2") + buf.write("\u017a\u017b\3\2\2\2\u017b\u017c\bB\2\2\u017c\u0085\3") + buf.write("\2\2\2\u017d\u017e\7*\2\2\u017e\u017f\7,\2\2\u017f\u0180") + buf.write("\3\2\2\2\u0180\u0181\bC\2\2\u0181\u0182\bC\3\2\u0182\u0087") + buf.write("\3\2\2\2\u0183\u0184\5\u0086C\2\u0184\u0185\5\u0088D\2") + buf.write("\u0185\u0186\5\u008aE\2\u0186\u018d\3\2\2\2\u0187\u0189") + buf.write("\13\2\2\2\u0188\u0187\3\2\2\2\u0189\u018a\3\2\2\2\u018a") + buf.write("\u018b\3\2\2\2\u018a\u0188\3\2\2\2\u018b\u018d\3\2\2\2") + buf.write("\u018c\u0183\3\2\2\2\u018c\u0188\3\2\2\2\u018d\u018e\3") + buf.write("\2\2\2\u018e\u018f\bD\2\2\u018f\u0089\3\2\2\2\u0190\u0191") + buf.write("\7,\2\2\u0191\u0192\7+\2\2\u0192\u0193\3\2\2\2\u0193\u0194") + buf.write("\bE\2\2\u0194\u0195\bE\4\2\u0195\u008b\3\2\2\2\20\2\3") + buf.write("\u00ed\u00ef\u00fb\u0100\u0106\u010d\u015e\u016b\u0175") + buf.write("\u0179\u018a\u018c\5\b\2\2\7\3\2\6\2\2") + return buf.getvalue() + + +class COOL_LEX(Lexer): + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] + + MULTILINE_COMMENT = 1 + + CLASS = 1 + ELSE = 2 + FALSE = 3 + FI = 4 + IF = 5 + IN = 6 + INHERITS = 7 + ISVOID = 8 + LET = 9 + LOOP = 10 + POOL = 11 + THEN = 12 + WHILE = 13 + CASE = 14 + ESAC = 15 + NEW = 16 + OF = 17 + NOT = 18 + TRUE = 19 + STRING = 20 + BREAK_STRING = 21 + INT = 22 + TYPEID = 23 + OBJECTID = 24 + ASSIGNMENT = 25 + CASE_ARROW = 26 + ADD = 27 + MINUS = 28 + MULTIPLY = 29 + DIVISION = 30 + LESS_THAN = 31 + LESS_EQUAL = 32 + EQUAL = 33 + INTEGER_NEGATIVE = 34 + OPEN_ROUND = 35 + CLOSE_ROUND = 36 + OPEN_CURLY = 37 + CLOSE_CURLY = 38 + AT = 39 + DOT = 40 + COMMA = 41 + COLON = 42 + SEMICOLON = 43 + WHITESPACE = 44 + ONE_LINE_COMMENT = 45 + OPEN_COMMENT = 46 + COMMENT = 47 + CLOSE_COMMENT = 48 + + channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] + + modeNames = [ "DEFAULT_MODE", "MULTILINE_COMMENT" ] + + literalNames = [ "", + "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", "'<='", "'='", + "'~'", "'('", "')'", "'{'", "'}'", "'@'", "'.'", "','", "':'", + "';'", "'(*'", "'*)'" ] + + symbolicNames = [ "", + "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", + "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", + "OF", "NOT", "TRUE", "STRING", "BREAK_STRING", "INT", "TYPEID", + "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", + "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", + "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", "CLOSE_CURLY", "AT", + "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", "ONE_LINE_COMMENT", + "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT" ] + + ruleNames = [ "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", + "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", + "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", "BREAK_STRING", + "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", + "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", + "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", + "OPEN_CURLY", "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", + "SEMICOLON", "A", "C", "D", "E", "F", "H", "I", "L", "N", + "O", "P", "R", "S", "T", "U", "V", "W", "ESC", "UNICODE", + "HEX", "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", + "COMMENT", "CLOSE_COMMENT" ] + + grammarFileName = "COOL_LEX.g4" + + def __init__(self, input=None, output:TextIO = sys.stdout): + super().__init__(input, output) + self.checkVersion("4.7.2") + self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) + self._actions = None + self._predicates = None + + diff --git a/COOL_LEX.tokens b/COOL_LEX.tokens new file mode 100644 index 00000000..bbdda836 --- /dev/null +++ b/COOL_LEX.tokens @@ -0,0 +1,69 @@ +CLASS=1 +ELSE=2 +FALSE=3 +FI=4 +IF=5 +IN=6 +INHERITS=7 +ISVOID=8 +LET=9 +LOOP=10 +POOL=11 +THEN=12 +WHILE=13 +CASE=14 +ESAC=15 +NEW=16 +OF=17 +NOT=18 +TRUE=19 +STRING=20 +BREAK_STRING=21 +INT=22 +TYPEID=23 +OBJECTID=24 +ASSIGNMENT=25 +CASE_ARROW=26 +ADD=27 +MINUS=28 +MULTIPLY=29 +DIVISION=30 +LESS_THAN=31 +LESS_EQUAL=32 +EQUAL=33 +INTEGER_NEGATIVE=34 +OPEN_ROUND=35 +CLOSE_ROUND=36 +OPEN_CURLY=37 +CLOSE_CURLY=38 +AT=39 +DOT=40 +COMMA=41 +COLON=42 +SEMICOLON=43 +WHITESPACE=44 +ONE_LINE_COMMENT=45 +OPEN_COMMENT=46 +COMMENT=47 +CLOSE_COMMENT=48 +'<-'=25 +'=>'=26 +'+'=27 +'-'=28 +'*'=29 +'/'=30 +'<'=31 +'<='=32 +'='=33 +'~'=34 +'('=35 +')'=36 +'{'=37 +'}'=38 +'@'=39 +'.'=40 +','=41 +':'=42 +';'=43 +'(*'=46 +'*)'=48 diff --git a/tests/lexer/test1.cl b/tests/lexer/test1.cl new file mode 100644 index 00000000..43ea44f6 --- /dev/null +++ b/tests/lexer/test1.cl @@ -0,0 +1,9 @@ +class Main { + str <- "The big brown fox + jumped over the fence"; + main() : Object { + { + out_string("Yay! This is the newest shites ); + } + }; +}; diff --git a/tests/lexer/test1_error.txt b/tests/lexer/test1_error.txt new file mode 100644 index 00000000..5145209d --- /dev/null +++ b/tests/lexer/test1_error.txt @@ -0,0 +1,3 @@ +(3, 4) - LexicographicError: Unterminated string constant +(4, 2) - LexicographicError: Unterminated string constant +(7, 4) - LexicographicError: Unterminated string constant \ No newline at end of file diff --git a/tests/lexer/test3.cl b/tests/lexer/test3.cl new file mode 100644 index 00000000..1fb6cedb --- /dev/null +++ b/tests/lexer/test3.cl @@ -0,0 +1,46 @@ +class Error() { + + (* There was once a comment, + that was quite long. + But, the reader soon discovered that + the comment was indeed longer than + previously assumed. Now, the reader + was in a real dilemma; is the comment + ever gonna end? If I stop reading, will + it end? + He started imagining all sorts of things. + He thought about heisenberg's cat and how + how that relates to the end of the sentence. + He thought to himself "I'm gonna stop reading". + "If I keep reading this comment, I'm gonna know + the fate of this sentence; That will be disastorous." + He knew that such a comment was gonna extend to + another file. It was too awesome to be contained in + a single file. And he would have kept reading too... + if only... + cool wasn't a super-duper-fab-awesomest language; + but cool is that language; + "This comment shall go not cross this file" said cool. + Alas! The reader could read no more. + There was once a comment, + that was quite long. + But, the reader soon discovered that + the comment was indeed longer than + previously assumed. Now, the reader + was in a real dilemma; is the comment + ever gonna end? If I stop reading, will + it end? + He started imagining all sorts of things. + He thought about heisenberg's cat and how + how that relates to the end of the sentence. + He thought to himself "I'm gonna stop reading". + "If I keep reading this comment, I'm gonna know + the fate of this sentence; That will be disastorous." + He knew that such a comment was gonna extend to + another file. It was too awesome to be contained in + a single file. And he would have kept reading too... + if only... + cool wasn't a super-duper-fab-awesomest language; + but cool is that language; + "This comment shall go not cross this file" said cool. + Alas! The reader could read no more. \ No newline at end of file diff --git a/tests/lexer/test3_error.txt b/tests/lexer/test3_error.txt new file mode 100644 index 00000000..dc48da75 --- /dev/null +++ b/tests/lexer/test3_error.txt @@ -0,0 +1 @@ +(46, 40) - LexicographicError: EOF in comment diff --git a/tests/lexer/test5.cl b/tests/lexer/test5.cl new file mode 100644 index 00000000..879e27a6 --- /dev/null +++ b/tests/lexer/test5.cl @@ -0,0 +1,4 @@ +"lkjdsafkljdsalfj\u0000dsafdsaf\u0000djafslkjdsalf\nsdajf\" lkjfdsasdkjfl"123 +adsfasklj# +LKldsajf +"lkdsajf" \ No newline at end of file diff --git a/tests/lexer/test5_error.txt b/tests/lexer/test5_error.txt new file mode 100644 index 00000000..99af5fbd --- /dev/null +++ b/tests/lexer/test5_error.txt @@ -0,0 +1 @@ +(2, 10) - LexicographicError: ERROR "#" diff --git a/tests/lexer/test6.cl b/tests/lexer/test6.cl new file mode 100644 index 00000000..d420df7c --- /dev/null +++ b/tests/lexer/test6.cl @@ -0,0 +1,6 @@ +"kjas\"lnnsdj\nfljrdsaf" +$ +$ +% +% +"alkjfldajf""dasfadsf \ No newline at end of file diff --git a/tests/lexer/test6_error.txt b/tests/lexer/test6_error.txt new file mode 100644 index 00000000..4ca5899e --- /dev/null +++ b/tests/lexer/test6_error.txt @@ -0,0 +1,5 @@ +(2, 1) - LexicographicError: ERROR "$" +(3, 1) - LexicographicError: ERROR "$" +(4, 1) - LexicographicError: ERROR "%" +(5, 1) - LexicographicError: ERROR "%" +(6, 22) - LexicographicError: EOF in string constant diff --git a/tests/parser/err2.cl b/tests/parser/err2.cl new file mode 100644 index 00000000..40149b89 --- /dev/null +++ b/tests/parser/err2.cl @@ -0,0 +1,14 @@ +class Main { + main(): Object { + (new alpha).print() + }; + +}; + +(* Class names must begin with uppercase letters *) +class alpha inherits IO { + print() : Object { + out_string("reached!!\n"); + }; +}; + diff --git a/tests/parser/err2_error.txt b/tests/parser/err2_error.txt new file mode 100644 index 00000000..92e47e37 --- /dev/null +++ b/tests/parser/err2_error.txt @@ -0,0 +1,2 @@ +(3, 10) - SyntacticError: ERROR at or near "alpha" +(9, 7) - SyntacticError: ERROR at or near "alpha" \ No newline at end of file diff --git a/tests/parser/isprime.cl b/tests/parser/isprime.cl new file mode 100644 index 00000000..5adaeda9 --- /dev/null +++ b/tests/parser/isprime.cl @@ -0,0 +1,40 @@ +class Main inherits IO { + main() : Object { + { + out_string("Enter a number to check if number is prime\n"); + let i : Int <- in_int() in { + if(i <= 1) then { + out_string("Invalid Input\n"); + abort(); + } else { + if (isPrime(i) = 1) then + out_string("Number is prime\n") + else + out_string("Number is composite\n") + fi; + } + fi; + }; + } + }; + + mod(i : Int, ) : Int { -- Formal list must be comma separated. A comma does not terminate a list of formals. + i - (i/k)*k + }; + + isPrime(i : Int) : Int { + { + let x : Int <- 2, + c : Int <- 1 in + { + while (not (x = i)) loop + if (mod(i, x) = 0) then { + c <- 0; + x <- i; + } else x <- x + 1 fi + pool; + c; + }; + } + }; +}; diff --git a/tests/parser/isprime_error.txt b/tests/parser/isprime_error.txt new file mode 100644 index 00000000..ea89e135 --- /dev/null +++ b/tests/parser/isprime_error.txt @@ -0,0 +1 @@ +(21, 15) - SyntacticError: Error at or near ')' diff --git a/tests/parser/prod.cl b/tests/parser/prod.cl new file mode 100644 index 00000000..effe5a7c --- /dev/null +++ b/tests/parser/prod.cl @@ -0,0 +1,21 @@ +class Main inherits IO { + main() : Object { + { + out_string("Enter number of numbers to multiply\n"); + out_int(prod(in_int())); + out_string("\n"); + } + }; + + prod(i : Int) : Int { + let y : Int <- 1 in { + while (not (i = 0) ) loop { + out_string("Enter Number: "); + y <- y * in_int(Main : Int); -- the parser correctly catches the error here + i <- i - 1; + } + pool; + y; + } + }; +}; diff --git a/tests/parser/prod_error.txt b/tests/parser/prod_error.txt new file mode 100644 index 00000000..ab4e7867 --- /dev/null +++ b/tests/parser/prod_error.txt @@ -0,0 +1 @@ +(14, 23) - SyntacticError: ERROR at or near "Main" \ No newline at end of file diff --git a/tests/parser/test2.cl b/tests/parser/test2.cl new file mode 100644 index 00000000..8fdb792e --- /dev/null +++ b/tests/parser/test2.cl @@ -0,0 +1,20 @@ +class Main inherits IO { + str <- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + main() : Object { + { + out_string("Enter number of numbers to multiply\n"); + out_int(prod(in_int())); + out_string("\n"); + } + }; + prod(i : Int) : Int { + let y : Int <- 1 in { + while (not (i = 0) ) loop { + out_string("Enter Number: "); + y <- y * in_int(); + i <- i - 1; + } + y; + } + }; +} diff --git a/tests/parser/test2_error.txt b/tests/parser/test2_error.txt new file mode 100644 index 00000000..2bfe70f3 --- /dev/null +++ b/tests/parser/test2_error.txt @@ -0,0 +1,4 @@ +(2, 6) - SyntacticError: ERROR at or near "<-" +(17, 4) - SyntacticError: ERROR at or near "y" +(21, 1) - SyntacticError: ERROR at or near EOF + diff --git a/tests/parser/test4.cl b/tests/parser/test4.cl new file mode 100644 index 00000000..aad6c503 --- /dev/null +++ b/tests/parser/test4.cl @@ -0,0 +1,5 @@ +classs Doom { + i : Int <- 0; + main() : Object { + if i = 0 then out_string("This is da real *h*t") + diff --git a/tests/parser/test4_error.txt b/tests/parser/test4_error.txt new file mode 100644 index 00000000..af75ca92 --- /dev/null +++ b/tests/parser/test4_error.txt @@ -0,0 +1 @@ +(1, 1) - SyntacticError: ERROR at or near "classs" \ No newline at end of file From bf7eb153111e990fd3f4a1feba6f2b097e68d065 Mon Sep 17 00:00:00 2001 From: LSilvaO Date: Sat, 29 Feb 2020 23:43:49 -0500 Subject: [PATCH 28/77] todos los miembros --- doc/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Readme.md b/doc/Readme.md index e32260f4..f9186022 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -5,7 +5,7 @@ **Nombre** | **Grupo** | **Github** --|--|-- Liset Silva Oropesa | C411 | [@Liset97](https://github.com/Liset97) -Pablo Antonio de Armas Suarez | C411 | [@github_user](https://github.com/) +Pablo Antonio de Armas Suarez | C411 | [@pablodearmas](https://github.com/pablodearmas) Yenli Gil Machado | C412 | [@YenGM](https://github.com/YenGM) ## Readme From 5ab16af2c1d902f79240c1c011a1cedd264ae956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 1 Mar 2020 00:02:36 -0500 Subject: [PATCH 29/77] Movimiento de los fuente a las carpeta src --- COOL.interp | 113 -- COOL.tokens | 69 - COOLCompiler.py | 36 - COOLLexer.py | 34 - COOLListener.py | 289 --- COOLParser.py | 24 - src/COOL.interp | 50 +- COOL.py => src/COOL.py | 0 src/COOL.tokens | 137 +- src/COOLCompiler.py | 21 + src/COOLLexer.py | 289 +-- .../COOLLexerErrorListener.py | 0 src/COOLListener.py | 265 ++- src/COOLParser.py | 1773 +---------------- .../COOLParserErrorListener.py | 0 COOL_LEX.interp => src/COOL_LEX.interp | 0 COOL_LEX.py => src/COOL_LEX.py | 0 COOL_LEX.tokens => src/COOL_LEX.tokens | 0 18 files changed, 292 insertions(+), 2808 deletions(-) delete mode 100644 COOL.interp delete mode 100644 COOL.tokens delete mode 100644 COOLCompiler.py delete mode 100644 COOLLexer.py delete mode 100644 COOLListener.py delete mode 100644 COOLParser.py rename COOL.py => src/COOL.py (100%) rename COOLLexerErrorListener.py => src/COOLLexerErrorListener.py (100%) rename COOLParserErrorListener.py => src/COOLParserErrorListener.py (100%) rename COOL_LEX.interp => src/COOL_LEX.interp (100%) rename COOL_LEX.py => src/COOL_LEX.py (100%) rename COOL_LEX.tokens => src/COOL_LEX.tokens (100%) diff --git a/COOL.interp b/COOL.interp deleted file mode 100644 index bba307e6..00000000 --- a/COOL.interp +++ /dev/null @@ -1,113 +0,0 @@ -token literal names: -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -null -'<-' -'=>' -'+' -'-' -'*' -'/' -'<' -'<=' -'=' -'~' -'(' -')' -'{' -'}' -'@' -'.' -',' -':' -';' -null -null -'(*' -null -'*)' - -token symbolic names: -null -CLASS -ELSE -FALSE -FI -IF -IN -INHERITS -ISVOID -LET -LOOP -POOL -THEN -WHILE -CASE -ESAC -NEW -OF -NOT -TRUE -STRING -BREAK_STRING -INT -TYPEID -OBJECTID -ASSIGNMENT -CASE_ARROW -ADD -MINUS -MULTIPLY -DIVISION -LESS_THAN -LESS_EQUAL -EQUAL -INTEGER_NEGATIVE -OPEN_ROUND -CLOSE_ROUND -OPEN_CURLY -CLOSE_CURLY -AT -DOT -COMMA -COLON -SEMICOLON -WHITESPACE -ONE_LINE_COMMENT -OPEN_COMMENT -COMMENT -CLOSE_COMMENT - -rule names: -program -programBlocks -classDefine -feature -formal -expression - - -atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 50, 225, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 7, 7, 86, 10, 7, 12, 7, 14, 7, 89, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 110, 10, 7, 13, 7, 14, 7, 111, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 122, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 130, 10, 7, 7, 7, 132, 10, 7, 12, 7, 14, 7, 135, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 149, 10, 7, 13, 7, 14, 7, 150, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 175, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 201, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 209, 10, 7, 12, 7, 14, 7, 212, 11, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 7, 7, 220, 10, 7, 12, 7, 14, 7, 223, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 259, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 174, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 45, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 25, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 25, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 39, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 45, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 40, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 26, 2, 2, 40, 51, 7, 37, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 43, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 38, 2, 2, 55, 56, 7, 44, 2, 2, 56, 57, 7, 25, 2, 2, 57, 58, 7, 39, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 40, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 26, 2, 2, 62, 63, 7, 44, 2, 2, 63, 66, 7, 25, 2, 2, 64, 65, 7, 27, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 26, 2, 2, 71, 72, 7, 44, 2, 2, 72, 73, 7, 25, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 26, 2, 2, 76, 87, 7, 37, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 43, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 90, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 175, 7, 38, 2, 2, 91, 92, 7, 7, 2, 2, 92, 93, 5, 12, 7, 2, 93, 94, 7, 14, 2, 2, 94, 95, 5, 12, 7, 2, 95, 96, 7, 4, 2, 2, 96, 97, 5, 12, 7, 2, 97, 98, 7, 6, 2, 2, 98, 175, 3, 2, 2, 2, 99, 100, 7, 15, 2, 2, 100, 101, 5, 12, 7, 2, 101, 102, 7, 12, 2, 2, 102, 103, 5, 12, 7, 2, 103, 104, 7, 13, 2, 2, 104, 175, 3, 2, 2, 2, 105, 109, 7, 39, 2, 2, 106, 107, 5, 12, 7, 2, 107, 108, 7, 45, 2, 2, 108, 110, 3, 2, 2, 2, 109, 106, 3, 2, 2, 2, 110, 111, 3, 2, 2, 2, 111, 109, 3, 2, 2, 2, 111, 112, 3, 2, 2, 2, 112, 113, 3, 2, 2, 2, 113, 114, 7, 40, 2, 2, 114, 175, 3, 2, 2, 2, 115, 116, 7, 11, 2, 2, 116, 117, 7, 26, 2, 2, 117, 118, 7, 44, 2, 2, 118, 121, 7, 25, 2, 2, 119, 120, 7, 27, 2, 2, 120, 122, 5, 12, 7, 2, 121, 119, 3, 2, 2, 2, 121, 122, 3, 2, 2, 2, 122, 133, 3, 2, 2, 2, 123, 124, 7, 43, 2, 2, 124, 125, 7, 26, 2, 2, 125, 126, 7, 44, 2, 2, 126, 129, 7, 25, 2, 2, 127, 128, 7, 27, 2, 2, 128, 130, 5, 12, 7, 2, 129, 127, 3, 2, 2, 2, 129, 130, 3, 2, 2, 2, 130, 132, 3, 2, 2, 2, 131, 123, 3, 2, 2, 2, 132, 135, 3, 2, 2, 2, 133, 131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 136, 3, 2, 2, 2, 135, 133, 3, 2, 2, 2, 136, 137, 7, 8, 2, 2, 137, 175, 5, 12, 7, 22, 138, 139, 7, 16, 2, 2, 139, 140, 5, 12, 7, 2, 140, 148, 7, 19, 2, 2, 141, 142, 7, 26, 2, 2, 142, 143, 7, 44, 2, 2, 143, 144, 7, 25, 2, 2, 144, 145, 7, 28, 2, 2, 145, 146, 5, 12, 7, 2, 146, 147, 7, 45, 2, 2, 147, 149, 3, 2, 2, 2, 148, 141, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 150, 148, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 7, 17, 2, 2, 153, 175, 3, 2, 2, 2, 154, 155, 7, 18, 2, 2, 155, 175, 7, 25, 2, 2, 156, 157, 7, 36, 2, 2, 157, 175, 5, 12, 7, 19, 158, 159, 7, 10, 2, 2, 159, 175, 5, 12, 7, 18, 160, 161, 7, 20, 2, 2, 161, 175, 5, 12, 7, 10, 162, 163, 7, 37, 2, 2, 163, 164, 5, 12, 7, 2, 164, 165, 7, 38, 2, 2, 165, 175, 3, 2, 2, 2, 166, 175, 7, 26, 2, 2, 167, 175, 7, 24, 2, 2, 168, 175, 7, 22, 2, 2, 169, 175, 7, 21, 2, 2, 170, 175, 7, 5, 2, 2, 171, 172, 7, 26, 2, 2, 172, 173, 7, 27, 2, 2, 173, 175, 5, 12, 7, 3, 174, 74, 3, 2, 2, 2, 174, 91, 3, 2, 2, 2, 174, 99, 3, 2, 2, 2, 174, 105, 3, 2, 2, 2, 174, 115, 3, 2, 2, 2, 174, 138, 3, 2, 2, 2, 174, 154, 3, 2, 2, 2, 174, 156, 3, 2, 2, 2, 174, 158, 3, 2, 2, 2, 174, 160, 3, 2, 2, 2, 174, 162, 3, 2, 2, 2, 174, 166, 3, 2, 2, 2, 174, 167, 3, 2, 2, 2, 174, 168, 3, 2, 2, 2, 174, 169, 3, 2, 2, 2, 174, 170, 3, 2, 2, 2, 174, 171, 3, 2, 2, 2, 175, 221, 3, 2, 2, 2, 176, 177, 12, 17, 2, 2, 177, 178, 7, 31, 2, 2, 178, 220, 5, 12, 7, 18, 179, 180, 12, 16, 2, 2, 180, 181, 7, 32, 2, 2, 181, 220, 5, 12, 7, 17, 182, 183, 12, 15, 2, 2, 183, 184, 7, 29, 2, 2, 184, 220, 5, 12, 7, 16, 185, 186, 12, 14, 2, 2, 186, 187, 7, 30, 2, 2, 187, 220, 5, 12, 7, 15, 188, 189, 12, 13, 2, 2, 189, 190, 7, 33, 2, 2, 190, 220, 5, 12, 7, 14, 191, 192, 12, 12, 2, 2, 192, 193, 7, 34, 2, 2, 193, 220, 5, 12, 7, 13, 194, 195, 12, 11, 2, 2, 195, 196, 7, 35, 2, 2, 196, 220, 5, 12, 7, 12, 197, 200, 12, 27, 2, 2, 198, 199, 7, 41, 2, 2, 199, 201, 7, 25, 2, 2, 200, 198, 3, 2, 2, 2, 200, 201, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 7, 42, 2, 2, 203, 204, 7, 26, 2, 2, 204, 215, 7, 37, 2, 2, 205, 210, 5, 12, 7, 2, 206, 207, 7, 43, 2, 2, 207, 209, 5, 12, 7, 2, 208, 206, 3, 2, 2, 2, 209, 212, 3, 2, 2, 2, 210, 208, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 214, 3, 2, 2, 2, 212, 210, 3, 2, 2, 2, 213, 205, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 218, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 218, 220, 7, 38, 2, 2, 219, 176, 3, 2, 2, 2, 219, 179, 3, 2, 2, 2, 219, 182, 3, 2, 2, 2, 219, 185, 3, 2, 2, 2, 219, 188, 3, 2, 2, 2, 219, 191, 3, 2, 2, 2, 219, 194, 3, 2, 2, 2, 219, 197, 3, 2, 2, 2, 220, 223, 3, 2, 2, 2, 221, 219, 3, 2, 2, 2, 221, 222, 3, 2, 2, 2, 222, 13, 3, 2, 2, 2, 223, 221, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 87, 111, 121, 129, 133, 150, 174, 200, 210, 215, 219, 221] \ No newline at end of file diff --git a/COOL.tokens b/COOL.tokens deleted file mode 100644 index bbdda836..00000000 --- a/COOL.tokens +++ /dev/null @@ -1,69 +0,0 @@ -CLASS=1 -ELSE=2 -FALSE=3 -FI=4 -IF=5 -IN=6 -INHERITS=7 -ISVOID=8 -LET=9 -LOOP=10 -POOL=11 -THEN=12 -WHILE=13 -CASE=14 -ESAC=15 -NEW=16 -OF=17 -NOT=18 -TRUE=19 -STRING=20 -BREAK_STRING=21 -INT=22 -TYPEID=23 -OBJECTID=24 -ASSIGNMENT=25 -CASE_ARROW=26 -ADD=27 -MINUS=28 -MULTIPLY=29 -DIVISION=30 -LESS_THAN=31 -LESS_EQUAL=32 -EQUAL=33 -INTEGER_NEGATIVE=34 -OPEN_ROUND=35 -CLOSE_ROUND=36 -OPEN_CURLY=37 -CLOSE_CURLY=38 -AT=39 -DOT=40 -COMMA=41 -COLON=42 -SEMICOLON=43 -WHITESPACE=44 -ONE_LINE_COMMENT=45 -OPEN_COMMENT=46 -COMMENT=47 -CLOSE_COMMENT=48 -'<-'=25 -'=>'=26 -'+'=27 -'-'=28 -'*'=29 -'/'=30 -'<'=31 -'<='=32 -'='=33 -'~'=34 -'('=35 -')'=36 -'{'=37 -'}'=38 -'@'=39 -'.'=40 -','=41 -':'=42 -';'=43 -'(*'=46 -'*)'=48 diff --git a/COOLCompiler.py b/COOLCompiler.py deleted file mode 100644 index 5a9b2584..00000000 --- a/COOLCompiler.py +++ /dev/null @@ -1,36 +0,0 @@ -import sys -import os.path -from antlr4 import * -from COOLLexer import COOLLexer -from COOLLexerErrorListener import COOLLexerErrorListener -from COOLParser import COOLParser -from COOLParserErrorListener import COOLParserErrorListener -from COOLListener import COOLListener - -def main(argv): - if not os.path.isfile(argv[1]): - print("invalid input filename") - return - - input = FileStream(argv[1]) - - lexer = COOLLexer(input) - lexer.removeErrorListeners() - lexer.addErrorListener(COOLLexerErrorListener()) - token = lexer.nextToken() - while token.type != Token.EOF: - token = lexer.nextToken() - - if lexer.hasErrors: - return - - lexer.reset(); - stream = CommonTokenStream(lexer) - parser = COOLParser(stream) - parser.removeErrorListeners() - parser.addErrorListener(COOLParserErrorListener()) - - tree = parser.program() - -if __name__ == '__main__': - main(sys.argv) diff --git a/COOLLexer.py b/COOLLexer.py deleted file mode 100644 index bcb2349c..00000000 --- a/COOLLexer.py +++ /dev/null @@ -1,34 +0,0 @@ -import sys -from io import StringIO -from typing.io import TextIO -from antlr4 import * -from COOL_LEX import COOL_LEX -from antlr4.CommonTokenFactory import CommonTokenFactory -from antlr4.atn.LexerATNSimulator import LexerATNSimulator -from antlr4.InputStream import InputStream -from antlr4.Recognizer import Recognizer -from antlr4.Token import Token -from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException - -class COOLLexer(COOL_LEX): - def __init__(self, input=None, output:TextIO = sys.stdout): - super().__init__(input, output) - self._hasErrors = False - - def notifyListeners(self, e:LexerNoViableAltException): - self._hasErrors = True - - start = self._tokenStartCharIndex - stop = self._input.index - text = self._input.getText(start, stop) - msg = "'" + self.getErrorDisplay(text) + "'" - listener = self.getErrorListenerDispatch() - listener.syntaxError(self, self._token, self._tokenStartLine, self._tokenStartColumn, msg, e) - - def reset(self): - super().reset() - self._hasErrors = False - - @property - def hasErrors(self): - return self._hasErrors \ No newline at end of file diff --git a/COOLListener.py b/COOLListener.py deleted file mode 100644 index e5e5d915..00000000 --- a/COOLListener.py +++ /dev/null @@ -1,289 +0,0 @@ -# Generated from COOL.g4 by ANTLR 4.7.2 -from antlr4 import * -if __name__ is not None and "." in __name__: - from .COOL import COOL -else: - from COOL import COOL - -# This class defines a complete listener for a parse tree produced by COOL. -class COOLListener(ParseTreeListener): - - # Enter a parse tree produced by COOL#program. - def enterProgram(self, ctx:COOL.ProgramContext): - pass - - # Exit a parse tree produced by COOL#program. - def exitProgram(self, ctx:COOL.ProgramContext): - pass - - - # Enter a parse tree produced by COOL#classes. - def enterClasses(self, ctx:COOL.ClassesContext): - pass - - # Exit a parse tree produced by COOL#classes. - def exitClasses(self, ctx:COOL.ClassesContext): - pass - - - # Enter a parse tree produced by COOL#classDefine. - def enterClassDefine(self, ctx:COOL.ClassDefineContext): - pass - - # Exit a parse tree produced by COOL#classDefine. - def exitClassDefine(self, ctx:COOL.ClassDefineContext): - pass - - - # Enter a parse tree produced by COOL#method. - def enterMethod(self, ctx:COOL.MethodContext): - pass - - # Exit a parse tree produced by COOL#method. - def exitMethod(self, ctx:COOL.MethodContext): - pass - - - # Enter a parse tree produced by COOL#property. - def enterProperty(self, ctx:COOL.PropertyContext): - pass - - # Exit a parse tree produced by COOL#property. - def exitProperty(self, ctx:COOL.PropertyContext): - pass - - - # Enter a parse tree produced by COOL#formal. - def enterFormal(self, ctx:COOL.FormalContext): - pass - - # Exit a parse tree produced by COOL#formal. - def exitFormal(self, ctx:COOL.FormalContext): - pass - - - # Enter a parse tree produced by COOL#letIn. - def enterLetIn(self, ctx:COOL.LetInContext): - pass - - # Exit a parse tree produced by COOL#letIn. - def exitLetIn(self, ctx:COOL.LetInContext): - pass - - - # Enter a parse tree produced by COOL#minus. - def enterMinus(self, ctx:COOL.MinusContext): - pass - - # Exit a parse tree produced by COOL#minus. - def exitMinus(self, ctx:COOL.MinusContext): - pass - - - # Enter a parse tree produced by COOL#string. - def enterString(self, ctx:COOL.StringContext): - pass - - # Exit a parse tree produced by COOL#string. - def exitString(self, ctx:COOL.StringContext): - pass - - - # Enter a parse tree produced by COOL#isvoid. - def enterIsvoid(self, ctx:COOL.IsvoidContext): - pass - - # Exit a parse tree produced by COOL#isvoid. - def exitIsvoid(self, ctx:COOL.IsvoidContext): - pass - - - # Enter a parse tree produced by COOL#while. - def enterWhile(self, ctx:COOL.WhileContext): - pass - - # Exit a parse tree produced by COOL#while. - def exitWhile(self, ctx:COOL.WhileContext): - pass - - - # Enter a parse tree produced by COOL#division. - def enterDivision(self, ctx:COOL.DivisionContext): - pass - - # Exit a parse tree produced by COOL#division. - def exitDivision(self, ctx:COOL.DivisionContext): - pass - - - # Enter a parse tree produced by COOL#negative. - def enterNegative(self, ctx:COOL.NegativeContext): - pass - - # Exit a parse tree produced by COOL#negative. - def exitNegative(self, ctx:COOL.NegativeContext): - pass - - - # Enter a parse tree produced by COOL#boolNot. - def enterBoolNot(self, ctx:COOL.BoolNotContext): - pass - - # Exit a parse tree produced by COOL#boolNot. - def exitBoolNot(self, ctx:COOL.BoolNotContext): - pass - - - # Enter a parse tree produced by COOL#lessThan. - def enterLessThan(self, ctx:COOL.LessThanContext): - pass - - # Exit a parse tree produced by COOL#lessThan. - def exitLessThan(self, ctx:COOL.LessThanContext): - pass - - - # Enter a parse tree produced by COOL#block. - def enterBlock(self, ctx:COOL.BlockContext): - pass - - # Exit a parse tree produced by COOL#block. - def exitBlock(self, ctx:COOL.BlockContext): - pass - - - # Enter a parse tree produced by COOL#id. - def enterId(self, ctx:COOL.IdContext): - pass - - # Exit a parse tree produced by COOL#id. - def exitId(self, ctx:COOL.IdContext): - pass - - - # Enter a parse tree produced by COOL#multiply. - def enterMultiply(self, ctx:COOL.MultiplyContext): - pass - - # Exit a parse tree produced by COOL#multiply. - def exitMultiply(self, ctx:COOL.MultiplyContext): - pass - - - # Enter a parse tree produced by COOL#if. - def enterIf(self, ctx:COOL.IfContext): - pass - - # Exit a parse tree produced by COOL#if. - def exitIf(self, ctx:COOL.IfContext): - pass - - - # Enter a parse tree produced by COOL#case. - def enterCase(self, ctx:COOL.CaseContext): - pass - - # Exit a parse tree produced by COOL#case. - def exitCase(self, ctx:COOL.CaseContext): - pass - - - # Enter a parse tree produced by COOL#ownMethodCall. - def enterOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): - pass - - # Exit a parse tree produced by COOL#ownMethodCall. - def exitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): - pass - - - # Enter a parse tree produced by COOL#add. - def enterAdd(self, ctx:COOL.AddContext): - pass - - # Exit a parse tree produced by COOL#add. - def exitAdd(self, ctx:COOL.AddContext): - pass - - - # Enter a parse tree produced by COOL#new. - def enterNew(self, ctx:COOL.NewContext): - pass - - # Exit a parse tree produced by COOL#new. - def exitNew(self, ctx:COOL.NewContext): - pass - - - # Enter a parse tree produced by COOL#parentheses. - def enterParentheses(self, ctx:COOL.ParenthesesContext): - pass - - # Exit a parse tree produced by COOL#parentheses. - def exitParentheses(self, ctx:COOL.ParenthesesContext): - pass - - - # Enter a parse tree produced by COOL#assignment. - def enterAssignment(self, ctx:COOL.AssignmentContext): - pass - - # Exit a parse tree produced by COOL#assignment. - def exitAssignment(self, ctx:COOL.AssignmentContext): - pass - - - # Enter a parse tree produced by COOL#false. - def enterFalse(self, ctx:COOL.FalseContext): - pass - - # Exit a parse tree produced by COOL#false. - def exitFalse(self, ctx:COOL.FalseContext): - pass - - - # Enter a parse tree produced by COOL#int. - def enterInt(self, ctx:COOL.IntContext): - pass - - # Exit a parse tree produced by COOL#int. - def exitInt(self, ctx:COOL.IntContext): - pass - - - # Enter a parse tree produced by COOL#equal. - def enterEqual(self, ctx:COOL.EqualContext): - pass - - # Exit a parse tree produced by COOL#equal. - def exitEqual(self, ctx:COOL.EqualContext): - pass - - - # Enter a parse tree produced by COOL#true. - def enterTrue(self, ctx:COOL.TrueContext): - pass - - # Exit a parse tree produced by COOL#true. - def exitTrue(self, ctx:COOL.TrueContext): - pass - - - # Enter a parse tree produced by COOL#lessEqual. - def enterLessEqual(self, ctx:COOL.LessEqualContext): - pass - - # Exit a parse tree produced by COOL#lessEqual. - def exitLessEqual(self, ctx:COOL.LessEqualContext): - pass - - - # Enter a parse tree produced by COOL#methodCall. - def enterMethodCall(self, ctx:COOL.MethodCallContext): - pass - - # Exit a parse tree produced by COOL#methodCall. - def exitMethodCall(self, ctx:COOL.MethodCallContext): - pass - - diff --git a/COOLParser.py b/COOLParser.py deleted file mode 100644 index 7f3ad8ac..00000000 --- a/COOLParser.py +++ /dev/null @@ -1,24 +0,0 @@ -import sys -from io import StringIO -from typing.io import TextIO -from antlr4 import * -from COOL import COOL -from antlr4.CommonTokenFactory import CommonTokenFactory -from antlr4.atn.LexerATNSimulator import LexerATNSimulator -from antlr4.InputStream import InputStream -from antlr4.Recognizer import Recognizer -from antlr4.Token import Token -from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException - -class COOLParser(COOL): - def __init__(self, input=None, output:TextIO = sys.stdout): - super().__init__(input, output) - - def notifyErrorListeners(self, msg:str, offendingToken:Token = None, e:RecognitionException = None): - if offendingToken is None: - offendingToken = self.getCurrentToken() - self._syntaxErrors += 1 - line = offendingToken.line - column = offendingToken.column - listener = self.getErrorListenerDispatch() - listener.syntaxError(self, offendingToken, line, column, msg, e) \ No newline at end of file diff --git a/src/COOL.interp b/src/COOL.interp index f2d42957..bba307e6 100644 --- a/src/COOL.interp +++ b/src/COOL.interp @@ -1,14 +1,6 @@ token literal names: null -';' -'{' -'}' -'(' -',' -')' -':' -'@' -'.' +null null null null @@ -42,23 +34,23 @@ null '<=' '=' '~' -'(*' -'*)' +'(' +')' +'{' +'}' +'@' +'.' +',' +':' +';' null null +'(*' null +'*)' token symbolic names: null -null -null -null -null -null -null -null -null -null CLASS ELSE FALSE @@ -79,6 +71,7 @@ OF NOT TRUE STRING +BREAK_STRING INT TYPEID OBJECTID @@ -92,11 +85,20 @@ LESS_THAN LESS_EQUAL EQUAL INTEGER_NEGATIVE +OPEN_ROUND +CLOSE_ROUND +OPEN_CURLY +CLOSE_CURLY +AT +DOT +COMMA +COLON +SEMICOLON +WHITESPACE +ONE_LINE_COMMENT OPEN_COMMENT -CLOSE_COMMENT COMMENT -ONE_LINE_COMMENT -WHITESPACE +CLOSE_COMMENT rule names: program @@ -108,4 +110,4 @@ expression atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 49, 226, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 22, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 28, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 34, 10, 4, 12, 4, 14, 4, 37, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 46, 10, 5, 12, 5, 14, 5, 49, 11, 5, 7, 5, 51, 10, 5, 12, 5, 14, 5, 54, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 68, 10, 5, 5, 5, 70, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 82, 10, 7, 12, 7, 14, 7, 85, 11, 7, 7, 7, 87, 10, 7, 12, 7, 14, 7, 90, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 111, 10, 7, 13, 7, 14, 7, 112, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 123, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 131, 10, 7, 7, 7, 133, 10, 7, 12, 7, 14, 7, 136, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 150, 10, 7, 13, 7, 14, 7, 151, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 176, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 202, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 210, 10, 7, 12, 7, 14, 7, 213, 11, 7, 7, 7, 215, 10, 7, 12, 7, 14, 7, 218, 11, 7, 3, 7, 7, 7, 221, 10, 7, 12, 7, 14, 7, 224, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 260, 2, 14, 3, 2, 2, 2, 4, 21, 3, 2, 2, 2, 6, 23, 3, 2, 2, 2, 8, 69, 3, 2, 2, 2, 10, 71, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 3, 3, 2, 2, 2, 16, 17, 5, 6, 4, 2, 17, 18, 7, 3, 2, 2, 18, 19, 5, 4, 3, 2, 19, 22, 3, 2, 2, 2, 20, 22, 7, 2, 2, 3, 21, 16, 3, 2, 2, 2, 21, 20, 3, 2, 2, 2, 22, 5, 3, 2, 2, 2, 23, 24, 7, 12, 2, 2, 24, 27, 7, 33, 2, 2, 25, 26, 7, 18, 2, 2, 26, 28, 7, 33, 2, 2, 27, 25, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 29, 3, 2, 2, 2, 29, 35, 7, 4, 2, 2, 30, 31, 5, 8, 5, 2, 31, 32, 7, 3, 2, 2, 32, 34, 3, 2, 2, 2, 33, 30, 3, 2, 2, 2, 34, 37, 3, 2, 2, 2, 35, 33, 3, 2, 2, 2, 35, 36, 3, 2, 2, 2, 36, 38, 3, 2, 2, 2, 37, 35, 3, 2, 2, 2, 38, 39, 7, 5, 2, 2, 39, 7, 3, 2, 2, 2, 40, 41, 7, 34, 2, 2, 41, 52, 7, 6, 2, 2, 42, 47, 5, 10, 6, 2, 43, 44, 7, 7, 2, 2, 44, 46, 5, 10, 6, 2, 45, 43, 3, 2, 2, 2, 46, 49, 3, 2, 2, 2, 47, 45, 3, 2, 2, 2, 47, 48, 3, 2, 2, 2, 48, 51, 3, 2, 2, 2, 49, 47, 3, 2, 2, 2, 50, 42, 3, 2, 2, 2, 51, 54, 3, 2, 2, 2, 52, 50, 3, 2, 2, 2, 52, 53, 3, 2, 2, 2, 53, 55, 3, 2, 2, 2, 54, 52, 3, 2, 2, 2, 55, 56, 7, 8, 2, 2, 56, 57, 7, 9, 2, 2, 57, 58, 7, 33, 2, 2, 58, 59, 7, 4, 2, 2, 59, 60, 5, 12, 7, 2, 60, 61, 7, 5, 2, 2, 61, 70, 3, 2, 2, 2, 62, 63, 7, 34, 2, 2, 63, 64, 7, 9, 2, 2, 64, 67, 7, 33, 2, 2, 65, 66, 7, 35, 2, 2, 66, 68, 5, 12, 7, 2, 67, 65, 3, 2, 2, 2, 67, 68, 3, 2, 2, 2, 68, 70, 3, 2, 2, 2, 69, 40, 3, 2, 2, 2, 69, 62, 3, 2, 2, 2, 70, 9, 3, 2, 2, 2, 71, 72, 7, 34, 2, 2, 72, 73, 7, 9, 2, 2, 73, 74, 7, 33, 2, 2, 74, 11, 3, 2, 2, 2, 75, 76, 8, 7, 1, 2, 76, 77, 7, 34, 2, 2, 77, 88, 7, 6, 2, 2, 78, 83, 5, 12, 7, 2, 79, 80, 7, 7, 2, 2, 80, 82, 5, 12, 7, 2, 81, 79, 3, 2, 2, 2, 82, 85, 3, 2, 2, 2, 83, 81, 3, 2, 2, 2, 83, 84, 3, 2, 2, 2, 84, 87, 3, 2, 2, 2, 85, 83, 3, 2, 2, 2, 86, 78, 3, 2, 2, 2, 87, 90, 3, 2, 2, 2, 88, 86, 3, 2, 2, 2, 88, 89, 3, 2, 2, 2, 89, 91, 3, 2, 2, 2, 90, 88, 3, 2, 2, 2, 91, 176, 7, 8, 2, 2, 92, 93, 7, 16, 2, 2, 93, 94, 5, 12, 7, 2, 94, 95, 7, 23, 2, 2, 95, 96, 5, 12, 7, 2, 96, 97, 7, 13, 2, 2, 97, 98, 5, 12, 7, 2, 98, 99, 7, 15, 2, 2, 99, 176, 3, 2, 2, 2, 100, 101, 7, 24, 2, 2, 101, 102, 5, 12, 7, 2, 102, 103, 7, 21, 2, 2, 103, 104, 5, 12, 7, 2, 104, 105, 7, 22, 2, 2, 105, 176, 3, 2, 2, 2, 106, 110, 7, 4, 2, 2, 107, 108, 5, 12, 7, 2, 108, 109, 7, 3, 2, 2, 109, 111, 3, 2, 2, 2, 110, 107, 3, 2, 2, 2, 111, 112, 3, 2, 2, 2, 112, 110, 3, 2, 2, 2, 112, 113, 3, 2, 2, 2, 113, 114, 3, 2, 2, 2, 114, 115, 7, 5, 2, 2, 115, 176, 3, 2, 2, 2, 116, 117, 7, 20, 2, 2, 117, 118, 7, 34, 2, 2, 118, 119, 7, 9, 2, 2, 119, 122, 7, 33, 2, 2, 120, 121, 7, 35, 2, 2, 121, 123, 5, 12, 7, 2, 122, 120, 3, 2, 2, 2, 122, 123, 3, 2, 2, 2, 123, 134, 3, 2, 2, 2, 124, 125, 7, 7, 2, 2, 125, 126, 7, 34, 2, 2, 126, 127, 7, 9, 2, 2, 127, 130, 7, 33, 2, 2, 128, 129, 7, 35, 2, 2, 129, 131, 5, 12, 7, 2, 130, 128, 3, 2, 2, 2, 130, 131, 3, 2, 2, 2, 131, 133, 3, 2, 2, 2, 132, 124, 3, 2, 2, 2, 133, 136, 3, 2, 2, 2, 134, 132, 3, 2, 2, 2, 134, 135, 3, 2, 2, 2, 135, 137, 3, 2, 2, 2, 136, 134, 3, 2, 2, 2, 137, 138, 7, 17, 2, 2, 138, 176, 5, 12, 7, 22, 139, 140, 7, 25, 2, 2, 140, 141, 5, 12, 7, 2, 141, 149, 7, 28, 2, 2, 142, 143, 7, 34, 2, 2, 143, 144, 7, 9, 2, 2, 144, 145, 7, 33, 2, 2, 145, 146, 7, 36, 2, 2, 146, 147, 5, 12, 7, 2, 147, 148, 7, 3, 2, 2, 148, 150, 3, 2, 2, 2, 149, 142, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 149, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 3, 2, 2, 2, 153, 154, 7, 26, 2, 2, 154, 176, 3, 2, 2, 2, 155, 156, 7, 27, 2, 2, 156, 176, 7, 33, 2, 2, 157, 158, 7, 44, 2, 2, 158, 176, 5, 12, 7, 19, 159, 160, 7, 19, 2, 2, 160, 176, 5, 12, 7, 18, 161, 162, 7, 29, 2, 2, 162, 176, 5, 12, 7, 10, 163, 164, 7, 6, 2, 2, 164, 165, 5, 12, 7, 2, 165, 166, 7, 8, 2, 2, 166, 176, 3, 2, 2, 2, 167, 176, 7, 34, 2, 2, 168, 176, 7, 32, 2, 2, 169, 176, 7, 31, 2, 2, 170, 176, 7, 30, 2, 2, 171, 176, 7, 14, 2, 2, 172, 173, 7, 34, 2, 2, 173, 174, 7, 35, 2, 2, 174, 176, 5, 12, 7, 3, 175, 75, 3, 2, 2, 2, 175, 92, 3, 2, 2, 2, 175, 100, 3, 2, 2, 2, 175, 106, 3, 2, 2, 2, 175, 116, 3, 2, 2, 2, 175, 139, 3, 2, 2, 2, 175, 155, 3, 2, 2, 2, 175, 157, 3, 2, 2, 2, 175, 159, 3, 2, 2, 2, 175, 161, 3, 2, 2, 2, 175, 163, 3, 2, 2, 2, 175, 167, 3, 2, 2, 2, 175, 168, 3, 2, 2, 2, 175, 169, 3, 2, 2, 2, 175, 170, 3, 2, 2, 2, 175, 171, 3, 2, 2, 2, 175, 172, 3, 2, 2, 2, 176, 222, 3, 2, 2, 2, 177, 178, 12, 17, 2, 2, 178, 179, 7, 39, 2, 2, 179, 221, 5, 12, 7, 18, 180, 181, 12, 16, 2, 2, 181, 182, 7, 40, 2, 2, 182, 221, 5, 12, 7, 17, 183, 184, 12, 15, 2, 2, 184, 185, 7, 37, 2, 2, 185, 221, 5, 12, 7, 16, 186, 187, 12, 14, 2, 2, 187, 188, 7, 38, 2, 2, 188, 221, 5, 12, 7, 15, 189, 190, 12, 13, 2, 2, 190, 191, 7, 41, 2, 2, 191, 221, 5, 12, 7, 14, 192, 193, 12, 12, 2, 2, 193, 194, 7, 42, 2, 2, 194, 221, 5, 12, 7, 13, 195, 196, 12, 11, 2, 2, 196, 197, 7, 43, 2, 2, 197, 221, 5, 12, 7, 12, 198, 201, 12, 27, 2, 2, 199, 200, 7, 10, 2, 2, 200, 202, 7, 33, 2, 2, 201, 199, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 3, 2, 2, 2, 203, 204, 7, 11, 2, 2, 204, 205, 7, 34, 2, 2, 205, 216, 7, 6, 2, 2, 206, 211, 5, 12, 7, 2, 207, 208, 7, 7, 2, 2, 208, 210, 5, 12, 7, 2, 209, 207, 3, 2, 2, 2, 210, 213, 3, 2, 2, 2, 211, 209, 3, 2, 2, 2, 211, 212, 3, 2, 2, 2, 212, 215, 3, 2, 2, 2, 213, 211, 3, 2, 2, 2, 214, 206, 3, 2, 2, 2, 215, 218, 3, 2, 2, 2, 216, 214, 3, 2, 2, 2, 216, 217, 3, 2, 2, 2, 217, 219, 3, 2, 2, 2, 218, 216, 3, 2, 2, 2, 219, 221, 7, 8, 2, 2, 220, 177, 3, 2, 2, 2, 220, 180, 3, 2, 2, 2, 220, 183, 3, 2, 2, 2, 220, 186, 3, 2, 2, 2, 220, 189, 3, 2, 2, 2, 220, 192, 3, 2, 2, 2, 220, 195, 3, 2, 2, 2, 220, 198, 3, 2, 2, 2, 221, 224, 3, 2, 2, 2, 222, 220, 3, 2, 2, 2, 222, 223, 3, 2, 2, 2, 223, 13, 3, 2, 2, 2, 224, 222, 3, 2, 2, 2, 22, 21, 27, 35, 47, 52, 67, 69, 83, 88, 112, 122, 130, 134, 151, 175, 201, 211, 216, 220, 222] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 50, 225, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 7, 7, 86, 10, 7, 12, 7, 14, 7, 89, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 110, 10, 7, 13, 7, 14, 7, 111, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 122, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 130, 10, 7, 7, 7, 132, 10, 7, 12, 7, 14, 7, 135, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 149, 10, 7, 13, 7, 14, 7, 150, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 175, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 201, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 209, 10, 7, 12, 7, 14, 7, 212, 11, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 7, 7, 220, 10, 7, 12, 7, 14, 7, 223, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 259, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 174, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 45, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 25, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 25, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 39, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 45, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 40, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 26, 2, 2, 40, 51, 7, 37, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 43, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 38, 2, 2, 55, 56, 7, 44, 2, 2, 56, 57, 7, 25, 2, 2, 57, 58, 7, 39, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 40, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 26, 2, 2, 62, 63, 7, 44, 2, 2, 63, 66, 7, 25, 2, 2, 64, 65, 7, 27, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 26, 2, 2, 71, 72, 7, 44, 2, 2, 72, 73, 7, 25, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 26, 2, 2, 76, 87, 7, 37, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 43, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 90, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 175, 7, 38, 2, 2, 91, 92, 7, 7, 2, 2, 92, 93, 5, 12, 7, 2, 93, 94, 7, 14, 2, 2, 94, 95, 5, 12, 7, 2, 95, 96, 7, 4, 2, 2, 96, 97, 5, 12, 7, 2, 97, 98, 7, 6, 2, 2, 98, 175, 3, 2, 2, 2, 99, 100, 7, 15, 2, 2, 100, 101, 5, 12, 7, 2, 101, 102, 7, 12, 2, 2, 102, 103, 5, 12, 7, 2, 103, 104, 7, 13, 2, 2, 104, 175, 3, 2, 2, 2, 105, 109, 7, 39, 2, 2, 106, 107, 5, 12, 7, 2, 107, 108, 7, 45, 2, 2, 108, 110, 3, 2, 2, 2, 109, 106, 3, 2, 2, 2, 110, 111, 3, 2, 2, 2, 111, 109, 3, 2, 2, 2, 111, 112, 3, 2, 2, 2, 112, 113, 3, 2, 2, 2, 113, 114, 7, 40, 2, 2, 114, 175, 3, 2, 2, 2, 115, 116, 7, 11, 2, 2, 116, 117, 7, 26, 2, 2, 117, 118, 7, 44, 2, 2, 118, 121, 7, 25, 2, 2, 119, 120, 7, 27, 2, 2, 120, 122, 5, 12, 7, 2, 121, 119, 3, 2, 2, 2, 121, 122, 3, 2, 2, 2, 122, 133, 3, 2, 2, 2, 123, 124, 7, 43, 2, 2, 124, 125, 7, 26, 2, 2, 125, 126, 7, 44, 2, 2, 126, 129, 7, 25, 2, 2, 127, 128, 7, 27, 2, 2, 128, 130, 5, 12, 7, 2, 129, 127, 3, 2, 2, 2, 129, 130, 3, 2, 2, 2, 130, 132, 3, 2, 2, 2, 131, 123, 3, 2, 2, 2, 132, 135, 3, 2, 2, 2, 133, 131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 136, 3, 2, 2, 2, 135, 133, 3, 2, 2, 2, 136, 137, 7, 8, 2, 2, 137, 175, 5, 12, 7, 22, 138, 139, 7, 16, 2, 2, 139, 140, 5, 12, 7, 2, 140, 148, 7, 19, 2, 2, 141, 142, 7, 26, 2, 2, 142, 143, 7, 44, 2, 2, 143, 144, 7, 25, 2, 2, 144, 145, 7, 28, 2, 2, 145, 146, 5, 12, 7, 2, 146, 147, 7, 45, 2, 2, 147, 149, 3, 2, 2, 2, 148, 141, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 150, 148, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 7, 17, 2, 2, 153, 175, 3, 2, 2, 2, 154, 155, 7, 18, 2, 2, 155, 175, 7, 25, 2, 2, 156, 157, 7, 36, 2, 2, 157, 175, 5, 12, 7, 19, 158, 159, 7, 10, 2, 2, 159, 175, 5, 12, 7, 18, 160, 161, 7, 20, 2, 2, 161, 175, 5, 12, 7, 10, 162, 163, 7, 37, 2, 2, 163, 164, 5, 12, 7, 2, 164, 165, 7, 38, 2, 2, 165, 175, 3, 2, 2, 2, 166, 175, 7, 26, 2, 2, 167, 175, 7, 24, 2, 2, 168, 175, 7, 22, 2, 2, 169, 175, 7, 21, 2, 2, 170, 175, 7, 5, 2, 2, 171, 172, 7, 26, 2, 2, 172, 173, 7, 27, 2, 2, 173, 175, 5, 12, 7, 3, 174, 74, 3, 2, 2, 2, 174, 91, 3, 2, 2, 2, 174, 99, 3, 2, 2, 2, 174, 105, 3, 2, 2, 2, 174, 115, 3, 2, 2, 2, 174, 138, 3, 2, 2, 2, 174, 154, 3, 2, 2, 2, 174, 156, 3, 2, 2, 2, 174, 158, 3, 2, 2, 2, 174, 160, 3, 2, 2, 2, 174, 162, 3, 2, 2, 2, 174, 166, 3, 2, 2, 2, 174, 167, 3, 2, 2, 2, 174, 168, 3, 2, 2, 2, 174, 169, 3, 2, 2, 2, 174, 170, 3, 2, 2, 2, 174, 171, 3, 2, 2, 2, 175, 221, 3, 2, 2, 2, 176, 177, 12, 17, 2, 2, 177, 178, 7, 31, 2, 2, 178, 220, 5, 12, 7, 18, 179, 180, 12, 16, 2, 2, 180, 181, 7, 32, 2, 2, 181, 220, 5, 12, 7, 17, 182, 183, 12, 15, 2, 2, 183, 184, 7, 29, 2, 2, 184, 220, 5, 12, 7, 16, 185, 186, 12, 14, 2, 2, 186, 187, 7, 30, 2, 2, 187, 220, 5, 12, 7, 15, 188, 189, 12, 13, 2, 2, 189, 190, 7, 33, 2, 2, 190, 220, 5, 12, 7, 14, 191, 192, 12, 12, 2, 2, 192, 193, 7, 34, 2, 2, 193, 220, 5, 12, 7, 13, 194, 195, 12, 11, 2, 2, 195, 196, 7, 35, 2, 2, 196, 220, 5, 12, 7, 12, 197, 200, 12, 27, 2, 2, 198, 199, 7, 41, 2, 2, 199, 201, 7, 25, 2, 2, 200, 198, 3, 2, 2, 2, 200, 201, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 7, 42, 2, 2, 203, 204, 7, 26, 2, 2, 204, 215, 7, 37, 2, 2, 205, 210, 5, 12, 7, 2, 206, 207, 7, 43, 2, 2, 207, 209, 5, 12, 7, 2, 208, 206, 3, 2, 2, 2, 209, 212, 3, 2, 2, 2, 210, 208, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 214, 3, 2, 2, 2, 212, 210, 3, 2, 2, 2, 213, 205, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 218, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 218, 220, 7, 38, 2, 2, 219, 176, 3, 2, 2, 2, 219, 179, 3, 2, 2, 2, 219, 182, 3, 2, 2, 2, 219, 185, 3, 2, 2, 2, 219, 188, 3, 2, 2, 2, 219, 191, 3, 2, 2, 2, 219, 194, 3, 2, 2, 2, 219, 197, 3, 2, 2, 2, 220, 223, 3, 2, 2, 2, 221, 219, 3, 2, 2, 2, 221, 222, 3, 2, 2, 2, 222, 13, 3, 2, 2, 2, 223, 221, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 87, 111, 121, 129, 133, 150, 174, 200, 210, 215, 219, 221] \ No newline at end of file diff --git a/COOL.py b/src/COOL.py similarity index 100% rename from COOL.py rename to src/COOL.py diff --git a/src/COOL.tokens b/src/COOL.tokens index 320277ee..bbdda836 100644 --- a/src/COOL.tokens +++ b/src/COOL.tokens @@ -1,68 +1,69 @@ -T__0=1 -T__1=2 -T__2=3 -T__3=4 -T__4=5 -T__5=6 -T__6=7 -T__7=8 -T__8=9 -CLASS=10 -ELSE=11 -FALSE=12 -FI=13 -IF=14 -IN=15 -INHERITS=16 -ISVOID=17 -LET=18 -LOOP=19 -POOL=20 -THEN=21 -WHILE=22 -CASE=23 -ESAC=24 -NEW=25 -OF=26 -NOT=27 -TRUE=28 -STRING=29 -INT=30 -TYPEID=31 -OBJECTID=32 -ASSIGNMENT=33 -CASE_ARROW=34 -ADD=35 -MINUS=36 -MULTIPLY=37 -DIVISION=38 -LESS_THAN=39 -LESS_EQUAL=40 -EQUAL=41 -INTEGER_NEGATIVE=42 -OPEN_COMMENT=43 -CLOSE_COMMENT=44 -COMMENT=45 -ONE_LINE_COMMENT=46 -WHITESPACE=47 -';'=1 -'{'=2 -'}'=3 -'('=4 -','=5 -')'=6 -':'=7 -'@'=8 -'.'=9 -'<-'=33 -'=>'=34 -'+'=35 -'-'=36 -'*'=37 -'/'=38 -'<'=39 -'<='=40 -'='=41 -'~'=42 -'(*'=43 -'*)'=44 +CLASS=1 +ELSE=2 +FALSE=3 +FI=4 +IF=5 +IN=6 +INHERITS=7 +ISVOID=8 +LET=9 +LOOP=10 +POOL=11 +THEN=12 +WHILE=13 +CASE=14 +ESAC=15 +NEW=16 +OF=17 +NOT=18 +TRUE=19 +STRING=20 +BREAK_STRING=21 +INT=22 +TYPEID=23 +OBJECTID=24 +ASSIGNMENT=25 +CASE_ARROW=26 +ADD=27 +MINUS=28 +MULTIPLY=29 +DIVISION=30 +LESS_THAN=31 +LESS_EQUAL=32 +EQUAL=33 +INTEGER_NEGATIVE=34 +OPEN_ROUND=35 +CLOSE_ROUND=36 +OPEN_CURLY=37 +CLOSE_CURLY=38 +AT=39 +DOT=40 +COMMA=41 +COLON=42 +SEMICOLON=43 +WHITESPACE=44 +ONE_LINE_COMMENT=45 +OPEN_COMMENT=46 +COMMENT=47 +CLOSE_COMMENT=48 +'<-'=25 +'=>'=26 +'+'=27 +'-'=28 +'*'=29 +'/'=30 +'<'=31 +'<='=32 +'='=33 +'~'=34 +'('=35 +')'=36 +'{'=37 +'}'=38 +'@'=39 +'.'=40 +','=41 +':'=42 +';'=43 +'(*'=46 +'*)'=48 diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index dd3d486b..5a9b2584 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -1,14 +1,35 @@ import sys +import os.path from antlr4 import * from COOLLexer import COOLLexer +from COOLLexerErrorListener import COOLLexerErrorListener from COOLParser import COOLParser +from COOLParserErrorListener import COOLParserErrorListener from COOLListener import COOLListener def main(argv): + if not os.path.isfile(argv[1]): + print("invalid input filename") + return + input = FileStream(argv[1]) + lexer = COOLLexer(input) + lexer.removeErrorListeners() + lexer.addErrorListener(COOLLexerErrorListener()) + token = lexer.nextToken() + while token.type != Token.EOF: + token = lexer.nextToken() + + if lexer.hasErrors: + return + + lexer.reset(); stream = CommonTokenStream(lexer) parser = COOLParser(stream) + parser.removeErrorListeners() + parser.addErrorListener(COOLParserErrorListener()) + tree = parser.program() if __name__ == '__main__': diff --git a/src/COOLLexer.py b/src/COOLLexer.py index d53e933d..bcb2349c 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -1,267 +1,34 @@ -# Generated from C:\Software\ANTLR\cool\COOL.g4 by ANTLR 4.7.2 -from antlr4 import * +import sys from io import StringIO from typing.io import TextIO -import sys - - - -def serializedATN(): - with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\61") - buf.write("\u0182\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7") - buf.write("\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r") - buf.write("\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23") - buf.write("\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30") - buf.write("\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36") - buf.write("\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\4%\t%") - buf.write("\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t,\4-\t-\4.") - buf.write("\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64") - buf.write("\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:") - buf.write("\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\t") - buf.write("C\4D\tD\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\7\3") - buf.write("\7\3\b\3\b\3\t\3\t\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3") - buf.write("\13\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3") - buf.write("\16\3\16\3\17\3\17\3\17\3\20\3\20\3\20\3\21\3\21\3\21") - buf.write("\3\21\3\21\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\22") - buf.write("\3\22\3\22\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24") - buf.write("\3\25\3\25\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3\27") - buf.write("\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3\30\3\31") - buf.write("\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32\3\33\3\33\3\33") - buf.write("\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\35\3\36\3\36") - buf.write("\3\36\7\36\u00fc\n\36\f\36\16\36\u00ff\13\36\3\36\3\36") - buf.write("\3\37\6\37\u0104\n\37\r\37\16\37\u0105\3 \3 \7 \u010a") - buf.write("\n \f \16 \u010d\13 \3!\3!\7!\u0111\n!\f!\16!\u0114\13") - buf.write("!\3\"\3\"\3\"\3#\3#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3") - buf.write("(\3)\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3") - buf.write("\60\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65") - buf.write("\3\66\3\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<\3<\3=") - buf.write("\3=\3=\5=\u0152\n=\3>\3>\3>\3>\3>\3>\3?\3?\3@\3@\3@\3") - buf.write("A\3A\3A\3B\3B\3B\7B\u0165\nB\fB\16B\u0168\13B\3B\3B\3") - buf.write("B\3B\3C\3C\3C\3C\7C\u0172\nC\fC\16C\u0175\13C\3C\5C\u0178") - buf.write("\nC\3C\3C\3D\6D\u017d\nD\rD\16D\u017e\3D\3D\3\u0166\2") - buf.write("E\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31") - buf.write("\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31") - buf.write("\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O") - buf.write(")Q*S+U,W\2Y\2[\2]\2_\2a\2c\2e\2g\2i\2k\2m\2o\2q\2s\2u") - buf.write("\2w\2y\2{\2}\2\177-\u0081.\u0083/\u0085\60\u0087\61\3") - buf.write("\2\34\4\2$$^^\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2") - buf.write("CCcc\4\2EEee\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4") - buf.write("\2NNnn\4\2PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVv") - buf.write("v\4\2WWww\4\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2") - buf.write("\62;CHch\3\2\f\f\5\2\13\f\16\17\"\"\2\u0178\2\3\3\2\2") - buf.write("\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2") - buf.write("\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25") - buf.write("\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3") - buf.write("\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2") - buf.write("\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2") - buf.write("\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\2") - buf.write("9\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2") - buf.write("\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2") - buf.write("\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2") - buf.write("\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085") - buf.write("\3\2\2\2\2\u0087\3\2\2\2\3\u0089\3\2\2\2\5\u008b\3\2\2") - buf.write("\2\7\u008d\3\2\2\2\t\u008f\3\2\2\2\13\u0091\3\2\2\2\r") - buf.write("\u0093\3\2\2\2\17\u0095\3\2\2\2\21\u0097\3\2\2\2\23\u0099") - buf.write("\3\2\2\2\25\u009b\3\2\2\2\27\u00a1\3\2\2\2\31\u00a6\3") - buf.write("\2\2\2\33\u00ac\3\2\2\2\35\u00af\3\2\2\2\37\u00b2\3\2") - buf.write("\2\2!\u00b5\3\2\2\2#\u00be\3\2\2\2%\u00c5\3\2\2\2\'\u00c9") - buf.write("\3\2\2\2)\u00ce\3\2\2\2+\u00d3\3\2\2\2-\u00d8\3\2\2\2") - buf.write("/\u00de\3\2\2\2\61\u00e3\3\2\2\2\63\u00e8\3\2\2\2\65\u00ec") - buf.write("\3\2\2\2\67\u00ef\3\2\2\29\u00f3\3\2\2\2;\u00f8\3\2\2") - buf.write("\2=\u0103\3\2\2\2?\u0107\3\2\2\2A\u010e\3\2\2\2C\u0115") - buf.write("\3\2\2\2E\u0118\3\2\2\2G\u011b\3\2\2\2I\u011d\3\2\2\2") - buf.write("K\u011f\3\2\2\2M\u0121\3\2\2\2O\u0123\3\2\2\2Q\u0125\3") - buf.write("\2\2\2S\u0128\3\2\2\2U\u012a\3\2\2\2W\u012c\3\2\2\2Y\u012e") - buf.write("\3\2\2\2[\u0130\3\2\2\2]\u0132\3\2\2\2_\u0134\3\2\2\2") - buf.write("a\u0136\3\2\2\2c\u0138\3\2\2\2e\u013a\3\2\2\2g\u013c\3") - buf.write("\2\2\2i\u013e\3\2\2\2k\u0140\3\2\2\2m\u0142\3\2\2\2o\u0144") - buf.write("\3\2\2\2q\u0146\3\2\2\2s\u0148\3\2\2\2u\u014a\3\2\2\2") - buf.write("w\u014c\3\2\2\2y\u014e\3\2\2\2{\u0153\3\2\2\2}\u0159\3") - buf.write("\2\2\2\177\u015b\3\2\2\2\u0081\u015e\3\2\2\2\u0083\u0161") - buf.write("\3\2\2\2\u0085\u016d\3\2\2\2\u0087\u017c\3\2\2\2\u0089") - buf.write("\u008a\7=\2\2\u008a\4\3\2\2\2\u008b\u008c\7}\2\2\u008c") - buf.write("\6\3\2\2\2\u008d\u008e\7\177\2\2\u008e\b\3\2\2\2\u008f") - buf.write("\u0090\7*\2\2\u0090\n\3\2\2\2\u0091\u0092\7.\2\2\u0092") - buf.write("\f\3\2\2\2\u0093\u0094\7+\2\2\u0094\16\3\2\2\2\u0095\u0096") - buf.write("\7<\2\2\u0096\20\3\2\2\2\u0097\u0098\7B\2\2\u0098\22\3") - buf.write("\2\2\2\u0099\u009a\7\60\2\2\u009a\24\3\2\2\2\u009b\u009c") - buf.write("\5Y-\2\u009c\u009d\5e\63\2\u009d\u009e\5W,\2\u009e\u009f") - buf.write("\5o8\2\u009f\u00a0\5o8\2\u00a0\26\3\2\2\2\u00a1\u00a2") - buf.write("\5]/\2\u00a2\u00a3\5e\63\2\u00a3\u00a4\5o8\2\u00a4\u00a5") - buf.write("\5]/\2\u00a5\30\3\2\2\2\u00a6\u00a7\7h\2\2\u00a7\u00a8") - buf.write("\5W,\2\u00a8\u00a9\5e\63\2\u00a9\u00aa\5o8\2\u00aa\u00ab") - buf.write("\5]/\2\u00ab\32\3\2\2\2\u00ac\u00ad\5_\60\2\u00ad\u00ae") - buf.write("\5c\62\2\u00ae\34\3\2\2\2\u00af\u00b0\5c\62\2\u00b0\u00b1") - buf.write("\5_\60\2\u00b1\36\3\2\2\2\u00b2\u00b3\5c\62\2\u00b3\u00b4") - buf.write("\5g\64\2\u00b4 \3\2\2\2\u00b5\u00b6\5c\62\2\u00b6\u00b7") - buf.write("\5g\64\2\u00b7\u00b8\5a\61\2\u00b8\u00b9\5]/\2\u00b9\u00ba") - buf.write("\5m\67\2\u00ba\u00bb\5c\62\2\u00bb\u00bc\5q9\2\u00bc\u00bd") - buf.write("\5o8\2\u00bd\"\3\2\2\2\u00be\u00bf\5c\62\2\u00bf\u00c0") - buf.write("\5o8\2\u00c0\u00c1\5u;\2\u00c1\u00c2\5i\65\2\u00c2\u00c3") - buf.write("\5c\62\2\u00c3\u00c4\5[.\2\u00c4$\3\2\2\2\u00c5\u00c6") - buf.write("\5e\63\2\u00c6\u00c7\5]/\2\u00c7\u00c8\5q9\2\u00c8&\3") - buf.write("\2\2\2\u00c9\u00ca\5e\63\2\u00ca\u00cb\5i\65\2\u00cb\u00cc") - buf.write("\5i\65\2\u00cc\u00cd\5k\66\2\u00cd(\3\2\2\2\u00ce\u00cf") - buf.write("\5k\66\2\u00cf\u00d0\5i\65\2\u00d0\u00d1\5i\65\2\u00d1") - buf.write("\u00d2\5e\63\2\u00d2*\3\2\2\2\u00d3\u00d4\5q9\2\u00d4") - buf.write("\u00d5\5a\61\2\u00d5\u00d6\5]/\2\u00d6\u00d7\5g\64\2\u00d7") - buf.write(",\3\2\2\2\u00d8\u00d9\5w<\2\u00d9\u00da\5a\61\2\u00da") - buf.write("\u00db\5c\62\2\u00db\u00dc\5e\63\2\u00dc\u00dd\5]/\2\u00dd") - buf.write(".\3\2\2\2\u00de\u00df\5Y-\2\u00df\u00e0\5W,\2\u00e0\u00e1") - buf.write("\5o8\2\u00e1\u00e2\5]/\2\u00e2\60\3\2\2\2\u00e3\u00e4") - buf.write("\5]/\2\u00e4\u00e5\5o8\2\u00e5\u00e6\5W,\2\u00e6\u00e7") - buf.write("\5Y-\2\u00e7\62\3\2\2\2\u00e8\u00e9\5g\64\2\u00e9\u00ea") - buf.write("\5]/\2\u00ea\u00eb\5w<\2\u00eb\64\3\2\2\2\u00ec\u00ed") - buf.write("\5i\65\2\u00ed\u00ee\5_\60\2\u00ee\66\3\2\2\2\u00ef\u00f0") - buf.write("\5g\64\2\u00f0\u00f1\5i\65\2\u00f1\u00f2\5q9\2\u00f28") - buf.write("\3\2\2\2\u00f3\u00f4\7v\2\2\u00f4\u00f5\5m\67\2\u00f5") - buf.write("\u00f6\5s:\2\u00f6\u00f7\5]/\2\u00f7:\3\2\2\2\u00f8\u00fd") - buf.write("\7$\2\2\u00f9\u00fc\5y=\2\u00fa\u00fc\n\2\2\2\u00fb\u00f9") - buf.write("\3\2\2\2\u00fb\u00fa\3\2\2\2\u00fc\u00ff\3\2\2\2\u00fd") - buf.write("\u00fb\3\2\2\2\u00fd\u00fe\3\2\2\2\u00fe\u0100\3\2\2\2") - buf.write("\u00ff\u00fd\3\2\2\2\u0100\u0101\7$\2\2\u0101<\3\2\2\2") - buf.write("\u0102\u0104\t\3\2\2\u0103\u0102\3\2\2\2\u0104\u0105\3") - buf.write("\2\2\2\u0105\u0103\3\2\2\2\u0105\u0106\3\2\2\2\u0106>") - buf.write("\3\2\2\2\u0107\u010b\t\4\2\2\u0108\u010a\t\5\2\2\u0109") - buf.write("\u0108\3\2\2\2\u010a\u010d\3\2\2\2\u010b\u0109\3\2\2\2") - buf.write("\u010b\u010c\3\2\2\2\u010c@\3\2\2\2\u010d\u010b\3\2\2") - buf.write("\2\u010e\u0112\t\6\2\2\u010f\u0111\t\5\2\2\u0110\u010f") - buf.write("\3\2\2\2\u0111\u0114\3\2\2\2\u0112\u0110\3\2\2\2\u0112") - buf.write("\u0113\3\2\2\2\u0113B\3\2\2\2\u0114\u0112\3\2\2\2\u0115") - buf.write("\u0116\7>\2\2\u0116\u0117\7/\2\2\u0117D\3\2\2\2\u0118") - buf.write("\u0119\7?\2\2\u0119\u011a\7@\2\2\u011aF\3\2\2\2\u011b") - buf.write("\u011c\7-\2\2\u011cH\3\2\2\2\u011d\u011e\7/\2\2\u011e") - buf.write("J\3\2\2\2\u011f\u0120\7,\2\2\u0120L\3\2\2\2\u0121\u0122") - buf.write("\7\61\2\2\u0122N\3\2\2\2\u0123\u0124\7>\2\2\u0124P\3\2") - buf.write("\2\2\u0125\u0126\7>\2\2\u0126\u0127\7?\2\2\u0127R\3\2") - buf.write("\2\2\u0128\u0129\7?\2\2\u0129T\3\2\2\2\u012a\u012b\7\u0080") - buf.write("\2\2\u012bV\3\2\2\2\u012c\u012d\t\7\2\2\u012dX\3\2\2\2") - buf.write("\u012e\u012f\t\b\2\2\u012fZ\3\2\2\2\u0130\u0131\t\t\2") - buf.write("\2\u0131\\\3\2\2\2\u0132\u0133\t\n\2\2\u0133^\3\2\2\2") - buf.write("\u0134\u0135\t\13\2\2\u0135`\3\2\2\2\u0136\u0137\t\f\2") - buf.write("\2\u0137b\3\2\2\2\u0138\u0139\t\r\2\2\u0139d\3\2\2\2\u013a") - buf.write("\u013b\t\16\2\2\u013bf\3\2\2\2\u013c\u013d\t\17\2\2\u013d") - buf.write("h\3\2\2\2\u013e\u013f\t\20\2\2\u013fj\3\2\2\2\u0140\u0141") - buf.write("\t\21\2\2\u0141l\3\2\2\2\u0142\u0143\t\22\2\2\u0143n\3") - buf.write("\2\2\2\u0144\u0145\t\23\2\2\u0145p\3\2\2\2\u0146\u0147") - buf.write("\t\24\2\2\u0147r\3\2\2\2\u0148\u0149\t\25\2\2\u0149t\3") - buf.write("\2\2\2\u014a\u014b\t\26\2\2\u014bv\3\2\2\2\u014c\u014d") - buf.write("\t\27\2\2\u014dx\3\2\2\2\u014e\u0151\7^\2\2\u014f\u0152") - buf.write("\t\30\2\2\u0150\u0152\5{>\2\u0151\u014f\3\2\2\2\u0151") - buf.write("\u0150\3\2\2\2\u0152z\3\2\2\2\u0153\u0154\7w\2\2\u0154") - buf.write("\u0155\5}?\2\u0155\u0156\5}?\2\u0156\u0157\5}?\2\u0157") - buf.write("\u0158\5}?\2\u0158|\3\2\2\2\u0159\u015a\t\31\2\2\u015a") - buf.write("~\3\2\2\2\u015b\u015c\7*\2\2\u015c\u015d\7,\2\2\u015d") - buf.write("\u0080\3\2\2\2\u015e\u015f\7,\2\2\u015f\u0160\7+\2\2\u0160") - buf.write("\u0082\3\2\2\2\u0161\u0166\5\177@\2\u0162\u0165\5\u0083") - buf.write("B\2\u0163\u0165\13\2\2\2\u0164\u0162\3\2\2\2\u0164\u0163") - buf.write("\3\2\2\2\u0165\u0168\3\2\2\2\u0166\u0167\3\2\2\2\u0166") - buf.write("\u0164\3\2\2\2\u0167\u0169\3\2\2\2\u0168\u0166\3\2\2\2") - buf.write("\u0169\u016a\5\u0081A\2\u016a\u016b\3\2\2\2\u016b\u016c") - buf.write("\bB\2\2\u016c\u0084\3\2\2\2\u016d\u016e\7/\2\2\u016e\u016f") - buf.write("\7/\2\2\u016f\u0173\3\2\2\2\u0170\u0172\n\32\2\2\u0171") - buf.write("\u0170\3\2\2\2\u0172\u0175\3\2\2\2\u0173\u0171\3\2\2\2") - buf.write("\u0173\u0174\3\2\2\2\u0174\u0177\3\2\2\2\u0175\u0173\3") - buf.write("\2\2\2\u0176\u0178\7\f\2\2\u0177\u0176\3\2\2\2\u0177\u0178") - buf.write("\3\2\2\2\u0178\u0179\3\2\2\2\u0179\u017a\bC\2\2\u017a") - buf.write("\u0086\3\2\2\2\u017b\u017d\t\33\2\2\u017c\u017b\3\2\2") - buf.write("\2\u017d\u017e\3\2\2\2\u017e\u017c\3\2\2\2\u017e\u017f") - buf.write("\3\2\2\2\u017f\u0180\3\2\2\2\u0180\u0181\bD\2\2\u0181") - buf.write("\u0088\3\2\2\2\16\2\u00fb\u00fd\u0105\u010b\u0112\u0151") - buf.write("\u0164\u0166\u0173\u0177\u017e\3\b\2\2") - return buf.getvalue() - - -class COOLLexer(Lexer): - - atn = ATNDeserializer().deserialize(serializedATN()) - - decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] - - T__0 = 1 - T__1 = 2 - T__2 = 3 - T__3 = 4 - T__4 = 5 - T__5 = 6 - T__6 = 7 - T__7 = 8 - T__8 = 9 - CLASS = 10 - ELSE = 11 - FALSE = 12 - FI = 13 - IF = 14 - IN = 15 - INHERITS = 16 - ISVOID = 17 - LET = 18 - LOOP = 19 - POOL = 20 - THEN = 21 - WHILE = 22 - CASE = 23 - ESAC = 24 - NEW = 25 - OF = 26 - NOT = 27 - TRUE = 28 - STRING = 29 - INT = 30 - TYPEID = 31 - OBJECTID = 32 - ASSIGNMENT = 33 - CASE_ARROW = 34 - ADD = 35 - MINUS = 36 - MULTIPLY = 37 - DIVISION = 38 - LESS_THAN = 39 - LESS_EQUAL = 40 - EQUAL = 41 - INTEGER_NEGATIVE = 42 - OPEN_COMMENT = 43 - CLOSE_COMMENT = 44 - COMMENT = 45 - ONE_LINE_COMMENT = 46 - WHITESPACE = 47 - - channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] - - modeNames = [ "DEFAULT_MODE" ] - - literalNames = [ "", - "';'", "'{'", "'}'", "'('", "','", "')'", "':'", "'@'", "'.'", - "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", "'<='", "'='", - "'~'", "'(*'", "'*)'" ] - - symbolicNames = [ "", - "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", - "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", - "OF", "NOT", "TRUE", "STRING", "INT", "TYPEID", "OBJECTID", - "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", - "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_COMMENT", - "CLOSE_COMMENT", "COMMENT", "ONE_LINE_COMMENT", "WHITESPACE" ] - - ruleNames = [ "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", - "T__7", "T__8", "CLASS", "ELSE", "FALSE", "FI", "IF", - "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", - "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", - "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", - "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", - "EQUAL", "INTEGER_NEGATIVE", "A", "C", "D", "E", "F", - "H", "I", "L", "N", "O", "P", "R", "S", "T", "U", "V", - "W", "ESC", "UNICODE", "HEX", "OPEN_COMMENT", "CLOSE_COMMENT", - "COMMENT", "ONE_LINE_COMMENT", "WHITESPACE" ] - - grammarFileName = "COOL.g4" - +from antlr4 import * +from COOL_LEX import COOL_LEX +from antlr4.CommonTokenFactory import CommonTokenFactory +from antlr4.atn.LexerATNSimulator import LexerATNSimulator +from antlr4.InputStream import InputStream +from antlr4.Recognizer import Recognizer +from antlr4.Token import Token +from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException + +class COOLLexer(COOL_LEX): def __init__(self, input=None, output:TextIO = sys.stdout): super().__init__(input, output) - self.checkVersion("4.7.2") - self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) - self._actions = None - self._predicates = None + self._hasErrors = False + + def notifyListeners(self, e:LexerNoViableAltException): + self._hasErrors = True + + start = self._tokenStartCharIndex + stop = self._input.index + text = self._input.getText(start, stop) + msg = "'" + self.getErrorDisplay(text) + "'" + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, self._token, self._tokenStartLine, self._tokenStartColumn, msg, e) + def reset(self): + super().reset() + self._hasErrors = False + @property + def hasErrors(self): + return self._hasErrors \ No newline at end of file diff --git a/COOLLexerErrorListener.py b/src/COOLLexerErrorListener.py similarity index 100% rename from COOLLexerErrorListener.py rename to src/COOLLexerErrorListener.py diff --git a/src/COOLListener.py b/src/COOLListener.py index 50a72320..e5e5d915 100644 --- a/src/COOLListener.py +++ b/src/COOLListener.py @@ -1,298 +1,289 @@ -# Generated from C:\Software\ANTLR\cool\COOL.g4 by ANTLR 4.7.2 +# Generated from COOL.g4 by ANTLR 4.7.2 from antlr4 import * if __name__ is not None and "." in __name__: - from .COOLParser import COOLParser + from .COOL import COOL else: - from COOLParser import COOLParser + from COOL import COOL -# This class defines a complete listener for a parse tree produced by COOLParser. +# This class defines a complete listener for a parse tree produced by COOL. class COOLListener(ParseTreeListener): - # Enter a parse tree produced by COOLParser#program. - def enterProgram(self, ctx:COOLParser.ProgramContext): + # Enter a parse tree produced by COOL#program. + def enterProgram(self, ctx:COOL.ProgramContext): pass - # Exit a parse tree produced by COOLParser#program. - def exitProgram(self, ctx:COOLParser.ProgramContext): + # Exit a parse tree produced by COOL#program. + def exitProgram(self, ctx:COOL.ProgramContext): pass - # Enter a parse tree produced by COOLParser#classes. - def enterClasses(self, ctx:COOLParser.ClassesContext): + # Enter a parse tree produced by COOL#classes. + def enterClasses(self, ctx:COOL.ClassesContext): pass - # Exit a parse tree produced by COOLParser#classes. - def exitClasses(self, ctx:COOLParser.ClassesContext): + # Exit a parse tree produced by COOL#classes. + def exitClasses(self, ctx:COOL.ClassesContext): pass - # Enter a parse tree produced by COOLParser#eof. - def enterEof(self, ctx:COOLParser.EofContext): + # Enter a parse tree produced by COOL#classDefine. + def enterClassDefine(self, ctx:COOL.ClassDefineContext): pass - # Exit a parse tree produced by COOLParser#eof. - def exitEof(self, ctx:COOLParser.EofContext): + # Exit a parse tree produced by COOL#classDefine. + def exitClassDefine(self, ctx:COOL.ClassDefineContext): pass - # Enter a parse tree produced by COOLParser#classDefine. - def enterClassDefine(self, ctx:COOLParser.ClassDefineContext): + # Enter a parse tree produced by COOL#method. + def enterMethod(self, ctx:COOL.MethodContext): pass - # Exit a parse tree produced by COOLParser#classDefine. - def exitClassDefine(self, ctx:COOLParser.ClassDefineContext): + # Exit a parse tree produced by COOL#method. + def exitMethod(self, ctx:COOL.MethodContext): pass - # Enter a parse tree produced by COOLParser#method. - def enterMethod(self, ctx:COOLParser.MethodContext): + # Enter a parse tree produced by COOL#property. + def enterProperty(self, ctx:COOL.PropertyContext): pass - # Exit a parse tree produced by COOLParser#method. - def exitMethod(self, ctx:COOLParser.MethodContext): + # Exit a parse tree produced by COOL#property. + def exitProperty(self, ctx:COOL.PropertyContext): pass - # Enter a parse tree produced by COOLParser#property. - def enterProperty(self, ctx:COOLParser.PropertyContext): + # Enter a parse tree produced by COOL#formal. + def enterFormal(self, ctx:COOL.FormalContext): pass - # Exit a parse tree produced by COOLParser#property. - def exitProperty(self, ctx:COOLParser.PropertyContext): + # Exit a parse tree produced by COOL#formal. + def exitFormal(self, ctx:COOL.FormalContext): pass - # Enter a parse tree produced by COOLParser#formal. - def enterFormal(self, ctx:COOLParser.FormalContext): + # Enter a parse tree produced by COOL#letIn. + def enterLetIn(self, ctx:COOL.LetInContext): pass - # Exit a parse tree produced by COOLParser#formal. - def exitFormal(self, ctx:COOLParser.FormalContext): + # Exit a parse tree produced by COOL#letIn. + def exitLetIn(self, ctx:COOL.LetInContext): pass - # Enter a parse tree produced by COOLParser#letIn. - def enterLetIn(self, ctx:COOLParser.LetInContext): + # Enter a parse tree produced by COOL#minus. + def enterMinus(self, ctx:COOL.MinusContext): pass - # Exit a parse tree produced by COOLParser#letIn. - def exitLetIn(self, ctx:COOLParser.LetInContext): + # Exit a parse tree produced by COOL#minus. + def exitMinus(self, ctx:COOL.MinusContext): pass - # Enter a parse tree produced by COOLParser#minus. - def enterMinus(self, ctx:COOLParser.MinusContext): + # Enter a parse tree produced by COOL#string. + def enterString(self, ctx:COOL.StringContext): pass - # Exit a parse tree produced by COOLParser#minus. - def exitMinus(self, ctx:COOLParser.MinusContext): + # Exit a parse tree produced by COOL#string. + def exitString(self, ctx:COOL.StringContext): pass - # Enter a parse tree produced by COOLParser#string. - def enterString(self, ctx:COOLParser.StringContext): + # Enter a parse tree produced by COOL#isvoid. + def enterIsvoid(self, ctx:COOL.IsvoidContext): pass - # Exit a parse tree produced by COOLParser#string. - def exitString(self, ctx:COOLParser.StringContext): + # Exit a parse tree produced by COOL#isvoid. + def exitIsvoid(self, ctx:COOL.IsvoidContext): pass - # Enter a parse tree produced by COOLParser#isvoid. - def enterIsvoid(self, ctx:COOLParser.IsvoidContext): + # Enter a parse tree produced by COOL#while. + def enterWhile(self, ctx:COOL.WhileContext): pass - # Exit a parse tree produced by COOLParser#isvoid. - def exitIsvoid(self, ctx:COOLParser.IsvoidContext): + # Exit a parse tree produced by COOL#while. + def exitWhile(self, ctx:COOL.WhileContext): pass - # Enter a parse tree produced by COOLParser#while. - def enterWhile(self, ctx:COOLParser.WhileContext): + # Enter a parse tree produced by COOL#division. + def enterDivision(self, ctx:COOL.DivisionContext): pass - # Exit a parse tree produced by COOLParser#while. - def exitWhile(self, ctx:COOLParser.WhileContext): + # Exit a parse tree produced by COOL#division. + def exitDivision(self, ctx:COOL.DivisionContext): pass - # Enter a parse tree produced by COOLParser#division. - def enterDivision(self, ctx:COOLParser.DivisionContext): + # Enter a parse tree produced by COOL#negative. + def enterNegative(self, ctx:COOL.NegativeContext): pass - # Exit a parse tree produced by COOLParser#division. - def exitDivision(self, ctx:COOLParser.DivisionContext): + # Exit a parse tree produced by COOL#negative. + def exitNegative(self, ctx:COOL.NegativeContext): pass - # Enter a parse tree produced by COOLParser#negative. - def enterNegative(self, ctx:COOLParser.NegativeContext): + # Enter a parse tree produced by COOL#boolNot. + def enterBoolNot(self, ctx:COOL.BoolNotContext): pass - # Exit a parse tree produced by COOLParser#negative. - def exitNegative(self, ctx:COOLParser.NegativeContext): + # Exit a parse tree produced by COOL#boolNot. + def exitBoolNot(self, ctx:COOL.BoolNotContext): pass - # Enter a parse tree produced by COOLParser#boolNot. - def enterBoolNot(self, ctx:COOLParser.BoolNotContext): + # Enter a parse tree produced by COOL#lessThan. + def enterLessThan(self, ctx:COOL.LessThanContext): pass - # Exit a parse tree produced by COOLParser#boolNot. - def exitBoolNot(self, ctx:COOLParser.BoolNotContext): + # Exit a parse tree produced by COOL#lessThan. + def exitLessThan(self, ctx:COOL.LessThanContext): pass - # Enter a parse tree produced by COOLParser#lessThan. - def enterLessThan(self, ctx:COOLParser.LessThanContext): + # Enter a parse tree produced by COOL#block. + def enterBlock(self, ctx:COOL.BlockContext): pass - # Exit a parse tree produced by COOLParser#lessThan. - def exitLessThan(self, ctx:COOLParser.LessThanContext): + # Exit a parse tree produced by COOL#block. + def exitBlock(self, ctx:COOL.BlockContext): pass - # Enter a parse tree produced by COOLParser#block. - def enterBlock(self, ctx:COOLParser.BlockContext): + # Enter a parse tree produced by COOL#id. + def enterId(self, ctx:COOL.IdContext): pass - # Exit a parse tree produced by COOLParser#block. - def exitBlock(self, ctx:COOLParser.BlockContext): + # Exit a parse tree produced by COOL#id. + def exitId(self, ctx:COOL.IdContext): pass - # Enter a parse tree produced by COOLParser#id. - def enterId(self, ctx:COOLParser.IdContext): + # Enter a parse tree produced by COOL#multiply. + def enterMultiply(self, ctx:COOL.MultiplyContext): pass - # Exit a parse tree produced by COOLParser#id. - def exitId(self, ctx:COOLParser.IdContext): + # Exit a parse tree produced by COOL#multiply. + def exitMultiply(self, ctx:COOL.MultiplyContext): pass - # Enter a parse tree produced by COOLParser#multiply. - def enterMultiply(self, ctx:COOLParser.MultiplyContext): + # Enter a parse tree produced by COOL#if. + def enterIf(self, ctx:COOL.IfContext): pass - # Exit a parse tree produced by COOLParser#multiply. - def exitMultiply(self, ctx:COOLParser.MultiplyContext): + # Exit a parse tree produced by COOL#if. + def exitIf(self, ctx:COOL.IfContext): pass - # Enter a parse tree produced by COOLParser#if. - def enterIf(self, ctx:COOLParser.IfContext): + # Enter a parse tree produced by COOL#case. + def enterCase(self, ctx:COOL.CaseContext): pass - # Exit a parse tree produced by COOLParser#if. - def exitIf(self, ctx:COOLParser.IfContext): + # Exit a parse tree produced by COOL#case. + def exitCase(self, ctx:COOL.CaseContext): pass - # Enter a parse tree produced by COOLParser#case. - def enterCase(self, ctx:COOLParser.CaseContext): + # Enter a parse tree produced by COOL#ownMethodCall. + def enterOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): pass - # Exit a parse tree produced by COOLParser#case. - def exitCase(self, ctx:COOLParser.CaseContext): + # Exit a parse tree produced by COOL#ownMethodCall. + def exitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): pass - # Enter a parse tree produced by COOLParser#ownMethodCall. - def enterOwnMethodCall(self, ctx:COOLParser.OwnMethodCallContext): + # Enter a parse tree produced by COOL#add. + def enterAdd(self, ctx:COOL.AddContext): pass - # Exit a parse tree produced by COOLParser#ownMethodCall. - def exitOwnMethodCall(self, ctx:COOLParser.OwnMethodCallContext): + # Exit a parse tree produced by COOL#add. + def exitAdd(self, ctx:COOL.AddContext): pass - # Enter a parse tree produced by COOLParser#add. - def enterAdd(self, ctx:COOLParser.AddContext): + # Enter a parse tree produced by COOL#new. + def enterNew(self, ctx:COOL.NewContext): pass - # Exit a parse tree produced by COOLParser#add. - def exitAdd(self, ctx:COOLParser.AddContext): + # Exit a parse tree produced by COOL#new. + def exitNew(self, ctx:COOL.NewContext): pass - # Enter a parse tree produced by COOLParser#new. - def enterNew(self, ctx:COOLParser.NewContext): + # Enter a parse tree produced by COOL#parentheses. + def enterParentheses(self, ctx:COOL.ParenthesesContext): pass - # Exit a parse tree produced by COOLParser#new. - def exitNew(self, ctx:COOLParser.NewContext): + # Exit a parse tree produced by COOL#parentheses. + def exitParentheses(self, ctx:COOL.ParenthesesContext): pass - # Enter a parse tree produced by COOLParser#parentheses. - def enterParentheses(self, ctx:COOLParser.ParenthesesContext): + # Enter a parse tree produced by COOL#assignment. + def enterAssignment(self, ctx:COOL.AssignmentContext): pass - # Exit a parse tree produced by COOLParser#parentheses. - def exitParentheses(self, ctx:COOLParser.ParenthesesContext): + # Exit a parse tree produced by COOL#assignment. + def exitAssignment(self, ctx:COOL.AssignmentContext): pass - # Enter a parse tree produced by COOLParser#assignment. - def enterAssignment(self, ctx:COOLParser.AssignmentContext): + # Enter a parse tree produced by COOL#false. + def enterFalse(self, ctx:COOL.FalseContext): pass - # Exit a parse tree produced by COOLParser#assignment. - def exitAssignment(self, ctx:COOLParser.AssignmentContext): + # Exit a parse tree produced by COOL#false. + def exitFalse(self, ctx:COOL.FalseContext): pass - # Enter a parse tree produced by COOLParser#false. - def enterFalse(self, ctx:COOLParser.FalseContext): + # Enter a parse tree produced by COOL#int. + def enterInt(self, ctx:COOL.IntContext): pass - # Exit a parse tree produced by COOLParser#false. - def exitFalse(self, ctx:COOLParser.FalseContext): + # Exit a parse tree produced by COOL#int. + def exitInt(self, ctx:COOL.IntContext): pass - # Enter a parse tree produced by COOLParser#int. - def enterInt(self, ctx:COOLParser.IntContext): + # Enter a parse tree produced by COOL#equal. + def enterEqual(self, ctx:COOL.EqualContext): pass - # Exit a parse tree produced by COOLParser#int. - def exitInt(self, ctx:COOLParser.IntContext): + # Exit a parse tree produced by COOL#equal. + def exitEqual(self, ctx:COOL.EqualContext): pass - # Enter a parse tree produced by COOLParser#equal. - def enterEqual(self, ctx:COOLParser.EqualContext): + # Enter a parse tree produced by COOL#true. + def enterTrue(self, ctx:COOL.TrueContext): pass - # Exit a parse tree produced by COOLParser#equal. - def exitEqual(self, ctx:COOLParser.EqualContext): + # Exit a parse tree produced by COOL#true. + def exitTrue(self, ctx:COOL.TrueContext): pass - # Enter a parse tree produced by COOLParser#true. - def enterTrue(self, ctx:COOLParser.TrueContext): + # Enter a parse tree produced by COOL#lessEqual. + def enterLessEqual(self, ctx:COOL.LessEqualContext): pass - # Exit a parse tree produced by COOLParser#true. - def exitTrue(self, ctx:COOLParser.TrueContext): + # Exit a parse tree produced by COOL#lessEqual. + def exitLessEqual(self, ctx:COOL.LessEqualContext): pass - # Enter a parse tree produced by COOLParser#lessEqual. - def enterLessEqual(self, ctx:COOLParser.LessEqualContext): + # Enter a parse tree produced by COOL#methodCall. + def enterMethodCall(self, ctx:COOL.MethodCallContext): pass - # Exit a parse tree produced by COOLParser#lessEqual. - def exitLessEqual(self, ctx:COOLParser.LessEqualContext): - pass - - - # Enter a parse tree produced by COOLParser#methodCall. - def enterMethodCall(self, ctx:COOLParser.MethodCallContext): - pass - - # Exit a parse tree produced by COOLParser#methodCall. - def exitMethodCall(self, ctx:COOLParser.MethodCallContext): + # Exit a parse tree produced by COOL#methodCall. + def exitMethodCall(self, ctx:COOL.MethodCallContext): pass diff --git a/src/COOLParser.py b/src/COOLParser.py index d30ff78b..7f3ad8ac 100644 --- a/src/COOLParser.py +++ b/src/COOLParser.py @@ -1,1757 +1,24 @@ -# Generated from C:\Software\ANTLR\cool\COOL.g4 by ANTLR 4.7.2 -# encoding: utf-8 -from antlr4 import * +import sys from io import StringIO from typing.io import TextIO -import sys - - -def serializedATN(): - with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\61") - buf.write("\u00e2\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") - buf.write("\3\2\3\2\3\3\3\3\3\3\3\3\3\3\5\3\26\n\3\3\4\3\4\3\4\3") - buf.write("\4\5\4\34\n\4\3\4\3\4\3\4\3\4\7\4\"\n\4\f\4\16\4%\13\4") - buf.write("\3\4\3\4\3\5\3\5\3\5\3\5\3\5\7\5.\n\5\f\5\16\5\61\13\5") - buf.write("\7\5\63\n\5\f\5\16\5\66\13\5\3\5\3\5\3\5\3\5\3\5\3\5\3") - buf.write("\5\3\5\3\5\3\5\3\5\3\5\5\5D\n\5\5\5F\n\5\3\6\3\6\3\6\3") - buf.write("\6\3\7\3\7\3\7\3\7\3\7\3\7\7\7R\n\7\f\7\16\7U\13\7\7\7") - buf.write("W\n\7\f\7\16\7Z\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") - buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\6\7o\n\7\r") - buf.write("\7\16\7p\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\5\7{\n\7\3\7") - buf.write("\3\7\3\7\3\7\3\7\3\7\5\7\u0083\n\7\7\7\u0085\n\7\f\7\16") - buf.write("\7\u0088\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\6\7\u0096\n\7\r\7\16\7\u0097\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") - buf.write("\7\3\7\3\7\3\7\3\7\5\7\u00b0\n\7\3\7\3\7\3\7\3\7\3\7\3") - buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\3\7\3\7\3\7\5\7\u00ca\n\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\7\7\u00d2\n\7\f\7\16\7\u00d5\13\7\7\7\u00d7\n\7\f") - buf.write("\7\16\7\u00da\13\7\3\7\7\7\u00dd\n\7\f\7\16\7\u00e0\13") - buf.write("\7\3\7\2\3\f\b\2\4\6\b\n\f\2\2\2\u0104\2\16\3\2\2\2\4") - buf.write("\25\3\2\2\2\6\27\3\2\2\2\bE\3\2\2\2\nG\3\2\2\2\f\u00af") - buf.write("\3\2\2\2\16\17\5\4\3\2\17\3\3\2\2\2\20\21\5\6\4\2\21\22") - buf.write("\7\3\2\2\22\23\5\4\3\2\23\26\3\2\2\2\24\26\7\2\2\3\25") - buf.write("\20\3\2\2\2\25\24\3\2\2\2\26\5\3\2\2\2\27\30\7\f\2\2\30") - buf.write("\33\7!\2\2\31\32\7\22\2\2\32\34\7!\2\2\33\31\3\2\2\2\33") - buf.write("\34\3\2\2\2\34\35\3\2\2\2\35#\7\4\2\2\36\37\5\b\5\2\37") - buf.write(" \7\3\2\2 \"\3\2\2\2!\36\3\2\2\2\"%\3\2\2\2#!\3\2\2\2") - buf.write("#$\3\2\2\2$&\3\2\2\2%#\3\2\2\2&\'\7\5\2\2\'\7\3\2\2\2") - buf.write("()\7\"\2\2)\64\7\6\2\2*/\5\n\6\2+,\7\7\2\2,.\5\n\6\2-") - buf.write("+\3\2\2\2.\61\3\2\2\2/-\3\2\2\2/\60\3\2\2\2\60\63\3\2") - buf.write("\2\2\61/\3\2\2\2\62*\3\2\2\2\63\66\3\2\2\2\64\62\3\2\2") - buf.write("\2\64\65\3\2\2\2\65\67\3\2\2\2\66\64\3\2\2\2\678\7\b\2") - buf.write("\289\7\t\2\29:\7!\2\2:;\7\4\2\2;<\5\f\7\2<=\7\5\2\2=F") - buf.write("\3\2\2\2>?\7\"\2\2?@\7\t\2\2@C\7!\2\2AB\7#\2\2BD\5\f\7") - buf.write("\2CA\3\2\2\2CD\3\2\2\2DF\3\2\2\2E(\3\2\2\2E>\3\2\2\2F") - buf.write("\t\3\2\2\2GH\7\"\2\2HI\7\t\2\2IJ\7!\2\2J\13\3\2\2\2KL") - buf.write("\b\7\1\2LM\7\"\2\2MX\7\6\2\2NS\5\f\7\2OP\7\7\2\2PR\5\f") - buf.write("\7\2QO\3\2\2\2RU\3\2\2\2SQ\3\2\2\2ST\3\2\2\2TW\3\2\2\2") - buf.write("US\3\2\2\2VN\3\2\2\2WZ\3\2\2\2XV\3\2\2\2XY\3\2\2\2Y[\3") - buf.write("\2\2\2ZX\3\2\2\2[\u00b0\7\b\2\2\\]\7\20\2\2]^\5\f\7\2") - buf.write("^_\7\27\2\2_`\5\f\7\2`a\7\r\2\2ab\5\f\7\2bc\7\17\2\2c") - buf.write("\u00b0\3\2\2\2de\7\30\2\2ef\5\f\7\2fg\7\25\2\2gh\5\f\7") - buf.write("\2hi\7\26\2\2i\u00b0\3\2\2\2jn\7\4\2\2kl\5\f\7\2lm\7\3") - buf.write("\2\2mo\3\2\2\2nk\3\2\2\2op\3\2\2\2pn\3\2\2\2pq\3\2\2\2") - buf.write("qr\3\2\2\2rs\7\5\2\2s\u00b0\3\2\2\2tu\7\24\2\2uv\7\"\2") - buf.write("\2vw\7\t\2\2wz\7!\2\2xy\7#\2\2y{\5\f\7\2zx\3\2\2\2z{\3") - buf.write("\2\2\2{\u0086\3\2\2\2|}\7\7\2\2}~\7\"\2\2~\177\7\t\2\2") - buf.write("\177\u0082\7!\2\2\u0080\u0081\7#\2\2\u0081\u0083\5\f\7") - buf.write("\2\u0082\u0080\3\2\2\2\u0082\u0083\3\2\2\2\u0083\u0085") - buf.write("\3\2\2\2\u0084|\3\2\2\2\u0085\u0088\3\2\2\2\u0086\u0084") - buf.write("\3\2\2\2\u0086\u0087\3\2\2\2\u0087\u0089\3\2\2\2\u0088") - buf.write("\u0086\3\2\2\2\u0089\u008a\7\21\2\2\u008a\u00b0\5\f\7") - buf.write("\26\u008b\u008c\7\31\2\2\u008c\u008d\5\f\7\2\u008d\u0095") - buf.write("\7\34\2\2\u008e\u008f\7\"\2\2\u008f\u0090\7\t\2\2\u0090") - buf.write("\u0091\7!\2\2\u0091\u0092\7$\2\2\u0092\u0093\5\f\7\2\u0093") - buf.write("\u0094\7\3\2\2\u0094\u0096\3\2\2\2\u0095\u008e\3\2\2\2") - buf.write("\u0096\u0097\3\2\2\2\u0097\u0095\3\2\2\2\u0097\u0098\3") - buf.write("\2\2\2\u0098\u0099\3\2\2\2\u0099\u009a\7\32\2\2\u009a") - buf.write("\u00b0\3\2\2\2\u009b\u009c\7\33\2\2\u009c\u00b0\7!\2\2") - buf.write("\u009d\u009e\7,\2\2\u009e\u00b0\5\f\7\23\u009f\u00a0\7") - buf.write("\23\2\2\u00a0\u00b0\5\f\7\22\u00a1\u00a2\7\35\2\2\u00a2") - buf.write("\u00b0\5\f\7\n\u00a3\u00a4\7\6\2\2\u00a4\u00a5\5\f\7\2") - buf.write("\u00a5\u00a6\7\b\2\2\u00a6\u00b0\3\2\2\2\u00a7\u00b0\7") - buf.write("\"\2\2\u00a8\u00b0\7 \2\2\u00a9\u00b0\7\37\2\2\u00aa\u00b0") - buf.write("\7\36\2\2\u00ab\u00b0\7\16\2\2\u00ac\u00ad\7\"\2\2\u00ad") - buf.write("\u00ae\7#\2\2\u00ae\u00b0\5\f\7\3\u00afK\3\2\2\2\u00af") - buf.write("\\\3\2\2\2\u00afd\3\2\2\2\u00afj\3\2\2\2\u00aft\3\2\2") - buf.write("\2\u00af\u008b\3\2\2\2\u00af\u009b\3\2\2\2\u00af\u009d") - buf.write("\3\2\2\2\u00af\u009f\3\2\2\2\u00af\u00a1\3\2\2\2\u00af") - buf.write("\u00a3\3\2\2\2\u00af\u00a7\3\2\2\2\u00af\u00a8\3\2\2\2") - buf.write("\u00af\u00a9\3\2\2\2\u00af\u00aa\3\2\2\2\u00af\u00ab\3") - buf.write("\2\2\2\u00af\u00ac\3\2\2\2\u00b0\u00de\3\2\2\2\u00b1\u00b2") - buf.write("\f\21\2\2\u00b2\u00b3\7\'\2\2\u00b3\u00dd\5\f\7\22\u00b4") - buf.write("\u00b5\f\20\2\2\u00b5\u00b6\7(\2\2\u00b6\u00dd\5\f\7\21") - buf.write("\u00b7\u00b8\f\17\2\2\u00b8\u00b9\7%\2\2\u00b9\u00dd\5") - buf.write("\f\7\20\u00ba\u00bb\f\16\2\2\u00bb\u00bc\7&\2\2\u00bc") - buf.write("\u00dd\5\f\7\17\u00bd\u00be\f\r\2\2\u00be\u00bf\7)\2\2") - buf.write("\u00bf\u00dd\5\f\7\16\u00c0\u00c1\f\f\2\2\u00c1\u00c2") - buf.write("\7*\2\2\u00c2\u00dd\5\f\7\r\u00c3\u00c4\f\13\2\2\u00c4") - buf.write("\u00c5\7+\2\2\u00c5\u00dd\5\f\7\f\u00c6\u00c9\f\33\2\2") - buf.write("\u00c7\u00c8\7\n\2\2\u00c8\u00ca\7!\2\2\u00c9\u00c7\3") - buf.write("\2\2\2\u00c9\u00ca\3\2\2\2\u00ca\u00cb\3\2\2\2\u00cb\u00cc") - buf.write("\7\13\2\2\u00cc\u00cd\7\"\2\2\u00cd\u00d8\7\6\2\2\u00ce") - buf.write("\u00d3\5\f\7\2\u00cf\u00d0\7\7\2\2\u00d0\u00d2\5\f\7\2") - buf.write("\u00d1\u00cf\3\2\2\2\u00d2\u00d5\3\2\2\2\u00d3\u00d1\3") - buf.write("\2\2\2\u00d3\u00d4\3\2\2\2\u00d4\u00d7\3\2\2\2\u00d5\u00d3") - buf.write("\3\2\2\2\u00d6\u00ce\3\2\2\2\u00d7\u00da\3\2\2\2\u00d8") - buf.write("\u00d6\3\2\2\2\u00d8\u00d9\3\2\2\2\u00d9\u00db\3\2\2\2") - buf.write("\u00da\u00d8\3\2\2\2\u00db\u00dd\7\b\2\2\u00dc\u00b1\3") - buf.write("\2\2\2\u00dc\u00b4\3\2\2\2\u00dc\u00b7\3\2\2\2\u00dc\u00ba") - buf.write("\3\2\2\2\u00dc\u00bd\3\2\2\2\u00dc\u00c0\3\2\2\2\u00dc") - buf.write("\u00c3\3\2\2\2\u00dc\u00c6\3\2\2\2\u00dd\u00e0\3\2\2\2") - buf.write("\u00de\u00dc\3\2\2\2\u00de\u00df\3\2\2\2\u00df\r\3\2\2") - buf.write("\2\u00e0\u00de\3\2\2\2\26\25\33#/\64CESXpz\u0082\u0086") - buf.write("\u0097\u00af\u00c9\u00d3\u00d8\u00dc\u00de") - return buf.getvalue() - - -class COOLParser ( Parser ): - - grammarFileName = "COOL.g4" - - atn = ATNDeserializer().deserialize(serializedATN()) - - decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] - - sharedContextCache = PredictionContextCache() - - literalNames = [ "", "';'", "'{'", "'}'", "'('", "','", "')'", - "':'", "'@'", "'.'", "", "", "", - "", "", "", "", - "", "", "", "", - "", "", "", "", - "", "", "", "", - "", "", "", "", - "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", - "'<='", "'='", "'~'", "'(*'", "'*)'" ] - - symbolicNames = [ "", "", "", "", - "", "", "", "", - "", "", "CLASS", "ELSE", "FALSE", - "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", - "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", - "NOT", "TRUE", "STRING", "INT", "TYPEID", "OBJECTID", - "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", - "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", - "OPEN_COMMENT", "CLOSE_COMMENT", "COMMENT", "ONE_LINE_COMMENT", - "WHITESPACE" ] - - RULE_program = 0 - RULE_programBlocks = 1 - RULE_classDefine = 2 - RULE_feature = 3 - RULE_formal = 4 - RULE_expression = 5 - - ruleNames = [ "program", "programBlocks", "classDefine", "feature", - "formal", "expression" ] - - EOF = Token.EOF - T__0=1 - T__1=2 - T__2=3 - T__3=4 - T__4=5 - T__5=6 - T__6=7 - T__7=8 - T__8=9 - CLASS=10 - ELSE=11 - FALSE=12 - FI=13 - IF=14 - IN=15 - INHERITS=16 - ISVOID=17 - LET=18 - LOOP=19 - POOL=20 - THEN=21 - WHILE=22 - CASE=23 - ESAC=24 - NEW=25 - OF=26 - NOT=27 - TRUE=28 - STRING=29 - INT=30 - TYPEID=31 - OBJECTID=32 - ASSIGNMENT=33 - CASE_ARROW=34 - ADD=35 - MINUS=36 - MULTIPLY=37 - DIVISION=38 - LESS_THAN=39 - LESS_EQUAL=40 - EQUAL=41 - INTEGER_NEGATIVE=42 - OPEN_COMMENT=43 - CLOSE_COMMENT=44 - COMMENT=45 - ONE_LINE_COMMENT=46 - WHITESPACE=47 - - def __init__(self, input:TokenStream, output:TextIO = sys.stdout): +from antlr4 import * +from COOL import COOL +from antlr4.CommonTokenFactory import CommonTokenFactory +from antlr4.atn.LexerATNSimulator import LexerATNSimulator +from antlr4.InputStream import InputStream +from antlr4.Recognizer import Recognizer +from antlr4.Token import Token +from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException + +class COOLParser(COOL): + def __init__(self, input=None, output:TextIO = sys.stdout): super().__init__(input, output) - self.checkVersion("4.7.2") - self._interp = ParserATNSimulator(self, self.atn, self.decisionsToDFA, self.sharedContextCache) - self._predicates = None - - - - - class ProgramContext(ParserRuleContext): - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - def programBlocks(self): - return self.getTypedRuleContext(COOLParser.ProgramBlocksContext,0) - - - def getRuleIndex(self): - return COOLParser.RULE_program - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterProgram" ): - listener.enterProgram(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitProgram" ): - listener.exitProgram(self) - - - - - def program(self): - - localctx = COOLParser.ProgramContext(self, self._ctx, self.state) - self.enterRule(localctx, 0, self.RULE_program) - try: - self.enterOuterAlt(localctx, 1) - self.state = 12 - self.programBlocks() - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.exitRule() - return localctx - - - class ProgramBlocksContext(ParserRuleContext): - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - - def getRuleIndex(self): - return COOLParser.RULE_programBlocks - - - def copyFrom(self, ctx:ParserRuleContext): - super().copyFrom(ctx) - - - - class ClassesContext(ProgramBlocksContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ProgramBlocksContext - super().__init__(parser) - self.copyFrom(ctx) - - def classDefine(self): - return self.getTypedRuleContext(COOLParser.ClassDefineContext,0) - - def programBlocks(self): - return self.getTypedRuleContext(COOLParser.ProgramBlocksContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterClasses" ): - listener.enterClasses(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitClasses" ): - listener.exitClasses(self) - - - class EofContext(ProgramBlocksContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ProgramBlocksContext - super().__init__(parser) - self.copyFrom(ctx) - - def EOF(self): - return self.getToken(COOLParser.EOF, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterEof" ): - listener.enterEof(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitEof" ): - listener.exitEof(self) - - - - def programBlocks(self): - - localctx = COOLParser.ProgramBlocksContext(self, self._ctx, self.state) - self.enterRule(localctx, 2, self.RULE_programBlocks) - try: - self.state = 19 - self._errHandler.sync(self) - token = self._input.LA(1) - if token in [COOLParser.CLASS]: - localctx = COOLParser.ClassesContext(self, localctx) - self.enterOuterAlt(localctx, 1) - self.state = 14 - self.classDefine() - self.state = 15 - self.match(COOLParser.T__0) - self.state = 16 - self.programBlocks() - pass - elif token in [COOLParser.EOF]: - localctx = COOLParser.EofContext(self, localctx) - self.enterOuterAlt(localctx, 2) - self.state = 18 - self.match(COOLParser.EOF) - pass - else: - raise NoViableAltException(self) - - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.exitRule() - return localctx - - - class ClassDefineContext(ParserRuleContext): - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - def CLASS(self): - return self.getToken(COOLParser.CLASS, 0) - - def TYPEID(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.TYPEID) - else: - return self.getToken(COOLParser.TYPEID, i) - - def INHERITS(self): - return self.getToken(COOLParser.INHERITS, 0) - - def feature(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.FeatureContext) - else: - return self.getTypedRuleContext(COOLParser.FeatureContext,i) - - - def getRuleIndex(self): - return COOLParser.RULE_classDefine - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterClassDefine" ): - listener.enterClassDefine(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitClassDefine" ): - listener.exitClassDefine(self) - - - - - def classDefine(self): - - localctx = COOLParser.ClassDefineContext(self, self._ctx, self.state) - self.enterRule(localctx, 4, self.RULE_classDefine) - self._la = 0 # Token type - try: - self.enterOuterAlt(localctx, 1) - self.state = 21 - self.match(COOLParser.CLASS) - self.state = 22 - self.match(COOLParser.TYPEID) - self.state = 25 - self._errHandler.sync(self) - _la = self._input.LA(1) - if _la==COOLParser.INHERITS: - self.state = 23 - self.match(COOLParser.INHERITS) - self.state = 24 - self.match(COOLParser.TYPEID) - - - self.state = 27 - self.match(COOLParser.T__1) - self.state = 33 - self._errHandler.sync(self) - _la = self._input.LA(1) - while _la==COOLParser.OBJECTID: - self.state = 28 - self.feature() - self.state = 29 - self.match(COOLParser.T__0) - self.state = 35 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 36 - self.match(COOLParser.T__2) - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.exitRule() - return localctx - - - class FeatureContext(ParserRuleContext): - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - - def getRuleIndex(self): - return COOLParser.RULE_feature - - - def copyFrom(self, ctx:ParserRuleContext): - super().copyFrom(ctx) - - - - class MethodContext(FeatureContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.FeatureContext - super().__init__(parser) - self.copyFrom(ctx) - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - def TYPEID(self): - return self.getToken(COOLParser.TYPEID, 0) - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - def formal(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.FormalContext) - else: - return self.getTypedRuleContext(COOLParser.FormalContext,i) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterMethod" ): - listener.enterMethod(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitMethod" ): - listener.exitMethod(self) - - - class PropertyContext(FeatureContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.FeatureContext - super().__init__(parser) - self.copyFrom(ctx) - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - def TYPEID(self): - return self.getToken(COOLParser.TYPEID, 0) - def ASSIGNMENT(self): - return self.getToken(COOLParser.ASSIGNMENT, 0) - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterProperty" ): - listener.enterProperty(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitProperty" ): - listener.exitProperty(self) - - - - def feature(self): - - localctx = COOLParser.FeatureContext(self, self._ctx, self.state) - self.enterRule(localctx, 6, self.RULE_feature) - self._la = 0 # Token type - try: - self.state = 67 - self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,6,self._ctx) - if la_ == 1: - localctx = COOLParser.MethodContext(self, localctx) - self.enterOuterAlt(localctx, 1) - self.state = 38 - self.match(COOLParser.OBJECTID) - self.state = 39 - self.match(COOLParser.T__3) - self.state = 50 - self._errHandler.sync(self) - _la = self._input.LA(1) - while _la==COOLParser.OBJECTID: - self.state = 40 - self.formal() - self.state = 45 - self._errHandler.sync(self) - _la = self._input.LA(1) - while _la==COOLParser.T__4: - self.state = 41 - self.match(COOLParser.T__4) - self.state = 42 - self.formal() - self.state = 47 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 52 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 53 - self.match(COOLParser.T__5) - self.state = 54 - self.match(COOLParser.T__6) - self.state = 55 - self.match(COOLParser.TYPEID) - self.state = 56 - self.match(COOLParser.T__1) - self.state = 57 - self.expression(0) - self.state = 58 - self.match(COOLParser.T__2) - pass - - elif la_ == 2: - localctx = COOLParser.PropertyContext(self, localctx) - self.enterOuterAlt(localctx, 2) - self.state = 60 - self.match(COOLParser.OBJECTID) - self.state = 61 - self.match(COOLParser.T__6) - self.state = 62 - self.match(COOLParser.TYPEID) - self.state = 65 - self._errHandler.sync(self) - _la = self._input.LA(1) - if _la==COOLParser.ASSIGNMENT: - self.state = 63 - self.match(COOLParser.ASSIGNMENT) - self.state = 64 - self.expression(0) - - - pass - - - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.exitRule() - return localctx - - - class FormalContext(ParserRuleContext): - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - - def TYPEID(self): - return self.getToken(COOLParser.TYPEID, 0) - - def getRuleIndex(self): - return COOLParser.RULE_formal - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterFormal" ): - listener.enterFormal(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitFormal" ): - listener.exitFormal(self) - - - - - def formal(self): - - localctx = COOLParser.FormalContext(self, self._ctx, self.state) - self.enterRule(localctx, 8, self.RULE_formal) - try: - self.enterOuterAlt(localctx, 1) - self.state = 69 - self.match(COOLParser.OBJECTID) - self.state = 70 - self.match(COOLParser.T__6) - self.state = 71 - self.match(COOLParser.TYPEID) - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.exitRule() - return localctx - - - class ExpressionContext(ParserRuleContext): - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - - def getRuleIndex(self): - return COOLParser.RULE_expression - - - def copyFrom(self, ctx:ParserRuleContext): - super().copyFrom(ctx) - - - class LetInContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def LET(self): - return self.getToken(COOLParser.LET, 0) - def OBJECTID(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.OBJECTID) - else: - return self.getToken(COOLParser.OBJECTID, i) - def TYPEID(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.TYPEID) - else: - return self.getToken(COOLParser.TYPEID, i) - def IN(self): - return self.getToken(COOLParser.IN, 0) - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def ASSIGNMENT(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.ASSIGNMENT) - else: - return self.getToken(COOLParser.ASSIGNMENT, i) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterLetIn" ): - listener.enterLetIn(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitLetIn" ): - listener.exitLetIn(self) - - - class MinusContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def MINUS(self): - return self.getToken(COOLParser.MINUS, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterMinus" ): - listener.enterMinus(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitMinus" ): - listener.exitMinus(self) - - - class StringContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def STRING(self): - return self.getToken(COOLParser.STRING, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterString" ): - listener.enterString(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitString" ): - listener.exitString(self) - - - class IsvoidContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def ISVOID(self): - return self.getToken(COOLParser.ISVOID, 0) - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterIsvoid" ): - listener.enterIsvoid(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitIsvoid" ): - listener.exitIsvoid(self) - - - class WhileContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def WHILE(self): - return self.getToken(COOLParser.WHILE, 0) - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def LOOP(self): - return self.getToken(COOLParser.LOOP, 0) - def POOL(self): - return self.getToken(COOLParser.POOL, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterWhile" ): - listener.enterWhile(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitWhile" ): - listener.exitWhile(self) - - - class DivisionContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def DIVISION(self): - return self.getToken(COOLParser.DIVISION, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterDivision" ): - listener.enterDivision(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitDivision" ): - listener.exitDivision(self) - - - class NegativeContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def INTEGER_NEGATIVE(self): - return self.getToken(COOLParser.INTEGER_NEGATIVE, 0) - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterNegative" ): - listener.enterNegative(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitNegative" ): - listener.exitNegative(self) - - - class BoolNotContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def NOT(self): - return self.getToken(COOLParser.NOT, 0) - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterBoolNot" ): - listener.enterBoolNot(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitBoolNot" ): - listener.exitBoolNot(self) - - - class LessThanContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def LESS_THAN(self): - return self.getToken(COOLParser.LESS_THAN, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterLessThan" ): - listener.enterLessThan(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitLessThan" ): - listener.exitLessThan(self) - - - class BlockContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterBlock" ): - listener.enterBlock(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitBlock" ): - listener.exitBlock(self) - - - class IdContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterId" ): - listener.enterId(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitId" ): - listener.exitId(self) - - - class MultiplyContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def MULTIPLY(self): - return self.getToken(COOLParser.MULTIPLY, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterMultiply" ): - listener.enterMultiply(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitMultiply" ): - listener.exitMultiply(self) - - - class IfContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def IF(self): - return self.getToken(COOLParser.IF, 0) - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def THEN(self): - return self.getToken(COOLParser.THEN, 0) - def ELSE(self): - return self.getToken(COOLParser.ELSE, 0) - def FI(self): - return self.getToken(COOLParser.FI, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterIf" ): - listener.enterIf(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitIf" ): - listener.exitIf(self) - - - class CaseContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def CASE(self): - return self.getToken(COOLParser.CASE, 0) - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def OF(self): - return self.getToken(COOLParser.OF, 0) - def ESAC(self): - return self.getToken(COOLParser.ESAC, 0) - def OBJECTID(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.OBJECTID) - else: - return self.getToken(COOLParser.OBJECTID, i) - def TYPEID(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.TYPEID) - else: - return self.getToken(COOLParser.TYPEID, i) - def CASE_ARROW(self, i:int=None): - if i is None: - return self.getTokens(COOLParser.CASE_ARROW) - else: - return self.getToken(COOLParser.CASE_ARROW, i) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterCase" ): - listener.enterCase(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitCase" ): - listener.exitCase(self) - - - class OwnMethodCallContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterOwnMethodCall" ): - listener.enterOwnMethodCall(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitOwnMethodCall" ): - listener.exitOwnMethodCall(self) - - - class AddContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def ADD(self): - return self.getToken(COOLParser.ADD, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterAdd" ): - listener.enterAdd(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitAdd" ): - listener.exitAdd(self) - - - class NewContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def NEW(self): - return self.getToken(COOLParser.NEW, 0) - def TYPEID(self): - return self.getToken(COOLParser.TYPEID, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterNew" ): - listener.enterNew(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitNew" ): - listener.exitNew(self) - - - class ParenthesesContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterParentheses" ): - listener.enterParentheses(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitParentheses" ): - listener.exitParentheses(self) - - - class AssignmentContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - def ASSIGNMENT(self): - return self.getToken(COOLParser.ASSIGNMENT, 0) - def expression(self): - return self.getTypedRuleContext(COOLParser.ExpressionContext,0) - - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterAssignment" ): - listener.enterAssignment(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitAssignment" ): - listener.exitAssignment(self) - - - class FalseContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def FALSE(self): - return self.getToken(COOLParser.FALSE, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterFalse" ): - listener.enterFalse(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitFalse" ): - listener.exitFalse(self) - - - class IntContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def INT(self): - return self.getToken(COOLParser.INT, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterInt" ): - listener.enterInt(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitInt" ): - listener.exitInt(self) - - - class EqualContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def EQUAL(self): - return self.getToken(COOLParser.EQUAL, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterEqual" ): - listener.enterEqual(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitEqual" ): - listener.exitEqual(self) - - - class TrueContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def TRUE(self): - return self.getToken(COOLParser.TRUE, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterTrue" ): - listener.enterTrue(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitTrue" ): - listener.exitTrue(self) - - - class LessEqualContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def LESS_EQUAL(self): - return self.getToken(COOLParser.LESS_EQUAL, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterLessEqual" ): - listener.enterLessEqual(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitLessEqual" ): - listener.exitLessEqual(self) - - - class MethodCallContext(ExpressionContext): - - def __init__(self, parser, ctx:ParserRuleContext): # actually a COOLParser.ExpressionContext - super().__init__(parser) - self.copyFrom(ctx) - - def expression(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(COOLParser.ExpressionContext) - else: - return self.getTypedRuleContext(COOLParser.ExpressionContext,i) - - def OBJECTID(self): - return self.getToken(COOLParser.OBJECTID, 0) - def TYPEID(self): - return self.getToken(COOLParser.TYPEID, 0) - - def enterRule(self, listener:ParseTreeListener): - if hasattr( listener, "enterMethodCall" ): - listener.enterMethodCall(self) - - def exitRule(self, listener:ParseTreeListener): - if hasattr( listener, "exitMethodCall" ): - listener.exitMethodCall(self) - - - - def expression(self, _p:int=0): - _parentctx = self._ctx - _parentState = self.state - localctx = COOLParser.ExpressionContext(self, self._ctx, _parentState) - _prevctx = localctx - _startState = 10 - self.enterRecursionRule(localctx, 10, self.RULE_expression, _p) - self._la = 0 # Token type - try: - self.enterOuterAlt(localctx, 1) - self.state = 173 - self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,14,self._ctx) - if la_ == 1: - localctx = COOLParser.OwnMethodCallContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - - self.state = 74 - self.match(COOLParser.OBJECTID) - self.state = 75 - self.match(COOLParser.T__3) - self.state = 86 - self._errHandler.sync(self) - _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOLParser.T__1) | (1 << COOLParser.T__3) | (1 << COOLParser.FALSE) | (1 << COOLParser.IF) | (1 << COOLParser.ISVOID) | (1 << COOLParser.LET) | (1 << COOLParser.WHILE) | (1 << COOLParser.CASE) | (1 << COOLParser.NEW) | (1 << COOLParser.NOT) | (1 << COOLParser.TRUE) | (1 << COOLParser.STRING) | (1 << COOLParser.INT) | (1 << COOLParser.OBJECTID) | (1 << COOLParser.INTEGER_NEGATIVE))) != 0): - self.state = 76 - self.expression(0) - self.state = 81 - self._errHandler.sync(self) - _la = self._input.LA(1) - while _la==COOLParser.T__4: - self.state = 77 - self.match(COOLParser.T__4) - self.state = 78 - self.expression(0) - self.state = 83 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 88 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 89 - self.match(COOLParser.T__5) - pass - - elif la_ == 2: - localctx = COOLParser.IfContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 90 - self.match(COOLParser.IF) - self.state = 91 - self.expression(0) - self.state = 92 - self.match(COOLParser.THEN) - self.state = 93 - self.expression(0) - self.state = 94 - self.match(COOLParser.ELSE) - self.state = 95 - self.expression(0) - self.state = 96 - self.match(COOLParser.FI) - pass - - elif la_ == 3: - localctx = COOLParser.WhileContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 98 - self.match(COOLParser.WHILE) - self.state = 99 - self.expression(0) - self.state = 100 - self.match(COOLParser.LOOP) - self.state = 101 - self.expression(0) - self.state = 102 - self.match(COOLParser.POOL) - pass - - elif la_ == 4: - localctx = COOLParser.BlockContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 104 - self.match(COOLParser.T__1) - self.state = 108 - self._errHandler.sync(self) - _la = self._input.LA(1) - while True: - self.state = 105 - self.expression(0) - self.state = 106 - self.match(COOLParser.T__0) - self.state = 110 - self._errHandler.sync(self) - _la = self._input.LA(1) - if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOLParser.T__1) | (1 << COOLParser.T__3) | (1 << COOLParser.FALSE) | (1 << COOLParser.IF) | (1 << COOLParser.ISVOID) | (1 << COOLParser.LET) | (1 << COOLParser.WHILE) | (1 << COOLParser.CASE) | (1 << COOLParser.NEW) | (1 << COOLParser.NOT) | (1 << COOLParser.TRUE) | (1 << COOLParser.STRING) | (1 << COOLParser.INT) | (1 << COOLParser.OBJECTID) | (1 << COOLParser.INTEGER_NEGATIVE))) != 0)): - break - - self.state = 112 - self.match(COOLParser.T__2) - pass - - elif la_ == 5: - localctx = COOLParser.LetInContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 114 - self.match(COOLParser.LET) - self.state = 115 - self.match(COOLParser.OBJECTID) - self.state = 116 - self.match(COOLParser.T__6) - self.state = 117 - self.match(COOLParser.TYPEID) - self.state = 120 - self._errHandler.sync(self) - _la = self._input.LA(1) - if _la==COOLParser.ASSIGNMENT: - self.state = 118 - self.match(COOLParser.ASSIGNMENT) - self.state = 119 - self.expression(0) - - - self.state = 132 - self._errHandler.sync(self) - _la = self._input.LA(1) - while _la==COOLParser.T__4: - self.state = 122 - self.match(COOLParser.T__4) - self.state = 123 - self.match(COOLParser.OBJECTID) - self.state = 124 - self.match(COOLParser.T__6) - self.state = 125 - self.match(COOLParser.TYPEID) - self.state = 128 - self._errHandler.sync(self) - _la = self._input.LA(1) - if _la==COOLParser.ASSIGNMENT: - self.state = 126 - self.match(COOLParser.ASSIGNMENT) - self.state = 127 - self.expression(0) - - - self.state = 134 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 135 - self.match(COOLParser.IN) - self.state = 136 - self.expression(20) - pass - - elif la_ == 6: - localctx = COOLParser.CaseContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 137 - self.match(COOLParser.CASE) - self.state = 138 - self.expression(0) - self.state = 139 - self.match(COOLParser.OF) - self.state = 147 - self._errHandler.sync(self) - _la = self._input.LA(1) - while True: - self.state = 140 - self.match(COOLParser.OBJECTID) - self.state = 141 - self.match(COOLParser.T__6) - self.state = 142 - self.match(COOLParser.TYPEID) - self.state = 143 - self.match(COOLParser.CASE_ARROW) - self.state = 144 - self.expression(0) - self.state = 145 - self.match(COOLParser.T__0) - self.state = 149 - self._errHandler.sync(self) - _la = self._input.LA(1) - if not (_la==COOLParser.OBJECTID): - break - - self.state = 151 - self.match(COOLParser.ESAC) - pass - - elif la_ == 7: - localctx = COOLParser.NewContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 153 - self.match(COOLParser.NEW) - self.state = 154 - self.match(COOLParser.TYPEID) - pass - - elif la_ == 8: - localctx = COOLParser.NegativeContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 155 - self.match(COOLParser.INTEGER_NEGATIVE) - self.state = 156 - self.expression(17) - pass - - elif la_ == 9: - localctx = COOLParser.IsvoidContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 157 - self.match(COOLParser.ISVOID) - self.state = 158 - self.expression(16) - pass - - elif la_ == 10: - localctx = COOLParser.BoolNotContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 159 - self.match(COOLParser.NOT) - self.state = 160 - self.expression(8) - pass - - elif la_ == 11: - localctx = COOLParser.ParenthesesContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 161 - self.match(COOLParser.T__3) - self.state = 162 - self.expression(0) - self.state = 163 - self.match(COOLParser.T__5) - pass - - elif la_ == 12: - localctx = COOLParser.IdContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 165 - self.match(COOLParser.OBJECTID) - pass - - elif la_ == 13: - localctx = COOLParser.IntContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 166 - self.match(COOLParser.INT) - pass - - elif la_ == 14: - localctx = COOLParser.StringContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 167 - self.match(COOLParser.STRING) - pass - - elif la_ == 15: - localctx = COOLParser.TrueContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 168 - self.match(COOLParser.TRUE) - pass - - elif la_ == 16: - localctx = COOLParser.FalseContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 169 - self.match(COOLParser.FALSE) - pass - - elif la_ == 17: - localctx = COOLParser.AssignmentContext(self, localctx) - self._ctx = localctx - _prevctx = localctx - self.state = 170 - self.match(COOLParser.OBJECTID) - self.state = 171 - self.match(COOLParser.ASSIGNMENT) - self.state = 172 - self.expression(1) - pass - - - self._ctx.stop = self._input.LT(-1) - self.state = 220 - self._errHandler.sync(self) - _alt = self._interp.adaptivePredict(self._input,19,self._ctx) - while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: - if _alt==1: - if self._parseListeners is not None: - self.triggerExitRuleEvent() - _prevctx = localctx - self.state = 218 - self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,18,self._ctx) - if la_ == 1: - localctx = COOLParser.MultiplyContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 175 - if not self.precpred(self._ctx, 15): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 15)") - self.state = 176 - self.match(COOLParser.MULTIPLY) - self.state = 177 - self.expression(16) - pass - - elif la_ == 2: - localctx = COOLParser.DivisionContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 178 - if not self.precpred(self._ctx, 14): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 14)") - self.state = 179 - self.match(COOLParser.DIVISION) - self.state = 180 - self.expression(15) - pass - - elif la_ == 3: - localctx = COOLParser.AddContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 181 - if not self.precpred(self._ctx, 13): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 13)") - self.state = 182 - self.match(COOLParser.ADD) - self.state = 183 - self.expression(14) - pass - - elif la_ == 4: - localctx = COOLParser.MinusContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 184 - if not self.precpred(self._ctx, 12): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 12)") - self.state = 185 - self.match(COOLParser.MINUS) - self.state = 186 - self.expression(13) - pass - - elif la_ == 5: - localctx = COOLParser.LessThanContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 187 - if not self.precpred(self._ctx, 11): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 11)") - self.state = 188 - self.match(COOLParser.LESS_THAN) - self.state = 189 - self.expression(12) - pass - - elif la_ == 6: - localctx = COOLParser.LessEqualContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 190 - if not self.precpred(self._ctx, 10): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 10)") - self.state = 191 - self.match(COOLParser.LESS_EQUAL) - self.state = 192 - self.expression(11) - pass - - elif la_ == 7: - localctx = COOLParser.EqualContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 193 - if not self.precpred(self._ctx, 9): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 9)") - self.state = 194 - self.match(COOLParser.EQUAL) - self.state = 195 - self.expression(10) - pass - - elif la_ == 8: - localctx = COOLParser.MethodCallContext(self, COOLParser.ExpressionContext(self, _parentctx, _parentState)) - self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 196 - if not self.precpred(self._ctx, 25): - from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 25)") - self.state = 199 - self._errHandler.sync(self) - _la = self._input.LA(1) - if _la==COOLParser.T__7: - self.state = 197 - self.match(COOLParser.T__7) - self.state = 198 - self.match(COOLParser.TYPEID) - - - self.state = 201 - self.match(COOLParser.T__8) - self.state = 202 - self.match(COOLParser.OBJECTID) - self.state = 203 - self.match(COOLParser.T__3) - self.state = 214 - self._errHandler.sync(self) - _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOLParser.T__1) | (1 << COOLParser.T__3) | (1 << COOLParser.FALSE) | (1 << COOLParser.IF) | (1 << COOLParser.ISVOID) | (1 << COOLParser.LET) | (1 << COOLParser.WHILE) | (1 << COOLParser.CASE) | (1 << COOLParser.NEW) | (1 << COOLParser.NOT) | (1 << COOLParser.TRUE) | (1 << COOLParser.STRING) | (1 << COOLParser.INT) | (1 << COOLParser.OBJECTID) | (1 << COOLParser.INTEGER_NEGATIVE))) != 0): - self.state = 204 - self.expression(0) - self.state = 209 - self._errHandler.sync(self) - _la = self._input.LA(1) - while _la==COOLParser.T__4: - self.state = 205 - self.match(COOLParser.T__4) - self.state = 206 - self.expression(0) - self.state = 211 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 216 - self._errHandler.sync(self) - _la = self._input.LA(1) - - self.state = 217 - self.match(COOLParser.T__5) - pass - - - self.state = 222 - self._errHandler.sync(self) - _alt = self._interp.adaptivePredict(self._input,19,self._ctx) - - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.unrollRecursionContexts(_parentctx) - return localctx - - - - def sempred(self, localctx:RuleContext, ruleIndex:int, predIndex:int): - if self._predicates == None: - self._predicates = dict() - self._predicates[5] = self.expression_sempred - pred = self._predicates.get(ruleIndex, None) - if pred is None: - raise Exception("No predicate with index:" + str(ruleIndex)) - else: - return pred(localctx, predIndex) - - def expression_sempred(self, localctx:ExpressionContext, predIndex:int): - if predIndex == 0: - return self.precpred(self._ctx, 15) - - - if predIndex == 1: - return self.precpred(self._ctx, 14) - - - if predIndex == 2: - return self.precpred(self._ctx, 13) - - - if predIndex == 3: - return self.precpred(self._ctx, 12) - - - if predIndex == 4: - return self.precpred(self._ctx, 11) - - - if predIndex == 5: - return self.precpred(self._ctx, 10) - - - if predIndex == 6: - return self.precpred(self._ctx, 9) - - - if predIndex == 7: - return self.precpred(self._ctx, 25) - - - - + def notifyErrorListeners(self, msg:str, offendingToken:Token = None, e:RecognitionException = None): + if offendingToken is None: + offendingToken = self.getCurrentToken() + self._syntaxErrors += 1 + line = offendingToken.line + column = offendingToken.column + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, offendingToken, line, column, msg, e) \ No newline at end of file diff --git a/COOLParserErrorListener.py b/src/COOLParserErrorListener.py similarity index 100% rename from COOLParserErrorListener.py rename to src/COOLParserErrorListener.py diff --git a/COOL_LEX.interp b/src/COOL_LEX.interp similarity index 100% rename from COOL_LEX.interp rename to src/COOL_LEX.interp diff --git a/COOL_LEX.py b/src/COOL_LEX.py similarity index 100% rename from COOL_LEX.py rename to src/COOL_LEX.py diff --git a/COOL_LEX.tokens b/src/COOL_LEX.tokens similarity index 100% rename from COOL_LEX.tokens rename to src/COOL_LEX.tokens From e21189362bb10224531a4e8300a41b0702b0f11f Mon Sep 17 00:00:00 2001 From: pablodearmas <57228410+pablodearmas@users.noreply.github.com> Date: Sun, 1 Mar 2020 00:17:01 -0500 Subject: [PATCH 30/77] =?UTF-8?q?Se=20actualiz=C3=B3=20nombre=20y=20versi?= =?UTF-8?q?=C3=B3n=20del=20compilador?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coolc.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coolc.sh b/src/coolc.sh index 32158b64..7f167c0e 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,8 +4,8 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas -echo "Copyright (c) 2019: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" # TODO: líneas a los valores correctos +echo "COOLCompiler 1.0.1" +echo "Copyright (c) 2019: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" # Llamar al compilador #echo "Compiling $INPUT_FILE into $OUTPUT_FILE" From 328a1f9463d68a23b4a100ddbbf57244687419a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 1 Mar 2020 03:09:50 -0500 Subject: [PATCH 31/77] =?UTF-8?q?Se=20arreglaron=20varios=20errores=20Se?= =?UTF-8?q?=20modificaron=20el=20lexer=20y=20el=20parser=20para=20que=20se?= =?UTF-8?q?an=20compatibles=20con=20lo=20que=20esperan=20los=20test=20auto?= =?UTF-8?q?m=C3=A1ticos=20Se=20mejor=C3=B3=20el=20c=C3=B3digo=20para=20sop?= =?UTF-8?q?ortar=20PyTest=20en=20Windows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/COOLCompiler.py | 9 ++++++--- src/COOLLexerErrorListener.py | 2 +- src/COOLParser.py | 5 ++++- src/COOLParserErrorListener.py | 2 +- src/coolc.sh | 2 +- tests/lexer/comment1.cl | 4 ++-- tests/lexer_test.py | 4 ++-- tests/parser_test.py | 4 ++-- 8 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 5a9b2584..6e21c735 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -1,5 +1,6 @@ import sys import os.path +import errno from antlr4 import * from COOLLexer import COOLLexer from COOLLexerErrorListener import COOLLexerErrorListener @@ -9,8 +10,8 @@ def main(argv): if not os.path.isfile(argv[1]): - print("invalid input filename") - return + print("invalid input filename: " + argv[1]) + return sys.exit(errno.EPERM) input = FileStream(argv[1]) @@ -22,7 +23,7 @@ def main(argv): token = lexer.nextToken() if lexer.hasErrors: - return + return sys.exit(errno.EPERM) lexer.reset(); stream = CommonTokenStream(lexer) @@ -31,6 +32,8 @@ def main(argv): parser.addErrorListener(COOLParserErrorListener()) tree = parser.program() + if parser.getNumberOfSyntaxErrors() > 0: + return sys.exit(errno.EPERM) if __name__ == '__main__': main(sys.argv) diff --git a/src/COOLLexerErrorListener.py b/src/COOLLexerErrorListener.py index 451cdba7..2eec5575 100644 --- a/src/COOLLexerErrorListener.py +++ b/src/COOLLexerErrorListener.py @@ -4,4 +4,4 @@ class COOLLexerErrorListener(ErrorListener): def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): - print("(" + str(line) + ", " + str(column+1) + ") - LexicographicError: " + msg, file=sys.stderr) \ No newline at end of file + print("(" + str(line) + ", " + str(column+1) + ") - LexicographicError: " + msg, file=sys.stdout) \ No newline at end of file diff --git a/src/COOLParser.py b/src/COOLParser.py index 7f3ad8ac..6decdd97 100644 --- a/src/COOLParser.py +++ b/src/COOLParser.py @@ -13,12 +13,15 @@ class COOLParser(COOL): def __init__(self, input=None, output:TextIO = sys.stdout): super().__init__(input, output) + self._hasErrors = False def notifyErrorListeners(self, msg:str, offendingToken:Token = None, e:RecognitionException = None): + self._hasErrors = True + if offendingToken is None: offendingToken = self.getCurrentToken() self._syntaxErrors += 1 line = offendingToken.line column = offendingToken.column listener = self.getErrorListenerDispatch() - listener.syntaxError(self, offendingToken, line, column, msg, e) \ No newline at end of file + listener.syntaxError(self, offendingToken, line, column, msg, e) diff --git a/src/COOLParserErrorListener.py b/src/COOLParserErrorListener.py index 5bae5069..0c4b79e9 100644 --- a/src/COOLParserErrorListener.py +++ b/src/COOLParserErrorListener.py @@ -9,4 +9,4 @@ def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): msg = "EOF" else: msg = "\"" + msg + "\"" - print("(" + str(line) + ", " + str(column+1) + ") - SyntacticError: ERROR at or near " +msg, file=sys.stderr) \ No newline at end of file + print("(" + str(line) + ", " + str(column+1) + ") - SyntacticError: ERROR at or near " +msg, file=sys.stdout) \ No newline at end of file diff --git a/src/coolc.sh b/src/coolc.sh index 7f167c0e..2b13ab2e 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -9,4 +9,4 @@ echo "Copyright (c) 2019: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli # Llamar al compilador #echo "Compiling $INPUT_FILE into $OUTPUT_FILE" -python COOLCompiler.py INPUT_FILE OUTPUT_FILE +python COOLCompiler.py $INPUT_FILE $OUTPUT_FILE diff --git a/tests/lexer/comment1.cl b/tests/lexer/comment1.cl index 69533f23..086922ea 100644 --- a/tests/lexer/comment1.cl +++ b/tests/lexer/comment1.cl @@ -1,9 +1,9 @@ ---Any characters between two dashes “--” and the next newline +--Any characters between two dashes "--" and the next newline --(or EOF, if there is no next newline) are treated as comments (*(*(* Comments may also be written by enclosing -text in (∗ . . . ∗). The latter form of comment may be nested. +text in (* . . . *). The latter form of comment may be nested. Comments cannot cross file boundaries. *)*)*) diff --git a/tests/lexer_test.py b/tests/lexer_test.py index 2a27223d..9ade030a 100644 --- a/tests/lexer_test.py +++ b/tests/lexer_test.py @@ -2,7 +2,7 @@ import os from utils import compare_errors -tests_dir = __file__.rpartition('/')[0] + '/lexer/' +tests_dir = os.path.join(__file__.rpartition(os.path.sep)[0], 'lexer') tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] @pytest.mark.lexer @@ -10,4 +10,4 @@ @pytest.mark.run(order=1) @pytest.mark.parametrize("cool_file", tests) def test_lexer_errors(compiler_path, cool_file): - compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file + compare_errors(compiler_path, os.path.join(tests_dir, cool_file), os.path.join(tests_dir, cool_file[:-3] + '_error.txt')) \ No newline at end of file diff --git a/tests/parser_test.py b/tests/parser_test.py index 129c0f20..0f5efa63 100644 --- a/tests/parser_test.py +++ b/tests/parser_test.py @@ -2,7 +2,7 @@ import os from utils import compare_errors -tests_dir = __file__.rpartition('/')[0] + '/parser/' +tests_dir = os.path.join(__file__.rpartition(os.path.sep)[0], 'parser') tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] @pytest.mark.parser @@ -10,4 +10,4 @@ @pytest.mark.run(order=2) @pytest.mark.parametrize("cool_file", tests) def test_parser_errors(compiler_path, cool_file): - compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file + compare_errors(compiler_path, os.path.join(tests_dir, cool_file), os.path.join(tests_dir, cool_file[:-3] + '_error.txt')) From 5a5e2e62e764b574e6cc893bdd5e0b128d603273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 2 Mar 2020 00:37:14 -0500 Subject: [PATCH 32/77] Se arreglaron errores en el lexer y el parser para los casos de prueba --- src/COOL.interp | 12 +- src/COOL.py | 488 ++++++++++++++++---------------- src/COOL.tokens | 102 +++---- src/COOLCompiler.py | 2 +- src/COOLLexer.py | 39 ++- src/COOL_LEX.interp | 20 +- src/COOL_LEX.py | 465 ++++++++++++++++-------------- src/COOL_LEX.tokens | 102 +++---- src/coolc.sh | 4 +- tests/parser/program1_error.txt | 2 +- 10 files changed, 665 insertions(+), 571 deletions(-) diff --git a/src/COOL.interp b/src/COOL.interp index bba307e6..740232fd 100644 --- a/src/COOL.interp +++ b/src/COOL.interp @@ -24,6 +24,7 @@ null null null null +null '<-' '=>' '+' @@ -48,6 +49,9 @@ null '(*' null '*)' +null +null +null token symbolic names: null @@ -71,7 +75,8 @@ OF NOT TRUE STRING -BREAK_STRING +STRING_SIMPLE +STRING_FIRSTLINE INT TYPEID OBJECTID @@ -99,6 +104,9 @@ ONE_LINE_COMMENT OPEN_COMMENT COMMENT CLOSE_COMMENT +STRING_INNERLINE +STRING_LASTLINE +STRING_MULTILINE rule names: program @@ -110,4 +118,4 @@ expression atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 50, 225, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 7, 7, 86, 10, 7, 12, 7, 14, 7, 89, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 110, 10, 7, 13, 7, 14, 7, 111, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 122, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 130, 10, 7, 7, 7, 132, 10, 7, 12, 7, 14, 7, 135, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 149, 10, 7, 13, 7, 14, 7, 150, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 175, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 201, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 209, 10, 7, 12, 7, 14, 7, 212, 11, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 7, 7, 220, 10, 7, 12, 7, 14, 7, 223, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 259, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 174, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 45, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 25, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 25, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 39, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 45, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 40, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 26, 2, 2, 40, 51, 7, 37, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 43, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 38, 2, 2, 55, 56, 7, 44, 2, 2, 56, 57, 7, 25, 2, 2, 57, 58, 7, 39, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 40, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 26, 2, 2, 62, 63, 7, 44, 2, 2, 63, 66, 7, 25, 2, 2, 64, 65, 7, 27, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 26, 2, 2, 71, 72, 7, 44, 2, 2, 72, 73, 7, 25, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 26, 2, 2, 76, 87, 7, 37, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 43, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 90, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 175, 7, 38, 2, 2, 91, 92, 7, 7, 2, 2, 92, 93, 5, 12, 7, 2, 93, 94, 7, 14, 2, 2, 94, 95, 5, 12, 7, 2, 95, 96, 7, 4, 2, 2, 96, 97, 5, 12, 7, 2, 97, 98, 7, 6, 2, 2, 98, 175, 3, 2, 2, 2, 99, 100, 7, 15, 2, 2, 100, 101, 5, 12, 7, 2, 101, 102, 7, 12, 2, 2, 102, 103, 5, 12, 7, 2, 103, 104, 7, 13, 2, 2, 104, 175, 3, 2, 2, 2, 105, 109, 7, 39, 2, 2, 106, 107, 5, 12, 7, 2, 107, 108, 7, 45, 2, 2, 108, 110, 3, 2, 2, 2, 109, 106, 3, 2, 2, 2, 110, 111, 3, 2, 2, 2, 111, 109, 3, 2, 2, 2, 111, 112, 3, 2, 2, 2, 112, 113, 3, 2, 2, 2, 113, 114, 7, 40, 2, 2, 114, 175, 3, 2, 2, 2, 115, 116, 7, 11, 2, 2, 116, 117, 7, 26, 2, 2, 117, 118, 7, 44, 2, 2, 118, 121, 7, 25, 2, 2, 119, 120, 7, 27, 2, 2, 120, 122, 5, 12, 7, 2, 121, 119, 3, 2, 2, 2, 121, 122, 3, 2, 2, 2, 122, 133, 3, 2, 2, 2, 123, 124, 7, 43, 2, 2, 124, 125, 7, 26, 2, 2, 125, 126, 7, 44, 2, 2, 126, 129, 7, 25, 2, 2, 127, 128, 7, 27, 2, 2, 128, 130, 5, 12, 7, 2, 129, 127, 3, 2, 2, 2, 129, 130, 3, 2, 2, 2, 130, 132, 3, 2, 2, 2, 131, 123, 3, 2, 2, 2, 132, 135, 3, 2, 2, 2, 133, 131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 136, 3, 2, 2, 2, 135, 133, 3, 2, 2, 2, 136, 137, 7, 8, 2, 2, 137, 175, 5, 12, 7, 22, 138, 139, 7, 16, 2, 2, 139, 140, 5, 12, 7, 2, 140, 148, 7, 19, 2, 2, 141, 142, 7, 26, 2, 2, 142, 143, 7, 44, 2, 2, 143, 144, 7, 25, 2, 2, 144, 145, 7, 28, 2, 2, 145, 146, 5, 12, 7, 2, 146, 147, 7, 45, 2, 2, 147, 149, 3, 2, 2, 2, 148, 141, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 150, 148, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 7, 17, 2, 2, 153, 175, 3, 2, 2, 2, 154, 155, 7, 18, 2, 2, 155, 175, 7, 25, 2, 2, 156, 157, 7, 36, 2, 2, 157, 175, 5, 12, 7, 19, 158, 159, 7, 10, 2, 2, 159, 175, 5, 12, 7, 18, 160, 161, 7, 20, 2, 2, 161, 175, 5, 12, 7, 10, 162, 163, 7, 37, 2, 2, 163, 164, 5, 12, 7, 2, 164, 165, 7, 38, 2, 2, 165, 175, 3, 2, 2, 2, 166, 175, 7, 26, 2, 2, 167, 175, 7, 24, 2, 2, 168, 175, 7, 22, 2, 2, 169, 175, 7, 21, 2, 2, 170, 175, 7, 5, 2, 2, 171, 172, 7, 26, 2, 2, 172, 173, 7, 27, 2, 2, 173, 175, 5, 12, 7, 3, 174, 74, 3, 2, 2, 2, 174, 91, 3, 2, 2, 2, 174, 99, 3, 2, 2, 2, 174, 105, 3, 2, 2, 2, 174, 115, 3, 2, 2, 2, 174, 138, 3, 2, 2, 2, 174, 154, 3, 2, 2, 2, 174, 156, 3, 2, 2, 2, 174, 158, 3, 2, 2, 2, 174, 160, 3, 2, 2, 2, 174, 162, 3, 2, 2, 2, 174, 166, 3, 2, 2, 2, 174, 167, 3, 2, 2, 2, 174, 168, 3, 2, 2, 2, 174, 169, 3, 2, 2, 2, 174, 170, 3, 2, 2, 2, 174, 171, 3, 2, 2, 2, 175, 221, 3, 2, 2, 2, 176, 177, 12, 17, 2, 2, 177, 178, 7, 31, 2, 2, 178, 220, 5, 12, 7, 18, 179, 180, 12, 16, 2, 2, 180, 181, 7, 32, 2, 2, 181, 220, 5, 12, 7, 17, 182, 183, 12, 15, 2, 2, 183, 184, 7, 29, 2, 2, 184, 220, 5, 12, 7, 16, 185, 186, 12, 14, 2, 2, 186, 187, 7, 30, 2, 2, 187, 220, 5, 12, 7, 15, 188, 189, 12, 13, 2, 2, 189, 190, 7, 33, 2, 2, 190, 220, 5, 12, 7, 14, 191, 192, 12, 12, 2, 2, 192, 193, 7, 34, 2, 2, 193, 220, 5, 12, 7, 13, 194, 195, 12, 11, 2, 2, 195, 196, 7, 35, 2, 2, 196, 220, 5, 12, 7, 12, 197, 200, 12, 27, 2, 2, 198, 199, 7, 41, 2, 2, 199, 201, 7, 25, 2, 2, 200, 198, 3, 2, 2, 2, 200, 201, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 7, 42, 2, 2, 203, 204, 7, 26, 2, 2, 204, 215, 7, 37, 2, 2, 205, 210, 5, 12, 7, 2, 206, 207, 7, 43, 2, 2, 207, 209, 5, 12, 7, 2, 208, 206, 3, 2, 2, 2, 209, 212, 3, 2, 2, 2, 210, 208, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 214, 3, 2, 2, 2, 212, 210, 3, 2, 2, 2, 213, 205, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 218, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 218, 220, 7, 38, 2, 2, 219, 176, 3, 2, 2, 2, 219, 179, 3, 2, 2, 2, 219, 182, 3, 2, 2, 2, 219, 185, 3, 2, 2, 2, 219, 188, 3, 2, 2, 2, 219, 191, 3, 2, 2, 2, 219, 194, 3, 2, 2, 2, 219, 197, 3, 2, 2, 2, 220, 223, 3, 2, 2, 2, 221, 219, 3, 2, 2, 2, 221, 222, 3, 2, 2, 2, 222, 13, 3, 2, 2, 2, 223, 221, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 87, 111, 121, 129, 133, 150, 174, 200, 210, 215, 219, 221] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 54, 219, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 5, 7, 86, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 107, 10, 7, 13, 7, 14, 7, 108, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 119, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 127, 10, 7, 7, 7, 129, 10, 7, 12, 7, 14, 7, 132, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 146, 10, 7, 13, 7, 14, 7, 147, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 172, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 198, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 206, 10, 7, 12, 7, 14, 7, 209, 11, 7, 5, 7, 211, 10, 7, 3, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 253, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 171, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 46, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 26, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 26, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 40, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 46, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 41, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 27, 2, 2, 40, 51, 7, 38, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 44, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 39, 2, 2, 55, 56, 7, 45, 2, 2, 56, 57, 7, 26, 2, 2, 57, 58, 7, 40, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 41, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 27, 2, 2, 62, 63, 7, 45, 2, 2, 63, 66, 7, 26, 2, 2, 64, 65, 7, 28, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 27, 2, 2, 71, 72, 7, 45, 2, 2, 72, 73, 7, 26, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 27, 2, 2, 76, 85, 7, 38, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 44, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 85, 86, 3, 2, 2, 2, 86, 87, 3, 2, 2, 2, 87, 172, 7, 39, 2, 2, 88, 89, 7, 7, 2, 2, 89, 90, 5, 12, 7, 2, 90, 91, 7, 14, 2, 2, 91, 92, 5, 12, 7, 2, 92, 93, 7, 4, 2, 2, 93, 94, 5, 12, 7, 2, 94, 95, 7, 6, 2, 2, 95, 172, 3, 2, 2, 2, 96, 97, 7, 15, 2, 2, 97, 98, 5, 12, 7, 2, 98, 99, 7, 12, 2, 2, 99, 100, 5, 12, 7, 2, 100, 101, 7, 13, 2, 2, 101, 172, 3, 2, 2, 2, 102, 106, 7, 40, 2, 2, 103, 104, 5, 12, 7, 2, 104, 105, 7, 46, 2, 2, 105, 107, 3, 2, 2, 2, 106, 103, 3, 2, 2, 2, 107, 108, 3, 2, 2, 2, 108, 106, 3, 2, 2, 2, 108, 109, 3, 2, 2, 2, 109, 110, 3, 2, 2, 2, 110, 111, 7, 41, 2, 2, 111, 172, 3, 2, 2, 2, 112, 113, 7, 11, 2, 2, 113, 114, 7, 27, 2, 2, 114, 115, 7, 45, 2, 2, 115, 118, 7, 26, 2, 2, 116, 117, 7, 28, 2, 2, 117, 119, 5, 12, 7, 2, 118, 116, 3, 2, 2, 2, 118, 119, 3, 2, 2, 2, 119, 130, 3, 2, 2, 2, 120, 121, 7, 44, 2, 2, 121, 122, 7, 27, 2, 2, 122, 123, 7, 45, 2, 2, 123, 126, 7, 26, 2, 2, 124, 125, 7, 28, 2, 2, 125, 127, 5, 12, 7, 2, 126, 124, 3, 2, 2, 2, 126, 127, 3, 2, 2, 2, 127, 129, 3, 2, 2, 2, 128, 120, 3, 2, 2, 2, 129, 132, 3, 2, 2, 2, 130, 128, 3, 2, 2, 2, 130, 131, 3, 2, 2, 2, 131, 133, 3, 2, 2, 2, 132, 130, 3, 2, 2, 2, 133, 134, 7, 8, 2, 2, 134, 172, 5, 12, 7, 22, 135, 136, 7, 16, 2, 2, 136, 137, 5, 12, 7, 2, 137, 145, 7, 19, 2, 2, 138, 139, 7, 27, 2, 2, 139, 140, 7, 45, 2, 2, 140, 141, 7, 26, 2, 2, 141, 142, 7, 29, 2, 2, 142, 143, 5, 12, 7, 2, 143, 144, 7, 46, 2, 2, 144, 146, 3, 2, 2, 2, 145, 138, 3, 2, 2, 2, 146, 147, 3, 2, 2, 2, 147, 145, 3, 2, 2, 2, 147, 148, 3, 2, 2, 2, 148, 149, 3, 2, 2, 2, 149, 150, 7, 17, 2, 2, 150, 172, 3, 2, 2, 2, 151, 152, 7, 18, 2, 2, 152, 172, 7, 26, 2, 2, 153, 154, 7, 37, 2, 2, 154, 172, 5, 12, 7, 19, 155, 156, 7, 10, 2, 2, 156, 172, 5, 12, 7, 18, 157, 158, 7, 20, 2, 2, 158, 172, 5, 12, 7, 10, 159, 160, 7, 38, 2, 2, 160, 161, 5, 12, 7, 2, 161, 162, 7, 39, 2, 2, 162, 172, 3, 2, 2, 2, 163, 172, 7, 27, 2, 2, 164, 172, 7, 25, 2, 2, 165, 172, 7, 22, 2, 2, 166, 172, 7, 21, 2, 2, 167, 172, 7, 5, 2, 2, 168, 169, 7, 27, 2, 2, 169, 170, 7, 28, 2, 2, 170, 172, 5, 12, 7, 3, 171, 74, 3, 2, 2, 2, 171, 88, 3, 2, 2, 2, 171, 96, 3, 2, 2, 2, 171, 102, 3, 2, 2, 2, 171, 112, 3, 2, 2, 2, 171, 135, 3, 2, 2, 2, 171, 151, 3, 2, 2, 2, 171, 153, 3, 2, 2, 2, 171, 155, 3, 2, 2, 2, 171, 157, 3, 2, 2, 2, 171, 159, 3, 2, 2, 2, 171, 163, 3, 2, 2, 2, 171, 164, 3, 2, 2, 2, 171, 165, 3, 2, 2, 2, 171, 166, 3, 2, 2, 2, 171, 167, 3, 2, 2, 2, 171, 168, 3, 2, 2, 2, 172, 215, 3, 2, 2, 2, 173, 174, 12, 17, 2, 2, 174, 175, 7, 32, 2, 2, 175, 214, 5, 12, 7, 18, 176, 177, 12, 16, 2, 2, 177, 178, 7, 33, 2, 2, 178, 214, 5, 12, 7, 17, 179, 180, 12, 15, 2, 2, 180, 181, 7, 30, 2, 2, 181, 214, 5, 12, 7, 16, 182, 183, 12, 14, 2, 2, 183, 184, 7, 31, 2, 2, 184, 214, 5, 12, 7, 15, 185, 186, 12, 13, 2, 2, 186, 187, 7, 34, 2, 2, 187, 214, 5, 12, 7, 14, 188, 189, 12, 12, 2, 2, 189, 190, 7, 35, 2, 2, 190, 214, 5, 12, 7, 13, 191, 192, 12, 11, 2, 2, 192, 193, 7, 36, 2, 2, 193, 214, 5, 12, 7, 12, 194, 197, 12, 27, 2, 2, 195, 196, 7, 42, 2, 2, 196, 198, 7, 26, 2, 2, 197, 195, 3, 2, 2, 2, 197, 198, 3, 2, 2, 2, 198, 199, 3, 2, 2, 2, 199, 200, 7, 43, 2, 2, 200, 201, 7, 27, 2, 2, 201, 210, 7, 38, 2, 2, 202, 207, 5, 12, 7, 2, 203, 204, 7, 44, 2, 2, 204, 206, 5, 12, 7, 2, 205, 203, 3, 2, 2, 2, 206, 209, 3, 2, 2, 2, 207, 205, 3, 2, 2, 2, 207, 208, 3, 2, 2, 2, 208, 211, 3, 2, 2, 2, 209, 207, 3, 2, 2, 2, 210, 202, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 212, 3, 2, 2, 2, 212, 214, 7, 39, 2, 2, 213, 173, 3, 2, 2, 2, 213, 176, 3, 2, 2, 2, 213, 179, 3, 2, 2, 2, 213, 182, 3, 2, 2, 2, 213, 185, 3, 2, 2, 2, 213, 188, 3, 2, 2, 2, 213, 191, 3, 2, 2, 2, 213, 194, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 13, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 85, 108, 118, 126, 130, 147, 171, 197, 207, 210, 213, 215] \ No newline at end of file diff --git a/src/COOL.py b/src/COOL.py index 7fca203d..a342382b 100644 --- a/src/COOL.py +++ b/src/COOL.py @@ -8,102 +8,99 @@ def serializedATN(): with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\62") - buf.write("\u00e1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\66") + buf.write("\u00db\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") buf.write("\3\2\3\2\3\2\3\3\3\3\3\3\5\3\25\n\3\3\4\3\4\3\4\3\4\5") buf.write("\4\33\n\4\3\4\3\4\3\4\3\4\7\4!\n\4\f\4\16\4$\13\4\3\4") buf.write("\3\4\3\5\3\5\3\5\3\5\3\5\7\5-\n\5\f\5\16\5\60\13\5\7\5") buf.write("\62\n\5\f\5\16\5\65\13\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3") buf.write("\5\3\5\3\5\3\5\3\5\5\5C\n\5\5\5E\n\5\3\6\3\6\3\6\3\6\3") - buf.write("\7\3\7\3\7\3\7\3\7\3\7\7\7Q\n\7\f\7\16\7T\13\7\7\7V\n") - buf.write("\7\f\7\16\7Y\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\6\7n\n\7\r\7") - buf.write("\16\7o\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\5\7z\n\7\3\7\3") - buf.write("\7\3\7\3\7\3\7\3\7\5\7\u0082\n\7\7\7\u0084\n\7\f\7\16") - buf.write("\7\u0087\13\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\6\7\u0095\n\7\r\7\16\7\u0096\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") - buf.write("\7\3\7\3\7\3\7\3\7\5\7\u00af\n\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\7\7Q\n\7\f\7\16\7T\13\7\5\7V\n") buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\3\7\3\7\3\7\3\7\5\7\u00c9\n\7\3\7\3\7\3\7\3\7\3\7") - buf.write("\3\7\7\7\u00d1\n\7\f\7\16\7\u00d4\13\7\7\7\u00d6\n\7\f") - buf.write("\7\16\7\u00d9\13\7\3\7\7\7\u00dc\n\7\f\7\16\7\u00df\13") - buf.write("\7\3\7\2\3\f\b\2\4\6\b\n\f\2\2\2\u0103\2\16\3\2\2\2\4") - buf.write("\21\3\2\2\2\6\26\3\2\2\2\bD\3\2\2\2\nF\3\2\2\2\f\u00ae") - buf.write("\3\2\2\2\16\17\5\4\3\2\17\20\7\2\2\3\20\3\3\2\2\2\21\22") - buf.write("\5\6\4\2\22\24\7-\2\2\23\25\5\4\3\2\24\23\3\2\2\2\24\25") - buf.write("\3\2\2\2\25\5\3\2\2\2\26\27\7\3\2\2\27\32\7\31\2\2\30") - buf.write("\31\7\t\2\2\31\33\7\31\2\2\32\30\3\2\2\2\32\33\3\2\2\2") - buf.write("\33\34\3\2\2\2\34\"\7\'\2\2\35\36\5\b\5\2\36\37\7-\2\2") - buf.write("\37!\3\2\2\2 \35\3\2\2\2!$\3\2\2\2\" \3\2\2\2\"#\3\2\2") - buf.write("\2#%\3\2\2\2$\"\3\2\2\2%&\7(\2\2&\7\3\2\2\2\'(\7\32\2") - buf.write("\2(\63\7%\2\2).\5\n\6\2*+\7+\2\2+-\5\n\6\2,*\3\2\2\2-") - buf.write("\60\3\2\2\2.,\3\2\2\2./\3\2\2\2/\62\3\2\2\2\60.\3\2\2") - buf.write("\2\61)\3\2\2\2\62\65\3\2\2\2\63\61\3\2\2\2\63\64\3\2\2") - buf.write("\2\64\66\3\2\2\2\65\63\3\2\2\2\66\67\7&\2\2\678\7,\2\2") - buf.write("89\7\31\2\29:\7\'\2\2:;\5\f\7\2;<\7(\2\2\7") - buf.write("\32\2\2>?\7,\2\2?B\7\31\2\2@A\7\33\2\2AC\5\f\7\2B@\3\2") - buf.write("\2\2BC\3\2\2\2CE\3\2\2\2D\'\3\2\2\2D=\3\2\2\2E\t\3\2\2") - buf.write("\2FG\7\32\2\2GH\7,\2\2HI\7\31\2\2I\13\3\2\2\2JK\b\7\1") - buf.write("\2KL\7\32\2\2LW\7%\2\2MR\5\f\7\2NO\7+\2\2OQ\5\f\7\2PN") - buf.write("\3\2\2\2QT\3\2\2\2RP\3\2\2\2RS\3\2\2\2SV\3\2\2\2TR\3\2") - buf.write("\2\2UM\3\2\2\2VY\3\2\2\2WU\3\2\2\2WX\3\2\2\2XZ\3\2\2\2") - buf.write("YW\3\2\2\2Z\u00af\7&\2\2[\\\7\7\2\2\\]\5\f\7\2]^\7\16") - buf.write("\2\2^_\5\f\7\2_`\7\4\2\2`a\5\f\7\2ab\7\6\2\2b\u00af\3") - buf.write("\2\2\2cd\7\17\2\2de\5\f\7\2ef\7\f\2\2fg\5\f\7\2gh\7\r") - buf.write("\2\2h\u00af\3\2\2\2im\7\'\2\2jk\5\f\7\2kl\7-\2\2ln\3\2") - buf.write("\2\2mj\3\2\2\2no\3\2\2\2om\3\2\2\2op\3\2\2\2pq\3\2\2\2") - buf.write("qr\7(\2\2r\u00af\3\2\2\2st\7\13\2\2tu\7\32\2\2uv\7,\2") - buf.write("\2vy\7\31\2\2wx\7\33\2\2xz\5\f\7\2yw\3\2\2\2yz\3\2\2\2") - buf.write("z\u0085\3\2\2\2{|\7+\2\2|}\7\32\2\2}~\7,\2\2~\u0081\7") - buf.write("\31\2\2\177\u0080\7\33\2\2\u0080\u0082\5\f\7\2\u0081\177") - buf.write("\3\2\2\2\u0081\u0082\3\2\2\2\u0082\u0084\3\2\2\2\u0083") - buf.write("{\3\2\2\2\u0084\u0087\3\2\2\2\u0085\u0083\3\2\2\2\u0085") - buf.write("\u0086\3\2\2\2\u0086\u0088\3\2\2\2\u0087\u0085\3\2\2\2") - buf.write("\u0088\u0089\7\b\2\2\u0089\u00af\5\f\7\26\u008a\u008b") - buf.write("\7\20\2\2\u008b\u008c\5\f\7\2\u008c\u0094\7\23\2\2\u008d") - buf.write("\u008e\7\32\2\2\u008e\u008f\7,\2\2\u008f\u0090\7\31\2") - buf.write("\2\u0090\u0091\7\34\2\2\u0091\u0092\5\f\7\2\u0092\u0093") - buf.write("\7-\2\2\u0093\u0095\3\2\2\2\u0094\u008d\3\2\2\2\u0095") - buf.write("\u0096\3\2\2\2\u0096\u0094\3\2\2\2\u0096\u0097\3\2\2\2") - buf.write("\u0097\u0098\3\2\2\2\u0098\u0099\7\21\2\2\u0099\u00af") - buf.write("\3\2\2\2\u009a\u009b\7\22\2\2\u009b\u00af\7\31\2\2\u009c") - buf.write("\u009d\7$\2\2\u009d\u00af\5\f\7\23\u009e\u009f\7\n\2\2") - buf.write("\u009f\u00af\5\f\7\22\u00a0\u00a1\7\24\2\2\u00a1\u00af") - buf.write("\5\f\7\n\u00a2\u00a3\7%\2\2\u00a3\u00a4\5\f\7\2\u00a4") - buf.write("\u00a5\7&\2\2\u00a5\u00af\3\2\2\2\u00a6\u00af\7\32\2\2") - buf.write("\u00a7\u00af\7\30\2\2\u00a8\u00af\7\26\2\2\u00a9\u00af") - buf.write("\7\25\2\2\u00aa\u00af\7\5\2\2\u00ab\u00ac\7\32\2\2\u00ac") - buf.write("\u00ad\7\33\2\2\u00ad\u00af\5\f\7\3\u00aeJ\3\2\2\2\u00ae") - buf.write("[\3\2\2\2\u00aec\3\2\2\2\u00aei\3\2\2\2\u00aes\3\2\2\2") - buf.write("\u00ae\u008a\3\2\2\2\u00ae\u009a\3\2\2\2\u00ae\u009c\3") - buf.write("\2\2\2\u00ae\u009e\3\2\2\2\u00ae\u00a0\3\2\2\2\u00ae\u00a2") - buf.write("\3\2\2\2\u00ae\u00a6\3\2\2\2\u00ae\u00a7\3\2\2\2\u00ae") - buf.write("\u00a8\3\2\2\2\u00ae\u00a9\3\2\2\2\u00ae\u00aa\3\2\2\2") - buf.write("\u00ae\u00ab\3\2\2\2\u00af\u00dd\3\2\2\2\u00b0\u00b1\f") - buf.write("\21\2\2\u00b1\u00b2\7\37\2\2\u00b2\u00dc\5\f\7\22\u00b3") - buf.write("\u00b4\f\20\2\2\u00b4\u00b5\7 \2\2\u00b5\u00dc\5\f\7\21") - buf.write("\u00b6\u00b7\f\17\2\2\u00b7\u00b8\7\35\2\2\u00b8\u00dc") - buf.write("\5\f\7\20\u00b9\u00ba\f\16\2\2\u00ba\u00bb\7\36\2\2\u00bb") - buf.write("\u00dc\5\f\7\17\u00bc\u00bd\f\r\2\2\u00bd\u00be\7!\2\2") - buf.write("\u00be\u00dc\5\f\7\16\u00bf\u00c0\f\f\2\2\u00c0\u00c1") - buf.write("\7\"\2\2\u00c1\u00dc\5\f\7\r\u00c2\u00c3\f\13\2\2\u00c3") - buf.write("\u00c4\7#\2\2\u00c4\u00dc\5\f\7\f\u00c5\u00c8\f\33\2\2") - buf.write("\u00c6\u00c7\7)\2\2\u00c7\u00c9\7\31\2\2\u00c8\u00c6\3") - buf.write("\2\2\2\u00c8\u00c9\3\2\2\2\u00c9\u00ca\3\2\2\2\u00ca\u00cb") - buf.write("\7*\2\2\u00cb\u00cc\7\32\2\2\u00cc\u00d7\7%\2\2\u00cd") - buf.write("\u00d2\5\f\7\2\u00ce\u00cf\7+\2\2\u00cf\u00d1\5\f\7\2") - buf.write("\u00d0\u00ce\3\2\2\2\u00d1\u00d4\3\2\2\2\u00d2\u00d0\3") - buf.write("\2\2\2\u00d2\u00d3\3\2\2\2\u00d3\u00d6\3\2\2\2\u00d4\u00d2") - buf.write("\3\2\2\2\u00d5\u00cd\3\2\2\2\u00d6\u00d9\3\2\2\2\u00d7") - buf.write("\u00d5\3\2\2\2\u00d7\u00d8\3\2\2\2\u00d8\u00da\3\2\2\2") - buf.write("\u00d9\u00d7\3\2\2\2\u00da\u00dc\7&\2\2\u00db\u00b0\3") - buf.write("\2\2\2\u00db\u00b3\3\2\2\2\u00db\u00b6\3\2\2\2\u00db\u00b9") - buf.write("\3\2\2\2\u00db\u00bc\3\2\2\2\u00db\u00bf\3\2\2\2\u00db") - buf.write("\u00c2\3\2\2\2\u00db\u00c5\3\2\2\2\u00dc\u00df\3\2\2\2") - buf.write("\u00dd\u00db\3\2\2\2\u00dd\u00de\3\2\2\2\u00de\r\3\2\2") - buf.write("\2\u00df\u00dd\3\2\2\2\26\24\32\".\63BDRWoy\u0081\u0085") - buf.write("\u0096\u00ae\u00c8\u00d2\u00d7\u00db\u00dd") + buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\6\7k\n\7\r\7\16\7l\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\5\7w\n\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\5\7\177\n\7\7\7\u0081\n\7\f\7\16\7\u0084\13\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\6\7\u0092\n") + buf.write("\7\r\7\16\7\u0093\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\5") + buf.write("\7\u00ac\n\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7") + buf.write("\5\7\u00c6\n\7\3\7\3\7\3\7\3\7\3\7\3\7\7\7\u00ce\n\7\f") + buf.write("\7\16\7\u00d1\13\7\5\7\u00d3\n\7\3\7\7\7\u00d6\n\7\f\7") + buf.write("\16\7\u00d9\13\7\3\7\2\3\f\b\2\4\6\b\n\f\2\2\2\u00fd\2") + buf.write("\16\3\2\2\2\4\21\3\2\2\2\6\26\3\2\2\2\bD\3\2\2\2\nF\3") + buf.write("\2\2\2\f\u00ab\3\2\2\2\16\17\5\4\3\2\17\20\7\2\2\3\20") + buf.write("\3\3\2\2\2\21\22\5\6\4\2\22\24\7.\2\2\23\25\5\4\3\2\24") + buf.write("\23\3\2\2\2\24\25\3\2\2\2\25\5\3\2\2\2\26\27\7\3\2\2\27") + buf.write("\32\7\32\2\2\30\31\7\t\2\2\31\33\7\32\2\2\32\30\3\2\2") + buf.write("\2\32\33\3\2\2\2\33\34\3\2\2\2\34\"\7(\2\2\35\36\5\b\5") + buf.write("\2\36\37\7.\2\2\37!\3\2\2\2 \35\3\2\2\2!$\3\2\2\2\" \3") + buf.write("\2\2\2\"#\3\2\2\2#%\3\2\2\2$\"\3\2\2\2%&\7)\2\2&\7\3\2") + buf.write("\2\2\'(\7\33\2\2(\63\7&\2\2).\5\n\6\2*+\7,\2\2+-\5\n\6") + buf.write("\2,*\3\2\2\2-\60\3\2\2\2.,\3\2\2\2./\3\2\2\2/\62\3\2\2") + buf.write("\2\60.\3\2\2\2\61)\3\2\2\2\62\65\3\2\2\2\63\61\3\2\2\2") + buf.write("\63\64\3\2\2\2\64\66\3\2\2\2\65\63\3\2\2\2\66\67\7\'\2") + buf.write("\2\678\7-\2\289\7\32\2\29:\7(\2\2:;\5\f\7\2;<\7)\2\2<") + buf.write("E\3\2\2\2=>\7\33\2\2>?\7-\2\2?B\7\32\2\2@A\7\34\2\2AC") + buf.write("\5\f\7\2B@\3\2\2\2BC\3\2\2\2CE\3\2\2\2D\'\3\2\2\2D=\3") + buf.write("\2\2\2E\t\3\2\2\2FG\7\33\2\2GH\7-\2\2HI\7\32\2\2I\13\3") + buf.write("\2\2\2JK\b\7\1\2KL\7\33\2\2LU\7&\2\2MR\5\f\7\2NO\7,\2") + buf.write("\2OQ\5\f\7\2PN\3\2\2\2QT\3\2\2\2RP\3\2\2\2RS\3\2\2\2S") + buf.write("V\3\2\2\2TR\3\2\2\2UM\3\2\2\2UV\3\2\2\2VW\3\2\2\2W\u00ac") + buf.write("\7\'\2\2XY\7\7\2\2YZ\5\f\7\2Z[\7\16\2\2[\\\5\f\7\2\\]") + buf.write("\7\4\2\2]^\5\f\7\2^_\7\6\2\2_\u00ac\3\2\2\2`a\7\17\2\2") + buf.write("ab\5\f\7\2bc\7\f\2\2cd\5\f\7\2de\7\r\2\2e\u00ac\3\2\2") + buf.write("\2fj\7(\2\2gh\5\f\7\2hi\7.\2\2ik\3\2\2\2jg\3\2\2\2kl\3") + buf.write("\2\2\2lj\3\2\2\2lm\3\2\2\2mn\3\2\2\2no\7)\2\2o\u00ac\3") + buf.write("\2\2\2pq\7\13\2\2qr\7\33\2\2rs\7-\2\2sv\7\32\2\2tu\7\34") + buf.write("\2\2uw\5\f\7\2vt\3\2\2\2vw\3\2\2\2w\u0082\3\2\2\2xy\7") + buf.write(",\2\2yz\7\33\2\2z{\7-\2\2{~\7\32\2\2|}\7\34\2\2}\177\5") + buf.write("\f\7\2~|\3\2\2\2~\177\3\2\2\2\177\u0081\3\2\2\2\u0080") + buf.write("x\3\2\2\2\u0081\u0084\3\2\2\2\u0082\u0080\3\2\2\2\u0082") + buf.write("\u0083\3\2\2\2\u0083\u0085\3\2\2\2\u0084\u0082\3\2\2\2") + buf.write("\u0085\u0086\7\b\2\2\u0086\u00ac\5\f\7\26\u0087\u0088") + buf.write("\7\20\2\2\u0088\u0089\5\f\7\2\u0089\u0091\7\23\2\2\u008a") + buf.write("\u008b\7\33\2\2\u008b\u008c\7-\2\2\u008c\u008d\7\32\2") + buf.write("\2\u008d\u008e\7\35\2\2\u008e\u008f\5\f\7\2\u008f\u0090") + buf.write("\7.\2\2\u0090\u0092\3\2\2\2\u0091\u008a\3\2\2\2\u0092") + buf.write("\u0093\3\2\2\2\u0093\u0091\3\2\2\2\u0093\u0094\3\2\2\2") + buf.write("\u0094\u0095\3\2\2\2\u0095\u0096\7\21\2\2\u0096\u00ac") + buf.write("\3\2\2\2\u0097\u0098\7\22\2\2\u0098\u00ac\7\32\2\2\u0099") + buf.write("\u009a\7%\2\2\u009a\u00ac\5\f\7\23\u009b\u009c\7\n\2\2") + buf.write("\u009c\u00ac\5\f\7\22\u009d\u009e\7\24\2\2\u009e\u00ac") + buf.write("\5\f\7\n\u009f\u00a0\7&\2\2\u00a0\u00a1\5\f\7\2\u00a1") + buf.write("\u00a2\7\'\2\2\u00a2\u00ac\3\2\2\2\u00a3\u00ac\7\33\2") + buf.write("\2\u00a4\u00ac\7\31\2\2\u00a5\u00ac\7\26\2\2\u00a6\u00ac") + buf.write("\7\25\2\2\u00a7\u00ac\7\5\2\2\u00a8\u00a9\7\33\2\2\u00a9") + buf.write("\u00aa\7\34\2\2\u00aa\u00ac\5\f\7\3\u00abJ\3\2\2\2\u00ab") + buf.write("X\3\2\2\2\u00ab`\3\2\2\2\u00abf\3\2\2\2\u00abp\3\2\2\2") + buf.write("\u00ab\u0087\3\2\2\2\u00ab\u0097\3\2\2\2\u00ab\u0099\3") + buf.write("\2\2\2\u00ab\u009b\3\2\2\2\u00ab\u009d\3\2\2\2\u00ab\u009f") + buf.write("\3\2\2\2\u00ab\u00a3\3\2\2\2\u00ab\u00a4\3\2\2\2\u00ab") + buf.write("\u00a5\3\2\2\2\u00ab\u00a6\3\2\2\2\u00ab\u00a7\3\2\2\2") + buf.write("\u00ab\u00a8\3\2\2\2\u00ac\u00d7\3\2\2\2\u00ad\u00ae\f") + buf.write("\21\2\2\u00ae\u00af\7 \2\2\u00af\u00d6\5\f\7\22\u00b0") + buf.write("\u00b1\f\20\2\2\u00b1\u00b2\7!\2\2\u00b2\u00d6\5\f\7\21") + buf.write("\u00b3\u00b4\f\17\2\2\u00b4\u00b5\7\36\2\2\u00b5\u00d6") + buf.write("\5\f\7\20\u00b6\u00b7\f\16\2\2\u00b7\u00b8\7\37\2\2\u00b8") + buf.write("\u00d6\5\f\7\17\u00b9\u00ba\f\r\2\2\u00ba\u00bb\7\"\2") + buf.write("\2\u00bb\u00d6\5\f\7\16\u00bc\u00bd\f\f\2\2\u00bd\u00be") + buf.write("\7#\2\2\u00be\u00d6\5\f\7\r\u00bf\u00c0\f\13\2\2\u00c0") + buf.write("\u00c1\7$\2\2\u00c1\u00d6\5\f\7\f\u00c2\u00c5\f\33\2\2") + buf.write("\u00c3\u00c4\7*\2\2\u00c4\u00c6\7\32\2\2\u00c5\u00c3\3") + buf.write("\2\2\2\u00c5\u00c6\3\2\2\2\u00c6\u00c7\3\2\2\2\u00c7\u00c8") + buf.write("\7+\2\2\u00c8\u00c9\7\33\2\2\u00c9\u00d2\7&\2\2\u00ca") + buf.write("\u00cf\5\f\7\2\u00cb\u00cc\7,\2\2\u00cc\u00ce\5\f\7\2") + buf.write("\u00cd\u00cb\3\2\2\2\u00ce\u00d1\3\2\2\2\u00cf\u00cd\3") + buf.write("\2\2\2\u00cf\u00d0\3\2\2\2\u00d0\u00d3\3\2\2\2\u00d1\u00cf") + buf.write("\3\2\2\2\u00d2\u00ca\3\2\2\2\u00d2\u00d3\3\2\2\2\u00d3") + buf.write("\u00d4\3\2\2\2\u00d4\u00d6\7\'\2\2\u00d5\u00ad\3\2\2\2") + buf.write("\u00d5\u00b0\3\2\2\2\u00d5\u00b3\3\2\2\2\u00d5\u00b6\3") + buf.write("\2\2\2\u00d5\u00b9\3\2\2\2\u00d5\u00bc\3\2\2\2\u00d5\u00bf") + buf.write("\3\2\2\2\u00d5\u00c2\3\2\2\2\u00d6\u00d9\3\2\2\2\u00d7") + buf.write("\u00d5\3\2\2\2\u00d7\u00d8\3\2\2\2\u00d8\r\3\2\2\2\u00d9") + buf.write("\u00d7\3\2\2\2\26\24\32\".\63BDRUlv~\u0082\u0093\u00ab") + buf.write("\u00c5\u00cf\u00d2\u00d5\u00d7") return buf.getvalue() @@ -123,21 +120,22 @@ class COOL ( Parser ): "", "", "", "", "", "", "", "", "", "", "", "", - "", "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", - "'<'", "'<='", "'='", "'~'", "'('", "')'", "'{'", "'}'", - "'@'", "'.'", "','", "':'", "';'", "", "", - "'(*'", "", "'*)'" ] + "", "", "'<-'", "'=>'", "'+'", "'-'", + "'*'", "'/'", "'<'", "'<='", "'='", "'~'", "'('", "')'", + "'{'", "'}'", "'@'", "'.'", "','", "':'", "';'", "", + "", "'(*'", "", "'*)'" ] symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", - "TRUE", "STRING", "BREAK_STRING", "INT", "TYPEID", - "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", - "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", - "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", - "OPEN_CURLY", "CLOSE_CURLY", "AT", "DOT", "COMMA", - "COLON", "SEMICOLON", "WHITESPACE", "ONE_LINE_COMMENT", - "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT" ] + "TRUE", "STRING", "STRING_SIMPLE", "STRING_FIRSTLINE", + "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", + "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", + "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", + "CLOSE_ROUND", "OPEN_CURLY", "CLOSE_CURLY", "AT", + "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", + "ONE_LINE_COMMENT", "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT", + "STRING_INNERLINE", "STRING_LASTLINE", "STRING_MULTILINE" ] RULE_program = 0 RULE_programBlocks = 1 @@ -170,34 +168,38 @@ class COOL ( Parser ): NOT=18 TRUE=19 STRING=20 - BREAK_STRING=21 - INT=22 - TYPEID=23 - OBJECTID=24 - ASSIGNMENT=25 - CASE_ARROW=26 - ADD=27 - MINUS=28 - MULTIPLY=29 - DIVISION=30 - LESS_THAN=31 - LESS_EQUAL=32 - EQUAL=33 - INTEGER_NEGATIVE=34 - OPEN_ROUND=35 - CLOSE_ROUND=36 - OPEN_CURLY=37 - CLOSE_CURLY=38 - AT=39 - DOT=40 - COMMA=41 - COLON=42 - SEMICOLON=43 - WHITESPACE=44 - ONE_LINE_COMMENT=45 - OPEN_COMMENT=46 - COMMENT=47 - CLOSE_COMMENT=48 + STRING_SIMPLE=21 + STRING_FIRSTLINE=22 + INT=23 + TYPEID=24 + OBJECTID=25 + ASSIGNMENT=26 + CASE_ARROW=27 + ADD=28 + MINUS=29 + MULTIPLY=30 + DIVISION=31 + LESS_THAN=32 + LESS_EQUAL=33 + EQUAL=34 + INTEGER_NEGATIVE=35 + OPEN_ROUND=36 + CLOSE_ROUND=37 + OPEN_CURLY=38 + CLOSE_CURLY=39 + AT=40 + DOT=41 + COMMA=42 + COLON=43 + SEMICOLON=44 + WHITESPACE=45 + ONE_LINE_COMMENT=46 + OPEN_COMMENT=47 + COMMENT=48 + CLOSE_COMMENT=49 + STRING_INNERLINE=50 + STRING_LASTLINE=51 + STRING_MULTILINE=52 def __init__(self, input:TokenStream, output:TextIO = sys.stdout): super().__init__(input, output) @@ -1320,7 +1322,7 @@ def expression(self, _p:int=0): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 172 + self.state = 169 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,14,self._ctx) if la_ == 1: @@ -1332,10 +1334,10 @@ def expression(self, _p:int=0): self.match(COOL.OBJECTID) self.state = 74 self.match(COOL.OPEN_ROUND) - self.state = 85 + self.state = 83 self._errHandler.sync(self) _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0): + if (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0): self.state = 75 self.expression(0) self.state = 80 @@ -1350,11 +1352,9 @@ def expression(self, _p:int=0): self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 87 - self._errHandler.sync(self) - _la = self._input.LA(1) - self.state = 88 + + self.state = 85 self.match(COOL.CLOSE_ROUND) pass @@ -1362,19 +1362,19 @@ def expression(self, _p:int=0): localctx = COOL.IfContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 89 + self.state = 86 self.match(COOL.IF) - self.state = 90 + self.state = 87 self.expression(0) - self.state = 91 + self.state = 88 self.match(COOL.THEN) - self.state = 92 + self.state = 89 self.expression(0) - self.state = 93 + self.state = 90 self.match(COOL.ELSE) - self.state = 94 + self.state = 91 self.expression(0) - self.state = 95 + self.state = 92 self.match(COOL.FI) pass @@ -1382,15 +1382,15 @@ def expression(self, _p:int=0): localctx = COOL.WhileContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 97 + self.state = 94 self.match(COOL.WHILE) - self.state = 98 + self.state = 95 self.expression(0) - self.state = 99 + self.state = 96 self.match(COOL.LOOP) - self.state = 100 + self.state = 97 self.expression(0) - self.state = 101 + self.state = 98 self.match(COOL.POOL) pass @@ -1398,23 +1398,23 @@ def expression(self, _p:int=0): localctx = COOL.BlockContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 103 + self.state = 100 self.match(COOL.OPEN_CURLY) - self.state = 107 + self.state = 104 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 104 + self.state = 101 self.expression(0) - self.state = 105 + self.state = 102 self.match(COOL.SEMICOLON) - self.state = 109 + self.state = 106 self._errHandler.sync(self) _la = self._input.LA(1) if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0)): break - self.state = 111 + self.state = 108 self.match(COOL.CLOSE_CURLY) pass @@ -1422,53 +1422,53 @@ def expression(self, _p:int=0): localctx = COOL.LetInContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 113 + self.state = 110 self.match(COOL.LET) - self.state = 114 + self.state = 111 self.match(COOL.OBJECTID) - self.state = 115 + self.state = 112 self.match(COOL.COLON) - self.state = 116 + self.state = 113 self.match(COOL.TYPEID) - self.state = 119 + self.state = 116 self._errHandler.sync(self) _la = self._input.LA(1) if _la==COOL.ASSIGNMENT: - self.state = 117 + self.state = 114 self.match(COOL.ASSIGNMENT) - self.state = 118 + self.state = 115 self.expression(0) - self.state = 131 + self.state = 128 self._errHandler.sync(self) _la = self._input.LA(1) while _la==COOL.COMMA: - self.state = 121 + self.state = 118 self.match(COOL.COMMA) - self.state = 122 + self.state = 119 self.match(COOL.OBJECTID) - self.state = 123 + self.state = 120 self.match(COOL.COLON) - self.state = 124 + self.state = 121 self.match(COOL.TYPEID) - self.state = 127 + self.state = 124 self._errHandler.sync(self) _la = self._input.LA(1) if _la==COOL.ASSIGNMENT: - self.state = 125 + self.state = 122 self.match(COOL.ASSIGNMENT) - self.state = 126 + self.state = 123 self.expression(0) - self.state = 133 + self.state = 130 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 134 + self.state = 131 self.match(COOL.IN) - self.state = 135 + self.state = 132 self.expression(20) pass @@ -1476,35 +1476,35 @@ def expression(self, _p:int=0): localctx = COOL.CaseContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 136 + self.state = 133 self.match(COOL.CASE) - self.state = 137 + self.state = 134 self.expression(0) - self.state = 138 + self.state = 135 self.match(COOL.OF) - self.state = 146 + self.state = 143 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 139 + self.state = 136 self.match(COOL.OBJECTID) - self.state = 140 + self.state = 137 self.match(COOL.COLON) - self.state = 141 + self.state = 138 self.match(COOL.TYPEID) - self.state = 142 + self.state = 139 self.match(COOL.CASE_ARROW) - self.state = 143 + self.state = 140 self.expression(0) - self.state = 144 + self.state = 141 self.match(COOL.SEMICOLON) - self.state = 148 + self.state = 145 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==COOL.OBJECTID): break - self.state = 150 + self.state = 147 self.match(COOL.ESAC) pass @@ -1512,9 +1512,9 @@ def expression(self, _p:int=0): localctx = COOL.NewContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 152 + self.state = 149 self.match(COOL.NEW) - self.state = 153 + self.state = 150 self.match(COOL.TYPEID) pass @@ -1522,9 +1522,9 @@ def expression(self, _p:int=0): localctx = COOL.NegativeContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 154 + self.state = 151 self.match(COOL.INTEGER_NEGATIVE) - self.state = 155 + self.state = 152 self.expression(17) pass @@ -1532,9 +1532,9 @@ def expression(self, _p:int=0): localctx = COOL.IsvoidContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 156 + self.state = 153 self.match(COOL.ISVOID) - self.state = 157 + self.state = 154 self.expression(16) pass @@ -1542,9 +1542,9 @@ def expression(self, _p:int=0): localctx = COOL.BoolNotContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 158 + self.state = 155 self.match(COOL.NOT) - self.state = 159 + self.state = 156 self.expression(8) pass @@ -1552,11 +1552,11 @@ def expression(self, _p:int=0): localctx = COOL.ParenthesesContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 160 + self.state = 157 self.match(COOL.OPEN_ROUND) - self.state = 161 + self.state = 158 self.expression(0) - self.state = 162 + self.state = 159 self.match(COOL.CLOSE_ROUND) pass @@ -1564,7 +1564,7 @@ def expression(self, _p:int=0): localctx = COOL.IdContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 164 + self.state = 161 self.match(COOL.OBJECTID) pass @@ -1572,7 +1572,7 @@ def expression(self, _p:int=0): localctx = COOL.IntContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 165 + self.state = 162 self.match(COOL.INT) pass @@ -1580,7 +1580,7 @@ def expression(self, _p:int=0): localctx = COOL.StringContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 166 + self.state = 163 self.match(COOL.STRING) pass @@ -1588,7 +1588,7 @@ def expression(self, _p:int=0): localctx = COOL.TrueContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 167 + self.state = 164 self.match(COOL.TRUE) pass @@ -1596,7 +1596,7 @@ def expression(self, _p:int=0): localctx = COOL.FalseContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 168 + self.state = 165 self.match(COOL.FALSE) pass @@ -1604,17 +1604,17 @@ def expression(self, _p:int=0): localctx = COOL.AssignmentContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 169 + self.state = 166 self.match(COOL.OBJECTID) - self.state = 170 + self.state = 167 self.match(COOL.ASSIGNMENT) - self.state = 171 + self.state = 168 self.expression(1) pass self._ctx.stop = self._input.LT(-1) - self.state = 219 + self.state = 213 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,19,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: @@ -1622,151 +1622,149 @@ def expression(self, _p:int=0): if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx - self.state = 217 + self.state = 211 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,18,self._ctx) if la_ == 1: localctx = COOL.MultiplyContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 174 + self.state = 171 if not self.precpred(self._ctx, 15): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 15)") - self.state = 175 + self.state = 172 self.match(COOL.MULTIPLY) - self.state = 176 + self.state = 173 self.expression(16) pass elif la_ == 2: localctx = COOL.DivisionContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 177 + self.state = 174 if not self.precpred(self._ctx, 14): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 14)") - self.state = 178 + self.state = 175 self.match(COOL.DIVISION) - self.state = 179 + self.state = 176 self.expression(15) pass elif la_ == 3: localctx = COOL.AddContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 180 + self.state = 177 if not self.precpred(self._ctx, 13): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 13)") - self.state = 181 + self.state = 178 self.match(COOL.ADD) - self.state = 182 + self.state = 179 self.expression(14) pass elif la_ == 4: localctx = COOL.MinusContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 183 + self.state = 180 if not self.precpred(self._ctx, 12): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 12)") - self.state = 184 + self.state = 181 self.match(COOL.MINUS) - self.state = 185 + self.state = 182 self.expression(13) pass elif la_ == 5: localctx = COOL.LessThanContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 186 + self.state = 183 if not self.precpred(self._ctx, 11): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 11)") - self.state = 187 + self.state = 184 self.match(COOL.LESS_THAN) - self.state = 188 + self.state = 185 self.expression(12) pass elif la_ == 6: localctx = COOL.LessEqualContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 189 + self.state = 186 if not self.precpred(self._ctx, 10): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 10)") - self.state = 190 + self.state = 187 self.match(COOL.LESS_EQUAL) - self.state = 191 + self.state = 188 self.expression(11) pass elif la_ == 7: localctx = COOL.EqualContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 192 + self.state = 189 if not self.precpred(self._ctx, 9): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 9)") - self.state = 193 + self.state = 190 self.match(COOL.EQUAL) - self.state = 194 + self.state = 191 self.expression(10) pass elif la_ == 8: localctx = COOL.MethodCallContext(self, COOL.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 195 + self.state = 192 if not self.precpred(self._ctx, 25): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 25)") - self.state = 198 + self.state = 195 self._errHandler.sync(self) _la = self._input.LA(1) if _la==COOL.AT: - self.state = 196 + self.state = 193 self.match(COOL.AT) - self.state = 197 + self.state = 194 self.match(COOL.TYPEID) - self.state = 200 + self.state = 197 self.match(COOL.DOT) - self.state = 201 + self.state = 198 self.match(COOL.OBJECTID) - self.state = 202 + self.state = 199 self.match(COOL.OPEN_ROUND) - self.state = 213 + self.state = 208 self._errHandler.sync(self) _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0): - self.state = 203 + if (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << COOL.FALSE) | (1 << COOL.IF) | (1 << COOL.ISVOID) | (1 << COOL.LET) | (1 << COOL.WHILE) | (1 << COOL.CASE) | (1 << COOL.NEW) | (1 << COOL.NOT) | (1 << COOL.TRUE) | (1 << COOL.STRING) | (1 << COOL.INT) | (1 << COOL.OBJECTID) | (1 << COOL.INTEGER_NEGATIVE) | (1 << COOL.OPEN_ROUND) | (1 << COOL.OPEN_CURLY))) != 0): + self.state = 200 self.expression(0) - self.state = 208 + self.state = 205 self._errHandler.sync(self) _la = self._input.LA(1) while _la==COOL.COMMA: - self.state = 204 + self.state = 201 self.match(COOL.COMMA) - self.state = 205 + self.state = 202 self.expression(0) - self.state = 210 + self.state = 207 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 215 - self._errHandler.sync(self) - _la = self._input.LA(1) - self.state = 216 + + self.state = 210 self.match(COOL.CLOSE_ROUND) pass - self.state = 221 + self.state = 215 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,19,self._ctx) diff --git a/src/COOL.tokens b/src/COOL.tokens index bbdda836..de4efcf0 100644 --- a/src/COOL.tokens +++ b/src/COOL.tokens @@ -18,52 +18,56 @@ OF=17 NOT=18 TRUE=19 STRING=20 -BREAK_STRING=21 -INT=22 -TYPEID=23 -OBJECTID=24 -ASSIGNMENT=25 -CASE_ARROW=26 -ADD=27 -MINUS=28 -MULTIPLY=29 -DIVISION=30 -LESS_THAN=31 -LESS_EQUAL=32 -EQUAL=33 -INTEGER_NEGATIVE=34 -OPEN_ROUND=35 -CLOSE_ROUND=36 -OPEN_CURLY=37 -CLOSE_CURLY=38 -AT=39 -DOT=40 -COMMA=41 -COLON=42 -SEMICOLON=43 -WHITESPACE=44 -ONE_LINE_COMMENT=45 -OPEN_COMMENT=46 -COMMENT=47 -CLOSE_COMMENT=48 -'<-'=25 -'=>'=26 -'+'=27 -'-'=28 -'*'=29 -'/'=30 -'<'=31 -'<='=32 -'='=33 -'~'=34 -'('=35 -')'=36 -'{'=37 -'}'=38 -'@'=39 -'.'=40 -','=41 -':'=42 -';'=43 -'(*'=46 -'*)'=48 +STRING_SIMPLE=21 +STRING_FIRSTLINE=22 +INT=23 +TYPEID=24 +OBJECTID=25 +ASSIGNMENT=26 +CASE_ARROW=27 +ADD=28 +MINUS=29 +MULTIPLY=30 +DIVISION=31 +LESS_THAN=32 +LESS_EQUAL=33 +EQUAL=34 +INTEGER_NEGATIVE=35 +OPEN_ROUND=36 +CLOSE_ROUND=37 +OPEN_CURLY=38 +CLOSE_CURLY=39 +AT=40 +DOT=41 +COMMA=42 +COLON=43 +SEMICOLON=44 +WHITESPACE=45 +ONE_LINE_COMMENT=46 +OPEN_COMMENT=47 +COMMENT=48 +CLOSE_COMMENT=49 +STRING_INNERLINE=50 +STRING_LASTLINE=51 +STRING_MULTILINE=52 +'<-'=26 +'=>'=27 +'+'=28 +'-'=29 +'*'=30 +'/'=31 +'<'=32 +'<='=33 +'='=34 +'~'=35 +'('=36 +')'=37 +'{'=38 +'}'=39 +'@'=40 +'.'=41 +','=42 +':'=43 +';'=44 +'(*'=47 +'*)'=49 diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 6e21c735..b2d7beab 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -20,8 +20,8 @@ def main(argv): lexer.addErrorListener(COOLLexerErrorListener()) token = lexer.nextToken() while token.type != Token.EOF: + #print(token.type) token = lexer.nextToken() - if lexer.hasErrors: return sys.exit(errno.EPERM) diff --git a/src/COOLLexer.py b/src/COOLLexer.py index bcb2349c..8456f1b6 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -14,6 +14,7 @@ class COOLLexer(COOL_LEX): def __init__(self, input=None, output:TextIO = sys.stdout): super().__init__(input, output) self._hasErrors = False + self._currentToken = None; def notifyListeners(self, e:LexerNoViableAltException): self._hasErrors = True @@ -21,13 +22,47 @@ def notifyListeners(self, e:LexerNoViableAltException): start = self._tokenStartCharIndex stop = self._input.index text = self._input.getText(start, stop) - msg = "'" + self.getErrorDisplay(text) + "'" + if self._currentToken.type in [COOL_LEX.STRING, COOL_LEX.STRING_FIRSTLINE, COOL_LEX.STRING_INNERLINE] or text[0] == '"': + if self.inputStream.size == self.inputStream.index: + msg = "EOF in string constant" + else: + msg = "Unterminated string constant" + else: + msg = "'" + self.getErrorDisplay(text) + "'" + if self._token == None: + line = self.line + col= self.column + else: + line = self._tokenStartLine + col = self._tokenStartColumn listener = self.getErrorListenerDispatch() - listener.syntaxError(self, self._token, self._tokenStartLine, self._tokenStartColumn, msg, e) + listener.syntaxError(self, self._token, line, col, msg, e) + + def nextToken(self): + while (True): + lastToken = self._currentToken + self._currentToken = super().nextToken() + if self._currentToken.type in [COOL_LEX.OPEN_COMMENT, COOL_LEX.CLOSE_COMMENT]: + continue + elif self._currentToken.type == COOL_LEX.STRING_FIRSTLINE: + continue + elif self._currentToken.type == COOL_LEX.STRING_INNERLINE: + continue + else: + break + + if self._currentToken.type == Token.EOF: + if lastToken != None and lastToken.type == COOL_LEX.OPEN_COMMENT: + self._hasErrors = True + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, self._currentToken, self._currentToken.line, self._currentToken.column, + "EOF in comment", None) + return self._currentToken; def reset(self): super().reset() self._hasErrors = False + self._currentToken = None; @property def hasErrors(self): diff --git a/src/COOL_LEX.interp b/src/COOL_LEX.interp index 5e362562..4d6e25e8 100644 --- a/src/COOL_LEX.interp +++ b/src/COOL_LEX.interp @@ -24,6 +24,7 @@ null null null null +null '<-' '=>' '+' @@ -48,6 +49,9 @@ null '(*' null '*)' +null +null +null token symbolic names: null @@ -71,7 +75,8 @@ OF NOT TRUE STRING -BREAK_STRING +STRING_SIMPLE +STRING_FIRSTLINE INT TYPEID OBJECTID @@ -99,6 +104,9 @@ ONE_LINE_COMMENT OPEN_COMMENT COMMENT CLOSE_COMMENT +STRING_INNERLINE +STRING_LASTLINE +STRING_MULTILINE rule names: CLASS @@ -121,7 +129,9 @@ OF NOT TRUE STRING -BREAK_STRING +STRING_SIMPLE +STRING_CONTENT +STRING_FIRSTLINE INT TYPEID OBJECTID @@ -169,6 +179,9 @@ ONE_LINE_COMMENT OPEN_COMMENT COMMENT CLOSE_COMMENT +STRING_INNERLINE +STRING_LASTLINE +STRING_MULTILINE channel names: DEFAULT_TOKEN_CHANNEL @@ -177,6 +190,7 @@ HIDDEN mode names: DEFAULT_MODE MULTILINE_COMMENT +MULTILINE_STR atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 50, 406, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 7, 21, 238, 10, 21, 12, 21, 14, 21, 241, 11, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 5, 22, 252, 10, 22, 3, 23, 6, 23, 255, 10, 23, 13, 23, 14, 23, 256, 3, 24, 3, 24, 7, 24, 261, 10, 24, 12, 24, 14, 24, 264, 11, 24, 3, 25, 3, 25, 7, 25, 268, 10, 25, 12, 25, 14, 25, 271, 11, 25, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 62, 5, 62, 351, 10, 62, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 6, 65, 362, 10, 65, 13, 65, 14, 65, 363, 3, 65, 3, 65, 3, 66, 3, 66, 3, 66, 3, 66, 7, 66, 372, 10, 66, 12, 66, 14, 66, 375, 11, 66, 3, 66, 5, 66, 378, 10, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 6, 68, 393, 10, 68, 13, 68, 14, 68, 394, 5, 68, 397, 10, 68, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 394, 2, 70, 4, 3, 6, 4, 8, 5, 10, 6, 12, 7, 14, 8, 16, 9, 18, 10, 20, 11, 22, 12, 24, 13, 26, 14, 28, 15, 30, 16, 32, 17, 34, 18, 36, 19, 38, 20, 40, 21, 42, 22, 44, 23, 46, 24, 48, 25, 50, 26, 52, 27, 54, 28, 56, 29, 58, 30, 60, 31, 62, 32, 64, 33, 66, 34, 68, 35, 70, 36, 72, 37, 74, 38, 76, 39, 78, 40, 80, 41, 82, 42, 84, 43, 86, 44, 88, 45, 90, 2, 92, 2, 94, 2, 96, 2, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 46, 132, 47, 134, 48, 136, 49, 138, 50, 4, 2, 3, 28, 6, 2, 12, 12, 15, 15, 36, 36, 94, 94, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 398, 2, 4, 3, 2, 2, 2, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 50, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 130, 3, 2, 2, 2, 2, 132, 3, 2, 2, 2, 2, 134, 3, 2, 2, 2, 3, 136, 3, 2, 2, 2, 3, 138, 3, 2, 2, 2, 4, 140, 3, 2, 2, 2, 6, 146, 3, 2, 2, 2, 8, 151, 3, 2, 2, 2, 10, 157, 3, 2, 2, 2, 12, 160, 3, 2, 2, 2, 14, 163, 3, 2, 2, 2, 16, 166, 3, 2, 2, 2, 18, 175, 3, 2, 2, 2, 20, 182, 3, 2, 2, 2, 22, 186, 3, 2, 2, 2, 24, 191, 3, 2, 2, 2, 26, 196, 3, 2, 2, 2, 28, 201, 3, 2, 2, 2, 30, 207, 3, 2, 2, 2, 32, 212, 3, 2, 2, 2, 34, 217, 3, 2, 2, 2, 36, 221, 3, 2, 2, 2, 38, 224, 3, 2, 2, 2, 40, 228, 3, 2, 2, 2, 42, 233, 3, 2, 2, 2, 44, 251, 3, 2, 2, 2, 46, 254, 3, 2, 2, 2, 48, 258, 3, 2, 2, 2, 50, 265, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 275, 3, 2, 2, 2, 56, 278, 3, 2, 2, 2, 58, 280, 3, 2, 2, 2, 60, 282, 3, 2, 2, 2, 62, 284, 3, 2, 2, 2, 64, 286, 3, 2, 2, 2, 66, 288, 3, 2, 2, 2, 68, 291, 3, 2, 2, 2, 70, 293, 3, 2, 2, 2, 72, 295, 3, 2, 2, 2, 74, 297, 3, 2, 2, 2, 76, 299, 3, 2, 2, 2, 78, 301, 3, 2, 2, 2, 80, 303, 3, 2, 2, 2, 82, 305, 3, 2, 2, 2, 84, 307, 3, 2, 2, 2, 86, 309, 3, 2, 2, 2, 88, 311, 3, 2, 2, 2, 90, 313, 3, 2, 2, 2, 92, 315, 3, 2, 2, 2, 94, 317, 3, 2, 2, 2, 96, 319, 3, 2, 2, 2, 98, 321, 3, 2, 2, 2, 100, 323, 3, 2, 2, 2, 102, 325, 3, 2, 2, 2, 104, 327, 3, 2, 2, 2, 106, 329, 3, 2, 2, 2, 108, 331, 3, 2, 2, 2, 110, 333, 3, 2, 2, 2, 112, 335, 3, 2, 2, 2, 114, 337, 3, 2, 2, 2, 116, 339, 3, 2, 2, 2, 118, 341, 3, 2, 2, 2, 120, 343, 3, 2, 2, 2, 122, 345, 3, 2, 2, 2, 124, 347, 3, 2, 2, 2, 126, 352, 3, 2, 2, 2, 128, 358, 3, 2, 2, 2, 130, 361, 3, 2, 2, 2, 132, 367, 3, 2, 2, 2, 134, 381, 3, 2, 2, 2, 136, 396, 3, 2, 2, 2, 138, 400, 3, 2, 2, 2, 140, 141, 5, 92, 46, 2, 141, 142, 5, 104, 52, 2, 142, 143, 5, 90, 45, 2, 143, 144, 5, 114, 57, 2, 144, 145, 5, 114, 57, 2, 145, 5, 3, 2, 2, 2, 146, 147, 5, 96, 48, 2, 147, 148, 5, 104, 52, 2, 148, 149, 5, 114, 57, 2, 149, 150, 5, 96, 48, 2, 150, 7, 3, 2, 2, 2, 151, 152, 7, 104, 2, 2, 152, 153, 5, 90, 45, 2, 153, 154, 5, 104, 52, 2, 154, 155, 5, 114, 57, 2, 155, 156, 5, 96, 48, 2, 156, 9, 3, 2, 2, 2, 157, 158, 5, 98, 49, 2, 158, 159, 5, 102, 51, 2, 159, 11, 3, 2, 2, 2, 160, 161, 5, 102, 51, 2, 161, 162, 5, 98, 49, 2, 162, 13, 3, 2, 2, 2, 163, 164, 5, 102, 51, 2, 164, 165, 5, 106, 53, 2, 165, 15, 3, 2, 2, 2, 166, 167, 5, 102, 51, 2, 167, 168, 5, 106, 53, 2, 168, 169, 5, 100, 50, 2, 169, 170, 5, 96, 48, 2, 170, 171, 5, 112, 56, 2, 171, 172, 5, 102, 51, 2, 172, 173, 5, 116, 58, 2, 173, 174, 5, 114, 57, 2, 174, 17, 3, 2, 2, 2, 175, 176, 5, 102, 51, 2, 176, 177, 5, 114, 57, 2, 177, 178, 5, 120, 60, 2, 178, 179, 5, 108, 54, 2, 179, 180, 5, 102, 51, 2, 180, 181, 5, 94, 47, 2, 181, 19, 3, 2, 2, 2, 182, 183, 5, 104, 52, 2, 183, 184, 5, 96, 48, 2, 184, 185, 5, 116, 58, 2, 185, 21, 3, 2, 2, 2, 186, 187, 5, 104, 52, 2, 187, 188, 5, 108, 54, 2, 188, 189, 5, 108, 54, 2, 189, 190, 5, 110, 55, 2, 190, 23, 3, 2, 2, 2, 191, 192, 5, 110, 55, 2, 192, 193, 5, 108, 54, 2, 193, 194, 5, 108, 54, 2, 194, 195, 5, 104, 52, 2, 195, 25, 3, 2, 2, 2, 196, 197, 5, 116, 58, 2, 197, 198, 5, 100, 50, 2, 198, 199, 5, 96, 48, 2, 199, 200, 5, 106, 53, 2, 200, 27, 3, 2, 2, 2, 201, 202, 5, 122, 61, 2, 202, 203, 5, 100, 50, 2, 203, 204, 5, 102, 51, 2, 204, 205, 5, 104, 52, 2, 205, 206, 5, 96, 48, 2, 206, 29, 3, 2, 2, 2, 207, 208, 5, 92, 46, 2, 208, 209, 5, 90, 45, 2, 209, 210, 5, 114, 57, 2, 210, 211, 5, 96, 48, 2, 211, 31, 3, 2, 2, 2, 212, 213, 5, 96, 48, 2, 213, 214, 5, 114, 57, 2, 214, 215, 5, 90, 45, 2, 215, 216, 5, 92, 46, 2, 216, 33, 3, 2, 2, 2, 217, 218, 5, 106, 53, 2, 218, 219, 5, 96, 48, 2, 219, 220, 5, 122, 61, 2, 220, 35, 3, 2, 2, 2, 221, 222, 5, 108, 54, 2, 222, 223, 5, 98, 49, 2, 223, 37, 3, 2, 2, 2, 224, 225, 5, 106, 53, 2, 225, 226, 5, 108, 54, 2, 226, 227, 5, 116, 58, 2, 227, 39, 3, 2, 2, 2, 228, 229, 7, 118, 2, 2, 229, 230, 5, 112, 56, 2, 230, 231, 5, 118, 59, 2, 231, 232, 5, 96, 48, 2, 232, 41, 3, 2, 2, 2, 233, 239, 7, 36, 2, 2, 234, 238, 5, 124, 62, 2, 235, 238, 5, 44, 22, 2, 236, 238, 10, 2, 2, 2, 237, 234, 3, 2, 2, 2, 237, 235, 3, 2, 2, 2, 237, 236, 3, 2, 2, 2, 238, 241, 3, 2, 2, 2, 239, 237, 3, 2, 2, 2, 239, 240, 3, 2, 2, 2, 240, 242, 3, 2, 2, 2, 241, 239, 3, 2, 2, 2, 242, 243, 7, 36, 2, 2, 243, 43, 3, 2, 2, 2, 244, 245, 7, 94, 2, 2, 245, 246, 7, 15, 2, 2, 246, 252, 7, 12, 2, 2, 247, 248, 7, 94, 2, 2, 248, 252, 7, 15, 2, 2, 249, 250, 7, 94, 2, 2, 250, 252, 7, 12, 2, 2, 251, 244, 3, 2, 2, 2, 251, 247, 3, 2, 2, 2, 251, 249, 3, 2, 2, 2, 252, 45, 3, 2, 2, 2, 253, 255, 9, 3, 2, 2, 254, 253, 3, 2, 2, 2, 255, 256, 3, 2, 2, 2, 256, 254, 3, 2, 2, 2, 256, 257, 3, 2, 2, 2, 257, 47, 3, 2, 2, 2, 258, 262, 9, 4, 2, 2, 259, 261, 9, 5, 2, 2, 260, 259, 3, 2, 2, 2, 261, 264, 3, 2, 2, 2, 262, 260, 3, 2, 2, 2, 262, 263, 3, 2, 2, 2, 263, 49, 3, 2, 2, 2, 264, 262, 3, 2, 2, 2, 265, 269, 9, 6, 2, 2, 266, 268, 9, 5, 2, 2, 267, 266, 3, 2, 2, 2, 268, 271, 3, 2, 2, 2, 269, 267, 3, 2, 2, 2, 269, 270, 3, 2, 2, 2, 270, 51, 3, 2, 2, 2, 271, 269, 3, 2, 2, 2, 272, 273, 7, 62, 2, 2, 273, 274, 7, 47, 2, 2, 274, 53, 3, 2, 2, 2, 275, 276, 7, 63, 2, 2, 276, 277, 7, 64, 2, 2, 277, 55, 3, 2, 2, 2, 278, 279, 7, 45, 2, 2, 279, 57, 3, 2, 2, 2, 280, 281, 7, 47, 2, 2, 281, 59, 3, 2, 2, 2, 282, 283, 7, 44, 2, 2, 283, 61, 3, 2, 2, 2, 284, 285, 7, 49, 2, 2, 285, 63, 3, 2, 2, 2, 286, 287, 7, 62, 2, 2, 287, 65, 3, 2, 2, 2, 288, 289, 7, 62, 2, 2, 289, 290, 7, 63, 2, 2, 290, 67, 3, 2, 2, 2, 291, 292, 7, 63, 2, 2, 292, 69, 3, 2, 2, 2, 293, 294, 7, 128, 2, 2, 294, 71, 3, 2, 2, 2, 295, 296, 7, 42, 2, 2, 296, 73, 3, 2, 2, 2, 297, 298, 7, 43, 2, 2, 298, 75, 3, 2, 2, 2, 299, 300, 7, 125, 2, 2, 300, 77, 3, 2, 2, 2, 301, 302, 7, 127, 2, 2, 302, 79, 3, 2, 2, 2, 303, 304, 7, 66, 2, 2, 304, 81, 3, 2, 2, 2, 305, 306, 7, 48, 2, 2, 306, 83, 3, 2, 2, 2, 307, 308, 7, 46, 2, 2, 308, 85, 3, 2, 2, 2, 309, 310, 7, 60, 2, 2, 310, 87, 3, 2, 2, 2, 311, 312, 7, 61, 2, 2, 312, 89, 3, 2, 2, 2, 313, 314, 9, 7, 2, 2, 314, 91, 3, 2, 2, 2, 315, 316, 9, 8, 2, 2, 316, 93, 3, 2, 2, 2, 317, 318, 9, 9, 2, 2, 318, 95, 3, 2, 2, 2, 319, 320, 9, 10, 2, 2, 320, 97, 3, 2, 2, 2, 321, 322, 9, 11, 2, 2, 322, 99, 3, 2, 2, 2, 323, 324, 9, 12, 2, 2, 324, 101, 3, 2, 2, 2, 325, 326, 9, 13, 2, 2, 326, 103, 3, 2, 2, 2, 327, 328, 9, 14, 2, 2, 328, 105, 3, 2, 2, 2, 329, 330, 9, 15, 2, 2, 330, 107, 3, 2, 2, 2, 331, 332, 9, 16, 2, 2, 332, 109, 3, 2, 2, 2, 333, 334, 9, 17, 2, 2, 334, 111, 3, 2, 2, 2, 335, 336, 9, 18, 2, 2, 336, 113, 3, 2, 2, 2, 337, 338, 9, 19, 2, 2, 338, 115, 3, 2, 2, 2, 339, 340, 9, 20, 2, 2, 340, 117, 3, 2, 2, 2, 341, 342, 9, 21, 2, 2, 342, 119, 3, 2, 2, 2, 343, 344, 9, 22, 2, 2, 344, 121, 3, 2, 2, 2, 345, 346, 9, 23, 2, 2, 346, 123, 3, 2, 2, 2, 347, 350, 7, 94, 2, 2, 348, 351, 9, 24, 2, 2, 349, 351, 5, 126, 63, 2, 350, 348, 3, 2, 2, 2, 350, 349, 3, 2, 2, 2, 351, 125, 3, 2, 2, 2, 352, 353, 7, 119, 2, 2, 353, 354, 5, 128, 64, 2, 354, 355, 5, 128, 64, 2, 355, 356, 5, 128, 64, 2, 356, 357, 5, 128, 64, 2, 357, 127, 3, 2, 2, 2, 358, 359, 9, 25, 2, 2, 359, 129, 3, 2, 2, 2, 360, 362, 9, 26, 2, 2, 361, 360, 3, 2, 2, 2, 362, 363, 3, 2, 2, 2, 363, 361, 3, 2, 2, 2, 363, 364, 3, 2, 2, 2, 364, 365, 3, 2, 2, 2, 365, 366, 8, 65, 2, 2, 366, 131, 3, 2, 2, 2, 367, 368, 7, 47, 2, 2, 368, 369, 7, 47, 2, 2, 369, 373, 3, 2, 2, 2, 370, 372, 10, 27, 2, 2, 371, 370, 3, 2, 2, 2, 372, 375, 3, 2, 2, 2, 373, 371, 3, 2, 2, 2, 373, 374, 3, 2, 2, 2, 374, 377, 3, 2, 2, 2, 375, 373, 3, 2, 2, 2, 376, 378, 7, 12, 2, 2, 377, 376, 3, 2, 2, 2, 377, 378, 3, 2, 2, 2, 378, 379, 3, 2, 2, 2, 379, 380, 8, 66, 2, 2, 380, 133, 3, 2, 2, 2, 381, 382, 7, 42, 2, 2, 382, 383, 7, 44, 2, 2, 383, 384, 3, 2, 2, 2, 384, 385, 8, 67, 2, 2, 385, 386, 8, 67, 3, 2, 386, 135, 3, 2, 2, 2, 387, 388, 5, 134, 67, 2, 388, 389, 5, 136, 68, 2, 389, 390, 5, 138, 69, 2, 390, 397, 3, 2, 2, 2, 391, 393, 11, 2, 2, 2, 392, 391, 3, 2, 2, 2, 393, 394, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 394, 392, 3, 2, 2, 2, 395, 397, 3, 2, 2, 2, 396, 387, 3, 2, 2, 2, 396, 392, 3, 2, 2, 2, 397, 398, 3, 2, 2, 2, 398, 399, 8, 68, 2, 2, 399, 137, 3, 2, 2, 2, 400, 401, 7, 44, 2, 2, 401, 402, 7, 43, 2, 2, 402, 403, 3, 2, 2, 2, 403, 404, 8, 69, 2, 2, 404, 405, 8, 69, 4, 2, 405, 139, 3, 2, 2, 2, 16, 2, 3, 237, 239, 251, 256, 262, 269, 350, 363, 373, 377, 394, 396, 5, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 54, 454, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 247, 10, 21, 3, 22, 3, 22, 7, 22, 251, 10, 22, 12, 22, 14, 22, 254, 11, 22, 3, 22, 3, 22, 3, 23, 3, 23, 5, 23, 260, 10, 23, 3, 24, 3, 24, 7, 24, 264, 10, 24, 12, 24, 14, 24, 267, 11, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 6, 25, 276, 10, 25, 13, 25, 14, 25, 277, 3, 26, 3, 26, 7, 26, 282, 10, 26, 12, 26, 14, 26, 285, 11, 26, 3, 27, 3, 27, 7, 27, 289, 10, 27, 12, 27, 14, 27, 292, 11, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 64, 5, 64, 372, 10, 64, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 66, 3, 66, 3, 67, 6, 67, 383, 10, 67, 13, 67, 14, 67, 384, 3, 67, 3, 67, 3, 68, 3, 68, 3, 68, 3, 68, 7, 68, 393, 10, 68, 12, 68, 14, 68, 396, 11, 68, 3, 68, 5, 68, 399, 10, 68, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 6, 70, 413, 10, 70, 13, 70, 14, 70, 414, 5, 70, 417, 10, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 72, 7, 72, 427, 10, 72, 12, 72, 14, 72, 430, 11, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 437, 10, 73, 12, 73, 14, 73, 440, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 3, 74, 7, 74, 448, 10, 74, 12, 74, 14, 74, 451, 11, 74, 3, 74, 3, 74, 3, 414, 2, 75, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 2, 49, 24, 51, 25, 53, 26, 55, 27, 57, 28, 59, 29, 61, 30, 63, 31, 65, 32, 67, 33, 69, 34, 71, 35, 73, 36, 75, 37, 77, 38, 79, 39, 81, 40, 83, 41, 85, 42, 87, 43, 89, 44, 91, 45, 93, 46, 95, 2, 97, 2, 99, 2, 101, 2, 103, 2, 105, 2, 107, 2, 109, 2, 111, 2, 113, 2, 115, 2, 117, 2, 119, 2, 121, 2, 123, 2, 125, 2, 127, 2, 129, 2, 131, 2, 133, 2, 135, 47, 137, 48, 139, 49, 141, 50, 143, 51, 145, 52, 147, 53, 149, 54, 5, 2, 3, 4, 28, 5, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 446, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 87, 3, 2, 2, 2, 2, 89, 3, 2, 2, 2, 2, 91, 3, 2, 2, 2, 2, 93, 3, 2, 2, 2, 2, 135, 3, 2, 2, 2, 2, 137, 3, 2, 2, 2, 2, 139, 3, 2, 2, 2, 3, 141, 3, 2, 2, 2, 3, 143, 3, 2, 2, 2, 4, 145, 3, 2, 2, 2, 4, 147, 3, 2, 2, 2, 4, 149, 3, 2, 2, 2, 5, 151, 3, 2, 2, 2, 7, 157, 3, 2, 2, 2, 9, 162, 3, 2, 2, 2, 11, 168, 3, 2, 2, 2, 13, 171, 3, 2, 2, 2, 15, 174, 3, 2, 2, 2, 17, 177, 3, 2, 2, 2, 19, 186, 3, 2, 2, 2, 21, 193, 3, 2, 2, 2, 23, 197, 3, 2, 2, 2, 25, 202, 3, 2, 2, 2, 27, 207, 3, 2, 2, 2, 29, 212, 3, 2, 2, 2, 31, 218, 3, 2, 2, 2, 33, 223, 3, 2, 2, 2, 35, 228, 3, 2, 2, 2, 37, 232, 3, 2, 2, 2, 39, 235, 3, 2, 2, 2, 41, 239, 3, 2, 2, 2, 43, 246, 3, 2, 2, 2, 45, 248, 3, 2, 2, 2, 47, 259, 3, 2, 2, 2, 49, 261, 3, 2, 2, 2, 51, 275, 3, 2, 2, 2, 53, 279, 3, 2, 2, 2, 55, 286, 3, 2, 2, 2, 57, 293, 3, 2, 2, 2, 59, 296, 3, 2, 2, 2, 61, 299, 3, 2, 2, 2, 63, 301, 3, 2, 2, 2, 65, 303, 3, 2, 2, 2, 67, 305, 3, 2, 2, 2, 69, 307, 3, 2, 2, 2, 71, 309, 3, 2, 2, 2, 73, 312, 3, 2, 2, 2, 75, 314, 3, 2, 2, 2, 77, 316, 3, 2, 2, 2, 79, 318, 3, 2, 2, 2, 81, 320, 3, 2, 2, 2, 83, 322, 3, 2, 2, 2, 85, 324, 3, 2, 2, 2, 87, 326, 3, 2, 2, 2, 89, 328, 3, 2, 2, 2, 91, 330, 3, 2, 2, 2, 93, 332, 3, 2, 2, 2, 95, 334, 3, 2, 2, 2, 97, 336, 3, 2, 2, 2, 99, 338, 3, 2, 2, 2, 101, 340, 3, 2, 2, 2, 103, 342, 3, 2, 2, 2, 105, 344, 3, 2, 2, 2, 107, 346, 3, 2, 2, 2, 109, 348, 3, 2, 2, 2, 111, 350, 3, 2, 2, 2, 113, 352, 3, 2, 2, 2, 115, 354, 3, 2, 2, 2, 117, 356, 3, 2, 2, 2, 119, 358, 3, 2, 2, 2, 121, 360, 3, 2, 2, 2, 123, 362, 3, 2, 2, 2, 125, 364, 3, 2, 2, 2, 127, 366, 3, 2, 2, 2, 129, 368, 3, 2, 2, 2, 131, 373, 3, 2, 2, 2, 133, 379, 3, 2, 2, 2, 135, 382, 3, 2, 2, 2, 137, 388, 3, 2, 2, 2, 139, 402, 3, 2, 2, 2, 141, 416, 3, 2, 2, 2, 143, 420, 3, 2, 2, 2, 145, 428, 3, 2, 2, 2, 147, 438, 3, 2, 2, 2, 149, 445, 3, 2, 2, 2, 151, 152, 5, 97, 48, 2, 152, 153, 5, 109, 54, 2, 153, 154, 5, 95, 47, 2, 154, 155, 5, 119, 59, 2, 155, 156, 5, 119, 59, 2, 156, 6, 3, 2, 2, 2, 157, 158, 5, 101, 50, 2, 158, 159, 5, 109, 54, 2, 159, 160, 5, 119, 59, 2, 160, 161, 5, 101, 50, 2, 161, 8, 3, 2, 2, 2, 162, 163, 7, 104, 2, 2, 163, 164, 5, 95, 47, 2, 164, 165, 5, 109, 54, 2, 165, 166, 5, 119, 59, 2, 166, 167, 5, 101, 50, 2, 167, 10, 3, 2, 2, 2, 168, 169, 5, 103, 51, 2, 169, 170, 5, 107, 53, 2, 170, 12, 3, 2, 2, 2, 171, 172, 5, 107, 53, 2, 172, 173, 5, 103, 51, 2, 173, 14, 3, 2, 2, 2, 174, 175, 5, 107, 53, 2, 175, 176, 5, 111, 55, 2, 176, 16, 3, 2, 2, 2, 177, 178, 5, 107, 53, 2, 178, 179, 5, 111, 55, 2, 179, 180, 5, 105, 52, 2, 180, 181, 5, 101, 50, 2, 181, 182, 5, 117, 58, 2, 182, 183, 5, 107, 53, 2, 183, 184, 5, 121, 60, 2, 184, 185, 5, 119, 59, 2, 185, 18, 3, 2, 2, 2, 186, 187, 5, 107, 53, 2, 187, 188, 5, 119, 59, 2, 188, 189, 5, 125, 62, 2, 189, 190, 5, 113, 56, 2, 190, 191, 5, 107, 53, 2, 191, 192, 5, 99, 49, 2, 192, 20, 3, 2, 2, 2, 193, 194, 5, 109, 54, 2, 194, 195, 5, 101, 50, 2, 195, 196, 5, 121, 60, 2, 196, 22, 3, 2, 2, 2, 197, 198, 5, 109, 54, 2, 198, 199, 5, 113, 56, 2, 199, 200, 5, 113, 56, 2, 200, 201, 5, 115, 57, 2, 201, 24, 3, 2, 2, 2, 202, 203, 5, 115, 57, 2, 203, 204, 5, 113, 56, 2, 204, 205, 5, 113, 56, 2, 205, 206, 5, 109, 54, 2, 206, 26, 3, 2, 2, 2, 207, 208, 5, 121, 60, 2, 208, 209, 5, 105, 52, 2, 209, 210, 5, 101, 50, 2, 210, 211, 5, 111, 55, 2, 211, 28, 3, 2, 2, 2, 212, 213, 5, 127, 63, 2, 213, 214, 5, 105, 52, 2, 214, 215, 5, 107, 53, 2, 215, 216, 5, 109, 54, 2, 216, 217, 5, 101, 50, 2, 217, 30, 3, 2, 2, 2, 218, 219, 5, 97, 48, 2, 219, 220, 5, 95, 47, 2, 220, 221, 5, 119, 59, 2, 221, 222, 5, 101, 50, 2, 222, 32, 3, 2, 2, 2, 223, 224, 5, 101, 50, 2, 224, 225, 5, 119, 59, 2, 225, 226, 5, 95, 47, 2, 226, 227, 5, 97, 48, 2, 227, 34, 3, 2, 2, 2, 228, 229, 5, 111, 55, 2, 229, 230, 5, 101, 50, 2, 230, 231, 5, 127, 63, 2, 231, 36, 3, 2, 2, 2, 232, 233, 5, 113, 56, 2, 233, 234, 5, 103, 51, 2, 234, 38, 3, 2, 2, 2, 235, 236, 5, 111, 55, 2, 236, 237, 5, 113, 56, 2, 237, 238, 5, 121, 60, 2, 238, 40, 3, 2, 2, 2, 239, 240, 7, 118, 2, 2, 240, 241, 5, 117, 58, 2, 241, 242, 5, 123, 61, 2, 242, 243, 5, 101, 50, 2, 243, 42, 3, 2, 2, 2, 244, 247, 5, 45, 22, 2, 245, 247, 5, 149, 74, 2, 246, 244, 3, 2, 2, 2, 246, 245, 3, 2, 2, 2, 247, 44, 3, 2, 2, 2, 248, 252, 7, 36, 2, 2, 249, 251, 5, 47, 23, 2, 250, 249, 3, 2, 2, 2, 251, 254, 3, 2, 2, 2, 252, 250, 3, 2, 2, 2, 252, 253, 3, 2, 2, 2, 253, 255, 3, 2, 2, 2, 254, 252, 3, 2, 2, 2, 255, 256, 7, 36, 2, 2, 256, 46, 3, 2, 2, 2, 257, 260, 5, 129, 64, 2, 258, 260, 10, 2, 2, 2, 259, 257, 3, 2, 2, 2, 259, 258, 3, 2, 2, 2, 260, 48, 3, 2, 2, 2, 261, 265, 7, 36, 2, 2, 262, 264, 5, 47, 23, 2, 263, 262, 3, 2, 2, 2, 264, 267, 3, 2, 2, 2, 265, 263, 3, 2, 2, 2, 265, 266, 3, 2, 2, 2, 266, 268, 3, 2, 2, 2, 267, 265, 3, 2, 2, 2, 268, 269, 7, 94, 2, 2, 269, 270, 7, 15, 2, 2, 270, 271, 7, 12, 2, 2, 271, 272, 3, 2, 2, 2, 272, 273, 8, 24, 2, 2, 273, 50, 3, 2, 2, 2, 274, 276, 9, 3, 2, 2, 275, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 275, 3, 2, 2, 2, 277, 278, 3, 2, 2, 2, 278, 52, 3, 2, 2, 2, 279, 283, 9, 4, 2, 2, 280, 282, 9, 5, 2, 2, 281, 280, 3, 2, 2, 2, 282, 285, 3, 2, 2, 2, 283, 281, 3, 2, 2, 2, 283, 284, 3, 2, 2, 2, 284, 54, 3, 2, 2, 2, 285, 283, 3, 2, 2, 2, 286, 290, 9, 6, 2, 2, 287, 289, 9, 5, 2, 2, 288, 287, 3, 2, 2, 2, 289, 292, 3, 2, 2, 2, 290, 288, 3, 2, 2, 2, 290, 291, 3, 2, 2, 2, 291, 56, 3, 2, 2, 2, 292, 290, 3, 2, 2, 2, 293, 294, 7, 62, 2, 2, 294, 295, 7, 47, 2, 2, 295, 58, 3, 2, 2, 2, 296, 297, 7, 63, 2, 2, 297, 298, 7, 64, 2, 2, 298, 60, 3, 2, 2, 2, 299, 300, 7, 45, 2, 2, 300, 62, 3, 2, 2, 2, 301, 302, 7, 47, 2, 2, 302, 64, 3, 2, 2, 2, 303, 304, 7, 44, 2, 2, 304, 66, 3, 2, 2, 2, 305, 306, 7, 49, 2, 2, 306, 68, 3, 2, 2, 2, 307, 308, 7, 62, 2, 2, 308, 70, 3, 2, 2, 2, 309, 310, 7, 62, 2, 2, 310, 311, 7, 63, 2, 2, 311, 72, 3, 2, 2, 2, 312, 313, 7, 63, 2, 2, 313, 74, 3, 2, 2, 2, 314, 315, 7, 128, 2, 2, 315, 76, 3, 2, 2, 2, 316, 317, 7, 42, 2, 2, 317, 78, 3, 2, 2, 2, 318, 319, 7, 43, 2, 2, 319, 80, 3, 2, 2, 2, 320, 321, 7, 125, 2, 2, 321, 82, 3, 2, 2, 2, 322, 323, 7, 127, 2, 2, 323, 84, 3, 2, 2, 2, 324, 325, 7, 66, 2, 2, 325, 86, 3, 2, 2, 2, 326, 327, 7, 48, 2, 2, 327, 88, 3, 2, 2, 2, 328, 329, 7, 46, 2, 2, 329, 90, 3, 2, 2, 2, 330, 331, 7, 60, 2, 2, 331, 92, 3, 2, 2, 2, 332, 333, 7, 61, 2, 2, 333, 94, 3, 2, 2, 2, 334, 335, 9, 7, 2, 2, 335, 96, 3, 2, 2, 2, 336, 337, 9, 8, 2, 2, 337, 98, 3, 2, 2, 2, 338, 339, 9, 9, 2, 2, 339, 100, 3, 2, 2, 2, 340, 341, 9, 10, 2, 2, 341, 102, 3, 2, 2, 2, 342, 343, 9, 11, 2, 2, 343, 104, 3, 2, 2, 2, 344, 345, 9, 12, 2, 2, 345, 106, 3, 2, 2, 2, 346, 347, 9, 13, 2, 2, 347, 108, 3, 2, 2, 2, 348, 349, 9, 14, 2, 2, 349, 110, 3, 2, 2, 2, 350, 351, 9, 15, 2, 2, 351, 112, 3, 2, 2, 2, 352, 353, 9, 16, 2, 2, 353, 114, 3, 2, 2, 2, 354, 355, 9, 17, 2, 2, 355, 116, 3, 2, 2, 2, 356, 357, 9, 18, 2, 2, 357, 118, 3, 2, 2, 2, 358, 359, 9, 19, 2, 2, 359, 120, 3, 2, 2, 2, 360, 361, 9, 20, 2, 2, 361, 122, 3, 2, 2, 2, 362, 363, 9, 21, 2, 2, 363, 124, 3, 2, 2, 2, 364, 365, 9, 22, 2, 2, 365, 126, 3, 2, 2, 2, 366, 367, 9, 23, 2, 2, 367, 128, 3, 2, 2, 2, 368, 371, 7, 94, 2, 2, 369, 372, 9, 24, 2, 2, 370, 372, 5, 131, 65, 2, 371, 369, 3, 2, 2, 2, 371, 370, 3, 2, 2, 2, 372, 130, 3, 2, 2, 2, 373, 374, 7, 119, 2, 2, 374, 375, 5, 133, 66, 2, 375, 376, 5, 133, 66, 2, 376, 377, 5, 133, 66, 2, 377, 378, 5, 133, 66, 2, 378, 132, 3, 2, 2, 2, 379, 380, 9, 25, 2, 2, 380, 134, 3, 2, 2, 2, 381, 383, 9, 26, 2, 2, 382, 381, 3, 2, 2, 2, 383, 384, 3, 2, 2, 2, 384, 382, 3, 2, 2, 2, 384, 385, 3, 2, 2, 2, 385, 386, 3, 2, 2, 2, 386, 387, 8, 67, 3, 2, 387, 136, 3, 2, 2, 2, 388, 389, 7, 47, 2, 2, 389, 390, 7, 47, 2, 2, 390, 394, 3, 2, 2, 2, 391, 393, 10, 27, 2, 2, 392, 391, 3, 2, 2, 2, 393, 396, 3, 2, 2, 2, 394, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 398, 3, 2, 2, 2, 396, 394, 3, 2, 2, 2, 397, 399, 7, 12, 2, 2, 398, 397, 3, 2, 2, 2, 398, 399, 3, 2, 2, 2, 399, 400, 3, 2, 2, 2, 400, 401, 8, 68, 3, 2, 401, 138, 3, 2, 2, 2, 402, 403, 7, 42, 2, 2, 403, 404, 7, 44, 2, 2, 404, 405, 3, 2, 2, 2, 405, 406, 8, 69, 4, 2, 406, 140, 3, 2, 2, 2, 407, 408, 5, 139, 69, 2, 408, 409, 5, 141, 70, 2, 409, 410, 5, 143, 71, 2, 410, 417, 3, 2, 2, 2, 411, 413, 11, 2, 2, 2, 412, 411, 3, 2, 2, 2, 413, 414, 3, 2, 2, 2, 414, 415, 3, 2, 2, 2, 414, 412, 3, 2, 2, 2, 415, 417, 3, 2, 2, 2, 416, 407, 3, 2, 2, 2, 416, 412, 3, 2, 2, 2, 417, 418, 3, 2, 2, 2, 418, 419, 8, 70, 3, 2, 419, 142, 3, 2, 2, 2, 420, 421, 7, 44, 2, 2, 421, 422, 7, 43, 2, 2, 422, 423, 3, 2, 2, 2, 423, 424, 8, 71, 5, 2, 424, 144, 3, 2, 2, 2, 425, 427, 5, 47, 23, 2, 426, 425, 3, 2, 2, 2, 427, 430, 3, 2, 2, 2, 428, 426, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 431, 3, 2, 2, 2, 430, 428, 3, 2, 2, 2, 431, 432, 7, 94, 2, 2, 432, 433, 7, 15, 2, 2, 433, 434, 7, 12, 2, 2, 434, 146, 3, 2, 2, 2, 435, 437, 5, 47, 23, 2, 436, 435, 3, 2, 2, 2, 437, 440, 3, 2, 2, 2, 438, 436, 3, 2, 2, 2, 438, 439, 3, 2, 2, 2, 439, 441, 3, 2, 2, 2, 440, 438, 3, 2, 2, 2, 441, 442, 7, 36, 2, 2, 442, 443, 3, 2, 2, 2, 443, 444, 8, 73, 5, 2, 444, 148, 3, 2, 2, 2, 445, 449, 5, 49, 24, 2, 446, 448, 5, 145, 72, 2, 447, 446, 3, 2, 2, 2, 448, 451, 3, 2, 2, 2, 449, 447, 3, 2, 2, 2, 449, 450, 3, 2, 2, 2, 450, 452, 3, 2, 2, 2, 451, 449, 3, 2, 2, 2, 452, 453, 5, 147, 73, 2, 453, 150, 3, 2, 2, 2, 21, 2, 3, 4, 246, 252, 259, 265, 277, 283, 290, 371, 384, 394, 398, 414, 416, 428, 438, 449, 6, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file diff --git a/src/COOL_LEX.py b/src/COOL_LEX.py index b5bb708c..c2fb0dc6 100644 --- a/src/COOL_LEX.py +++ b/src/COOL_LEX.py @@ -8,179 +8,202 @@ def serializedATN(): with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\62") - buf.write("\u0196\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6") - buf.write("\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r") - buf.write("\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22") - buf.write("\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30") - buf.write("\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35") - buf.write("\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\4") - buf.write("%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t,\4-\t") - buf.write("-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63") - buf.write("\4\64\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4") - buf.write(":\t:\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4") - buf.write("C\tC\4D\tD\4E\tE\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3") - buf.write("\3\3\3\3\4\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\6\3\6\3\6") - buf.write("\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3") - buf.write("\t\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\13") - buf.write("\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\16") - buf.write("\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20") - buf.write("\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\22\3\22\3\22") - buf.write("\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\25\3\25") - buf.write("\3\25\3\25\7\25\u00ee\n\25\f\25\16\25\u00f1\13\25\3\25") - buf.write("\3\25\3\26\3\26\3\26\3\26\3\26\3\26\3\26\5\26\u00fc\n") - buf.write("\26\3\27\6\27\u00ff\n\27\r\27\16\27\u0100\3\30\3\30\7") - buf.write("\30\u0105\n\30\f\30\16\30\u0108\13\30\3\31\3\31\7\31\u010c") - buf.write("\n\31\f\31\16\31\u010f\13\31\3\32\3\32\3\32\3\33\3\33") - buf.write("\3\33\3\34\3\34\3\35\3\35\3\36\3\36\3\37\3\37\3 \3 \3") - buf.write("!\3!\3!\3\"\3\"\3#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(") - buf.write("\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3\60\3") - buf.write("\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65\3\66") - buf.write("\3\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<\3<\3=\3=\3") - buf.write(">\3>\3>\5>\u015f\n>\3?\3?\3?\3?\3?\3?\3@\3@\3A\6A\u016a") - buf.write("\nA\rA\16A\u016b\3A\3A\3B\3B\3B\3B\7B\u0174\nB\fB\16B") - buf.write("\u0177\13B\3B\5B\u017a\nB\3B\3B\3C\3C\3C\3C\3C\3C\3D\3") - buf.write("D\3D\3D\3D\6D\u0189\nD\rD\16D\u018a\5D\u018d\nD\3D\3D") - buf.write("\3E\3E\3E\3E\3E\3E\3\u018a\2F\4\3\6\4\b\5\n\6\f\7\16\b") - buf.write("\20\t\22\n\24\13\26\f\30\r\32\16\34\17\36\20 \21\"\22") - buf.write("$\23&\24(\25*\26,\27.\30\60\31\62\32\64\33\66\348\35:") - buf.write("\36<\37> @!B\"D#F$H%J&L\'N(P)R*T+V,X-Z\2\\\2^\2`\2b\2") - buf.write("d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2|\2~\2\u0080\2\u0082") - buf.write(".\u0084/\u0086\60\u0088\61\u008a\62\4\2\3\34\6\2\f\f\17") - buf.write("\17$$^^\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4") - buf.write("\2EEee\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNn") - buf.write("n\4\2PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2") - buf.write("WWww\4\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;C") - buf.write("Hch\5\2\13\f\16\17\"\"\3\2\f\f\2\u018e\2\4\3\2\2\2\2\6") - buf.write("\3\2\2\2\2\b\3\2\2\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16\3\2") - buf.write("\2\2\2\20\3\2\2\2\2\22\3\2\2\2\2\24\3\2\2\2\2\26\3\2\2") - buf.write("\2\2\30\3\2\2\2\2\32\3\2\2\2\2\34\3\2\2\2\2\36\3\2\2\2") - buf.write("\2 \3\2\2\2\2\"\3\2\2\2\2$\3\2\2\2\2&\3\2\2\2\2(\3\2\2") - buf.write("\2\2*\3\2\2\2\2,\3\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2\62") - buf.write("\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\28\3\2\2\2\2:\3\2\2") - buf.write("\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2\2\2\2B\3\2\2\2\2D\3\2") - buf.write("\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3\2\2\2\2L\3\2\2\2\2N\3") - buf.write("\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2\2\2\2V\3\2\2\2\2X") - buf.write("\3\2\2\2\2\u0082\3\2\2\2\2\u0084\3\2\2\2\2\u0086\3\2\2") - buf.write("\2\3\u0088\3\2\2\2\3\u008a\3\2\2\2\4\u008c\3\2\2\2\6\u0092") - buf.write("\3\2\2\2\b\u0097\3\2\2\2\n\u009d\3\2\2\2\f\u00a0\3\2\2") - buf.write("\2\16\u00a3\3\2\2\2\20\u00a6\3\2\2\2\22\u00af\3\2\2\2") - buf.write("\24\u00b6\3\2\2\2\26\u00ba\3\2\2\2\30\u00bf\3\2\2\2\32") - buf.write("\u00c4\3\2\2\2\34\u00c9\3\2\2\2\36\u00cf\3\2\2\2 \u00d4") - buf.write("\3\2\2\2\"\u00d9\3\2\2\2$\u00dd\3\2\2\2&\u00e0\3\2\2\2") - buf.write("(\u00e4\3\2\2\2*\u00e9\3\2\2\2,\u00fb\3\2\2\2.\u00fe\3") - buf.write("\2\2\2\60\u0102\3\2\2\2\62\u0109\3\2\2\2\64\u0110\3\2") - buf.write("\2\2\66\u0113\3\2\2\28\u0116\3\2\2\2:\u0118\3\2\2\2<\u011a") - buf.write("\3\2\2\2>\u011c\3\2\2\2@\u011e\3\2\2\2B\u0120\3\2\2\2") - buf.write("D\u0123\3\2\2\2F\u0125\3\2\2\2H\u0127\3\2\2\2J\u0129\3") - buf.write("\2\2\2L\u012b\3\2\2\2N\u012d\3\2\2\2P\u012f\3\2\2\2R\u0131") - buf.write("\3\2\2\2T\u0133\3\2\2\2V\u0135\3\2\2\2X\u0137\3\2\2\2") - buf.write("Z\u0139\3\2\2\2\\\u013b\3\2\2\2^\u013d\3\2\2\2`\u013f") - buf.write("\3\2\2\2b\u0141\3\2\2\2d\u0143\3\2\2\2f\u0145\3\2\2\2") - buf.write("h\u0147\3\2\2\2j\u0149\3\2\2\2l\u014b\3\2\2\2n\u014d\3") - buf.write("\2\2\2p\u014f\3\2\2\2r\u0151\3\2\2\2t\u0153\3\2\2\2v\u0155") - buf.write("\3\2\2\2x\u0157\3\2\2\2z\u0159\3\2\2\2|\u015b\3\2\2\2") - buf.write("~\u0160\3\2\2\2\u0080\u0166\3\2\2\2\u0082\u0169\3\2\2") - buf.write("\2\u0084\u016f\3\2\2\2\u0086\u017d\3\2\2\2\u0088\u018c") - buf.write("\3\2\2\2\u008a\u0190\3\2\2\2\u008c\u008d\5\\.\2\u008d") - buf.write("\u008e\5h\64\2\u008e\u008f\5Z-\2\u008f\u0090\5r9\2\u0090") - buf.write("\u0091\5r9\2\u0091\5\3\2\2\2\u0092\u0093\5`\60\2\u0093") - buf.write("\u0094\5h\64\2\u0094\u0095\5r9\2\u0095\u0096\5`\60\2\u0096") - buf.write("\7\3\2\2\2\u0097\u0098\7h\2\2\u0098\u0099\5Z-\2\u0099") - buf.write("\u009a\5h\64\2\u009a\u009b\5r9\2\u009b\u009c\5`\60\2\u009c") - buf.write("\t\3\2\2\2\u009d\u009e\5b\61\2\u009e\u009f\5f\63\2\u009f") - buf.write("\13\3\2\2\2\u00a0\u00a1\5f\63\2\u00a1\u00a2\5b\61\2\u00a2") - buf.write("\r\3\2\2\2\u00a3\u00a4\5f\63\2\u00a4\u00a5\5j\65\2\u00a5") - buf.write("\17\3\2\2\2\u00a6\u00a7\5f\63\2\u00a7\u00a8\5j\65\2\u00a8") - buf.write("\u00a9\5d\62\2\u00a9\u00aa\5`\60\2\u00aa\u00ab\5p8\2\u00ab") - buf.write("\u00ac\5f\63\2\u00ac\u00ad\5t:\2\u00ad\u00ae\5r9\2\u00ae") - buf.write("\21\3\2\2\2\u00af\u00b0\5f\63\2\u00b0\u00b1\5r9\2\u00b1") - buf.write("\u00b2\5x<\2\u00b2\u00b3\5l\66\2\u00b3\u00b4\5f\63\2\u00b4") - buf.write("\u00b5\5^/\2\u00b5\23\3\2\2\2\u00b6\u00b7\5h\64\2\u00b7") - buf.write("\u00b8\5`\60\2\u00b8\u00b9\5t:\2\u00b9\25\3\2\2\2\u00ba") - buf.write("\u00bb\5h\64\2\u00bb\u00bc\5l\66\2\u00bc\u00bd\5l\66\2") - buf.write("\u00bd\u00be\5n\67\2\u00be\27\3\2\2\2\u00bf\u00c0\5n\67") - buf.write("\2\u00c0\u00c1\5l\66\2\u00c1\u00c2\5l\66\2\u00c2\u00c3") - buf.write("\5h\64\2\u00c3\31\3\2\2\2\u00c4\u00c5\5t:\2\u00c5\u00c6") - buf.write("\5d\62\2\u00c6\u00c7\5`\60\2\u00c7\u00c8\5j\65\2\u00c8") - buf.write("\33\3\2\2\2\u00c9\u00ca\5z=\2\u00ca\u00cb\5d\62\2\u00cb") - buf.write("\u00cc\5f\63\2\u00cc\u00cd\5h\64\2\u00cd\u00ce\5`\60\2") - buf.write("\u00ce\35\3\2\2\2\u00cf\u00d0\5\\.\2\u00d0\u00d1\5Z-\2") - buf.write("\u00d1\u00d2\5r9\2\u00d2\u00d3\5`\60\2\u00d3\37\3\2\2") - buf.write("\2\u00d4\u00d5\5`\60\2\u00d5\u00d6\5r9\2\u00d6\u00d7\5") - buf.write("Z-\2\u00d7\u00d8\5\\.\2\u00d8!\3\2\2\2\u00d9\u00da\5j") - buf.write("\65\2\u00da\u00db\5`\60\2\u00db\u00dc\5z=\2\u00dc#\3\2") - buf.write("\2\2\u00dd\u00de\5l\66\2\u00de\u00df\5b\61\2\u00df%\3") - buf.write("\2\2\2\u00e0\u00e1\5j\65\2\u00e1\u00e2\5l\66\2\u00e2\u00e3") - buf.write("\5t:\2\u00e3\'\3\2\2\2\u00e4\u00e5\7v\2\2\u00e5\u00e6") - buf.write("\5p8\2\u00e6\u00e7\5v;\2\u00e7\u00e8\5`\60\2\u00e8)\3") - buf.write("\2\2\2\u00e9\u00ef\7$\2\2\u00ea\u00ee\5|>\2\u00eb\u00ee") - buf.write("\5,\26\2\u00ec\u00ee\n\2\2\2\u00ed\u00ea\3\2\2\2\u00ed") - buf.write("\u00eb\3\2\2\2\u00ed\u00ec\3\2\2\2\u00ee\u00f1\3\2\2\2") - buf.write("\u00ef\u00ed\3\2\2\2\u00ef\u00f0\3\2\2\2\u00f0\u00f2\3") - buf.write("\2\2\2\u00f1\u00ef\3\2\2\2\u00f2\u00f3\7$\2\2\u00f3+\3") - buf.write("\2\2\2\u00f4\u00f5\7^\2\2\u00f5\u00f6\7\17\2\2\u00f6\u00fc") - buf.write("\7\f\2\2\u00f7\u00f8\7^\2\2\u00f8\u00fc\7\17\2\2\u00f9") - buf.write("\u00fa\7^\2\2\u00fa\u00fc\7\f\2\2\u00fb\u00f4\3\2\2\2") - buf.write("\u00fb\u00f7\3\2\2\2\u00fb\u00f9\3\2\2\2\u00fc-\3\2\2") - buf.write("\2\u00fd\u00ff\t\3\2\2\u00fe\u00fd\3\2\2\2\u00ff\u0100") - buf.write("\3\2\2\2\u0100\u00fe\3\2\2\2\u0100\u0101\3\2\2\2\u0101") - buf.write("/\3\2\2\2\u0102\u0106\t\4\2\2\u0103\u0105\t\5\2\2\u0104") - buf.write("\u0103\3\2\2\2\u0105\u0108\3\2\2\2\u0106\u0104\3\2\2\2") - buf.write("\u0106\u0107\3\2\2\2\u0107\61\3\2\2\2\u0108\u0106\3\2") - buf.write("\2\2\u0109\u010d\t\6\2\2\u010a\u010c\t\5\2\2\u010b\u010a") - buf.write("\3\2\2\2\u010c\u010f\3\2\2\2\u010d\u010b\3\2\2\2\u010d") - buf.write("\u010e\3\2\2\2\u010e\63\3\2\2\2\u010f\u010d\3\2\2\2\u0110") - buf.write("\u0111\7>\2\2\u0111\u0112\7/\2\2\u0112\65\3\2\2\2\u0113") - buf.write("\u0114\7?\2\2\u0114\u0115\7@\2\2\u0115\67\3\2\2\2\u0116") - buf.write("\u0117\7-\2\2\u01179\3\2\2\2\u0118\u0119\7/\2\2\u0119") - buf.write(";\3\2\2\2\u011a\u011b\7,\2\2\u011b=\3\2\2\2\u011c\u011d") - buf.write("\7\61\2\2\u011d?\3\2\2\2\u011e\u011f\7>\2\2\u011fA\3\2") - buf.write("\2\2\u0120\u0121\7>\2\2\u0121\u0122\7?\2\2\u0122C\3\2") - buf.write("\2\2\u0123\u0124\7?\2\2\u0124E\3\2\2\2\u0125\u0126\7\u0080") - buf.write("\2\2\u0126G\3\2\2\2\u0127\u0128\7*\2\2\u0128I\3\2\2\2") - buf.write("\u0129\u012a\7+\2\2\u012aK\3\2\2\2\u012b\u012c\7}\2\2") - buf.write("\u012cM\3\2\2\2\u012d\u012e\7\177\2\2\u012eO\3\2\2\2\u012f") - buf.write("\u0130\7B\2\2\u0130Q\3\2\2\2\u0131\u0132\7\60\2\2\u0132") - buf.write("S\3\2\2\2\u0133\u0134\7.\2\2\u0134U\3\2\2\2\u0135\u0136") - buf.write("\7<\2\2\u0136W\3\2\2\2\u0137\u0138\7=\2\2\u0138Y\3\2\2") - buf.write("\2\u0139\u013a\t\7\2\2\u013a[\3\2\2\2\u013b\u013c\t\b") - buf.write("\2\2\u013c]\3\2\2\2\u013d\u013e\t\t\2\2\u013e_\3\2\2\2") - buf.write("\u013f\u0140\t\n\2\2\u0140a\3\2\2\2\u0141\u0142\t\13\2") - buf.write("\2\u0142c\3\2\2\2\u0143\u0144\t\f\2\2\u0144e\3\2\2\2\u0145") - buf.write("\u0146\t\r\2\2\u0146g\3\2\2\2\u0147\u0148\t\16\2\2\u0148") - buf.write("i\3\2\2\2\u0149\u014a\t\17\2\2\u014ak\3\2\2\2\u014b\u014c") - buf.write("\t\20\2\2\u014cm\3\2\2\2\u014d\u014e\t\21\2\2\u014eo\3") - buf.write("\2\2\2\u014f\u0150\t\22\2\2\u0150q\3\2\2\2\u0151\u0152") - buf.write("\t\23\2\2\u0152s\3\2\2\2\u0153\u0154\t\24\2\2\u0154u\3") - buf.write("\2\2\2\u0155\u0156\t\25\2\2\u0156w\3\2\2\2\u0157\u0158") - buf.write("\t\26\2\2\u0158y\3\2\2\2\u0159\u015a\t\27\2\2\u015a{\3") - buf.write("\2\2\2\u015b\u015e\7^\2\2\u015c\u015f\t\30\2\2\u015d\u015f") - buf.write("\5~?\2\u015e\u015c\3\2\2\2\u015e\u015d\3\2\2\2\u015f}") - buf.write("\3\2\2\2\u0160\u0161\7w\2\2\u0161\u0162\5\u0080@\2\u0162") - buf.write("\u0163\5\u0080@\2\u0163\u0164\5\u0080@\2\u0164\u0165\5") - buf.write("\u0080@\2\u0165\177\3\2\2\2\u0166\u0167\t\31\2\2\u0167") - buf.write("\u0081\3\2\2\2\u0168\u016a\t\32\2\2\u0169\u0168\3\2\2") - buf.write("\2\u016a\u016b\3\2\2\2\u016b\u0169\3\2\2\2\u016b\u016c") - buf.write("\3\2\2\2\u016c\u016d\3\2\2\2\u016d\u016e\bA\2\2\u016e") - buf.write("\u0083\3\2\2\2\u016f\u0170\7/\2\2\u0170\u0171\7/\2\2\u0171") - buf.write("\u0175\3\2\2\2\u0172\u0174\n\33\2\2\u0173\u0172\3\2\2") - buf.write("\2\u0174\u0177\3\2\2\2\u0175\u0173\3\2\2\2\u0175\u0176") - buf.write("\3\2\2\2\u0176\u0179\3\2\2\2\u0177\u0175\3\2\2\2\u0178") - buf.write("\u017a\7\f\2\2\u0179\u0178\3\2\2\2\u0179\u017a\3\2\2\2") - buf.write("\u017a\u017b\3\2\2\2\u017b\u017c\bB\2\2\u017c\u0085\3") - buf.write("\2\2\2\u017d\u017e\7*\2\2\u017e\u017f\7,\2\2\u017f\u0180") - buf.write("\3\2\2\2\u0180\u0181\bC\2\2\u0181\u0182\bC\3\2\u0182\u0087") - buf.write("\3\2\2\2\u0183\u0184\5\u0086C\2\u0184\u0185\5\u0088D\2") - buf.write("\u0185\u0186\5\u008aE\2\u0186\u018d\3\2\2\2\u0187\u0189") - buf.write("\13\2\2\2\u0188\u0187\3\2\2\2\u0189\u018a\3\2\2\2\u018a") - buf.write("\u018b\3\2\2\2\u018a\u0188\3\2\2\2\u018b\u018d\3\2\2\2") - buf.write("\u018c\u0183\3\2\2\2\u018c\u0188\3\2\2\2\u018d\u018e\3") - buf.write("\2\2\2\u018e\u018f\bD\2\2\u018f\u0089\3\2\2\2\u0190\u0191") - buf.write("\7,\2\2\u0191\u0192\7+\2\2\u0192\u0193\3\2\2\2\u0193\u0194") - buf.write("\bE\2\2\u0194\u0195\bE\4\2\u0195\u008b\3\2\2\2\20\2\3") - buf.write("\u00ed\u00ef\u00fb\u0100\u0106\u010d\u015e\u016b\u0175") - buf.write("\u0179\u018a\u018c\5\b\2\2\7\3\2\6\2\2") + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\66") + buf.write("\u01c6\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6") + buf.write("\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f") + buf.write("\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22") + buf.write("\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27") + buf.write("\4\30\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35") + buf.write("\t\35\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4") + buf.write("$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t") + buf.write(",\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63") + buf.write("\t\63\4\64\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\4") + buf.write("9\t9\4:\t:\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA\4") + buf.write("B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I\tI\4J\tJ\3") + buf.write("\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\4\3\4\3\4") + buf.write("\3\4\3\4\3\4\3\5\3\5\3\5\3\6\3\6\3\6\3\7\3\7\3\7\3\b\3") + buf.write("\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t") + buf.write("\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3\f\3\f") + buf.write("\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3") + buf.write("\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20") + buf.write("\3\20\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\23\3\23\3\23") + buf.write("\3\23\3\24\3\24\3\24\3\24\3\24\3\25\3\25\5\25\u00f7\n") + buf.write("\25\3\26\3\26\7\26\u00fb\n\26\f\26\16\26\u00fe\13\26\3") + buf.write("\26\3\26\3\27\3\27\5\27\u0104\n\27\3\30\3\30\7\30\u0108") + buf.write("\n\30\f\30\16\30\u010b\13\30\3\30\3\30\3\30\3\30\3\30") + buf.write("\3\30\3\31\6\31\u0114\n\31\r\31\16\31\u0115\3\32\3\32") + buf.write("\7\32\u011a\n\32\f\32\16\32\u011d\13\32\3\33\3\33\7\33") + buf.write("\u0121\n\33\f\33\16\33\u0124\13\33\3\34\3\34\3\34\3\35") + buf.write("\3\35\3\35\3\36\3\36\3\37\3\37\3 \3 \3!\3!\3\"\3\"\3#") + buf.write("\3#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(\3)\3)\3*\3*\3+") + buf.write("\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3\60\3\61\3\61\3\62\3") + buf.write("\62\3\63\3\63\3\64\3\64\3\65\3\65\3\66\3\66\3\67\3\67") + buf.write("\38\38\39\39\3:\3:\3;\3;\3<\3<\3=\3=\3>\3>\3?\3?\3@\3") + buf.write("@\3@\5@\u0174\n@\3A\3A\3A\3A\3A\3A\3B\3B\3C\6C\u017f\n") + buf.write("C\rC\16C\u0180\3C\3C\3D\3D\3D\3D\7D\u0189\nD\fD\16D\u018c") + buf.write("\13D\3D\5D\u018f\nD\3D\3D\3E\3E\3E\3E\3E\3F\3F\3F\3F\3") + buf.write("F\6F\u019d\nF\rF\16F\u019e\5F\u01a1\nF\3F\3F\3G\3G\3G") + buf.write("\3G\3G\3H\7H\u01ab\nH\fH\16H\u01ae\13H\3H\3H\3H\3H\3I") + buf.write("\7I\u01b5\nI\fI\16I\u01b8\13I\3I\3I\3I\3I\3J\3J\7J\u01c0") + buf.write("\nJ\fJ\16J\u01c3\13J\3J\3J\3\u019e\2K\5\3\7\4\t\5\13\6") + buf.write("\r\7\17\b\21\t\23\n\25\13\27\f\31\r\33\16\35\17\37\20") + buf.write("!\21#\22%\23\'\24)\25+\26-\27/\2\61\30\63\31\65\32\67") + buf.write("\339\34;\35=\36?\37A C!E\"G#I$K%M&O\'Q(S)U*W+Y,[-]._\2") + buf.write("a\2c\2e\2g\2i\2k\2m\2o\2q\2s\2u\2w\2y\2{\2}\2\177\2\u0081") + buf.write("\2\u0083\2\u0085\2\u0087/\u0089\60\u008b\61\u008d\62\u008f") + buf.write("\63\u0091\64\u0093\65\u0095\66\5\2\3\4\34\5\2\f\f\17\17") + buf.write("$$\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEe") + buf.write("e\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2") + buf.write("PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4") + buf.write("\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2") + buf.write("\13\f\16\17\"\"\3\2\f\f\2\u01be\2\5\3\2\2\2\2\7\3\2\2") + buf.write("\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2") + buf.write("\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31") + buf.write("\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2") + buf.write("\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3") + buf.write("\2\2\2\2-\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2") + buf.write("\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3") + buf.write("\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I") + buf.write("\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2") + buf.write("S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2") + buf.write("\2]\3\2\2\2\2\u0087\3\2\2\2\2\u0089\3\2\2\2\2\u008b\3") + buf.write("\2\2\2\3\u008d\3\2\2\2\3\u008f\3\2\2\2\4\u0091\3\2\2\2") + buf.write("\4\u0093\3\2\2\2\4\u0095\3\2\2\2\5\u0097\3\2\2\2\7\u009d") + buf.write("\3\2\2\2\t\u00a2\3\2\2\2\13\u00a8\3\2\2\2\r\u00ab\3\2") + buf.write("\2\2\17\u00ae\3\2\2\2\21\u00b1\3\2\2\2\23\u00ba\3\2\2") + buf.write("\2\25\u00c1\3\2\2\2\27\u00c5\3\2\2\2\31\u00ca\3\2\2\2") + buf.write("\33\u00cf\3\2\2\2\35\u00d4\3\2\2\2\37\u00da\3\2\2\2!\u00df") + buf.write("\3\2\2\2#\u00e4\3\2\2\2%\u00e8\3\2\2\2\'\u00eb\3\2\2\2") + buf.write(")\u00ef\3\2\2\2+\u00f6\3\2\2\2-\u00f8\3\2\2\2/\u0103\3") + buf.write("\2\2\2\61\u0105\3\2\2\2\63\u0113\3\2\2\2\65\u0117\3\2") + buf.write("\2\2\67\u011e\3\2\2\29\u0125\3\2\2\2;\u0128\3\2\2\2=\u012b") + buf.write("\3\2\2\2?\u012d\3\2\2\2A\u012f\3\2\2\2C\u0131\3\2\2\2") + buf.write("E\u0133\3\2\2\2G\u0135\3\2\2\2I\u0138\3\2\2\2K\u013a\3") + buf.write("\2\2\2M\u013c\3\2\2\2O\u013e\3\2\2\2Q\u0140\3\2\2\2S\u0142") + buf.write("\3\2\2\2U\u0144\3\2\2\2W\u0146\3\2\2\2Y\u0148\3\2\2\2") + buf.write("[\u014a\3\2\2\2]\u014c\3\2\2\2_\u014e\3\2\2\2a\u0150\3") + buf.write("\2\2\2c\u0152\3\2\2\2e\u0154\3\2\2\2g\u0156\3\2\2\2i\u0158") + buf.write("\3\2\2\2k\u015a\3\2\2\2m\u015c\3\2\2\2o\u015e\3\2\2\2") + buf.write("q\u0160\3\2\2\2s\u0162\3\2\2\2u\u0164\3\2\2\2w\u0166\3") + buf.write("\2\2\2y\u0168\3\2\2\2{\u016a\3\2\2\2}\u016c\3\2\2\2\177") + buf.write("\u016e\3\2\2\2\u0081\u0170\3\2\2\2\u0083\u0175\3\2\2\2") + buf.write("\u0085\u017b\3\2\2\2\u0087\u017e\3\2\2\2\u0089\u0184\3") + buf.write("\2\2\2\u008b\u0192\3\2\2\2\u008d\u01a0\3\2\2\2\u008f\u01a4") + buf.write("\3\2\2\2\u0091\u01ac\3\2\2\2\u0093\u01b6\3\2\2\2\u0095") + buf.write("\u01bd\3\2\2\2\u0097\u0098\5a\60\2\u0098\u0099\5m\66\2") + buf.write("\u0099\u009a\5_/\2\u009a\u009b\5w;\2\u009b\u009c\5w;\2") + buf.write("\u009c\6\3\2\2\2\u009d\u009e\5e\62\2\u009e\u009f\5m\66") + buf.write("\2\u009f\u00a0\5w;\2\u00a0\u00a1\5e\62\2\u00a1\b\3\2\2") + buf.write("\2\u00a2\u00a3\7h\2\2\u00a3\u00a4\5_/\2\u00a4\u00a5\5") + buf.write("m\66\2\u00a5\u00a6\5w;\2\u00a6\u00a7\5e\62\2\u00a7\n\3") + buf.write("\2\2\2\u00a8\u00a9\5g\63\2\u00a9\u00aa\5k\65\2\u00aa\f") + buf.write("\3\2\2\2\u00ab\u00ac\5k\65\2\u00ac\u00ad\5g\63\2\u00ad") + buf.write("\16\3\2\2\2\u00ae\u00af\5k\65\2\u00af\u00b0\5o\67\2\u00b0") + buf.write("\20\3\2\2\2\u00b1\u00b2\5k\65\2\u00b2\u00b3\5o\67\2\u00b3") + buf.write("\u00b4\5i\64\2\u00b4\u00b5\5e\62\2\u00b5\u00b6\5u:\2\u00b6") + buf.write("\u00b7\5k\65\2\u00b7\u00b8\5y<\2\u00b8\u00b9\5w;\2\u00b9") + buf.write("\22\3\2\2\2\u00ba\u00bb\5k\65\2\u00bb\u00bc\5w;\2\u00bc") + buf.write("\u00bd\5}>\2\u00bd\u00be\5q8\2\u00be\u00bf\5k\65\2\u00bf") + buf.write("\u00c0\5c\61\2\u00c0\24\3\2\2\2\u00c1\u00c2\5m\66\2\u00c2") + buf.write("\u00c3\5e\62\2\u00c3\u00c4\5y<\2\u00c4\26\3\2\2\2\u00c5") + buf.write("\u00c6\5m\66\2\u00c6\u00c7\5q8\2\u00c7\u00c8\5q8\2\u00c8") + buf.write("\u00c9\5s9\2\u00c9\30\3\2\2\2\u00ca\u00cb\5s9\2\u00cb") + buf.write("\u00cc\5q8\2\u00cc\u00cd\5q8\2\u00cd\u00ce\5m\66\2\u00ce") + buf.write("\32\3\2\2\2\u00cf\u00d0\5y<\2\u00d0\u00d1\5i\64\2\u00d1") + buf.write("\u00d2\5e\62\2\u00d2\u00d3\5o\67\2\u00d3\34\3\2\2\2\u00d4") + buf.write("\u00d5\5\177?\2\u00d5\u00d6\5i\64\2\u00d6\u00d7\5k\65") + buf.write("\2\u00d7\u00d8\5m\66\2\u00d8\u00d9\5e\62\2\u00d9\36\3") + buf.write("\2\2\2\u00da\u00db\5a\60\2\u00db\u00dc\5_/\2\u00dc\u00dd") + buf.write("\5w;\2\u00dd\u00de\5e\62\2\u00de \3\2\2\2\u00df\u00e0") + buf.write("\5e\62\2\u00e0\u00e1\5w;\2\u00e1\u00e2\5_/\2\u00e2\u00e3") + buf.write("\5a\60\2\u00e3\"\3\2\2\2\u00e4\u00e5\5o\67\2\u00e5\u00e6") + buf.write("\5e\62\2\u00e6\u00e7\5\177?\2\u00e7$\3\2\2\2\u00e8\u00e9") + buf.write("\5q8\2\u00e9\u00ea\5g\63\2\u00ea&\3\2\2\2\u00eb\u00ec") + buf.write("\5o\67\2\u00ec\u00ed\5q8\2\u00ed\u00ee\5y<\2\u00ee(\3") + buf.write("\2\2\2\u00ef\u00f0\7v\2\2\u00f0\u00f1\5u:\2\u00f1\u00f2") + buf.write("\5{=\2\u00f2\u00f3\5e\62\2\u00f3*\3\2\2\2\u00f4\u00f7") + buf.write("\5-\26\2\u00f5\u00f7\5\u0095J\2\u00f6\u00f4\3\2\2\2\u00f6") + buf.write("\u00f5\3\2\2\2\u00f7,\3\2\2\2\u00f8\u00fc\7$\2\2\u00f9") + buf.write("\u00fb\5/\27\2\u00fa\u00f9\3\2\2\2\u00fb\u00fe\3\2\2\2") + buf.write("\u00fc\u00fa\3\2\2\2\u00fc\u00fd\3\2\2\2\u00fd\u00ff\3") + buf.write("\2\2\2\u00fe\u00fc\3\2\2\2\u00ff\u0100\7$\2\2\u0100.\3") + buf.write("\2\2\2\u0101\u0104\5\u0081@\2\u0102\u0104\n\2\2\2\u0103") + buf.write("\u0101\3\2\2\2\u0103\u0102\3\2\2\2\u0104\60\3\2\2\2\u0105") + buf.write("\u0109\7$\2\2\u0106\u0108\5/\27\2\u0107\u0106\3\2\2\2") + buf.write("\u0108\u010b\3\2\2\2\u0109\u0107\3\2\2\2\u0109\u010a\3") + buf.write("\2\2\2\u010a\u010c\3\2\2\2\u010b\u0109\3\2\2\2\u010c\u010d") + buf.write("\7^\2\2\u010d\u010e\7\17\2\2\u010e\u010f\7\f\2\2\u010f") + buf.write("\u0110\3\2\2\2\u0110\u0111\b\30\2\2\u0111\62\3\2\2\2\u0112") + buf.write("\u0114\t\3\2\2\u0113\u0112\3\2\2\2\u0114\u0115\3\2\2\2") + buf.write("\u0115\u0113\3\2\2\2\u0115\u0116\3\2\2\2\u0116\64\3\2") + buf.write("\2\2\u0117\u011b\t\4\2\2\u0118\u011a\t\5\2\2\u0119\u0118") + buf.write("\3\2\2\2\u011a\u011d\3\2\2\2\u011b\u0119\3\2\2\2\u011b") + buf.write("\u011c\3\2\2\2\u011c\66\3\2\2\2\u011d\u011b\3\2\2\2\u011e") + buf.write("\u0122\t\6\2\2\u011f\u0121\t\5\2\2\u0120\u011f\3\2\2\2") + buf.write("\u0121\u0124\3\2\2\2\u0122\u0120\3\2\2\2\u0122\u0123\3") + buf.write("\2\2\2\u01238\3\2\2\2\u0124\u0122\3\2\2\2\u0125\u0126") + buf.write("\7>\2\2\u0126\u0127\7/\2\2\u0127:\3\2\2\2\u0128\u0129") + buf.write("\7?\2\2\u0129\u012a\7@\2\2\u012a<\3\2\2\2\u012b\u012c") + buf.write("\7-\2\2\u012c>\3\2\2\2\u012d\u012e\7/\2\2\u012e@\3\2\2") + buf.write("\2\u012f\u0130\7,\2\2\u0130B\3\2\2\2\u0131\u0132\7\61") + buf.write("\2\2\u0132D\3\2\2\2\u0133\u0134\7>\2\2\u0134F\3\2\2\2") + buf.write("\u0135\u0136\7>\2\2\u0136\u0137\7?\2\2\u0137H\3\2\2\2") + buf.write("\u0138\u0139\7?\2\2\u0139J\3\2\2\2\u013a\u013b\7\u0080") + buf.write("\2\2\u013bL\3\2\2\2\u013c\u013d\7*\2\2\u013dN\3\2\2\2") + buf.write("\u013e\u013f\7+\2\2\u013fP\3\2\2\2\u0140\u0141\7}\2\2") + buf.write("\u0141R\3\2\2\2\u0142\u0143\7\177\2\2\u0143T\3\2\2\2\u0144") + buf.write("\u0145\7B\2\2\u0145V\3\2\2\2\u0146\u0147\7\60\2\2\u0147") + buf.write("X\3\2\2\2\u0148\u0149\7.\2\2\u0149Z\3\2\2\2\u014a\u014b") + buf.write("\7<\2\2\u014b\\\3\2\2\2\u014c\u014d\7=\2\2\u014d^\3\2") + buf.write("\2\2\u014e\u014f\t\7\2\2\u014f`\3\2\2\2\u0150\u0151\t") + buf.write("\b\2\2\u0151b\3\2\2\2\u0152\u0153\t\t\2\2\u0153d\3\2\2") + buf.write("\2\u0154\u0155\t\n\2\2\u0155f\3\2\2\2\u0156\u0157\t\13") + buf.write("\2\2\u0157h\3\2\2\2\u0158\u0159\t\f\2\2\u0159j\3\2\2\2") + buf.write("\u015a\u015b\t\r\2\2\u015bl\3\2\2\2\u015c\u015d\t\16\2") + buf.write("\2\u015dn\3\2\2\2\u015e\u015f\t\17\2\2\u015fp\3\2\2\2") + buf.write("\u0160\u0161\t\20\2\2\u0161r\3\2\2\2\u0162\u0163\t\21") + buf.write("\2\2\u0163t\3\2\2\2\u0164\u0165\t\22\2\2\u0165v\3\2\2") + buf.write("\2\u0166\u0167\t\23\2\2\u0167x\3\2\2\2\u0168\u0169\t\24") + buf.write("\2\2\u0169z\3\2\2\2\u016a\u016b\t\25\2\2\u016b|\3\2\2") + buf.write("\2\u016c\u016d\t\26\2\2\u016d~\3\2\2\2\u016e\u016f\t\27") + buf.write("\2\2\u016f\u0080\3\2\2\2\u0170\u0173\7^\2\2\u0171\u0174") + buf.write("\t\30\2\2\u0172\u0174\5\u0083A\2\u0173\u0171\3\2\2\2\u0173") + buf.write("\u0172\3\2\2\2\u0174\u0082\3\2\2\2\u0175\u0176\7w\2\2") + buf.write("\u0176\u0177\5\u0085B\2\u0177\u0178\5\u0085B\2\u0178\u0179") + buf.write("\5\u0085B\2\u0179\u017a\5\u0085B\2\u017a\u0084\3\2\2\2") + buf.write("\u017b\u017c\t\31\2\2\u017c\u0086\3\2\2\2\u017d\u017f") + buf.write("\t\32\2\2\u017e\u017d\3\2\2\2\u017f\u0180\3\2\2\2\u0180") + buf.write("\u017e\3\2\2\2\u0180\u0181\3\2\2\2\u0181\u0182\3\2\2\2") + buf.write("\u0182\u0183\bC\3\2\u0183\u0088\3\2\2\2\u0184\u0185\7") + buf.write("/\2\2\u0185\u0186\7/\2\2\u0186\u018a\3\2\2\2\u0187\u0189") + buf.write("\n\33\2\2\u0188\u0187\3\2\2\2\u0189\u018c\3\2\2\2\u018a") + buf.write("\u0188\3\2\2\2\u018a\u018b\3\2\2\2\u018b\u018e\3\2\2\2") + buf.write("\u018c\u018a\3\2\2\2\u018d\u018f\7\f\2\2\u018e\u018d\3") + buf.write("\2\2\2\u018e\u018f\3\2\2\2\u018f\u0190\3\2\2\2\u0190\u0191") + buf.write("\bD\3\2\u0191\u008a\3\2\2\2\u0192\u0193\7*\2\2\u0193\u0194") + buf.write("\7,\2\2\u0194\u0195\3\2\2\2\u0195\u0196\bE\4\2\u0196\u008c") + buf.write("\3\2\2\2\u0197\u0198\5\u008bE\2\u0198\u0199\5\u008dF\2") + buf.write("\u0199\u019a\5\u008fG\2\u019a\u01a1\3\2\2\2\u019b\u019d") + buf.write("\13\2\2\2\u019c\u019b\3\2\2\2\u019d\u019e\3\2\2\2\u019e") + buf.write("\u019f\3\2\2\2\u019e\u019c\3\2\2\2\u019f\u01a1\3\2\2\2") + buf.write("\u01a0\u0197\3\2\2\2\u01a0\u019c\3\2\2\2\u01a1\u01a2\3") + buf.write("\2\2\2\u01a2\u01a3\bF\3\2\u01a3\u008e\3\2\2\2\u01a4\u01a5") + buf.write("\7,\2\2\u01a5\u01a6\7+\2\2\u01a6\u01a7\3\2\2\2\u01a7\u01a8") + buf.write("\bG\5\2\u01a8\u0090\3\2\2\2\u01a9\u01ab\5/\27\2\u01aa") + buf.write("\u01a9\3\2\2\2\u01ab\u01ae\3\2\2\2\u01ac\u01aa\3\2\2\2") + buf.write("\u01ac\u01ad\3\2\2\2\u01ad\u01af\3\2\2\2\u01ae\u01ac\3") + buf.write("\2\2\2\u01af\u01b0\7^\2\2\u01b0\u01b1\7\17\2\2\u01b1\u01b2") + buf.write("\7\f\2\2\u01b2\u0092\3\2\2\2\u01b3\u01b5\5/\27\2\u01b4") + buf.write("\u01b3\3\2\2\2\u01b5\u01b8\3\2\2\2\u01b6\u01b4\3\2\2\2") + buf.write("\u01b6\u01b7\3\2\2\2\u01b7\u01b9\3\2\2\2\u01b8\u01b6\3") + buf.write("\2\2\2\u01b9\u01ba\7$\2\2\u01ba\u01bb\3\2\2\2\u01bb\u01bc") + buf.write("\bI\5\2\u01bc\u0094\3\2\2\2\u01bd\u01c1\5\61\30\2\u01be") + buf.write("\u01c0\5\u0091H\2\u01bf\u01be\3\2\2\2\u01c0\u01c3\3\2") + buf.write("\2\2\u01c1\u01bf\3\2\2\2\u01c1\u01c2\3\2\2\2\u01c2\u01c4") + buf.write("\3\2\2\2\u01c3\u01c1\3\2\2\2\u01c4\u01c5\5\u0093I\2\u01c5") + buf.write("\u0096\3\2\2\2\25\2\3\4\u00f6\u00fc\u0103\u0109\u0115") + buf.write("\u011b\u0122\u0173\u0180\u018a\u018e\u019e\u01a0\u01ac") + buf.write("\u01b6\u01c1\6\7\4\2\b\2\2\7\3\2\6\2\2") return buf.getvalue() @@ -191,6 +214,7 @@ class COOL_LEX(Lexer): decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] MULTILINE_COMMENT = 1 + MULTILINE_STR = 2 CLASS = 1 ELSE = 2 @@ -212,38 +236,42 @@ class COOL_LEX(Lexer): NOT = 18 TRUE = 19 STRING = 20 - BREAK_STRING = 21 - INT = 22 - TYPEID = 23 - OBJECTID = 24 - ASSIGNMENT = 25 - CASE_ARROW = 26 - ADD = 27 - MINUS = 28 - MULTIPLY = 29 - DIVISION = 30 - LESS_THAN = 31 - LESS_EQUAL = 32 - EQUAL = 33 - INTEGER_NEGATIVE = 34 - OPEN_ROUND = 35 - CLOSE_ROUND = 36 - OPEN_CURLY = 37 - CLOSE_CURLY = 38 - AT = 39 - DOT = 40 - COMMA = 41 - COLON = 42 - SEMICOLON = 43 - WHITESPACE = 44 - ONE_LINE_COMMENT = 45 - OPEN_COMMENT = 46 - COMMENT = 47 - CLOSE_COMMENT = 48 + STRING_SIMPLE = 21 + STRING_FIRSTLINE = 22 + INT = 23 + TYPEID = 24 + OBJECTID = 25 + ASSIGNMENT = 26 + CASE_ARROW = 27 + ADD = 28 + MINUS = 29 + MULTIPLY = 30 + DIVISION = 31 + LESS_THAN = 32 + LESS_EQUAL = 33 + EQUAL = 34 + INTEGER_NEGATIVE = 35 + OPEN_ROUND = 36 + CLOSE_ROUND = 37 + OPEN_CURLY = 38 + CLOSE_CURLY = 39 + AT = 40 + DOT = 41 + COMMA = 42 + COLON = 43 + SEMICOLON = 44 + WHITESPACE = 45 + ONE_LINE_COMMENT = 46 + OPEN_COMMENT = 47 + COMMENT = 48 + CLOSE_COMMENT = 49 + STRING_INNERLINE = 50 + STRING_LASTLINE = 51 + STRING_MULTILINE = 52 channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] - modeNames = [ "DEFAULT_MODE", "MULTILINE_COMMENT" ] + modeNames = [ "DEFAULT_MODE", "MULTILINE_COMMENT", "MULTILINE_STR" ] literalNames = [ "", "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", "'<='", "'='", @@ -253,24 +281,27 @@ class COOL_LEX(Lexer): symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", - "OF", "NOT", "TRUE", "STRING", "BREAK_STRING", "INT", "TYPEID", - "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", - "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", - "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", "CLOSE_CURLY", "AT", - "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", "ONE_LINE_COMMENT", - "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT" ] + "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", "STRING_FIRSTLINE", + "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", + "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", + "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", + "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", + "ONE_LINE_COMMENT", "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT", + "STRING_INNERLINE", "STRING_LASTLINE", "STRING_MULTILINE" ] ruleNames = [ "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", - "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", "BREAK_STRING", - "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", - "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", - "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", - "OPEN_CURLY", "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", - "SEMICOLON", "A", "C", "D", "E", "F", "H", "I", "L", "N", - "O", "P", "R", "S", "T", "U", "V", "W", "ESC", "UNICODE", - "HEX", "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", - "COMMENT", "CLOSE_COMMENT" ] + "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", + "STRING_CONTENT", "STRING_FIRSTLINE", "INT", "TYPEID", + "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", + "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", + "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", + "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", "SEMICOLON", + "A", "C", "D", "E", "F", "H", "I", "L", "N", "O", "P", + "R", "S", "T", "U", "V", "W", "ESC", "UNICODE", "HEX", + "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", "COMMENT", + "CLOSE_COMMENT", "STRING_INNERLINE", "STRING_LASTLINE", + "STRING_MULTILINE" ] grammarFileName = "COOL_LEX.g4" diff --git a/src/COOL_LEX.tokens b/src/COOL_LEX.tokens index bbdda836..de4efcf0 100644 --- a/src/COOL_LEX.tokens +++ b/src/COOL_LEX.tokens @@ -18,52 +18,56 @@ OF=17 NOT=18 TRUE=19 STRING=20 -BREAK_STRING=21 -INT=22 -TYPEID=23 -OBJECTID=24 -ASSIGNMENT=25 -CASE_ARROW=26 -ADD=27 -MINUS=28 -MULTIPLY=29 -DIVISION=30 -LESS_THAN=31 -LESS_EQUAL=32 -EQUAL=33 -INTEGER_NEGATIVE=34 -OPEN_ROUND=35 -CLOSE_ROUND=36 -OPEN_CURLY=37 -CLOSE_CURLY=38 -AT=39 -DOT=40 -COMMA=41 -COLON=42 -SEMICOLON=43 -WHITESPACE=44 -ONE_LINE_COMMENT=45 -OPEN_COMMENT=46 -COMMENT=47 -CLOSE_COMMENT=48 -'<-'=25 -'=>'=26 -'+'=27 -'-'=28 -'*'=29 -'/'=30 -'<'=31 -'<='=32 -'='=33 -'~'=34 -'('=35 -')'=36 -'{'=37 -'}'=38 -'@'=39 -'.'=40 -','=41 -':'=42 -';'=43 -'(*'=46 -'*)'=48 +STRING_SIMPLE=21 +STRING_FIRSTLINE=22 +INT=23 +TYPEID=24 +OBJECTID=25 +ASSIGNMENT=26 +CASE_ARROW=27 +ADD=28 +MINUS=29 +MULTIPLY=30 +DIVISION=31 +LESS_THAN=32 +LESS_EQUAL=33 +EQUAL=34 +INTEGER_NEGATIVE=35 +OPEN_ROUND=36 +CLOSE_ROUND=37 +OPEN_CURLY=38 +CLOSE_CURLY=39 +AT=40 +DOT=41 +COMMA=42 +COLON=43 +SEMICOLON=44 +WHITESPACE=45 +ONE_LINE_COMMENT=46 +OPEN_COMMENT=47 +COMMENT=48 +CLOSE_COMMENT=49 +STRING_INNERLINE=50 +STRING_LASTLINE=51 +STRING_MULTILINE=52 +'<-'=26 +'=>'=27 +'+'=28 +'-'=29 +'*'=30 +'/'=31 +'<'=32 +'<='=33 +'='=34 +'~'=35 +'('=36 +')'=37 +'{'=38 +'}'=39 +'@'=40 +'.'=41 +','=42 +':'=43 +';'=44 +'(*'=47 +'*)'=49 diff --git a/src/coolc.sh b/src/coolc.sh index 2b13ab2e..bfea5d60 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,8 +4,8 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "COOLCompiler 1.0.1" -echo "Copyright (c) 2019: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" +echo "COOLCompiler 1.0.2" +echo "Copyright (C) 2019-2020: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" # Llamar al compilador #echo "Compiling $INPUT_FILE into $OUTPUT_FILE" diff --git a/tests/parser/program1_error.txt b/tests/parser/program1_error.txt index de00ac46..d7474383 100644 --- a/tests/parser/program1_error.txt +++ b/tests/parser/program1_error.txt @@ -1 +1 @@ -(0, 0) - SyntacticError: ERROR at or near EOF \ No newline at end of file +(1, 36) - SyntacticError: ERROR at or near EOF \ No newline at end of file From e458ce570f79d46ddfaf0d23bc67acaae39a9486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 16 Mar 2020 10:52:10 -0400 Subject: [PATCH 33/77] Se arreglo el lexer para detectar caracter nulo --- src/COOL.interp | 8 +- src/COOL.py | 177 +++++++------ src/COOL.tokens | 107 ++++---- src/COOLLexer.py | 6 +- src/COOL_LEX.interp | 12 +- src/COOL_LEX.py | 504 ++++++++++++++++++------------------ src/COOL_LEX.tokens | 107 ++++---- tests/lexer/test1_error.txt | 6 +- 8 files changed, 485 insertions(+), 442 deletions(-) diff --git a/src/COOL.interp b/src/COOL.interp index 740232fd..0a51d34e 100644 --- a/src/COOL.interp +++ b/src/COOL.interp @@ -25,6 +25,7 @@ null null null null +null '<-' '=>' '+' @@ -52,6 +53,8 @@ null null null null +null +null token symbolic names: null @@ -76,6 +79,7 @@ NOT TRUE STRING STRING_SIMPLE +STRING_SIMPLE_START STRING_FIRSTLINE INT TYPEID @@ -107,6 +111,8 @@ CLOSE_COMMENT STRING_INNERLINE STRING_LASTLINE STRING_MULTILINE +STRING_SIMPLE_CONTENT +STRING_SIMPLE_STOP rule names: program @@ -118,4 +124,4 @@ expression atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 54, 219, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 5, 7, 86, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 107, 10, 7, 13, 7, 14, 7, 108, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 119, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 127, 10, 7, 7, 7, 129, 10, 7, 12, 7, 14, 7, 132, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 146, 10, 7, 13, 7, 14, 7, 147, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 172, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 198, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 206, 10, 7, 12, 7, 14, 7, 209, 11, 7, 5, 7, 211, 10, 7, 3, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 253, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 171, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 46, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 26, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 26, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 40, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 46, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 41, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 27, 2, 2, 40, 51, 7, 38, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 44, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 39, 2, 2, 55, 56, 7, 45, 2, 2, 56, 57, 7, 26, 2, 2, 57, 58, 7, 40, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 41, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 27, 2, 2, 62, 63, 7, 45, 2, 2, 63, 66, 7, 26, 2, 2, 64, 65, 7, 28, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 27, 2, 2, 71, 72, 7, 45, 2, 2, 72, 73, 7, 26, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 27, 2, 2, 76, 85, 7, 38, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 44, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 85, 86, 3, 2, 2, 2, 86, 87, 3, 2, 2, 2, 87, 172, 7, 39, 2, 2, 88, 89, 7, 7, 2, 2, 89, 90, 5, 12, 7, 2, 90, 91, 7, 14, 2, 2, 91, 92, 5, 12, 7, 2, 92, 93, 7, 4, 2, 2, 93, 94, 5, 12, 7, 2, 94, 95, 7, 6, 2, 2, 95, 172, 3, 2, 2, 2, 96, 97, 7, 15, 2, 2, 97, 98, 5, 12, 7, 2, 98, 99, 7, 12, 2, 2, 99, 100, 5, 12, 7, 2, 100, 101, 7, 13, 2, 2, 101, 172, 3, 2, 2, 2, 102, 106, 7, 40, 2, 2, 103, 104, 5, 12, 7, 2, 104, 105, 7, 46, 2, 2, 105, 107, 3, 2, 2, 2, 106, 103, 3, 2, 2, 2, 107, 108, 3, 2, 2, 2, 108, 106, 3, 2, 2, 2, 108, 109, 3, 2, 2, 2, 109, 110, 3, 2, 2, 2, 110, 111, 7, 41, 2, 2, 111, 172, 3, 2, 2, 2, 112, 113, 7, 11, 2, 2, 113, 114, 7, 27, 2, 2, 114, 115, 7, 45, 2, 2, 115, 118, 7, 26, 2, 2, 116, 117, 7, 28, 2, 2, 117, 119, 5, 12, 7, 2, 118, 116, 3, 2, 2, 2, 118, 119, 3, 2, 2, 2, 119, 130, 3, 2, 2, 2, 120, 121, 7, 44, 2, 2, 121, 122, 7, 27, 2, 2, 122, 123, 7, 45, 2, 2, 123, 126, 7, 26, 2, 2, 124, 125, 7, 28, 2, 2, 125, 127, 5, 12, 7, 2, 126, 124, 3, 2, 2, 2, 126, 127, 3, 2, 2, 2, 127, 129, 3, 2, 2, 2, 128, 120, 3, 2, 2, 2, 129, 132, 3, 2, 2, 2, 130, 128, 3, 2, 2, 2, 130, 131, 3, 2, 2, 2, 131, 133, 3, 2, 2, 2, 132, 130, 3, 2, 2, 2, 133, 134, 7, 8, 2, 2, 134, 172, 5, 12, 7, 22, 135, 136, 7, 16, 2, 2, 136, 137, 5, 12, 7, 2, 137, 145, 7, 19, 2, 2, 138, 139, 7, 27, 2, 2, 139, 140, 7, 45, 2, 2, 140, 141, 7, 26, 2, 2, 141, 142, 7, 29, 2, 2, 142, 143, 5, 12, 7, 2, 143, 144, 7, 46, 2, 2, 144, 146, 3, 2, 2, 2, 145, 138, 3, 2, 2, 2, 146, 147, 3, 2, 2, 2, 147, 145, 3, 2, 2, 2, 147, 148, 3, 2, 2, 2, 148, 149, 3, 2, 2, 2, 149, 150, 7, 17, 2, 2, 150, 172, 3, 2, 2, 2, 151, 152, 7, 18, 2, 2, 152, 172, 7, 26, 2, 2, 153, 154, 7, 37, 2, 2, 154, 172, 5, 12, 7, 19, 155, 156, 7, 10, 2, 2, 156, 172, 5, 12, 7, 18, 157, 158, 7, 20, 2, 2, 158, 172, 5, 12, 7, 10, 159, 160, 7, 38, 2, 2, 160, 161, 5, 12, 7, 2, 161, 162, 7, 39, 2, 2, 162, 172, 3, 2, 2, 2, 163, 172, 7, 27, 2, 2, 164, 172, 7, 25, 2, 2, 165, 172, 7, 22, 2, 2, 166, 172, 7, 21, 2, 2, 167, 172, 7, 5, 2, 2, 168, 169, 7, 27, 2, 2, 169, 170, 7, 28, 2, 2, 170, 172, 5, 12, 7, 3, 171, 74, 3, 2, 2, 2, 171, 88, 3, 2, 2, 2, 171, 96, 3, 2, 2, 2, 171, 102, 3, 2, 2, 2, 171, 112, 3, 2, 2, 2, 171, 135, 3, 2, 2, 2, 171, 151, 3, 2, 2, 2, 171, 153, 3, 2, 2, 2, 171, 155, 3, 2, 2, 2, 171, 157, 3, 2, 2, 2, 171, 159, 3, 2, 2, 2, 171, 163, 3, 2, 2, 2, 171, 164, 3, 2, 2, 2, 171, 165, 3, 2, 2, 2, 171, 166, 3, 2, 2, 2, 171, 167, 3, 2, 2, 2, 171, 168, 3, 2, 2, 2, 172, 215, 3, 2, 2, 2, 173, 174, 12, 17, 2, 2, 174, 175, 7, 32, 2, 2, 175, 214, 5, 12, 7, 18, 176, 177, 12, 16, 2, 2, 177, 178, 7, 33, 2, 2, 178, 214, 5, 12, 7, 17, 179, 180, 12, 15, 2, 2, 180, 181, 7, 30, 2, 2, 181, 214, 5, 12, 7, 16, 182, 183, 12, 14, 2, 2, 183, 184, 7, 31, 2, 2, 184, 214, 5, 12, 7, 15, 185, 186, 12, 13, 2, 2, 186, 187, 7, 34, 2, 2, 187, 214, 5, 12, 7, 14, 188, 189, 12, 12, 2, 2, 189, 190, 7, 35, 2, 2, 190, 214, 5, 12, 7, 13, 191, 192, 12, 11, 2, 2, 192, 193, 7, 36, 2, 2, 193, 214, 5, 12, 7, 12, 194, 197, 12, 27, 2, 2, 195, 196, 7, 42, 2, 2, 196, 198, 7, 26, 2, 2, 197, 195, 3, 2, 2, 2, 197, 198, 3, 2, 2, 2, 198, 199, 3, 2, 2, 2, 199, 200, 7, 43, 2, 2, 200, 201, 7, 27, 2, 2, 201, 210, 7, 38, 2, 2, 202, 207, 5, 12, 7, 2, 203, 204, 7, 44, 2, 2, 204, 206, 5, 12, 7, 2, 205, 203, 3, 2, 2, 2, 206, 209, 3, 2, 2, 2, 207, 205, 3, 2, 2, 2, 207, 208, 3, 2, 2, 2, 208, 211, 3, 2, 2, 2, 209, 207, 3, 2, 2, 2, 210, 202, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 212, 3, 2, 2, 2, 212, 214, 7, 39, 2, 2, 213, 173, 3, 2, 2, 2, 213, 176, 3, 2, 2, 2, 213, 179, 3, 2, 2, 2, 213, 182, 3, 2, 2, 2, 213, 185, 3, 2, 2, 2, 213, 188, 3, 2, 2, 2, 213, 191, 3, 2, 2, 2, 213, 194, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 13, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 85, 108, 118, 126, 130, 147, 171, 197, 207, 210, 213, 215] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 57, 219, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 5, 3, 21, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 27, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 33, 10, 4, 12, 4, 14, 4, 36, 11, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 7, 5, 45, 10, 5, 12, 5, 14, 5, 48, 11, 5, 7, 5, 50, 10, 5, 12, 5, 14, 5, 53, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 67, 10, 5, 5, 5, 69, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 81, 10, 7, 12, 7, 14, 7, 84, 11, 7, 5, 7, 86, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 107, 10, 7, 13, 7, 14, 7, 108, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 119, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 127, 10, 7, 7, 7, 129, 10, 7, 12, 7, 14, 7, 132, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 6, 7, 146, 10, 7, 13, 7, 14, 7, 147, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 172, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 198, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 206, 10, 7, 12, 7, 14, 7, 209, 11, 7, 5, 7, 211, 10, 7, 3, 7, 7, 7, 214, 10, 7, 12, 7, 14, 7, 217, 11, 7, 3, 7, 2, 3, 12, 8, 2, 4, 6, 8, 10, 12, 2, 2, 2, 253, 2, 14, 3, 2, 2, 2, 4, 17, 3, 2, 2, 2, 6, 22, 3, 2, 2, 2, 8, 68, 3, 2, 2, 2, 10, 70, 3, 2, 2, 2, 12, 171, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 5, 6, 4, 2, 18, 20, 7, 47, 2, 2, 19, 21, 5, 4, 3, 2, 20, 19, 3, 2, 2, 2, 20, 21, 3, 2, 2, 2, 21, 5, 3, 2, 2, 2, 22, 23, 7, 3, 2, 2, 23, 26, 7, 27, 2, 2, 24, 25, 7, 9, 2, 2, 25, 27, 7, 27, 2, 2, 26, 24, 3, 2, 2, 2, 26, 27, 3, 2, 2, 2, 27, 28, 3, 2, 2, 2, 28, 34, 7, 41, 2, 2, 29, 30, 5, 8, 5, 2, 30, 31, 7, 47, 2, 2, 31, 33, 3, 2, 2, 2, 32, 29, 3, 2, 2, 2, 33, 36, 3, 2, 2, 2, 34, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 37, 3, 2, 2, 2, 36, 34, 3, 2, 2, 2, 37, 38, 7, 42, 2, 2, 38, 7, 3, 2, 2, 2, 39, 40, 7, 28, 2, 2, 40, 51, 7, 39, 2, 2, 41, 46, 5, 10, 6, 2, 42, 43, 7, 45, 2, 2, 43, 45, 5, 10, 6, 2, 44, 42, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 50, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 41, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 54, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 40, 2, 2, 55, 56, 7, 46, 2, 2, 56, 57, 7, 27, 2, 2, 57, 58, 7, 41, 2, 2, 58, 59, 5, 12, 7, 2, 59, 60, 7, 42, 2, 2, 60, 69, 3, 2, 2, 2, 61, 62, 7, 28, 2, 2, 62, 63, 7, 46, 2, 2, 63, 66, 7, 27, 2, 2, 64, 65, 7, 29, 2, 2, 65, 67, 5, 12, 7, 2, 66, 64, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 69, 3, 2, 2, 2, 68, 39, 3, 2, 2, 2, 68, 61, 3, 2, 2, 2, 69, 9, 3, 2, 2, 2, 70, 71, 7, 28, 2, 2, 71, 72, 7, 46, 2, 2, 72, 73, 7, 27, 2, 2, 73, 11, 3, 2, 2, 2, 74, 75, 8, 7, 1, 2, 75, 76, 7, 28, 2, 2, 76, 85, 7, 39, 2, 2, 77, 82, 5, 12, 7, 2, 78, 79, 7, 45, 2, 2, 79, 81, 5, 12, 7, 2, 80, 78, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 85, 86, 3, 2, 2, 2, 86, 87, 3, 2, 2, 2, 87, 172, 7, 40, 2, 2, 88, 89, 7, 7, 2, 2, 89, 90, 5, 12, 7, 2, 90, 91, 7, 14, 2, 2, 91, 92, 5, 12, 7, 2, 92, 93, 7, 4, 2, 2, 93, 94, 5, 12, 7, 2, 94, 95, 7, 6, 2, 2, 95, 172, 3, 2, 2, 2, 96, 97, 7, 15, 2, 2, 97, 98, 5, 12, 7, 2, 98, 99, 7, 12, 2, 2, 99, 100, 5, 12, 7, 2, 100, 101, 7, 13, 2, 2, 101, 172, 3, 2, 2, 2, 102, 106, 7, 41, 2, 2, 103, 104, 5, 12, 7, 2, 104, 105, 7, 47, 2, 2, 105, 107, 3, 2, 2, 2, 106, 103, 3, 2, 2, 2, 107, 108, 3, 2, 2, 2, 108, 106, 3, 2, 2, 2, 108, 109, 3, 2, 2, 2, 109, 110, 3, 2, 2, 2, 110, 111, 7, 42, 2, 2, 111, 172, 3, 2, 2, 2, 112, 113, 7, 11, 2, 2, 113, 114, 7, 28, 2, 2, 114, 115, 7, 46, 2, 2, 115, 118, 7, 27, 2, 2, 116, 117, 7, 29, 2, 2, 117, 119, 5, 12, 7, 2, 118, 116, 3, 2, 2, 2, 118, 119, 3, 2, 2, 2, 119, 130, 3, 2, 2, 2, 120, 121, 7, 45, 2, 2, 121, 122, 7, 28, 2, 2, 122, 123, 7, 46, 2, 2, 123, 126, 7, 27, 2, 2, 124, 125, 7, 29, 2, 2, 125, 127, 5, 12, 7, 2, 126, 124, 3, 2, 2, 2, 126, 127, 3, 2, 2, 2, 127, 129, 3, 2, 2, 2, 128, 120, 3, 2, 2, 2, 129, 132, 3, 2, 2, 2, 130, 128, 3, 2, 2, 2, 130, 131, 3, 2, 2, 2, 131, 133, 3, 2, 2, 2, 132, 130, 3, 2, 2, 2, 133, 134, 7, 8, 2, 2, 134, 172, 5, 12, 7, 22, 135, 136, 7, 16, 2, 2, 136, 137, 5, 12, 7, 2, 137, 145, 7, 19, 2, 2, 138, 139, 7, 28, 2, 2, 139, 140, 7, 46, 2, 2, 140, 141, 7, 27, 2, 2, 141, 142, 7, 30, 2, 2, 142, 143, 5, 12, 7, 2, 143, 144, 7, 47, 2, 2, 144, 146, 3, 2, 2, 2, 145, 138, 3, 2, 2, 2, 146, 147, 3, 2, 2, 2, 147, 145, 3, 2, 2, 2, 147, 148, 3, 2, 2, 2, 148, 149, 3, 2, 2, 2, 149, 150, 7, 17, 2, 2, 150, 172, 3, 2, 2, 2, 151, 152, 7, 18, 2, 2, 152, 172, 7, 27, 2, 2, 153, 154, 7, 38, 2, 2, 154, 172, 5, 12, 7, 19, 155, 156, 7, 10, 2, 2, 156, 172, 5, 12, 7, 18, 157, 158, 7, 20, 2, 2, 158, 172, 5, 12, 7, 10, 159, 160, 7, 39, 2, 2, 160, 161, 5, 12, 7, 2, 161, 162, 7, 40, 2, 2, 162, 172, 3, 2, 2, 2, 163, 172, 7, 28, 2, 2, 164, 172, 7, 26, 2, 2, 165, 172, 7, 22, 2, 2, 166, 172, 7, 21, 2, 2, 167, 172, 7, 5, 2, 2, 168, 169, 7, 28, 2, 2, 169, 170, 7, 29, 2, 2, 170, 172, 5, 12, 7, 3, 171, 74, 3, 2, 2, 2, 171, 88, 3, 2, 2, 2, 171, 96, 3, 2, 2, 2, 171, 102, 3, 2, 2, 2, 171, 112, 3, 2, 2, 2, 171, 135, 3, 2, 2, 2, 171, 151, 3, 2, 2, 2, 171, 153, 3, 2, 2, 2, 171, 155, 3, 2, 2, 2, 171, 157, 3, 2, 2, 2, 171, 159, 3, 2, 2, 2, 171, 163, 3, 2, 2, 2, 171, 164, 3, 2, 2, 2, 171, 165, 3, 2, 2, 2, 171, 166, 3, 2, 2, 2, 171, 167, 3, 2, 2, 2, 171, 168, 3, 2, 2, 2, 172, 215, 3, 2, 2, 2, 173, 174, 12, 17, 2, 2, 174, 175, 7, 33, 2, 2, 175, 214, 5, 12, 7, 18, 176, 177, 12, 16, 2, 2, 177, 178, 7, 34, 2, 2, 178, 214, 5, 12, 7, 17, 179, 180, 12, 15, 2, 2, 180, 181, 7, 31, 2, 2, 181, 214, 5, 12, 7, 16, 182, 183, 12, 14, 2, 2, 183, 184, 7, 32, 2, 2, 184, 214, 5, 12, 7, 15, 185, 186, 12, 13, 2, 2, 186, 187, 7, 35, 2, 2, 187, 214, 5, 12, 7, 14, 188, 189, 12, 12, 2, 2, 189, 190, 7, 36, 2, 2, 190, 214, 5, 12, 7, 13, 191, 192, 12, 11, 2, 2, 192, 193, 7, 37, 2, 2, 193, 214, 5, 12, 7, 12, 194, 197, 12, 27, 2, 2, 195, 196, 7, 43, 2, 2, 196, 198, 7, 27, 2, 2, 197, 195, 3, 2, 2, 2, 197, 198, 3, 2, 2, 2, 198, 199, 3, 2, 2, 2, 199, 200, 7, 44, 2, 2, 200, 201, 7, 28, 2, 2, 201, 210, 7, 39, 2, 2, 202, 207, 5, 12, 7, 2, 203, 204, 7, 45, 2, 2, 204, 206, 5, 12, 7, 2, 205, 203, 3, 2, 2, 2, 206, 209, 3, 2, 2, 2, 207, 205, 3, 2, 2, 2, 207, 208, 3, 2, 2, 2, 208, 211, 3, 2, 2, 2, 209, 207, 3, 2, 2, 2, 210, 202, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 212, 3, 2, 2, 2, 212, 214, 7, 40, 2, 2, 213, 173, 3, 2, 2, 2, 213, 176, 3, 2, 2, 2, 213, 179, 3, 2, 2, 2, 213, 182, 3, 2, 2, 2, 213, 185, 3, 2, 2, 2, 213, 188, 3, 2, 2, 2, 213, 191, 3, 2, 2, 2, 213, 194, 3, 2, 2, 2, 214, 217, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 13, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 22, 20, 26, 34, 46, 51, 66, 68, 82, 85, 108, 118, 126, 130, 147, 171, 197, 207, 210, 213, 215] \ No newline at end of file diff --git a/src/COOL.py b/src/COOL.py index a342382b..1e1ab864 100644 --- a/src/COOL.py +++ b/src/COOL.py @@ -8,7 +8,7 @@ def serializedATN(): with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\66") + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\39") buf.write("\u00db\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") buf.write("\3\2\3\2\3\2\3\3\3\3\3\3\5\3\25\n\3\3\4\3\4\3\4\3\4\5") buf.write("\4\33\n\4\3\4\3\4\3\4\3\4\7\4!\n\4\f\4\16\4$\13\4\3\4") @@ -30,71 +30,71 @@ def serializedATN(): buf.write("\16\7\u00d9\13\7\3\7\2\3\f\b\2\4\6\b\n\f\2\2\2\u00fd\2") buf.write("\16\3\2\2\2\4\21\3\2\2\2\6\26\3\2\2\2\bD\3\2\2\2\nF\3") buf.write("\2\2\2\f\u00ab\3\2\2\2\16\17\5\4\3\2\17\20\7\2\2\3\20") - buf.write("\3\3\2\2\2\21\22\5\6\4\2\22\24\7.\2\2\23\25\5\4\3\2\24") + buf.write("\3\3\2\2\2\21\22\5\6\4\2\22\24\7/\2\2\23\25\5\4\3\2\24") buf.write("\23\3\2\2\2\24\25\3\2\2\2\25\5\3\2\2\2\26\27\7\3\2\2\27") - buf.write("\32\7\32\2\2\30\31\7\t\2\2\31\33\7\32\2\2\32\30\3\2\2") - buf.write("\2\32\33\3\2\2\2\33\34\3\2\2\2\34\"\7(\2\2\35\36\5\b\5") - buf.write("\2\36\37\7.\2\2\37!\3\2\2\2 \35\3\2\2\2!$\3\2\2\2\" \3") - buf.write("\2\2\2\"#\3\2\2\2#%\3\2\2\2$\"\3\2\2\2%&\7)\2\2&\7\3\2") - buf.write("\2\2\'(\7\33\2\2(\63\7&\2\2).\5\n\6\2*+\7,\2\2+-\5\n\6") - buf.write("\2,*\3\2\2\2-\60\3\2\2\2.,\3\2\2\2./\3\2\2\2/\62\3\2\2") - buf.write("\2\60.\3\2\2\2\61)\3\2\2\2\62\65\3\2\2\2\63\61\3\2\2\2") - buf.write("\63\64\3\2\2\2\64\66\3\2\2\2\65\63\3\2\2\2\66\67\7\'\2") - buf.write("\2\678\7-\2\289\7\32\2\29:\7(\2\2:;\5\f\7\2;<\7)\2\2<") - buf.write("E\3\2\2\2=>\7\33\2\2>?\7-\2\2?B\7\32\2\2@A\7\34\2\2AC") - buf.write("\5\f\7\2B@\3\2\2\2BC\3\2\2\2CE\3\2\2\2D\'\3\2\2\2D=\3") - buf.write("\2\2\2E\t\3\2\2\2FG\7\33\2\2GH\7-\2\2HI\7\32\2\2I\13\3") - buf.write("\2\2\2JK\b\7\1\2KL\7\33\2\2LU\7&\2\2MR\5\f\7\2NO\7,\2") + buf.write("\32\7\33\2\2\30\31\7\t\2\2\31\33\7\33\2\2\32\30\3\2\2") + buf.write("\2\32\33\3\2\2\2\33\34\3\2\2\2\34\"\7)\2\2\35\36\5\b\5") + buf.write("\2\36\37\7/\2\2\37!\3\2\2\2 \35\3\2\2\2!$\3\2\2\2\" \3") + buf.write("\2\2\2\"#\3\2\2\2#%\3\2\2\2$\"\3\2\2\2%&\7*\2\2&\7\3\2") + buf.write("\2\2\'(\7\34\2\2(\63\7\'\2\2).\5\n\6\2*+\7-\2\2+-\5\n") + buf.write("\6\2,*\3\2\2\2-\60\3\2\2\2.,\3\2\2\2./\3\2\2\2/\62\3\2") + buf.write("\2\2\60.\3\2\2\2\61)\3\2\2\2\62\65\3\2\2\2\63\61\3\2\2") + buf.write("\2\63\64\3\2\2\2\64\66\3\2\2\2\65\63\3\2\2\2\66\67\7(") + buf.write("\2\2\678\7.\2\289\7\33\2\29:\7)\2\2:;\5\f\7\2;<\7*\2\2") + buf.write("\7\34\2\2>?\7.\2\2?B\7\33\2\2@A\7\35\2\2A") + buf.write("C\5\f\7\2B@\3\2\2\2BC\3\2\2\2CE\3\2\2\2D\'\3\2\2\2D=\3") + buf.write("\2\2\2E\t\3\2\2\2FG\7\34\2\2GH\7.\2\2HI\7\33\2\2I\13\3") + buf.write("\2\2\2JK\b\7\1\2KL\7\34\2\2LU\7\'\2\2MR\5\f\7\2NO\7-\2") buf.write("\2OQ\5\f\7\2PN\3\2\2\2QT\3\2\2\2RP\3\2\2\2RS\3\2\2\2S") buf.write("V\3\2\2\2TR\3\2\2\2UM\3\2\2\2UV\3\2\2\2VW\3\2\2\2W\u00ac") - buf.write("\7\'\2\2XY\7\7\2\2YZ\5\f\7\2Z[\7\16\2\2[\\\5\f\7\2\\]") - buf.write("\7\4\2\2]^\5\f\7\2^_\7\6\2\2_\u00ac\3\2\2\2`a\7\17\2\2") - buf.write("ab\5\f\7\2bc\7\f\2\2cd\5\f\7\2de\7\r\2\2e\u00ac\3\2\2") - buf.write("\2fj\7(\2\2gh\5\f\7\2hi\7.\2\2ik\3\2\2\2jg\3\2\2\2kl\3") - buf.write("\2\2\2lj\3\2\2\2lm\3\2\2\2mn\3\2\2\2no\7)\2\2o\u00ac\3") - buf.write("\2\2\2pq\7\13\2\2qr\7\33\2\2rs\7-\2\2sv\7\32\2\2tu\7\34") + buf.write("\7(\2\2XY\7\7\2\2YZ\5\f\7\2Z[\7\16\2\2[\\\5\f\7\2\\]\7") + buf.write("\4\2\2]^\5\f\7\2^_\7\6\2\2_\u00ac\3\2\2\2`a\7\17\2\2a") + buf.write("b\5\f\7\2bc\7\f\2\2cd\5\f\7\2de\7\r\2\2e\u00ac\3\2\2\2") + buf.write("fj\7)\2\2gh\5\f\7\2hi\7/\2\2ik\3\2\2\2jg\3\2\2\2kl\3\2") + buf.write("\2\2lj\3\2\2\2lm\3\2\2\2mn\3\2\2\2no\7*\2\2o\u00ac\3\2") + buf.write("\2\2pq\7\13\2\2qr\7\34\2\2rs\7.\2\2sv\7\33\2\2tu\7\35") buf.write("\2\2uw\5\f\7\2vt\3\2\2\2vw\3\2\2\2w\u0082\3\2\2\2xy\7") - buf.write(",\2\2yz\7\33\2\2z{\7-\2\2{~\7\32\2\2|}\7\34\2\2}\177\5") + buf.write("-\2\2yz\7\34\2\2z{\7.\2\2{~\7\33\2\2|}\7\35\2\2}\177\5") buf.write("\f\7\2~|\3\2\2\2~\177\3\2\2\2\177\u0081\3\2\2\2\u0080") buf.write("x\3\2\2\2\u0081\u0084\3\2\2\2\u0082\u0080\3\2\2\2\u0082") buf.write("\u0083\3\2\2\2\u0083\u0085\3\2\2\2\u0084\u0082\3\2\2\2") buf.write("\u0085\u0086\7\b\2\2\u0086\u00ac\5\f\7\26\u0087\u0088") buf.write("\7\20\2\2\u0088\u0089\5\f\7\2\u0089\u0091\7\23\2\2\u008a") - buf.write("\u008b\7\33\2\2\u008b\u008c\7-\2\2\u008c\u008d\7\32\2") - buf.write("\2\u008d\u008e\7\35\2\2\u008e\u008f\5\f\7\2\u008f\u0090") - buf.write("\7.\2\2\u0090\u0092\3\2\2\2\u0091\u008a\3\2\2\2\u0092") + buf.write("\u008b\7\34\2\2\u008b\u008c\7.\2\2\u008c\u008d\7\33\2") + buf.write("\2\u008d\u008e\7\36\2\2\u008e\u008f\5\f\7\2\u008f\u0090") + buf.write("\7/\2\2\u0090\u0092\3\2\2\2\u0091\u008a\3\2\2\2\u0092") buf.write("\u0093\3\2\2\2\u0093\u0091\3\2\2\2\u0093\u0094\3\2\2\2") buf.write("\u0094\u0095\3\2\2\2\u0095\u0096\7\21\2\2\u0096\u00ac") - buf.write("\3\2\2\2\u0097\u0098\7\22\2\2\u0098\u00ac\7\32\2\2\u0099") - buf.write("\u009a\7%\2\2\u009a\u00ac\5\f\7\23\u009b\u009c\7\n\2\2") + buf.write("\3\2\2\2\u0097\u0098\7\22\2\2\u0098\u00ac\7\33\2\2\u0099") + buf.write("\u009a\7&\2\2\u009a\u00ac\5\f\7\23\u009b\u009c\7\n\2\2") buf.write("\u009c\u00ac\5\f\7\22\u009d\u009e\7\24\2\2\u009e\u00ac") - buf.write("\5\f\7\n\u009f\u00a0\7&\2\2\u00a0\u00a1\5\f\7\2\u00a1") - buf.write("\u00a2\7\'\2\2\u00a2\u00ac\3\2\2\2\u00a3\u00ac\7\33\2") - buf.write("\2\u00a4\u00ac\7\31\2\2\u00a5\u00ac\7\26\2\2\u00a6\u00ac") - buf.write("\7\25\2\2\u00a7\u00ac\7\5\2\2\u00a8\u00a9\7\33\2\2\u00a9") - buf.write("\u00aa\7\34\2\2\u00aa\u00ac\5\f\7\3\u00abJ\3\2\2\2\u00ab") + buf.write("\5\f\7\n\u009f\u00a0\7\'\2\2\u00a0\u00a1\5\f\7\2\u00a1") + buf.write("\u00a2\7(\2\2\u00a2\u00ac\3\2\2\2\u00a3\u00ac\7\34\2\2") + buf.write("\u00a4\u00ac\7\32\2\2\u00a5\u00ac\7\26\2\2\u00a6\u00ac") + buf.write("\7\25\2\2\u00a7\u00ac\7\5\2\2\u00a8\u00a9\7\34\2\2\u00a9") + buf.write("\u00aa\7\35\2\2\u00aa\u00ac\5\f\7\3\u00abJ\3\2\2\2\u00ab") buf.write("X\3\2\2\2\u00ab`\3\2\2\2\u00abf\3\2\2\2\u00abp\3\2\2\2") buf.write("\u00ab\u0087\3\2\2\2\u00ab\u0097\3\2\2\2\u00ab\u0099\3") buf.write("\2\2\2\u00ab\u009b\3\2\2\2\u00ab\u009d\3\2\2\2\u00ab\u009f") buf.write("\3\2\2\2\u00ab\u00a3\3\2\2\2\u00ab\u00a4\3\2\2\2\u00ab") buf.write("\u00a5\3\2\2\2\u00ab\u00a6\3\2\2\2\u00ab\u00a7\3\2\2\2") buf.write("\u00ab\u00a8\3\2\2\2\u00ac\u00d7\3\2\2\2\u00ad\u00ae\f") - buf.write("\21\2\2\u00ae\u00af\7 \2\2\u00af\u00d6\5\f\7\22\u00b0") - buf.write("\u00b1\f\20\2\2\u00b1\u00b2\7!\2\2\u00b2\u00d6\5\f\7\21") - buf.write("\u00b3\u00b4\f\17\2\2\u00b4\u00b5\7\36\2\2\u00b5\u00d6") - buf.write("\5\f\7\20\u00b6\u00b7\f\16\2\2\u00b7\u00b8\7\37\2\2\u00b8") - buf.write("\u00d6\5\f\7\17\u00b9\u00ba\f\r\2\2\u00ba\u00bb\7\"\2") - buf.write("\2\u00bb\u00d6\5\f\7\16\u00bc\u00bd\f\f\2\2\u00bd\u00be") - buf.write("\7#\2\2\u00be\u00d6\5\f\7\r\u00bf\u00c0\f\13\2\2\u00c0") - buf.write("\u00c1\7$\2\2\u00c1\u00d6\5\f\7\f\u00c2\u00c5\f\33\2\2") - buf.write("\u00c3\u00c4\7*\2\2\u00c4\u00c6\7\32\2\2\u00c5\u00c3\3") + buf.write("\21\2\2\u00ae\u00af\7!\2\2\u00af\u00d6\5\f\7\22\u00b0") + buf.write("\u00b1\f\20\2\2\u00b1\u00b2\7\"\2\2\u00b2\u00d6\5\f\7") + buf.write("\21\u00b3\u00b4\f\17\2\2\u00b4\u00b5\7\37\2\2\u00b5\u00d6") + buf.write("\5\f\7\20\u00b6\u00b7\f\16\2\2\u00b7\u00b8\7 \2\2\u00b8") + buf.write("\u00d6\5\f\7\17\u00b9\u00ba\f\r\2\2\u00ba\u00bb\7#\2\2") + buf.write("\u00bb\u00d6\5\f\7\16\u00bc\u00bd\f\f\2\2\u00bd\u00be") + buf.write("\7$\2\2\u00be\u00d6\5\f\7\r\u00bf\u00c0\f\13\2\2\u00c0") + buf.write("\u00c1\7%\2\2\u00c1\u00d6\5\f\7\f\u00c2\u00c5\f\33\2\2") + buf.write("\u00c3\u00c4\7+\2\2\u00c4\u00c6\7\33\2\2\u00c5\u00c3\3") buf.write("\2\2\2\u00c5\u00c6\3\2\2\2\u00c6\u00c7\3\2\2\2\u00c7\u00c8") - buf.write("\7+\2\2\u00c8\u00c9\7\33\2\2\u00c9\u00d2\7&\2\2\u00ca") - buf.write("\u00cf\5\f\7\2\u00cb\u00cc\7,\2\2\u00cc\u00ce\5\f\7\2") + buf.write("\7,\2\2\u00c8\u00c9\7\34\2\2\u00c9\u00d2\7\'\2\2\u00ca") + buf.write("\u00cf\5\f\7\2\u00cb\u00cc\7-\2\2\u00cc\u00ce\5\f\7\2") buf.write("\u00cd\u00cb\3\2\2\2\u00ce\u00d1\3\2\2\2\u00cf\u00cd\3") buf.write("\2\2\2\u00cf\u00d0\3\2\2\2\u00d0\u00d3\3\2\2\2\u00d1\u00cf") buf.write("\3\2\2\2\u00d2\u00ca\3\2\2\2\u00d2\u00d3\3\2\2\2\u00d3") - buf.write("\u00d4\3\2\2\2\u00d4\u00d6\7\'\2\2\u00d5\u00ad\3\2\2\2") + buf.write("\u00d4\3\2\2\2\u00d4\u00d6\7(\2\2\u00d5\u00ad\3\2\2\2") buf.write("\u00d5\u00b0\3\2\2\2\u00d5\u00b3\3\2\2\2\u00d5\u00b6\3") buf.write("\2\2\2\u00d5\u00b9\3\2\2\2\u00d5\u00bc\3\2\2\2\u00d5\u00bf") buf.write("\3\2\2\2\u00d5\u00c2\3\2\2\2\u00d6\u00d9\3\2\2\2\u00d7") @@ -120,22 +120,24 @@ class COOL ( Parser ): "", "", "", "", "", "", "", "", "", "", "", "", - "", "", "'<-'", "'=>'", "'+'", "'-'", - "'*'", "'/'", "'<'", "'<='", "'='", "'~'", "'('", "')'", - "'{'", "'}'", "'@'", "'.'", "','", "':'", "';'", "", - "", "'(*'", "", "'*)'" ] + "", "", "", "'<-'", "'=>'", + "'+'", "'-'", "'*'", "'/'", "'<'", "'<='", "'='", "'~'", + "'('", "')'", "'{'", "'}'", "'@'", "'.'", "','", "':'", + "';'", "", "", "'(*'", "", + "'*)'" ] symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", - "TRUE", "STRING", "STRING_SIMPLE", "STRING_FIRSTLINE", - "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", - "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", - "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", - "CLOSE_ROUND", "OPEN_CURLY", "CLOSE_CURLY", "AT", - "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", + "TRUE", "STRING", "STRING_SIMPLE", "STRING_SIMPLE_START", + "STRING_FIRSTLINE", "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", + "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", + "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", + "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", "CLOSE_CURLY", + "AT", "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT", - "STRING_INNERLINE", "STRING_LASTLINE", "STRING_MULTILINE" ] + "STRING_INNERLINE", "STRING_LASTLINE", "STRING_MULTILINE", + "STRING_SIMPLE_CONTENT", "STRING_SIMPLE_STOP" ] RULE_program = 0 RULE_programBlocks = 1 @@ -169,37 +171,40 @@ class COOL ( Parser ): TRUE=19 STRING=20 STRING_SIMPLE=21 - STRING_FIRSTLINE=22 - INT=23 - TYPEID=24 - OBJECTID=25 - ASSIGNMENT=26 - CASE_ARROW=27 - ADD=28 - MINUS=29 - MULTIPLY=30 - DIVISION=31 - LESS_THAN=32 - LESS_EQUAL=33 - EQUAL=34 - INTEGER_NEGATIVE=35 - OPEN_ROUND=36 - CLOSE_ROUND=37 - OPEN_CURLY=38 - CLOSE_CURLY=39 - AT=40 - DOT=41 - COMMA=42 - COLON=43 - SEMICOLON=44 - WHITESPACE=45 - ONE_LINE_COMMENT=46 - OPEN_COMMENT=47 - COMMENT=48 - CLOSE_COMMENT=49 - STRING_INNERLINE=50 - STRING_LASTLINE=51 - STRING_MULTILINE=52 + STRING_SIMPLE_START=22 + STRING_FIRSTLINE=23 + INT=24 + TYPEID=25 + OBJECTID=26 + ASSIGNMENT=27 + CASE_ARROW=28 + ADD=29 + MINUS=30 + MULTIPLY=31 + DIVISION=32 + LESS_THAN=33 + LESS_EQUAL=34 + EQUAL=35 + INTEGER_NEGATIVE=36 + OPEN_ROUND=37 + CLOSE_ROUND=38 + OPEN_CURLY=39 + CLOSE_CURLY=40 + AT=41 + DOT=42 + COMMA=43 + COLON=44 + SEMICOLON=45 + WHITESPACE=46 + ONE_LINE_COMMENT=47 + OPEN_COMMENT=48 + COMMENT=49 + CLOSE_COMMENT=50 + STRING_INNERLINE=51 + STRING_LASTLINE=52 + STRING_MULTILINE=53 + STRING_SIMPLE_CONTENT=54 + STRING_SIMPLE_STOP=55 def __init__(self, input:TokenStream, output:TextIO = sys.stdout): super().__init__(input, output) diff --git a/src/COOL.tokens b/src/COOL.tokens index de4efcf0..c7eacfe4 100644 --- a/src/COOL.tokens +++ b/src/COOL.tokens @@ -19,55 +19,58 @@ NOT=18 TRUE=19 STRING=20 STRING_SIMPLE=21 -STRING_FIRSTLINE=22 -INT=23 -TYPEID=24 -OBJECTID=25 -ASSIGNMENT=26 -CASE_ARROW=27 -ADD=28 -MINUS=29 -MULTIPLY=30 -DIVISION=31 -LESS_THAN=32 -LESS_EQUAL=33 -EQUAL=34 -INTEGER_NEGATIVE=35 -OPEN_ROUND=36 -CLOSE_ROUND=37 -OPEN_CURLY=38 -CLOSE_CURLY=39 -AT=40 -DOT=41 -COMMA=42 -COLON=43 -SEMICOLON=44 -WHITESPACE=45 -ONE_LINE_COMMENT=46 -OPEN_COMMENT=47 -COMMENT=48 -CLOSE_COMMENT=49 -STRING_INNERLINE=50 -STRING_LASTLINE=51 -STRING_MULTILINE=52 -'<-'=26 -'=>'=27 -'+'=28 -'-'=29 -'*'=30 -'/'=31 -'<'=32 -'<='=33 -'='=34 -'~'=35 -'('=36 -')'=37 -'{'=38 -'}'=39 -'@'=40 -'.'=41 -','=42 -':'=43 -';'=44 -'(*'=47 -'*)'=49 +STRING_SIMPLE_START=22 +STRING_FIRSTLINE=23 +INT=24 +TYPEID=25 +OBJECTID=26 +ASSIGNMENT=27 +CASE_ARROW=28 +ADD=29 +MINUS=30 +MULTIPLY=31 +DIVISION=32 +LESS_THAN=33 +LESS_EQUAL=34 +EQUAL=35 +INTEGER_NEGATIVE=36 +OPEN_ROUND=37 +CLOSE_ROUND=38 +OPEN_CURLY=39 +CLOSE_CURLY=40 +AT=41 +DOT=42 +COMMA=43 +COLON=44 +SEMICOLON=45 +WHITESPACE=46 +ONE_LINE_COMMENT=47 +OPEN_COMMENT=48 +COMMENT=49 +CLOSE_COMMENT=50 +STRING_INNERLINE=51 +STRING_LASTLINE=52 +STRING_MULTILINE=53 +STRING_SIMPLE_CONTENT=54 +STRING_SIMPLE_STOP=55 +'<-'=27 +'=>'=28 +'+'=29 +'-'=30 +'*'=31 +'/'=32 +'<'=33 +'<='=34 +'='=35 +'~'=36 +'('=37 +')'=38 +'{'=39 +'}'=40 +'@'=41 +'.'=42 +','=43 +':'=44 +';'=45 +'(*'=48 +'*)'=50 diff --git a/src/COOLLexer.py b/src/COOLLexer.py index 8456f1b6..62b3502f 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -22,8 +22,10 @@ def notifyListeners(self, e:LexerNoViableAltException): start = self._tokenStartCharIndex stop = self._input.index text = self._input.getText(start, stop) - if self._currentToken.type in [COOL_LEX.STRING, COOL_LEX.STRING_FIRSTLINE, COOL_LEX.STRING_INNERLINE] or text[0] == '"': - if self.inputStream.size == self.inputStream.index: + if self._currentToken.type in [COOL_LEX.STRING, COOL_LEX.STRING_FIRSTLINE, COOL_LEX.STRING_INNERLINE, COOL_LEX.STRING_SIMPLE_START, COOL_LEX.STRING_SIMPLE_CONTENT ] or text[0] == '"': + if self._input.data[start] == 0: + msg = "String contains null character" + elif self.inputStream.size == self.inputStream.index: msg = "EOF in string constant" else: msg = "Unterminated string constant" diff --git a/src/COOL_LEX.interp b/src/COOL_LEX.interp index 4d6e25e8..b7975eb6 100644 --- a/src/COOL_LEX.interp +++ b/src/COOL_LEX.interp @@ -25,6 +25,7 @@ null null null null +null '<-' '=>' '+' @@ -52,6 +53,8 @@ null null null null +null +null token symbolic names: null @@ -76,6 +79,7 @@ NOT TRUE STRING STRING_SIMPLE +STRING_SIMPLE_START STRING_FIRSTLINE INT TYPEID @@ -107,6 +111,8 @@ CLOSE_COMMENT STRING_INNERLINE STRING_LASTLINE STRING_MULTILINE +STRING_SIMPLE_CONTENT +STRING_SIMPLE_STOP rule names: CLASS @@ -130,6 +136,7 @@ NOT TRUE STRING STRING_SIMPLE +STRING_SIMPLE_START STRING_CONTENT STRING_FIRSTLINE INT @@ -182,6 +189,8 @@ CLOSE_COMMENT STRING_INNERLINE STRING_LASTLINE STRING_MULTILINE +STRING_SIMPLE_CONTENT +STRING_SIMPLE_STOP channel names: DEFAULT_TOKEN_CHANNEL @@ -191,6 +200,7 @@ mode names: DEFAULT_MODE MULTILINE_COMMENT MULTILINE_STR +SIMPLE_STR atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 54, 454, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 247, 10, 21, 3, 22, 3, 22, 7, 22, 251, 10, 22, 12, 22, 14, 22, 254, 11, 22, 3, 22, 3, 22, 3, 23, 3, 23, 5, 23, 260, 10, 23, 3, 24, 3, 24, 7, 24, 264, 10, 24, 12, 24, 14, 24, 267, 11, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 6, 25, 276, 10, 25, 13, 25, 14, 25, 277, 3, 26, 3, 26, 7, 26, 282, 10, 26, 12, 26, 14, 26, 285, 11, 26, 3, 27, 3, 27, 7, 27, 289, 10, 27, 12, 27, 14, 27, 292, 11, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 64, 5, 64, 372, 10, 64, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 66, 3, 66, 3, 67, 6, 67, 383, 10, 67, 13, 67, 14, 67, 384, 3, 67, 3, 67, 3, 68, 3, 68, 3, 68, 3, 68, 7, 68, 393, 10, 68, 12, 68, 14, 68, 396, 11, 68, 3, 68, 5, 68, 399, 10, 68, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 6, 70, 413, 10, 70, 13, 70, 14, 70, 414, 5, 70, 417, 10, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 72, 7, 72, 427, 10, 72, 12, 72, 14, 72, 430, 11, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 437, 10, 73, 12, 73, 14, 73, 440, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 3, 74, 7, 74, 448, 10, 74, 12, 74, 14, 74, 451, 11, 74, 3, 74, 3, 74, 3, 414, 2, 75, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 2, 49, 24, 51, 25, 53, 26, 55, 27, 57, 28, 59, 29, 61, 30, 63, 31, 65, 32, 67, 33, 69, 34, 71, 35, 73, 36, 75, 37, 77, 38, 79, 39, 81, 40, 83, 41, 85, 42, 87, 43, 89, 44, 91, 45, 93, 46, 95, 2, 97, 2, 99, 2, 101, 2, 103, 2, 105, 2, 107, 2, 109, 2, 111, 2, 113, 2, 115, 2, 117, 2, 119, 2, 121, 2, 123, 2, 125, 2, 127, 2, 129, 2, 131, 2, 133, 2, 135, 47, 137, 48, 139, 49, 141, 50, 143, 51, 145, 52, 147, 53, 149, 54, 5, 2, 3, 4, 28, 5, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 446, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 87, 3, 2, 2, 2, 2, 89, 3, 2, 2, 2, 2, 91, 3, 2, 2, 2, 2, 93, 3, 2, 2, 2, 2, 135, 3, 2, 2, 2, 2, 137, 3, 2, 2, 2, 2, 139, 3, 2, 2, 2, 3, 141, 3, 2, 2, 2, 3, 143, 3, 2, 2, 2, 4, 145, 3, 2, 2, 2, 4, 147, 3, 2, 2, 2, 4, 149, 3, 2, 2, 2, 5, 151, 3, 2, 2, 2, 7, 157, 3, 2, 2, 2, 9, 162, 3, 2, 2, 2, 11, 168, 3, 2, 2, 2, 13, 171, 3, 2, 2, 2, 15, 174, 3, 2, 2, 2, 17, 177, 3, 2, 2, 2, 19, 186, 3, 2, 2, 2, 21, 193, 3, 2, 2, 2, 23, 197, 3, 2, 2, 2, 25, 202, 3, 2, 2, 2, 27, 207, 3, 2, 2, 2, 29, 212, 3, 2, 2, 2, 31, 218, 3, 2, 2, 2, 33, 223, 3, 2, 2, 2, 35, 228, 3, 2, 2, 2, 37, 232, 3, 2, 2, 2, 39, 235, 3, 2, 2, 2, 41, 239, 3, 2, 2, 2, 43, 246, 3, 2, 2, 2, 45, 248, 3, 2, 2, 2, 47, 259, 3, 2, 2, 2, 49, 261, 3, 2, 2, 2, 51, 275, 3, 2, 2, 2, 53, 279, 3, 2, 2, 2, 55, 286, 3, 2, 2, 2, 57, 293, 3, 2, 2, 2, 59, 296, 3, 2, 2, 2, 61, 299, 3, 2, 2, 2, 63, 301, 3, 2, 2, 2, 65, 303, 3, 2, 2, 2, 67, 305, 3, 2, 2, 2, 69, 307, 3, 2, 2, 2, 71, 309, 3, 2, 2, 2, 73, 312, 3, 2, 2, 2, 75, 314, 3, 2, 2, 2, 77, 316, 3, 2, 2, 2, 79, 318, 3, 2, 2, 2, 81, 320, 3, 2, 2, 2, 83, 322, 3, 2, 2, 2, 85, 324, 3, 2, 2, 2, 87, 326, 3, 2, 2, 2, 89, 328, 3, 2, 2, 2, 91, 330, 3, 2, 2, 2, 93, 332, 3, 2, 2, 2, 95, 334, 3, 2, 2, 2, 97, 336, 3, 2, 2, 2, 99, 338, 3, 2, 2, 2, 101, 340, 3, 2, 2, 2, 103, 342, 3, 2, 2, 2, 105, 344, 3, 2, 2, 2, 107, 346, 3, 2, 2, 2, 109, 348, 3, 2, 2, 2, 111, 350, 3, 2, 2, 2, 113, 352, 3, 2, 2, 2, 115, 354, 3, 2, 2, 2, 117, 356, 3, 2, 2, 2, 119, 358, 3, 2, 2, 2, 121, 360, 3, 2, 2, 2, 123, 362, 3, 2, 2, 2, 125, 364, 3, 2, 2, 2, 127, 366, 3, 2, 2, 2, 129, 368, 3, 2, 2, 2, 131, 373, 3, 2, 2, 2, 133, 379, 3, 2, 2, 2, 135, 382, 3, 2, 2, 2, 137, 388, 3, 2, 2, 2, 139, 402, 3, 2, 2, 2, 141, 416, 3, 2, 2, 2, 143, 420, 3, 2, 2, 2, 145, 428, 3, 2, 2, 2, 147, 438, 3, 2, 2, 2, 149, 445, 3, 2, 2, 2, 151, 152, 5, 97, 48, 2, 152, 153, 5, 109, 54, 2, 153, 154, 5, 95, 47, 2, 154, 155, 5, 119, 59, 2, 155, 156, 5, 119, 59, 2, 156, 6, 3, 2, 2, 2, 157, 158, 5, 101, 50, 2, 158, 159, 5, 109, 54, 2, 159, 160, 5, 119, 59, 2, 160, 161, 5, 101, 50, 2, 161, 8, 3, 2, 2, 2, 162, 163, 7, 104, 2, 2, 163, 164, 5, 95, 47, 2, 164, 165, 5, 109, 54, 2, 165, 166, 5, 119, 59, 2, 166, 167, 5, 101, 50, 2, 167, 10, 3, 2, 2, 2, 168, 169, 5, 103, 51, 2, 169, 170, 5, 107, 53, 2, 170, 12, 3, 2, 2, 2, 171, 172, 5, 107, 53, 2, 172, 173, 5, 103, 51, 2, 173, 14, 3, 2, 2, 2, 174, 175, 5, 107, 53, 2, 175, 176, 5, 111, 55, 2, 176, 16, 3, 2, 2, 2, 177, 178, 5, 107, 53, 2, 178, 179, 5, 111, 55, 2, 179, 180, 5, 105, 52, 2, 180, 181, 5, 101, 50, 2, 181, 182, 5, 117, 58, 2, 182, 183, 5, 107, 53, 2, 183, 184, 5, 121, 60, 2, 184, 185, 5, 119, 59, 2, 185, 18, 3, 2, 2, 2, 186, 187, 5, 107, 53, 2, 187, 188, 5, 119, 59, 2, 188, 189, 5, 125, 62, 2, 189, 190, 5, 113, 56, 2, 190, 191, 5, 107, 53, 2, 191, 192, 5, 99, 49, 2, 192, 20, 3, 2, 2, 2, 193, 194, 5, 109, 54, 2, 194, 195, 5, 101, 50, 2, 195, 196, 5, 121, 60, 2, 196, 22, 3, 2, 2, 2, 197, 198, 5, 109, 54, 2, 198, 199, 5, 113, 56, 2, 199, 200, 5, 113, 56, 2, 200, 201, 5, 115, 57, 2, 201, 24, 3, 2, 2, 2, 202, 203, 5, 115, 57, 2, 203, 204, 5, 113, 56, 2, 204, 205, 5, 113, 56, 2, 205, 206, 5, 109, 54, 2, 206, 26, 3, 2, 2, 2, 207, 208, 5, 121, 60, 2, 208, 209, 5, 105, 52, 2, 209, 210, 5, 101, 50, 2, 210, 211, 5, 111, 55, 2, 211, 28, 3, 2, 2, 2, 212, 213, 5, 127, 63, 2, 213, 214, 5, 105, 52, 2, 214, 215, 5, 107, 53, 2, 215, 216, 5, 109, 54, 2, 216, 217, 5, 101, 50, 2, 217, 30, 3, 2, 2, 2, 218, 219, 5, 97, 48, 2, 219, 220, 5, 95, 47, 2, 220, 221, 5, 119, 59, 2, 221, 222, 5, 101, 50, 2, 222, 32, 3, 2, 2, 2, 223, 224, 5, 101, 50, 2, 224, 225, 5, 119, 59, 2, 225, 226, 5, 95, 47, 2, 226, 227, 5, 97, 48, 2, 227, 34, 3, 2, 2, 2, 228, 229, 5, 111, 55, 2, 229, 230, 5, 101, 50, 2, 230, 231, 5, 127, 63, 2, 231, 36, 3, 2, 2, 2, 232, 233, 5, 113, 56, 2, 233, 234, 5, 103, 51, 2, 234, 38, 3, 2, 2, 2, 235, 236, 5, 111, 55, 2, 236, 237, 5, 113, 56, 2, 237, 238, 5, 121, 60, 2, 238, 40, 3, 2, 2, 2, 239, 240, 7, 118, 2, 2, 240, 241, 5, 117, 58, 2, 241, 242, 5, 123, 61, 2, 242, 243, 5, 101, 50, 2, 243, 42, 3, 2, 2, 2, 244, 247, 5, 45, 22, 2, 245, 247, 5, 149, 74, 2, 246, 244, 3, 2, 2, 2, 246, 245, 3, 2, 2, 2, 247, 44, 3, 2, 2, 2, 248, 252, 7, 36, 2, 2, 249, 251, 5, 47, 23, 2, 250, 249, 3, 2, 2, 2, 251, 254, 3, 2, 2, 2, 252, 250, 3, 2, 2, 2, 252, 253, 3, 2, 2, 2, 253, 255, 3, 2, 2, 2, 254, 252, 3, 2, 2, 2, 255, 256, 7, 36, 2, 2, 256, 46, 3, 2, 2, 2, 257, 260, 5, 129, 64, 2, 258, 260, 10, 2, 2, 2, 259, 257, 3, 2, 2, 2, 259, 258, 3, 2, 2, 2, 260, 48, 3, 2, 2, 2, 261, 265, 7, 36, 2, 2, 262, 264, 5, 47, 23, 2, 263, 262, 3, 2, 2, 2, 264, 267, 3, 2, 2, 2, 265, 263, 3, 2, 2, 2, 265, 266, 3, 2, 2, 2, 266, 268, 3, 2, 2, 2, 267, 265, 3, 2, 2, 2, 268, 269, 7, 94, 2, 2, 269, 270, 7, 15, 2, 2, 270, 271, 7, 12, 2, 2, 271, 272, 3, 2, 2, 2, 272, 273, 8, 24, 2, 2, 273, 50, 3, 2, 2, 2, 274, 276, 9, 3, 2, 2, 275, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 275, 3, 2, 2, 2, 277, 278, 3, 2, 2, 2, 278, 52, 3, 2, 2, 2, 279, 283, 9, 4, 2, 2, 280, 282, 9, 5, 2, 2, 281, 280, 3, 2, 2, 2, 282, 285, 3, 2, 2, 2, 283, 281, 3, 2, 2, 2, 283, 284, 3, 2, 2, 2, 284, 54, 3, 2, 2, 2, 285, 283, 3, 2, 2, 2, 286, 290, 9, 6, 2, 2, 287, 289, 9, 5, 2, 2, 288, 287, 3, 2, 2, 2, 289, 292, 3, 2, 2, 2, 290, 288, 3, 2, 2, 2, 290, 291, 3, 2, 2, 2, 291, 56, 3, 2, 2, 2, 292, 290, 3, 2, 2, 2, 293, 294, 7, 62, 2, 2, 294, 295, 7, 47, 2, 2, 295, 58, 3, 2, 2, 2, 296, 297, 7, 63, 2, 2, 297, 298, 7, 64, 2, 2, 298, 60, 3, 2, 2, 2, 299, 300, 7, 45, 2, 2, 300, 62, 3, 2, 2, 2, 301, 302, 7, 47, 2, 2, 302, 64, 3, 2, 2, 2, 303, 304, 7, 44, 2, 2, 304, 66, 3, 2, 2, 2, 305, 306, 7, 49, 2, 2, 306, 68, 3, 2, 2, 2, 307, 308, 7, 62, 2, 2, 308, 70, 3, 2, 2, 2, 309, 310, 7, 62, 2, 2, 310, 311, 7, 63, 2, 2, 311, 72, 3, 2, 2, 2, 312, 313, 7, 63, 2, 2, 313, 74, 3, 2, 2, 2, 314, 315, 7, 128, 2, 2, 315, 76, 3, 2, 2, 2, 316, 317, 7, 42, 2, 2, 317, 78, 3, 2, 2, 2, 318, 319, 7, 43, 2, 2, 319, 80, 3, 2, 2, 2, 320, 321, 7, 125, 2, 2, 321, 82, 3, 2, 2, 2, 322, 323, 7, 127, 2, 2, 323, 84, 3, 2, 2, 2, 324, 325, 7, 66, 2, 2, 325, 86, 3, 2, 2, 2, 326, 327, 7, 48, 2, 2, 327, 88, 3, 2, 2, 2, 328, 329, 7, 46, 2, 2, 329, 90, 3, 2, 2, 2, 330, 331, 7, 60, 2, 2, 331, 92, 3, 2, 2, 2, 332, 333, 7, 61, 2, 2, 333, 94, 3, 2, 2, 2, 334, 335, 9, 7, 2, 2, 335, 96, 3, 2, 2, 2, 336, 337, 9, 8, 2, 2, 337, 98, 3, 2, 2, 2, 338, 339, 9, 9, 2, 2, 339, 100, 3, 2, 2, 2, 340, 341, 9, 10, 2, 2, 341, 102, 3, 2, 2, 2, 342, 343, 9, 11, 2, 2, 343, 104, 3, 2, 2, 2, 344, 345, 9, 12, 2, 2, 345, 106, 3, 2, 2, 2, 346, 347, 9, 13, 2, 2, 347, 108, 3, 2, 2, 2, 348, 349, 9, 14, 2, 2, 349, 110, 3, 2, 2, 2, 350, 351, 9, 15, 2, 2, 351, 112, 3, 2, 2, 2, 352, 353, 9, 16, 2, 2, 353, 114, 3, 2, 2, 2, 354, 355, 9, 17, 2, 2, 355, 116, 3, 2, 2, 2, 356, 357, 9, 18, 2, 2, 357, 118, 3, 2, 2, 2, 358, 359, 9, 19, 2, 2, 359, 120, 3, 2, 2, 2, 360, 361, 9, 20, 2, 2, 361, 122, 3, 2, 2, 2, 362, 363, 9, 21, 2, 2, 363, 124, 3, 2, 2, 2, 364, 365, 9, 22, 2, 2, 365, 126, 3, 2, 2, 2, 366, 367, 9, 23, 2, 2, 367, 128, 3, 2, 2, 2, 368, 371, 7, 94, 2, 2, 369, 372, 9, 24, 2, 2, 370, 372, 5, 131, 65, 2, 371, 369, 3, 2, 2, 2, 371, 370, 3, 2, 2, 2, 372, 130, 3, 2, 2, 2, 373, 374, 7, 119, 2, 2, 374, 375, 5, 133, 66, 2, 375, 376, 5, 133, 66, 2, 376, 377, 5, 133, 66, 2, 377, 378, 5, 133, 66, 2, 378, 132, 3, 2, 2, 2, 379, 380, 9, 25, 2, 2, 380, 134, 3, 2, 2, 2, 381, 383, 9, 26, 2, 2, 382, 381, 3, 2, 2, 2, 383, 384, 3, 2, 2, 2, 384, 382, 3, 2, 2, 2, 384, 385, 3, 2, 2, 2, 385, 386, 3, 2, 2, 2, 386, 387, 8, 67, 3, 2, 387, 136, 3, 2, 2, 2, 388, 389, 7, 47, 2, 2, 389, 390, 7, 47, 2, 2, 390, 394, 3, 2, 2, 2, 391, 393, 10, 27, 2, 2, 392, 391, 3, 2, 2, 2, 393, 396, 3, 2, 2, 2, 394, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 398, 3, 2, 2, 2, 396, 394, 3, 2, 2, 2, 397, 399, 7, 12, 2, 2, 398, 397, 3, 2, 2, 2, 398, 399, 3, 2, 2, 2, 399, 400, 3, 2, 2, 2, 400, 401, 8, 68, 3, 2, 401, 138, 3, 2, 2, 2, 402, 403, 7, 42, 2, 2, 403, 404, 7, 44, 2, 2, 404, 405, 3, 2, 2, 2, 405, 406, 8, 69, 4, 2, 406, 140, 3, 2, 2, 2, 407, 408, 5, 139, 69, 2, 408, 409, 5, 141, 70, 2, 409, 410, 5, 143, 71, 2, 410, 417, 3, 2, 2, 2, 411, 413, 11, 2, 2, 2, 412, 411, 3, 2, 2, 2, 413, 414, 3, 2, 2, 2, 414, 415, 3, 2, 2, 2, 414, 412, 3, 2, 2, 2, 415, 417, 3, 2, 2, 2, 416, 407, 3, 2, 2, 2, 416, 412, 3, 2, 2, 2, 417, 418, 3, 2, 2, 2, 418, 419, 8, 70, 3, 2, 419, 142, 3, 2, 2, 2, 420, 421, 7, 44, 2, 2, 421, 422, 7, 43, 2, 2, 422, 423, 3, 2, 2, 2, 423, 424, 8, 71, 5, 2, 424, 144, 3, 2, 2, 2, 425, 427, 5, 47, 23, 2, 426, 425, 3, 2, 2, 2, 427, 430, 3, 2, 2, 2, 428, 426, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 431, 3, 2, 2, 2, 430, 428, 3, 2, 2, 2, 431, 432, 7, 94, 2, 2, 432, 433, 7, 15, 2, 2, 433, 434, 7, 12, 2, 2, 434, 146, 3, 2, 2, 2, 435, 437, 5, 47, 23, 2, 436, 435, 3, 2, 2, 2, 437, 440, 3, 2, 2, 2, 438, 436, 3, 2, 2, 2, 438, 439, 3, 2, 2, 2, 439, 441, 3, 2, 2, 2, 440, 438, 3, 2, 2, 2, 441, 442, 7, 36, 2, 2, 442, 443, 3, 2, 2, 2, 443, 444, 8, 73, 5, 2, 444, 148, 3, 2, 2, 2, 445, 449, 5, 49, 24, 2, 446, 448, 5, 145, 72, 2, 447, 446, 3, 2, 2, 2, 448, 451, 3, 2, 2, 2, 449, 447, 3, 2, 2, 2, 449, 450, 3, 2, 2, 2, 450, 452, 3, 2, 2, 2, 451, 449, 3, 2, 2, 2, 452, 453, 5, 147, 73, 2, 453, 150, 3, 2, 2, 2, 21, 2, 3, 4, 246, 252, 259, 265, 277, 283, 290, 371, 384, 394, 398, 414, 416, 428, 438, 449, 6, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 57, 471, 8, 1, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 254, 10, 21, 3, 22, 3, 22, 7, 22, 258, 10, 22, 12, 22, 14, 22, 261, 11, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 5, 24, 271, 10, 24, 3, 25, 3, 25, 7, 25, 275, 10, 25, 12, 25, 14, 25, 278, 11, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 6, 26, 287, 10, 26, 13, 26, 14, 26, 288, 3, 27, 3, 27, 7, 27, 293, 10, 27, 12, 27, 14, 27, 296, 11, 27, 3, 28, 3, 28, 7, 28, 300, 10, 28, 12, 28, 14, 28, 303, 11, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 5, 65, 383, 10, 65, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 6, 68, 394, 10, 68, 13, 68, 14, 68, 395, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 7, 69, 404, 10, 69, 12, 69, 14, 69, 407, 11, 69, 3, 69, 5, 69, 410, 10, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 424, 10, 71, 13, 71, 14, 71, 425, 5, 71, 428, 10, 71, 3, 71, 3, 71, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 438, 10, 73, 12, 73, 14, 73, 441, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 7, 74, 448, 10, 74, 12, 74, 14, 74, 451, 11, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 75, 3, 75, 7, 75, 459, 10, 75, 12, 75, 14, 75, 462, 11, 75, 3, 75, 3, 75, 3, 76, 3, 76, 3, 77, 3, 77, 3, 77, 3, 77, 3, 425, 2, 78, 6, 3, 8, 4, 10, 5, 12, 6, 14, 7, 16, 8, 18, 9, 20, 10, 22, 11, 24, 12, 26, 13, 28, 14, 30, 15, 32, 16, 34, 17, 36, 18, 38, 19, 40, 20, 42, 21, 44, 22, 46, 23, 48, 24, 50, 2, 52, 25, 54, 26, 56, 27, 58, 28, 60, 29, 62, 30, 64, 31, 66, 32, 68, 33, 70, 34, 72, 35, 74, 36, 76, 37, 78, 38, 80, 39, 82, 40, 84, 41, 86, 42, 88, 43, 90, 44, 92, 45, 94, 46, 96, 47, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 2, 132, 2, 134, 2, 136, 2, 138, 48, 140, 49, 142, 50, 144, 51, 146, 52, 148, 53, 150, 54, 152, 55, 154, 56, 156, 57, 6, 2, 3, 4, 5, 28, 6, 2, 2, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 462, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 90, 3, 2, 2, 2, 2, 92, 3, 2, 2, 2, 2, 94, 3, 2, 2, 2, 2, 96, 3, 2, 2, 2, 2, 138, 3, 2, 2, 2, 2, 140, 3, 2, 2, 2, 2, 142, 3, 2, 2, 2, 3, 144, 3, 2, 2, 2, 3, 146, 3, 2, 2, 2, 4, 148, 3, 2, 2, 2, 4, 150, 3, 2, 2, 2, 4, 152, 3, 2, 2, 2, 5, 154, 3, 2, 2, 2, 5, 156, 3, 2, 2, 2, 6, 158, 3, 2, 2, 2, 8, 164, 3, 2, 2, 2, 10, 169, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 178, 3, 2, 2, 2, 16, 181, 3, 2, 2, 2, 18, 184, 3, 2, 2, 2, 20, 193, 3, 2, 2, 2, 22, 200, 3, 2, 2, 2, 24, 204, 3, 2, 2, 2, 26, 209, 3, 2, 2, 2, 28, 214, 3, 2, 2, 2, 30, 219, 3, 2, 2, 2, 32, 225, 3, 2, 2, 2, 34, 230, 3, 2, 2, 2, 36, 235, 3, 2, 2, 2, 38, 239, 3, 2, 2, 2, 40, 242, 3, 2, 2, 2, 42, 246, 3, 2, 2, 2, 44, 253, 3, 2, 2, 2, 46, 255, 3, 2, 2, 2, 48, 264, 3, 2, 2, 2, 50, 270, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 286, 3, 2, 2, 2, 56, 290, 3, 2, 2, 2, 58, 297, 3, 2, 2, 2, 60, 304, 3, 2, 2, 2, 62, 307, 3, 2, 2, 2, 64, 310, 3, 2, 2, 2, 66, 312, 3, 2, 2, 2, 68, 314, 3, 2, 2, 2, 70, 316, 3, 2, 2, 2, 72, 318, 3, 2, 2, 2, 74, 320, 3, 2, 2, 2, 76, 323, 3, 2, 2, 2, 78, 325, 3, 2, 2, 2, 80, 327, 3, 2, 2, 2, 82, 329, 3, 2, 2, 2, 84, 331, 3, 2, 2, 2, 86, 333, 3, 2, 2, 2, 88, 335, 3, 2, 2, 2, 90, 337, 3, 2, 2, 2, 92, 339, 3, 2, 2, 2, 94, 341, 3, 2, 2, 2, 96, 343, 3, 2, 2, 2, 98, 345, 3, 2, 2, 2, 100, 347, 3, 2, 2, 2, 102, 349, 3, 2, 2, 2, 104, 351, 3, 2, 2, 2, 106, 353, 3, 2, 2, 2, 108, 355, 3, 2, 2, 2, 110, 357, 3, 2, 2, 2, 112, 359, 3, 2, 2, 2, 114, 361, 3, 2, 2, 2, 116, 363, 3, 2, 2, 2, 118, 365, 3, 2, 2, 2, 120, 367, 3, 2, 2, 2, 122, 369, 3, 2, 2, 2, 124, 371, 3, 2, 2, 2, 126, 373, 3, 2, 2, 2, 128, 375, 3, 2, 2, 2, 130, 377, 3, 2, 2, 2, 132, 379, 3, 2, 2, 2, 134, 384, 3, 2, 2, 2, 136, 390, 3, 2, 2, 2, 138, 393, 3, 2, 2, 2, 140, 399, 3, 2, 2, 2, 142, 413, 3, 2, 2, 2, 144, 427, 3, 2, 2, 2, 146, 431, 3, 2, 2, 2, 148, 439, 3, 2, 2, 2, 150, 449, 3, 2, 2, 2, 152, 456, 3, 2, 2, 2, 154, 465, 3, 2, 2, 2, 156, 467, 3, 2, 2, 2, 158, 159, 5, 100, 49, 2, 159, 160, 5, 112, 55, 2, 160, 161, 5, 98, 48, 2, 161, 162, 5, 122, 60, 2, 162, 163, 5, 122, 60, 2, 163, 7, 3, 2, 2, 2, 164, 165, 5, 104, 51, 2, 165, 166, 5, 112, 55, 2, 166, 167, 5, 122, 60, 2, 167, 168, 5, 104, 51, 2, 168, 9, 3, 2, 2, 2, 169, 170, 7, 104, 2, 2, 170, 171, 5, 98, 48, 2, 171, 172, 5, 112, 55, 2, 172, 173, 5, 122, 60, 2, 173, 174, 5, 104, 51, 2, 174, 11, 3, 2, 2, 2, 175, 176, 5, 106, 52, 2, 176, 177, 5, 110, 54, 2, 177, 13, 3, 2, 2, 2, 178, 179, 5, 110, 54, 2, 179, 180, 5, 106, 52, 2, 180, 15, 3, 2, 2, 2, 181, 182, 5, 110, 54, 2, 182, 183, 5, 114, 56, 2, 183, 17, 3, 2, 2, 2, 184, 185, 5, 110, 54, 2, 185, 186, 5, 114, 56, 2, 186, 187, 5, 108, 53, 2, 187, 188, 5, 104, 51, 2, 188, 189, 5, 120, 59, 2, 189, 190, 5, 110, 54, 2, 190, 191, 5, 124, 61, 2, 191, 192, 5, 122, 60, 2, 192, 19, 3, 2, 2, 2, 193, 194, 5, 110, 54, 2, 194, 195, 5, 122, 60, 2, 195, 196, 5, 128, 63, 2, 196, 197, 5, 116, 57, 2, 197, 198, 5, 110, 54, 2, 198, 199, 5, 102, 50, 2, 199, 21, 3, 2, 2, 2, 200, 201, 5, 112, 55, 2, 201, 202, 5, 104, 51, 2, 202, 203, 5, 124, 61, 2, 203, 23, 3, 2, 2, 2, 204, 205, 5, 112, 55, 2, 205, 206, 5, 116, 57, 2, 206, 207, 5, 116, 57, 2, 207, 208, 5, 118, 58, 2, 208, 25, 3, 2, 2, 2, 209, 210, 5, 118, 58, 2, 210, 211, 5, 116, 57, 2, 211, 212, 5, 116, 57, 2, 212, 213, 5, 112, 55, 2, 213, 27, 3, 2, 2, 2, 214, 215, 5, 124, 61, 2, 215, 216, 5, 108, 53, 2, 216, 217, 5, 104, 51, 2, 217, 218, 5, 114, 56, 2, 218, 29, 3, 2, 2, 2, 219, 220, 5, 130, 64, 2, 220, 221, 5, 108, 53, 2, 221, 222, 5, 110, 54, 2, 222, 223, 5, 112, 55, 2, 223, 224, 5, 104, 51, 2, 224, 31, 3, 2, 2, 2, 225, 226, 5, 100, 49, 2, 226, 227, 5, 98, 48, 2, 227, 228, 5, 122, 60, 2, 228, 229, 5, 104, 51, 2, 229, 33, 3, 2, 2, 2, 230, 231, 5, 104, 51, 2, 231, 232, 5, 122, 60, 2, 232, 233, 5, 98, 48, 2, 233, 234, 5, 100, 49, 2, 234, 35, 3, 2, 2, 2, 235, 236, 5, 114, 56, 2, 236, 237, 5, 104, 51, 2, 237, 238, 5, 130, 64, 2, 238, 37, 3, 2, 2, 2, 239, 240, 5, 116, 57, 2, 240, 241, 5, 106, 52, 2, 241, 39, 3, 2, 2, 2, 242, 243, 5, 114, 56, 2, 243, 244, 5, 116, 57, 2, 244, 245, 5, 124, 61, 2, 245, 41, 3, 2, 2, 2, 246, 247, 7, 118, 2, 2, 247, 248, 5, 120, 59, 2, 248, 249, 5, 126, 62, 2, 249, 250, 5, 104, 51, 2, 250, 43, 3, 2, 2, 2, 251, 254, 5, 46, 22, 2, 252, 254, 5, 152, 75, 2, 253, 251, 3, 2, 2, 2, 253, 252, 3, 2, 2, 2, 254, 45, 3, 2, 2, 2, 255, 259, 5, 48, 23, 2, 256, 258, 5, 154, 76, 2, 257, 256, 3, 2, 2, 2, 258, 261, 3, 2, 2, 2, 259, 257, 3, 2, 2, 2, 259, 260, 3, 2, 2, 2, 260, 262, 3, 2, 2, 2, 261, 259, 3, 2, 2, 2, 262, 263, 5, 156, 77, 2, 263, 47, 3, 2, 2, 2, 264, 265, 7, 36, 2, 2, 265, 266, 3, 2, 2, 2, 266, 267, 8, 23, 2, 2, 267, 49, 3, 2, 2, 2, 268, 271, 5, 132, 65, 2, 269, 271, 10, 2, 2, 2, 270, 268, 3, 2, 2, 2, 270, 269, 3, 2, 2, 2, 271, 51, 3, 2, 2, 2, 272, 276, 7, 36, 2, 2, 273, 275, 5, 50, 24, 2, 274, 273, 3, 2, 2, 2, 275, 278, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 279, 3, 2, 2, 2, 278, 276, 3, 2, 2, 2, 279, 280, 7, 94, 2, 2, 280, 281, 7, 15, 2, 2, 281, 282, 7, 12, 2, 2, 282, 283, 3, 2, 2, 2, 283, 284, 8, 25, 3, 2, 284, 53, 3, 2, 2, 2, 285, 287, 9, 3, 2, 2, 286, 285, 3, 2, 2, 2, 287, 288, 3, 2, 2, 2, 288, 286, 3, 2, 2, 2, 288, 289, 3, 2, 2, 2, 289, 55, 3, 2, 2, 2, 290, 294, 9, 4, 2, 2, 291, 293, 9, 5, 2, 2, 292, 291, 3, 2, 2, 2, 293, 296, 3, 2, 2, 2, 294, 292, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 57, 3, 2, 2, 2, 296, 294, 3, 2, 2, 2, 297, 301, 9, 6, 2, 2, 298, 300, 9, 5, 2, 2, 299, 298, 3, 2, 2, 2, 300, 303, 3, 2, 2, 2, 301, 299, 3, 2, 2, 2, 301, 302, 3, 2, 2, 2, 302, 59, 3, 2, 2, 2, 303, 301, 3, 2, 2, 2, 304, 305, 7, 62, 2, 2, 305, 306, 7, 47, 2, 2, 306, 61, 3, 2, 2, 2, 307, 308, 7, 63, 2, 2, 308, 309, 7, 64, 2, 2, 309, 63, 3, 2, 2, 2, 310, 311, 7, 45, 2, 2, 311, 65, 3, 2, 2, 2, 312, 313, 7, 47, 2, 2, 313, 67, 3, 2, 2, 2, 314, 315, 7, 44, 2, 2, 315, 69, 3, 2, 2, 2, 316, 317, 7, 49, 2, 2, 317, 71, 3, 2, 2, 2, 318, 319, 7, 62, 2, 2, 319, 73, 3, 2, 2, 2, 320, 321, 7, 62, 2, 2, 321, 322, 7, 63, 2, 2, 322, 75, 3, 2, 2, 2, 323, 324, 7, 63, 2, 2, 324, 77, 3, 2, 2, 2, 325, 326, 7, 128, 2, 2, 326, 79, 3, 2, 2, 2, 327, 328, 7, 42, 2, 2, 328, 81, 3, 2, 2, 2, 329, 330, 7, 43, 2, 2, 330, 83, 3, 2, 2, 2, 331, 332, 7, 125, 2, 2, 332, 85, 3, 2, 2, 2, 333, 334, 7, 127, 2, 2, 334, 87, 3, 2, 2, 2, 335, 336, 7, 66, 2, 2, 336, 89, 3, 2, 2, 2, 337, 338, 7, 48, 2, 2, 338, 91, 3, 2, 2, 2, 339, 340, 7, 46, 2, 2, 340, 93, 3, 2, 2, 2, 341, 342, 7, 60, 2, 2, 342, 95, 3, 2, 2, 2, 343, 344, 7, 61, 2, 2, 344, 97, 3, 2, 2, 2, 345, 346, 9, 7, 2, 2, 346, 99, 3, 2, 2, 2, 347, 348, 9, 8, 2, 2, 348, 101, 3, 2, 2, 2, 349, 350, 9, 9, 2, 2, 350, 103, 3, 2, 2, 2, 351, 352, 9, 10, 2, 2, 352, 105, 3, 2, 2, 2, 353, 354, 9, 11, 2, 2, 354, 107, 3, 2, 2, 2, 355, 356, 9, 12, 2, 2, 356, 109, 3, 2, 2, 2, 357, 358, 9, 13, 2, 2, 358, 111, 3, 2, 2, 2, 359, 360, 9, 14, 2, 2, 360, 113, 3, 2, 2, 2, 361, 362, 9, 15, 2, 2, 362, 115, 3, 2, 2, 2, 363, 364, 9, 16, 2, 2, 364, 117, 3, 2, 2, 2, 365, 366, 9, 17, 2, 2, 366, 119, 3, 2, 2, 2, 367, 368, 9, 18, 2, 2, 368, 121, 3, 2, 2, 2, 369, 370, 9, 19, 2, 2, 370, 123, 3, 2, 2, 2, 371, 372, 9, 20, 2, 2, 372, 125, 3, 2, 2, 2, 373, 374, 9, 21, 2, 2, 374, 127, 3, 2, 2, 2, 375, 376, 9, 22, 2, 2, 376, 129, 3, 2, 2, 2, 377, 378, 9, 23, 2, 2, 378, 131, 3, 2, 2, 2, 379, 382, 7, 94, 2, 2, 380, 383, 9, 24, 2, 2, 381, 383, 5, 134, 66, 2, 382, 380, 3, 2, 2, 2, 382, 381, 3, 2, 2, 2, 383, 133, 3, 2, 2, 2, 384, 385, 7, 119, 2, 2, 385, 386, 5, 136, 67, 2, 386, 387, 5, 136, 67, 2, 387, 388, 5, 136, 67, 2, 388, 389, 5, 136, 67, 2, 389, 135, 3, 2, 2, 2, 390, 391, 9, 25, 2, 2, 391, 137, 3, 2, 2, 2, 392, 394, 9, 26, 2, 2, 393, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 393, 3, 2, 2, 2, 395, 396, 3, 2, 2, 2, 396, 397, 3, 2, 2, 2, 397, 398, 8, 68, 4, 2, 398, 139, 3, 2, 2, 2, 399, 400, 7, 47, 2, 2, 400, 401, 7, 47, 2, 2, 401, 405, 3, 2, 2, 2, 402, 404, 10, 27, 2, 2, 403, 402, 3, 2, 2, 2, 404, 407, 3, 2, 2, 2, 405, 403, 3, 2, 2, 2, 405, 406, 3, 2, 2, 2, 406, 409, 3, 2, 2, 2, 407, 405, 3, 2, 2, 2, 408, 410, 7, 12, 2, 2, 409, 408, 3, 2, 2, 2, 409, 410, 3, 2, 2, 2, 410, 411, 3, 2, 2, 2, 411, 412, 8, 69, 4, 2, 412, 141, 3, 2, 2, 2, 413, 414, 7, 42, 2, 2, 414, 415, 7, 44, 2, 2, 415, 416, 3, 2, 2, 2, 416, 417, 8, 70, 5, 2, 417, 143, 3, 2, 2, 2, 418, 419, 5, 142, 70, 2, 419, 420, 5, 144, 71, 2, 420, 421, 5, 146, 72, 2, 421, 428, 3, 2, 2, 2, 422, 424, 11, 2, 2, 2, 423, 422, 3, 2, 2, 2, 424, 425, 3, 2, 2, 2, 425, 426, 3, 2, 2, 2, 425, 423, 3, 2, 2, 2, 426, 428, 3, 2, 2, 2, 427, 418, 3, 2, 2, 2, 427, 423, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 430, 8, 71, 4, 2, 430, 145, 3, 2, 2, 2, 431, 432, 7, 44, 2, 2, 432, 433, 7, 43, 2, 2, 433, 434, 3, 2, 2, 2, 434, 435, 8, 72, 6, 2, 435, 147, 3, 2, 2, 2, 436, 438, 5, 50, 24, 2, 437, 436, 3, 2, 2, 2, 438, 441, 3, 2, 2, 2, 439, 437, 3, 2, 2, 2, 439, 440, 3, 2, 2, 2, 440, 442, 3, 2, 2, 2, 441, 439, 3, 2, 2, 2, 442, 443, 7, 94, 2, 2, 443, 444, 7, 15, 2, 2, 444, 445, 7, 12, 2, 2, 445, 149, 3, 2, 2, 2, 446, 448, 5, 50, 24, 2, 447, 446, 3, 2, 2, 2, 448, 451, 3, 2, 2, 2, 449, 447, 3, 2, 2, 2, 449, 450, 3, 2, 2, 2, 450, 452, 3, 2, 2, 2, 451, 449, 3, 2, 2, 2, 452, 453, 7, 36, 2, 2, 453, 454, 3, 2, 2, 2, 454, 455, 8, 74, 6, 2, 455, 151, 3, 2, 2, 2, 456, 460, 5, 52, 25, 2, 457, 459, 5, 148, 73, 2, 458, 457, 3, 2, 2, 2, 459, 462, 3, 2, 2, 2, 460, 458, 3, 2, 2, 2, 460, 461, 3, 2, 2, 2, 461, 463, 3, 2, 2, 2, 462, 460, 3, 2, 2, 2, 463, 464, 5, 150, 74, 2, 464, 153, 3, 2, 2, 2, 465, 466, 5, 50, 24, 2, 466, 155, 3, 2, 2, 2, 467, 468, 7, 36, 2, 2, 468, 469, 3, 2, 2, 2, 469, 470, 8, 77, 6, 2, 470, 157, 3, 2, 2, 2, 22, 2, 3, 4, 5, 253, 259, 270, 276, 288, 294, 301, 382, 395, 405, 409, 425, 427, 439, 449, 460, 7, 7, 5, 2, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file diff --git a/src/COOL_LEX.py b/src/COOL_LEX.py index c2fb0dc6..02c42de2 100644 --- a/src/COOL_LEX.py +++ b/src/COOL_LEX.py @@ -8,202 +8,210 @@ def serializedATN(): with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\66") - buf.write("\u01c6\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6") - buf.write("\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f") - buf.write("\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22") - buf.write("\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27") - buf.write("\4\30\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35") - buf.write("\t\35\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4") - buf.write("$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t") - buf.write(",\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63") - buf.write("\t\63\4\64\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\4") - buf.write("9\t9\4:\t:\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA\4") - buf.write("B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I\tI\4J\tJ\3") - buf.write("\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\4\3\4\3\4") - buf.write("\3\4\3\4\3\4\3\5\3\5\3\5\3\6\3\6\3\6\3\7\3\7\3\7\3\b\3") - buf.write("\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t") - buf.write("\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3\f\3\f") - buf.write("\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3") - buf.write("\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20") - buf.write("\3\20\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\23\3\23\3\23") - buf.write("\3\23\3\24\3\24\3\24\3\24\3\24\3\25\3\25\5\25\u00f7\n") - buf.write("\25\3\26\3\26\7\26\u00fb\n\26\f\26\16\26\u00fe\13\26\3") - buf.write("\26\3\26\3\27\3\27\5\27\u0104\n\27\3\30\3\30\7\30\u0108") - buf.write("\n\30\f\30\16\30\u010b\13\30\3\30\3\30\3\30\3\30\3\30") - buf.write("\3\30\3\31\6\31\u0114\n\31\r\31\16\31\u0115\3\32\3\32") - buf.write("\7\32\u011a\n\32\f\32\16\32\u011d\13\32\3\33\3\33\7\33") - buf.write("\u0121\n\33\f\33\16\33\u0124\13\33\3\34\3\34\3\34\3\35") - buf.write("\3\35\3\35\3\36\3\36\3\37\3\37\3 \3 \3!\3!\3\"\3\"\3#") - buf.write("\3#\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(\3)\3)\3*\3*\3+") - buf.write("\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3\60\3\61\3\61\3\62\3") - buf.write("\62\3\63\3\63\3\64\3\64\3\65\3\65\3\66\3\66\3\67\3\67") - buf.write("\38\38\39\39\3:\3:\3;\3;\3<\3<\3=\3=\3>\3>\3?\3?\3@\3") - buf.write("@\3@\5@\u0174\n@\3A\3A\3A\3A\3A\3A\3B\3B\3C\6C\u017f\n") - buf.write("C\rC\16C\u0180\3C\3C\3D\3D\3D\3D\7D\u0189\nD\fD\16D\u018c") - buf.write("\13D\3D\5D\u018f\nD\3D\3D\3E\3E\3E\3E\3E\3F\3F\3F\3F\3") - buf.write("F\6F\u019d\nF\rF\16F\u019e\5F\u01a1\nF\3F\3F\3G\3G\3G") - buf.write("\3G\3G\3H\7H\u01ab\nH\fH\16H\u01ae\13H\3H\3H\3H\3H\3I") - buf.write("\7I\u01b5\nI\fI\16I\u01b8\13I\3I\3I\3I\3I\3J\3J\7J\u01c0") - buf.write("\nJ\fJ\16J\u01c3\13J\3J\3J\3\u019e\2K\5\3\7\4\t\5\13\6") - buf.write("\r\7\17\b\21\t\23\n\25\13\27\f\31\r\33\16\35\17\37\20") - buf.write("!\21#\22%\23\'\24)\25+\26-\27/\2\61\30\63\31\65\32\67") - buf.write("\339\34;\35=\36?\37A C!E\"G#I$K%M&O\'Q(S)U*W+Y,[-]._\2") - buf.write("a\2c\2e\2g\2i\2k\2m\2o\2q\2s\2u\2w\2y\2{\2}\2\177\2\u0081") - buf.write("\2\u0083\2\u0085\2\u0087/\u0089\60\u008b\61\u008d\62\u008f") - buf.write("\63\u0091\64\u0093\65\u0095\66\5\2\3\4\34\5\2\f\f\17\17") - buf.write("$$\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEe") - buf.write("e\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2") - buf.write("PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4") - buf.write("\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2") - buf.write("\13\f\16\17\"\"\3\2\f\f\2\u01be\2\5\3\2\2\2\2\7\3\2\2") - buf.write("\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2") - buf.write("\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31") - buf.write("\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2") - buf.write("\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3") - buf.write("\2\2\2\2-\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2") - buf.write("\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3") - buf.write("\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I") - buf.write("\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2") - buf.write("S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2") - buf.write("\2]\3\2\2\2\2\u0087\3\2\2\2\2\u0089\3\2\2\2\2\u008b\3") - buf.write("\2\2\2\3\u008d\3\2\2\2\3\u008f\3\2\2\2\4\u0091\3\2\2\2") - buf.write("\4\u0093\3\2\2\2\4\u0095\3\2\2\2\5\u0097\3\2\2\2\7\u009d") - buf.write("\3\2\2\2\t\u00a2\3\2\2\2\13\u00a8\3\2\2\2\r\u00ab\3\2") - buf.write("\2\2\17\u00ae\3\2\2\2\21\u00b1\3\2\2\2\23\u00ba\3\2\2") - buf.write("\2\25\u00c1\3\2\2\2\27\u00c5\3\2\2\2\31\u00ca\3\2\2\2") - buf.write("\33\u00cf\3\2\2\2\35\u00d4\3\2\2\2\37\u00da\3\2\2\2!\u00df") - buf.write("\3\2\2\2#\u00e4\3\2\2\2%\u00e8\3\2\2\2\'\u00eb\3\2\2\2") - buf.write(")\u00ef\3\2\2\2+\u00f6\3\2\2\2-\u00f8\3\2\2\2/\u0103\3") - buf.write("\2\2\2\61\u0105\3\2\2\2\63\u0113\3\2\2\2\65\u0117\3\2") - buf.write("\2\2\67\u011e\3\2\2\29\u0125\3\2\2\2;\u0128\3\2\2\2=\u012b") - buf.write("\3\2\2\2?\u012d\3\2\2\2A\u012f\3\2\2\2C\u0131\3\2\2\2") - buf.write("E\u0133\3\2\2\2G\u0135\3\2\2\2I\u0138\3\2\2\2K\u013a\3") - buf.write("\2\2\2M\u013c\3\2\2\2O\u013e\3\2\2\2Q\u0140\3\2\2\2S\u0142") - buf.write("\3\2\2\2U\u0144\3\2\2\2W\u0146\3\2\2\2Y\u0148\3\2\2\2") - buf.write("[\u014a\3\2\2\2]\u014c\3\2\2\2_\u014e\3\2\2\2a\u0150\3") - buf.write("\2\2\2c\u0152\3\2\2\2e\u0154\3\2\2\2g\u0156\3\2\2\2i\u0158") - buf.write("\3\2\2\2k\u015a\3\2\2\2m\u015c\3\2\2\2o\u015e\3\2\2\2") - buf.write("q\u0160\3\2\2\2s\u0162\3\2\2\2u\u0164\3\2\2\2w\u0166\3") - buf.write("\2\2\2y\u0168\3\2\2\2{\u016a\3\2\2\2}\u016c\3\2\2\2\177") - buf.write("\u016e\3\2\2\2\u0081\u0170\3\2\2\2\u0083\u0175\3\2\2\2") - buf.write("\u0085\u017b\3\2\2\2\u0087\u017e\3\2\2\2\u0089\u0184\3") - buf.write("\2\2\2\u008b\u0192\3\2\2\2\u008d\u01a0\3\2\2\2\u008f\u01a4") - buf.write("\3\2\2\2\u0091\u01ac\3\2\2\2\u0093\u01b6\3\2\2\2\u0095") - buf.write("\u01bd\3\2\2\2\u0097\u0098\5a\60\2\u0098\u0099\5m\66\2") - buf.write("\u0099\u009a\5_/\2\u009a\u009b\5w;\2\u009b\u009c\5w;\2") - buf.write("\u009c\6\3\2\2\2\u009d\u009e\5e\62\2\u009e\u009f\5m\66") - buf.write("\2\u009f\u00a0\5w;\2\u00a0\u00a1\5e\62\2\u00a1\b\3\2\2") - buf.write("\2\u00a2\u00a3\7h\2\2\u00a3\u00a4\5_/\2\u00a4\u00a5\5") - buf.write("m\66\2\u00a5\u00a6\5w;\2\u00a6\u00a7\5e\62\2\u00a7\n\3") - buf.write("\2\2\2\u00a8\u00a9\5g\63\2\u00a9\u00aa\5k\65\2\u00aa\f") - buf.write("\3\2\2\2\u00ab\u00ac\5k\65\2\u00ac\u00ad\5g\63\2\u00ad") - buf.write("\16\3\2\2\2\u00ae\u00af\5k\65\2\u00af\u00b0\5o\67\2\u00b0") - buf.write("\20\3\2\2\2\u00b1\u00b2\5k\65\2\u00b2\u00b3\5o\67\2\u00b3") - buf.write("\u00b4\5i\64\2\u00b4\u00b5\5e\62\2\u00b5\u00b6\5u:\2\u00b6") - buf.write("\u00b7\5k\65\2\u00b7\u00b8\5y<\2\u00b8\u00b9\5w;\2\u00b9") - buf.write("\22\3\2\2\2\u00ba\u00bb\5k\65\2\u00bb\u00bc\5w;\2\u00bc") - buf.write("\u00bd\5}>\2\u00bd\u00be\5q8\2\u00be\u00bf\5k\65\2\u00bf") - buf.write("\u00c0\5c\61\2\u00c0\24\3\2\2\2\u00c1\u00c2\5m\66\2\u00c2") - buf.write("\u00c3\5e\62\2\u00c3\u00c4\5y<\2\u00c4\26\3\2\2\2\u00c5") - buf.write("\u00c6\5m\66\2\u00c6\u00c7\5q8\2\u00c7\u00c8\5q8\2\u00c8") - buf.write("\u00c9\5s9\2\u00c9\30\3\2\2\2\u00ca\u00cb\5s9\2\u00cb") - buf.write("\u00cc\5q8\2\u00cc\u00cd\5q8\2\u00cd\u00ce\5m\66\2\u00ce") - buf.write("\32\3\2\2\2\u00cf\u00d0\5y<\2\u00d0\u00d1\5i\64\2\u00d1") - buf.write("\u00d2\5e\62\2\u00d2\u00d3\5o\67\2\u00d3\34\3\2\2\2\u00d4") - buf.write("\u00d5\5\177?\2\u00d5\u00d6\5i\64\2\u00d6\u00d7\5k\65") - buf.write("\2\u00d7\u00d8\5m\66\2\u00d8\u00d9\5e\62\2\u00d9\36\3") - buf.write("\2\2\2\u00da\u00db\5a\60\2\u00db\u00dc\5_/\2\u00dc\u00dd") - buf.write("\5w;\2\u00dd\u00de\5e\62\2\u00de \3\2\2\2\u00df\u00e0") - buf.write("\5e\62\2\u00e0\u00e1\5w;\2\u00e1\u00e2\5_/\2\u00e2\u00e3") - buf.write("\5a\60\2\u00e3\"\3\2\2\2\u00e4\u00e5\5o\67\2\u00e5\u00e6") - buf.write("\5e\62\2\u00e6\u00e7\5\177?\2\u00e7$\3\2\2\2\u00e8\u00e9") - buf.write("\5q8\2\u00e9\u00ea\5g\63\2\u00ea&\3\2\2\2\u00eb\u00ec") - buf.write("\5o\67\2\u00ec\u00ed\5q8\2\u00ed\u00ee\5y<\2\u00ee(\3") - buf.write("\2\2\2\u00ef\u00f0\7v\2\2\u00f0\u00f1\5u:\2\u00f1\u00f2") - buf.write("\5{=\2\u00f2\u00f3\5e\62\2\u00f3*\3\2\2\2\u00f4\u00f7") - buf.write("\5-\26\2\u00f5\u00f7\5\u0095J\2\u00f6\u00f4\3\2\2\2\u00f6") - buf.write("\u00f5\3\2\2\2\u00f7,\3\2\2\2\u00f8\u00fc\7$\2\2\u00f9") - buf.write("\u00fb\5/\27\2\u00fa\u00f9\3\2\2\2\u00fb\u00fe\3\2\2\2") - buf.write("\u00fc\u00fa\3\2\2\2\u00fc\u00fd\3\2\2\2\u00fd\u00ff\3") - buf.write("\2\2\2\u00fe\u00fc\3\2\2\2\u00ff\u0100\7$\2\2\u0100.\3") - buf.write("\2\2\2\u0101\u0104\5\u0081@\2\u0102\u0104\n\2\2\2\u0103") - buf.write("\u0101\3\2\2\2\u0103\u0102\3\2\2\2\u0104\60\3\2\2\2\u0105") - buf.write("\u0109\7$\2\2\u0106\u0108\5/\27\2\u0107\u0106\3\2\2\2") - buf.write("\u0108\u010b\3\2\2\2\u0109\u0107\3\2\2\2\u0109\u010a\3") - buf.write("\2\2\2\u010a\u010c\3\2\2\2\u010b\u0109\3\2\2\2\u010c\u010d") - buf.write("\7^\2\2\u010d\u010e\7\17\2\2\u010e\u010f\7\f\2\2\u010f") - buf.write("\u0110\3\2\2\2\u0110\u0111\b\30\2\2\u0111\62\3\2\2\2\u0112") - buf.write("\u0114\t\3\2\2\u0113\u0112\3\2\2\2\u0114\u0115\3\2\2\2") - buf.write("\u0115\u0113\3\2\2\2\u0115\u0116\3\2\2\2\u0116\64\3\2") - buf.write("\2\2\u0117\u011b\t\4\2\2\u0118\u011a\t\5\2\2\u0119\u0118") - buf.write("\3\2\2\2\u011a\u011d\3\2\2\2\u011b\u0119\3\2\2\2\u011b") - buf.write("\u011c\3\2\2\2\u011c\66\3\2\2\2\u011d\u011b\3\2\2\2\u011e") - buf.write("\u0122\t\6\2\2\u011f\u0121\t\5\2\2\u0120\u011f\3\2\2\2") - buf.write("\u0121\u0124\3\2\2\2\u0122\u0120\3\2\2\2\u0122\u0123\3") - buf.write("\2\2\2\u01238\3\2\2\2\u0124\u0122\3\2\2\2\u0125\u0126") - buf.write("\7>\2\2\u0126\u0127\7/\2\2\u0127:\3\2\2\2\u0128\u0129") - buf.write("\7?\2\2\u0129\u012a\7@\2\2\u012a<\3\2\2\2\u012b\u012c") - buf.write("\7-\2\2\u012c>\3\2\2\2\u012d\u012e\7/\2\2\u012e@\3\2\2") - buf.write("\2\u012f\u0130\7,\2\2\u0130B\3\2\2\2\u0131\u0132\7\61") - buf.write("\2\2\u0132D\3\2\2\2\u0133\u0134\7>\2\2\u0134F\3\2\2\2") - buf.write("\u0135\u0136\7>\2\2\u0136\u0137\7?\2\2\u0137H\3\2\2\2") - buf.write("\u0138\u0139\7?\2\2\u0139J\3\2\2\2\u013a\u013b\7\u0080") - buf.write("\2\2\u013bL\3\2\2\2\u013c\u013d\7*\2\2\u013dN\3\2\2\2") - buf.write("\u013e\u013f\7+\2\2\u013fP\3\2\2\2\u0140\u0141\7}\2\2") - buf.write("\u0141R\3\2\2\2\u0142\u0143\7\177\2\2\u0143T\3\2\2\2\u0144") - buf.write("\u0145\7B\2\2\u0145V\3\2\2\2\u0146\u0147\7\60\2\2\u0147") - buf.write("X\3\2\2\2\u0148\u0149\7.\2\2\u0149Z\3\2\2\2\u014a\u014b") - buf.write("\7<\2\2\u014b\\\3\2\2\2\u014c\u014d\7=\2\2\u014d^\3\2") - buf.write("\2\2\u014e\u014f\t\7\2\2\u014f`\3\2\2\2\u0150\u0151\t") - buf.write("\b\2\2\u0151b\3\2\2\2\u0152\u0153\t\t\2\2\u0153d\3\2\2") - buf.write("\2\u0154\u0155\t\n\2\2\u0155f\3\2\2\2\u0156\u0157\t\13") - buf.write("\2\2\u0157h\3\2\2\2\u0158\u0159\t\f\2\2\u0159j\3\2\2\2") - buf.write("\u015a\u015b\t\r\2\2\u015bl\3\2\2\2\u015c\u015d\t\16\2") - buf.write("\2\u015dn\3\2\2\2\u015e\u015f\t\17\2\2\u015fp\3\2\2\2") - buf.write("\u0160\u0161\t\20\2\2\u0161r\3\2\2\2\u0162\u0163\t\21") - buf.write("\2\2\u0163t\3\2\2\2\u0164\u0165\t\22\2\2\u0165v\3\2\2") - buf.write("\2\u0166\u0167\t\23\2\2\u0167x\3\2\2\2\u0168\u0169\t\24") - buf.write("\2\2\u0169z\3\2\2\2\u016a\u016b\t\25\2\2\u016b|\3\2\2") - buf.write("\2\u016c\u016d\t\26\2\2\u016d~\3\2\2\2\u016e\u016f\t\27") - buf.write("\2\2\u016f\u0080\3\2\2\2\u0170\u0173\7^\2\2\u0171\u0174") - buf.write("\t\30\2\2\u0172\u0174\5\u0083A\2\u0173\u0171\3\2\2\2\u0173") - buf.write("\u0172\3\2\2\2\u0174\u0082\3\2\2\2\u0175\u0176\7w\2\2") - buf.write("\u0176\u0177\5\u0085B\2\u0177\u0178\5\u0085B\2\u0178\u0179") - buf.write("\5\u0085B\2\u0179\u017a\5\u0085B\2\u017a\u0084\3\2\2\2") - buf.write("\u017b\u017c\t\31\2\2\u017c\u0086\3\2\2\2\u017d\u017f") - buf.write("\t\32\2\2\u017e\u017d\3\2\2\2\u017f\u0180\3\2\2\2\u0180") - buf.write("\u017e\3\2\2\2\u0180\u0181\3\2\2\2\u0181\u0182\3\2\2\2") - buf.write("\u0182\u0183\bC\3\2\u0183\u0088\3\2\2\2\u0184\u0185\7") - buf.write("/\2\2\u0185\u0186\7/\2\2\u0186\u018a\3\2\2\2\u0187\u0189") - buf.write("\n\33\2\2\u0188\u0187\3\2\2\2\u0189\u018c\3\2\2\2\u018a") - buf.write("\u0188\3\2\2\2\u018a\u018b\3\2\2\2\u018b\u018e\3\2\2\2") - buf.write("\u018c\u018a\3\2\2\2\u018d\u018f\7\f\2\2\u018e\u018d\3") - buf.write("\2\2\2\u018e\u018f\3\2\2\2\u018f\u0190\3\2\2\2\u0190\u0191") - buf.write("\bD\3\2\u0191\u008a\3\2\2\2\u0192\u0193\7*\2\2\u0193\u0194") - buf.write("\7,\2\2\u0194\u0195\3\2\2\2\u0195\u0196\bE\4\2\u0196\u008c") - buf.write("\3\2\2\2\u0197\u0198\5\u008bE\2\u0198\u0199\5\u008dF\2") - buf.write("\u0199\u019a\5\u008fG\2\u019a\u01a1\3\2\2\2\u019b\u019d") - buf.write("\13\2\2\2\u019c\u019b\3\2\2\2\u019d\u019e\3\2\2\2\u019e") - buf.write("\u019f\3\2\2\2\u019e\u019c\3\2\2\2\u019f\u01a1\3\2\2\2") - buf.write("\u01a0\u0197\3\2\2\2\u01a0\u019c\3\2\2\2\u01a1\u01a2\3") - buf.write("\2\2\2\u01a2\u01a3\bF\3\2\u01a3\u008e\3\2\2\2\u01a4\u01a5") - buf.write("\7,\2\2\u01a5\u01a6\7+\2\2\u01a6\u01a7\3\2\2\2\u01a7\u01a8") - buf.write("\bG\5\2\u01a8\u0090\3\2\2\2\u01a9\u01ab\5/\27\2\u01aa") - buf.write("\u01a9\3\2\2\2\u01ab\u01ae\3\2\2\2\u01ac\u01aa\3\2\2\2") - buf.write("\u01ac\u01ad\3\2\2\2\u01ad\u01af\3\2\2\2\u01ae\u01ac\3") - buf.write("\2\2\2\u01af\u01b0\7^\2\2\u01b0\u01b1\7\17\2\2\u01b1\u01b2") - buf.write("\7\f\2\2\u01b2\u0092\3\2\2\2\u01b3\u01b5\5/\27\2\u01b4") - buf.write("\u01b3\3\2\2\2\u01b5\u01b8\3\2\2\2\u01b6\u01b4\3\2\2\2") - buf.write("\u01b6\u01b7\3\2\2\2\u01b7\u01b9\3\2\2\2\u01b8\u01b6\3") - buf.write("\2\2\2\u01b9\u01ba\7$\2\2\u01ba\u01bb\3\2\2\2\u01bb\u01bc") - buf.write("\bI\5\2\u01bc\u0094\3\2\2\2\u01bd\u01c1\5\61\30\2\u01be") - buf.write("\u01c0\5\u0091H\2\u01bf\u01be\3\2\2\2\u01c0\u01c3\3\2") - buf.write("\2\2\u01c1\u01bf\3\2\2\2\u01c1\u01c2\3\2\2\2\u01c2\u01c4") - buf.write("\3\2\2\2\u01c3\u01c1\3\2\2\2\u01c4\u01c5\5\u0093I\2\u01c5") - buf.write("\u0096\3\2\2\2\25\2\3\4\u00f6\u00fc\u0103\u0109\u0115") - buf.write("\u011b\u0122\u0173\u0180\u018a\u018e\u019e\u01a0\u01ac") - buf.write("\u01b6\u01c1\6\7\4\2\b\2\2\7\3\2\6\2\2") + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\29") + buf.write("\u01d7\b\1\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5") + buf.write("\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f") + buf.write("\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4") + buf.write("\22\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27") + buf.write("\t\27\4\30\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34") + buf.write("\4\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#") + buf.write("\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+") + buf.write("\4,\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62") + buf.write("\4\63\t\63\4\64\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48") + buf.write("\t8\49\t9\4:\t:\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4") + buf.write("A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I\tI\4") + buf.write("J\tJ\4K\tK\4L\tL\4M\tM\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3") + buf.write("\3\3\3\3\3\3\3\4\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\6\3") + buf.write("\6\3\6\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b") + buf.write("\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\13\3\13") + buf.write("\3\13\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3") + buf.write("\r\3\16\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3") + buf.write("\17\3\20\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\22") + buf.write("\3\22\3\22\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24") + buf.write("\3\25\3\25\5\25\u00fe\n\25\3\26\3\26\7\26\u0102\n\26\f") + buf.write("\26\16\26\u0105\13\26\3\26\3\26\3\27\3\27\3\27\3\27\3") + buf.write("\30\3\30\5\30\u010f\n\30\3\31\3\31\7\31\u0113\n\31\f\31") + buf.write("\16\31\u0116\13\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32") + buf.write("\6\32\u011f\n\32\r\32\16\32\u0120\3\33\3\33\7\33\u0125") + buf.write("\n\33\f\33\16\33\u0128\13\33\3\34\3\34\7\34\u012c\n\34") + buf.write("\f\34\16\34\u012f\13\34\3\35\3\35\3\35\3\36\3\36\3\36") + buf.write("\3\37\3\37\3 \3 \3!\3!\3\"\3\"\3#\3#\3$\3$\3$\3%\3%\3") + buf.write("&\3&\3\'\3\'\3(\3(\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3") + buf.write(".\3/\3/\3\60\3\60\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3") + buf.write("\64\3\65\3\65\3\66\3\66\3\67\3\67\38\38\39\39\3:\3:\3") + buf.write(";\3;\3<\3<\3=\3=\3>\3>\3?\3?\3@\3@\3A\3A\3A\5A\u017f\n") + buf.write("A\3B\3B\3B\3B\3B\3B\3C\3C\3D\6D\u018a\nD\rD\16D\u018b") + buf.write("\3D\3D\3E\3E\3E\3E\7E\u0194\nE\fE\16E\u0197\13E\3E\5E") + buf.write("\u019a\nE\3E\3E\3F\3F\3F\3F\3F\3G\3G\3G\3G\3G\6G\u01a8") + buf.write("\nG\rG\16G\u01a9\5G\u01ac\nG\3G\3G\3H\3H\3H\3H\3H\3I\7") + buf.write("I\u01b6\nI\fI\16I\u01b9\13I\3I\3I\3I\3I\3J\7J\u01c0\n") + buf.write("J\fJ\16J\u01c3\13J\3J\3J\3J\3J\3K\3K\7K\u01cb\nK\fK\16") + buf.write("K\u01ce\13K\3K\3K\3L\3L\3M\3M\3M\3M\3\u01a9\2N\6\3\b\4") + buf.write("\n\5\f\6\16\7\20\b\22\t\24\n\26\13\30\f\32\r\34\16\36") + buf.write("\17 \20\"\21$\22&\23(\24*\25,\26.\27\60\30\62\2\64\31") + buf.write("\66\328\33:\34<\35>\36@\37B D!F\"H#J$L%N&P\'R(T)V*X+Z") + buf.write(",\\-^.`/b\2d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2|\2~\2") + buf.write("\u0080\2\u0082\2\u0084\2\u0086\2\u0088\2\u008a\60\u008c") + buf.write("\61\u008e\62\u0090\63\u0092\64\u0094\65\u0096\66\u0098") + buf.write("\67\u009a8\u009c9\6\2\3\4\5\34\6\2\2\2\f\f\17\17$$\3\2") + buf.write("\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEee\4\2F") + buf.write("Fff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2PPpp\4") + buf.write("\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4\2XXx") + buf.write("x\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2\13\f") + buf.write("\16\17\"\"\3\2\f\f\2\u01ce\2\6\3\2\2\2\2\b\3\2\2\2\2\n") + buf.write("\3\2\2\2\2\f\3\2\2\2\2\16\3\2\2\2\2\20\3\2\2\2\2\22\3") + buf.write("\2\2\2\2\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32\3\2") + buf.write("\2\2\2\34\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2\2\2") + buf.write("\2$\3\2\2\2\2&\3\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3\2\2") + buf.write("\2\2.\3\2\2\2\2\60\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\2") + buf.write("8\3\2\2\2\2:\3\2\2\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2\2\2") + buf.write("\2B\3\2\2\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3\2\2") + buf.write("\2\2L\3\2\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2") + buf.write("\2\2\2V\3\2\2\2\2X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2\2^\3") + buf.write("\2\2\2\2`\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2\2\u008e") + buf.write("\3\2\2\2\3\u0090\3\2\2\2\3\u0092\3\2\2\2\4\u0094\3\2\2") + buf.write("\2\4\u0096\3\2\2\2\4\u0098\3\2\2\2\5\u009a\3\2\2\2\5\u009c") + buf.write("\3\2\2\2\6\u009e\3\2\2\2\b\u00a4\3\2\2\2\n\u00a9\3\2\2") + buf.write("\2\f\u00af\3\2\2\2\16\u00b2\3\2\2\2\20\u00b5\3\2\2\2\22") + buf.write("\u00b8\3\2\2\2\24\u00c1\3\2\2\2\26\u00c8\3\2\2\2\30\u00cc") + buf.write("\3\2\2\2\32\u00d1\3\2\2\2\34\u00d6\3\2\2\2\36\u00db\3") + buf.write("\2\2\2 \u00e1\3\2\2\2\"\u00e6\3\2\2\2$\u00eb\3\2\2\2&") + buf.write("\u00ef\3\2\2\2(\u00f2\3\2\2\2*\u00f6\3\2\2\2,\u00fd\3") + buf.write("\2\2\2.\u00ff\3\2\2\2\60\u0108\3\2\2\2\62\u010e\3\2\2") + buf.write("\2\64\u0110\3\2\2\2\66\u011e\3\2\2\28\u0122\3\2\2\2:\u0129") + buf.write("\3\2\2\2<\u0130\3\2\2\2>\u0133\3\2\2\2@\u0136\3\2\2\2") + buf.write("B\u0138\3\2\2\2D\u013a\3\2\2\2F\u013c\3\2\2\2H\u013e\3") + buf.write("\2\2\2J\u0140\3\2\2\2L\u0143\3\2\2\2N\u0145\3\2\2\2P\u0147") + buf.write("\3\2\2\2R\u0149\3\2\2\2T\u014b\3\2\2\2V\u014d\3\2\2\2") + buf.write("X\u014f\3\2\2\2Z\u0151\3\2\2\2\\\u0153\3\2\2\2^\u0155") + buf.write("\3\2\2\2`\u0157\3\2\2\2b\u0159\3\2\2\2d\u015b\3\2\2\2") + buf.write("f\u015d\3\2\2\2h\u015f\3\2\2\2j\u0161\3\2\2\2l\u0163\3") + buf.write("\2\2\2n\u0165\3\2\2\2p\u0167\3\2\2\2r\u0169\3\2\2\2t\u016b") + buf.write("\3\2\2\2v\u016d\3\2\2\2x\u016f\3\2\2\2z\u0171\3\2\2\2") + buf.write("|\u0173\3\2\2\2~\u0175\3\2\2\2\u0080\u0177\3\2\2\2\u0082") + buf.write("\u0179\3\2\2\2\u0084\u017b\3\2\2\2\u0086\u0180\3\2\2\2") + buf.write("\u0088\u0186\3\2\2\2\u008a\u0189\3\2\2\2\u008c\u018f\3") + buf.write("\2\2\2\u008e\u019d\3\2\2\2\u0090\u01ab\3\2\2\2\u0092\u01af") + buf.write("\3\2\2\2\u0094\u01b7\3\2\2\2\u0096\u01c1\3\2\2\2\u0098") + buf.write("\u01c8\3\2\2\2\u009a\u01d1\3\2\2\2\u009c\u01d3\3\2\2\2") + buf.write("\u009e\u009f\5d\61\2\u009f\u00a0\5p\67\2\u00a0\u00a1\5") + buf.write("b\60\2\u00a1\u00a2\5z<\2\u00a2\u00a3\5z<\2\u00a3\7\3\2") + buf.write("\2\2\u00a4\u00a5\5h\63\2\u00a5\u00a6\5p\67\2\u00a6\u00a7") + buf.write("\5z<\2\u00a7\u00a8\5h\63\2\u00a8\t\3\2\2\2\u00a9\u00aa") + buf.write("\7h\2\2\u00aa\u00ab\5b\60\2\u00ab\u00ac\5p\67\2\u00ac") + buf.write("\u00ad\5z<\2\u00ad\u00ae\5h\63\2\u00ae\13\3\2\2\2\u00af") + buf.write("\u00b0\5j\64\2\u00b0\u00b1\5n\66\2\u00b1\r\3\2\2\2\u00b2") + buf.write("\u00b3\5n\66\2\u00b3\u00b4\5j\64\2\u00b4\17\3\2\2\2\u00b5") + buf.write("\u00b6\5n\66\2\u00b6\u00b7\5r8\2\u00b7\21\3\2\2\2\u00b8") + buf.write("\u00b9\5n\66\2\u00b9\u00ba\5r8\2\u00ba\u00bb\5l\65\2\u00bb") + buf.write("\u00bc\5h\63\2\u00bc\u00bd\5x;\2\u00bd\u00be\5n\66\2\u00be") + buf.write("\u00bf\5|=\2\u00bf\u00c0\5z<\2\u00c0\23\3\2\2\2\u00c1") + buf.write("\u00c2\5n\66\2\u00c2\u00c3\5z<\2\u00c3\u00c4\5\u0080?") + buf.write("\2\u00c4\u00c5\5t9\2\u00c5\u00c6\5n\66\2\u00c6\u00c7\5") + buf.write("f\62\2\u00c7\25\3\2\2\2\u00c8\u00c9\5p\67\2\u00c9\u00ca") + buf.write("\5h\63\2\u00ca\u00cb\5|=\2\u00cb\27\3\2\2\2\u00cc\u00cd") + buf.write("\5p\67\2\u00cd\u00ce\5t9\2\u00ce\u00cf\5t9\2\u00cf\u00d0") + buf.write("\5v:\2\u00d0\31\3\2\2\2\u00d1\u00d2\5v:\2\u00d2\u00d3") + buf.write("\5t9\2\u00d3\u00d4\5t9\2\u00d4\u00d5\5p\67\2\u00d5\33") + buf.write("\3\2\2\2\u00d6\u00d7\5|=\2\u00d7\u00d8\5l\65\2\u00d8\u00d9") + buf.write("\5h\63\2\u00d9\u00da\5r8\2\u00da\35\3\2\2\2\u00db\u00dc") + buf.write("\5\u0082@\2\u00dc\u00dd\5l\65\2\u00dd\u00de\5n\66\2\u00de") + buf.write("\u00df\5p\67\2\u00df\u00e0\5h\63\2\u00e0\37\3\2\2\2\u00e1") + buf.write("\u00e2\5d\61\2\u00e2\u00e3\5b\60\2\u00e3\u00e4\5z<\2\u00e4") + buf.write("\u00e5\5h\63\2\u00e5!\3\2\2\2\u00e6\u00e7\5h\63\2\u00e7") + buf.write("\u00e8\5z<\2\u00e8\u00e9\5b\60\2\u00e9\u00ea\5d\61\2\u00ea") + buf.write("#\3\2\2\2\u00eb\u00ec\5r8\2\u00ec\u00ed\5h\63\2\u00ed") + buf.write("\u00ee\5\u0082@\2\u00ee%\3\2\2\2\u00ef\u00f0\5t9\2\u00f0") + buf.write("\u00f1\5j\64\2\u00f1\'\3\2\2\2\u00f2\u00f3\5r8\2\u00f3") + buf.write("\u00f4\5t9\2\u00f4\u00f5\5|=\2\u00f5)\3\2\2\2\u00f6\u00f7") + buf.write("\7v\2\2\u00f7\u00f8\5x;\2\u00f8\u00f9\5~>\2\u00f9\u00fa") + buf.write("\5h\63\2\u00fa+\3\2\2\2\u00fb\u00fe\5.\26\2\u00fc\u00fe") + buf.write("\5\u0098K\2\u00fd\u00fb\3\2\2\2\u00fd\u00fc\3\2\2\2\u00fe") + buf.write("-\3\2\2\2\u00ff\u0103\5\60\27\2\u0100\u0102\5\u009aL\2") + buf.write("\u0101\u0100\3\2\2\2\u0102\u0105\3\2\2\2\u0103\u0101\3") + buf.write("\2\2\2\u0103\u0104\3\2\2\2\u0104\u0106\3\2\2\2\u0105\u0103") + buf.write("\3\2\2\2\u0106\u0107\5\u009cM\2\u0107/\3\2\2\2\u0108\u0109") + buf.write("\7$\2\2\u0109\u010a\3\2\2\2\u010a\u010b\b\27\2\2\u010b") + buf.write("\61\3\2\2\2\u010c\u010f\5\u0084A\2\u010d\u010f\n\2\2\2") + buf.write("\u010e\u010c\3\2\2\2\u010e\u010d\3\2\2\2\u010f\63\3\2") + buf.write("\2\2\u0110\u0114\7$\2\2\u0111\u0113\5\62\30\2\u0112\u0111") + buf.write("\3\2\2\2\u0113\u0116\3\2\2\2\u0114\u0112\3\2\2\2\u0114") + buf.write("\u0115\3\2\2\2\u0115\u0117\3\2\2\2\u0116\u0114\3\2\2\2") + buf.write("\u0117\u0118\7^\2\2\u0118\u0119\7\17\2\2\u0119\u011a\7") + buf.write("\f\2\2\u011a\u011b\3\2\2\2\u011b\u011c\b\31\3\2\u011c") + buf.write("\65\3\2\2\2\u011d\u011f\t\3\2\2\u011e\u011d\3\2\2\2\u011f") + buf.write("\u0120\3\2\2\2\u0120\u011e\3\2\2\2\u0120\u0121\3\2\2\2") + buf.write("\u0121\67\3\2\2\2\u0122\u0126\t\4\2\2\u0123\u0125\t\5") + buf.write("\2\2\u0124\u0123\3\2\2\2\u0125\u0128\3\2\2\2\u0126\u0124") + buf.write("\3\2\2\2\u0126\u0127\3\2\2\2\u01279\3\2\2\2\u0128\u0126") + buf.write("\3\2\2\2\u0129\u012d\t\6\2\2\u012a\u012c\t\5\2\2\u012b") + buf.write("\u012a\3\2\2\2\u012c\u012f\3\2\2\2\u012d\u012b\3\2\2\2") + buf.write("\u012d\u012e\3\2\2\2\u012e;\3\2\2\2\u012f\u012d\3\2\2") + buf.write("\2\u0130\u0131\7>\2\2\u0131\u0132\7/\2\2\u0132=\3\2\2") + buf.write("\2\u0133\u0134\7?\2\2\u0134\u0135\7@\2\2\u0135?\3\2\2") + buf.write("\2\u0136\u0137\7-\2\2\u0137A\3\2\2\2\u0138\u0139\7/\2") + buf.write("\2\u0139C\3\2\2\2\u013a\u013b\7,\2\2\u013bE\3\2\2\2\u013c") + buf.write("\u013d\7\61\2\2\u013dG\3\2\2\2\u013e\u013f\7>\2\2\u013f") + buf.write("I\3\2\2\2\u0140\u0141\7>\2\2\u0141\u0142\7?\2\2\u0142") + buf.write("K\3\2\2\2\u0143\u0144\7?\2\2\u0144M\3\2\2\2\u0145\u0146") + buf.write("\7\u0080\2\2\u0146O\3\2\2\2\u0147\u0148\7*\2\2\u0148Q") + buf.write("\3\2\2\2\u0149\u014a\7+\2\2\u014aS\3\2\2\2\u014b\u014c") + buf.write("\7}\2\2\u014cU\3\2\2\2\u014d\u014e\7\177\2\2\u014eW\3") + buf.write("\2\2\2\u014f\u0150\7B\2\2\u0150Y\3\2\2\2\u0151\u0152\7") + buf.write("\60\2\2\u0152[\3\2\2\2\u0153\u0154\7.\2\2\u0154]\3\2\2") + buf.write("\2\u0155\u0156\7<\2\2\u0156_\3\2\2\2\u0157\u0158\7=\2") + buf.write("\2\u0158a\3\2\2\2\u0159\u015a\t\7\2\2\u015ac\3\2\2\2\u015b") + buf.write("\u015c\t\b\2\2\u015ce\3\2\2\2\u015d\u015e\t\t\2\2\u015e") + buf.write("g\3\2\2\2\u015f\u0160\t\n\2\2\u0160i\3\2\2\2\u0161\u0162") + buf.write("\t\13\2\2\u0162k\3\2\2\2\u0163\u0164\t\f\2\2\u0164m\3") + buf.write("\2\2\2\u0165\u0166\t\r\2\2\u0166o\3\2\2\2\u0167\u0168") + buf.write("\t\16\2\2\u0168q\3\2\2\2\u0169\u016a\t\17\2\2\u016as\3") + buf.write("\2\2\2\u016b\u016c\t\20\2\2\u016cu\3\2\2\2\u016d\u016e") + buf.write("\t\21\2\2\u016ew\3\2\2\2\u016f\u0170\t\22\2\2\u0170y\3") + buf.write("\2\2\2\u0171\u0172\t\23\2\2\u0172{\3\2\2\2\u0173\u0174") + buf.write("\t\24\2\2\u0174}\3\2\2\2\u0175\u0176\t\25\2\2\u0176\177") + buf.write("\3\2\2\2\u0177\u0178\t\26\2\2\u0178\u0081\3\2\2\2\u0179") + buf.write("\u017a\t\27\2\2\u017a\u0083\3\2\2\2\u017b\u017e\7^\2\2") + buf.write("\u017c\u017f\t\30\2\2\u017d\u017f\5\u0086B\2\u017e\u017c") + buf.write("\3\2\2\2\u017e\u017d\3\2\2\2\u017f\u0085\3\2\2\2\u0180") + buf.write("\u0181\7w\2\2\u0181\u0182\5\u0088C\2\u0182\u0183\5\u0088") + buf.write("C\2\u0183\u0184\5\u0088C\2\u0184\u0185\5\u0088C\2\u0185") + buf.write("\u0087\3\2\2\2\u0186\u0187\t\31\2\2\u0187\u0089\3\2\2") + buf.write("\2\u0188\u018a\t\32\2\2\u0189\u0188\3\2\2\2\u018a\u018b") + buf.write("\3\2\2\2\u018b\u0189\3\2\2\2\u018b\u018c\3\2\2\2\u018c") + buf.write("\u018d\3\2\2\2\u018d\u018e\bD\4\2\u018e\u008b\3\2\2\2") + buf.write("\u018f\u0190\7/\2\2\u0190\u0191\7/\2\2\u0191\u0195\3\2") + buf.write("\2\2\u0192\u0194\n\33\2\2\u0193\u0192\3\2\2\2\u0194\u0197") + buf.write("\3\2\2\2\u0195\u0193\3\2\2\2\u0195\u0196\3\2\2\2\u0196") + buf.write("\u0199\3\2\2\2\u0197\u0195\3\2\2\2\u0198\u019a\7\f\2\2") + buf.write("\u0199\u0198\3\2\2\2\u0199\u019a\3\2\2\2\u019a\u019b\3") + buf.write("\2\2\2\u019b\u019c\bE\4\2\u019c\u008d\3\2\2\2\u019d\u019e") + buf.write("\7*\2\2\u019e\u019f\7,\2\2\u019f\u01a0\3\2\2\2\u01a0\u01a1") + buf.write("\bF\5\2\u01a1\u008f\3\2\2\2\u01a2\u01a3\5\u008eF\2\u01a3") + buf.write("\u01a4\5\u0090G\2\u01a4\u01a5\5\u0092H\2\u01a5\u01ac\3") + buf.write("\2\2\2\u01a6\u01a8\13\2\2\2\u01a7\u01a6\3\2\2\2\u01a8") + buf.write("\u01a9\3\2\2\2\u01a9\u01aa\3\2\2\2\u01a9\u01a7\3\2\2\2") + buf.write("\u01aa\u01ac\3\2\2\2\u01ab\u01a2\3\2\2\2\u01ab\u01a7\3") + buf.write("\2\2\2\u01ac\u01ad\3\2\2\2\u01ad\u01ae\bG\4\2\u01ae\u0091") + buf.write("\3\2\2\2\u01af\u01b0\7,\2\2\u01b0\u01b1\7+\2\2\u01b1\u01b2") + buf.write("\3\2\2\2\u01b2\u01b3\bH\6\2\u01b3\u0093\3\2\2\2\u01b4") + buf.write("\u01b6\5\62\30\2\u01b5\u01b4\3\2\2\2\u01b6\u01b9\3\2\2") + buf.write("\2\u01b7\u01b5\3\2\2\2\u01b7\u01b8\3\2\2\2\u01b8\u01ba") + buf.write("\3\2\2\2\u01b9\u01b7\3\2\2\2\u01ba\u01bb\7^\2\2\u01bb") + buf.write("\u01bc\7\17\2\2\u01bc\u01bd\7\f\2\2\u01bd\u0095\3\2\2") + buf.write("\2\u01be\u01c0\5\62\30\2\u01bf\u01be\3\2\2\2\u01c0\u01c3") + buf.write("\3\2\2\2\u01c1\u01bf\3\2\2\2\u01c1\u01c2\3\2\2\2\u01c2") + buf.write("\u01c4\3\2\2\2\u01c3\u01c1\3\2\2\2\u01c4\u01c5\7$\2\2") + buf.write("\u01c5\u01c6\3\2\2\2\u01c6\u01c7\bJ\6\2\u01c7\u0097\3") + buf.write("\2\2\2\u01c8\u01cc\5\64\31\2\u01c9\u01cb\5\u0094I\2\u01ca") + buf.write("\u01c9\3\2\2\2\u01cb\u01ce\3\2\2\2\u01cc\u01ca\3\2\2\2") + buf.write("\u01cc\u01cd\3\2\2\2\u01cd\u01cf\3\2\2\2\u01ce\u01cc\3") + buf.write("\2\2\2\u01cf\u01d0\5\u0096J\2\u01d0\u0099\3\2\2\2\u01d1") + buf.write("\u01d2\5\62\30\2\u01d2\u009b\3\2\2\2\u01d3\u01d4\7$\2") + buf.write("\2\u01d4\u01d5\3\2\2\2\u01d5\u01d6\bM\6\2\u01d6\u009d") + buf.write("\3\2\2\2\26\2\3\4\5\u00fd\u0103\u010e\u0114\u0120\u0126") + buf.write("\u012d\u017e\u018b\u0195\u0199\u01a9\u01ab\u01b7\u01c1") + buf.write("\u01cc\7\7\5\2\7\4\2\b\2\2\7\3\2\6\2\2") return buf.getvalue() @@ -215,6 +223,7 @@ class COOL_LEX(Lexer): MULTILINE_COMMENT = 1 MULTILINE_STR = 2 + SIMPLE_STR = 3 CLASS = 1 ELSE = 2 @@ -237,41 +246,45 @@ class COOL_LEX(Lexer): TRUE = 19 STRING = 20 STRING_SIMPLE = 21 - STRING_FIRSTLINE = 22 - INT = 23 - TYPEID = 24 - OBJECTID = 25 - ASSIGNMENT = 26 - CASE_ARROW = 27 - ADD = 28 - MINUS = 29 - MULTIPLY = 30 - DIVISION = 31 - LESS_THAN = 32 - LESS_EQUAL = 33 - EQUAL = 34 - INTEGER_NEGATIVE = 35 - OPEN_ROUND = 36 - CLOSE_ROUND = 37 - OPEN_CURLY = 38 - CLOSE_CURLY = 39 - AT = 40 - DOT = 41 - COMMA = 42 - COLON = 43 - SEMICOLON = 44 - WHITESPACE = 45 - ONE_LINE_COMMENT = 46 - OPEN_COMMENT = 47 - COMMENT = 48 - CLOSE_COMMENT = 49 - STRING_INNERLINE = 50 - STRING_LASTLINE = 51 - STRING_MULTILINE = 52 + STRING_SIMPLE_START = 22 + STRING_FIRSTLINE = 23 + INT = 24 + TYPEID = 25 + OBJECTID = 26 + ASSIGNMENT = 27 + CASE_ARROW = 28 + ADD = 29 + MINUS = 30 + MULTIPLY = 31 + DIVISION = 32 + LESS_THAN = 33 + LESS_EQUAL = 34 + EQUAL = 35 + INTEGER_NEGATIVE = 36 + OPEN_ROUND = 37 + CLOSE_ROUND = 38 + OPEN_CURLY = 39 + CLOSE_CURLY = 40 + AT = 41 + DOT = 42 + COMMA = 43 + COLON = 44 + SEMICOLON = 45 + WHITESPACE = 46 + ONE_LINE_COMMENT = 47 + OPEN_COMMENT = 48 + COMMENT = 49 + CLOSE_COMMENT = 50 + STRING_INNERLINE = 51 + STRING_LASTLINE = 52 + STRING_MULTILINE = 53 + STRING_SIMPLE_CONTENT = 54 + STRING_SIMPLE_STOP = 55 channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] - modeNames = [ "DEFAULT_MODE", "MULTILINE_COMMENT", "MULTILINE_STR" ] + modeNames = [ "DEFAULT_MODE", "MULTILINE_COMMENT", "MULTILINE_STR", + "SIMPLE_STR" ] literalNames = [ "", "'<-'", "'=>'", "'+'", "'-'", "'*'", "'/'", "'<'", "'<='", "'='", @@ -281,27 +294,28 @@ class COOL_LEX(Lexer): symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", - "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", "STRING_FIRSTLINE", - "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", - "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", - "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", - "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", "SEMICOLON", "WHITESPACE", - "ONE_LINE_COMMENT", "OPEN_COMMENT", "COMMENT", "CLOSE_COMMENT", - "STRING_INNERLINE", "STRING_LASTLINE", "STRING_MULTILINE" ] + "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", "STRING_SIMPLE_START", + "STRING_FIRSTLINE", "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", + "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", + "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", + "OPEN_CURLY", "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", + "SEMICOLON", "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", + "COMMENT", "CLOSE_COMMENT", "STRING_INNERLINE", "STRING_LASTLINE", + "STRING_MULTILINE", "STRING_SIMPLE_CONTENT", "STRING_SIMPLE_STOP" ] ruleNames = [ "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", - "STRING_CONTENT", "STRING_FIRSTLINE", "INT", "TYPEID", - "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", - "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", - "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", "OPEN_CURLY", - "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", "SEMICOLON", - "A", "C", "D", "E", "F", "H", "I", "L", "N", "O", "P", - "R", "S", "T", "U", "V", "W", "ESC", "UNICODE", "HEX", - "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", "COMMENT", - "CLOSE_COMMENT", "STRING_INNERLINE", "STRING_LASTLINE", - "STRING_MULTILINE" ] + "STRING_SIMPLE_START", "STRING_CONTENT", "STRING_FIRSTLINE", + "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", + "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", + "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", + "OPEN_CURLY", "CLOSE_CURLY", "AT", "DOT", "COMMA", "COLON", + "SEMICOLON", "A", "C", "D", "E", "F", "H", "I", "L", "N", + "O", "P", "R", "S", "T", "U", "V", "W", "ESC", "UNICODE", + "HEX", "WHITESPACE", "ONE_LINE_COMMENT", "OPEN_COMMENT", + "COMMENT", "CLOSE_COMMENT", "STRING_INNERLINE", "STRING_LASTLINE", + "STRING_MULTILINE", "STRING_SIMPLE_CONTENT", "STRING_SIMPLE_STOP" ] grammarFileName = "COOL_LEX.g4" diff --git a/src/COOL_LEX.tokens b/src/COOL_LEX.tokens index de4efcf0..c7eacfe4 100644 --- a/src/COOL_LEX.tokens +++ b/src/COOL_LEX.tokens @@ -19,55 +19,58 @@ NOT=18 TRUE=19 STRING=20 STRING_SIMPLE=21 -STRING_FIRSTLINE=22 -INT=23 -TYPEID=24 -OBJECTID=25 -ASSIGNMENT=26 -CASE_ARROW=27 -ADD=28 -MINUS=29 -MULTIPLY=30 -DIVISION=31 -LESS_THAN=32 -LESS_EQUAL=33 -EQUAL=34 -INTEGER_NEGATIVE=35 -OPEN_ROUND=36 -CLOSE_ROUND=37 -OPEN_CURLY=38 -CLOSE_CURLY=39 -AT=40 -DOT=41 -COMMA=42 -COLON=43 -SEMICOLON=44 -WHITESPACE=45 -ONE_LINE_COMMENT=46 -OPEN_COMMENT=47 -COMMENT=48 -CLOSE_COMMENT=49 -STRING_INNERLINE=50 -STRING_LASTLINE=51 -STRING_MULTILINE=52 -'<-'=26 -'=>'=27 -'+'=28 -'-'=29 -'*'=30 -'/'=31 -'<'=32 -'<='=33 -'='=34 -'~'=35 -'('=36 -')'=37 -'{'=38 -'}'=39 -'@'=40 -'.'=41 -','=42 -':'=43 -';'=44 -'(*'=47 -'*)'=49 +STRING_SIMPLE_START=22 +STRING_FIRSTLINE=23 +INT=24 +TYPEID=25 +OBJECTID=26 +ASSIGNMENT=27 +CASE_ARROW=28 +ADD=29 +MINUS=30 +MULTIPLY=31 +DIVISION=32 +LESS_THAN=33 +LESS_EQUAL=34 +EQUAL=35 +INTEGER_NEGATIVE=36 +OPEN_ROUND=37 +CLOSE_ROUND=38 +OPEN_CURLY=39 +CLOSE_CURLY=40 +AT=41 +DOT=42 +COMMA=43 +COLON=44 +SEMICOLON=45 +WHITESPACE=46 +ONE_LINE_COMMENT=47 +OPEN_COMMENT=48 +COMMENT=49 +CLOSE_COMMENT=50 +STRING_INNERLINE=51 +STRING_LASTLINE=52 +STRING_MULTILINE=53 +STRING_SIMPLE_CONTENT=54 +STRING_SIMPLE_STOP=55 +'<-'=27 +'=>'=28 +'+'=29 +'-'=30 +'*'=31 +'/'=32 +'<'=33 +'<='=34 +'='=35 +'~'=36 +'('=37 +')'=38 +'{'=39 +'}'=40 +'@'=41 +'.'=42 +','=43 +':'=44 +';'=45 +'(*'=48 +'*)'=50 diff --git a/tests/lexer/test1_error.txt b/tests/lexer/test1_error.txt index 5145209d..05df8e6c 100644 --- a/tests/lexer/test1_error.txt +++ b/tests/lexer/test1_error.txt @@ -1,3 +1,3 @@ -(3, 4) - LexicographicError: Unterminated string constant -(4, 2) - LexicographicError: Unterminated string constant -(7, 4) - LexicographicError: Unterminated string constant \ No newline at end of file +(2, 27) - LexicographicError: Unterminated string constant +(3, 27) - LexicographicError: Unterminated string constant +(6, 51) - LexicographicError: Unterminated string constant \ No newline at end of file From ca3b55af91529d4c6cd4b283e945c6ee1ee3a2ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 16 Mar 2020 12:55:06 -0400 Subject: [PATCH 34/77] =?UTF-8?q?Se=20arregl=C3=B3=20un=20bug=20del=20lexe?= =?UTF-8?q?r=20relativo=20a=20las=20cadenas=20simples=20no=20terminadas=20?= =?UTF-8?q?correctamente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + grammar/COOL.g4 | 57 +++++++ grammar/COOL_LEX.g4 | 320 +++++++++++++++++++++++++++++++++++++ src/COOL.interp | 2 +- src/COOL.py | 6 +- src/COOL.tokens | 4 +- src/COOLLexer.py | 2 + src/COOL_LEX.interp | 6 +- src/COOL_LEX.py | 382 ++++++++++++++++++++++---------------------- src/COOL_LEX.tokens | 4 +- 10 files changed, 583 insertions(+), 201 deletions(-) create mode 100644 grammar/COOL.g4 create mode 100644 grammar/COOL_LEX.g4 diff --git a/.gitignore b/.gitignore index 4acafde1..ebfe77c1 100644 --- a/.gitignore +++ b/.gitignore @@ -408,3 +408,4 @@ dmypy.json # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) +/.idea diff --git a/grammar/COOL.g4 b/grammar/COOL.g4 new file mode 100644 index 00000000..76a2f58f --- /dev/null +++ b/grammar/COOL.g4 @@ -0,0 +1,57 @@ +parser grammar COOL; + +options { + tokenVocab=COOL_LEX; +} + +program + : programBlocks EOF + ; + +programBlocks + : classDefine SEMICOLON programBlocks? # classes + ; + +classDefine + : CLASS TYPEID (INHERITS TYPEID)? OPEN_CURLY (feature SEMICOLON)* CLOSE_CURLY + ; + +feature + : OBJECTID OPEN_ROUND (formal (COMMA formal)*)* CLOSE_ROUND COLON TYPEID OPEN_CURLY expression CLOSE_CURLY # method + | OBJECTID COLON TYPEID (ASSIGNMENT expression)? # property + ; + +formal + : OBJECTID COLON TYPEID + ; +/* method argument */ + + +expression + : expression (AT TYPEID)? DOT OBJECTID OPEN_ROUND (expression (COMMA expression)*)? CLOSE_ROUND # methodCall + | OBJECTID OPEN_ROUND (expression (COMMA expression)*)? CLOSE_ROUND # ownMethodCall + | IF expression THEN expression ELSE expression FI # if + | WHILE expression LOOP expression POOL # while + | OPEN_CURLY (expression SEMICOLON)+ CLOSE_CURLY # block + | LET OBJECTID COLON TYPEID (ASSIGNMENT expression)? (COMMA OBJECTID COLON TYPEID (ASSIGNMENT expression)?)* IN expression # letIn + | CASE expression OF (OBJECTID COLON TYPEID CASE_ARROW expression SEMICOLON)+ ESAC # case + | NEW TYPEID # new + | INTEGER_NEGATIVE expression # negative + | ISVOID expression # isvoid + | expression MULTIPLY expression # multiply + | expression DIVISION expression # division + | expression ADD expression # add + | expression MINUS expression # minus + | expression LESS_THAN expression # lessThan + | expression LESS_EQUAL expression # lessEqual + | expression EQUAL expression # equal + | NOT expression # boolNot + | OPEN_ROUND expression CLOSE_ROUND # parentheses + | OBJECTID # id + | INT # int + | STRING # string + | TRUE # true + | FALSE # false + | OBJECTID ASSIGNMENT expression # assignment + ; + // key words diff --git a/grammar/COOL_LEX.g4 b/grammar/COOL_LEX.g4 new file mode 100644 index 00000000..ae23319b --- /dev/null +++ b/grammar/COOL_LEX.g4 @@ -0,0 +1,320 @@ +lexer grammar COOL_LEX; + +CLASS + : C L A S S + ; + +ELSE + : E L S E + ; + +FALSE + : 'f' A L S E + ; + +FI + : F I + ; + +IF + : I F + ; + +IN + : I N + ; + +INHERITS + : I N H E R I T S + ; + +ISVOID + : I S V O I D + ; + +LET + : L E T + ; + +LOOP + : L O O P + ; + +POOL + : P O O L + ; + +THEN + : T H E N + ; + +WHILE + : W H I L E + ; + +CASE + : C A S E + ; + +ESAC + : E S A C + ; + +NEW + : N E W + ; + +OF + : O F + ; + +NOT + : N O T + ; + +TRUE + : 't' R U E + ; + // primitives + +STRING + : STRING_SIMPLE + | STRING_MULTILINE + ; + +STRING_SIMPLE_START : + '"' -> pushMode(SIMPLE_STR) + ; + +STRING_SIMPLE + : STRING_SIMPLE_START STRING_SIMPLE_CONTENT STRING_SIMPLE_STOP + | STRING_SIMPLE_START STRING_SIMPLE_STOP + ; + +fragment +STRING_CONTENT + : ESC | ~["\r\n\u0000] + ; + +STRING_FIRSTLINE + : '"' STRING_CONTENT* '\\\r\n' -> pushMode(MULTILINE_STR) + ; + +INT + : [0-9]+ + ; + +TYPEID + : [A-Z] [_0-9A-Za-z]* + ; + +OBJECTID + : [a-z] [_0-9A-Za-z]* + ; + +ASSIGNMENT + : '<-' + ; + +CASE_ARROW + : '=>' + ; + +ADD + : '+' + ; + +MINUS + : '-' + ; + +MULTIPLY + : '*' + ; + +DIVISION + : '/' + ; + +LESS_THAN + : '<' + ; + +LESS_EQUAL + : '<=' + ; + +EQUAL + : '=' + ; + +INTEGER_NEGATIVE + : '~' + ; + +OPEN_ROUND + : '(' + ; + +CLOSE_ROUND + : ')' + ; + +OPEN_CURLY + : '{' + ; + +CLOSE_CURLY + : '}' + ; + +AT + : '@' + ; + +DOT + : '.' + ; + +COMMA + : ',' + ; + +COLON + : ':' + ; + +SEMICOLON + : ';' + ; + +fragment A + : [aA] + ; + +fragment C + : [cC] + ; + +fragment D + : [dD] + ; + +fragment E + : [eE] + ; + +fragment F + : [fF] + ; + +fragment H + : [hH] + ; + +fragment I + : [iI] + ; + +fragment L + : [lL] + ; + +fragment N + : [nN] + ; + +fragment O + : [oO] + ; + +fragment P + : [pP] + ; + +fragment R + : [rR] + ; + +fragment S + : [sS] + ; + +fragment T + : [tT] + ; + +fragment U + : [uU] + ; + +fragment V + : [vV] + ; + +fragment W + : [wW] + ; + +fragment ESC + : '\\' (["\\/bfnrt] | UNICODE) + ; + +fragment UNICODE + : 'u' HEX HEX HEX HEX + ; + +fragment HEX + : [0-9a-fA-F] + ; + + // skip spaces, tabs, newlines, note that \v is not suppoted in antlr + +WHITESPACE + : [ \t\r\n\f]+ -> skip + ; + + // comments + +ONE_LINE_COMMENT + : '--' (~ '\n')* '\n'? -> skip + ; + +OPEN_COMMENT + : '(*' -> pushMode(MULTILINE_COMMENT) + ; + +mode MULTILINE_COMMENT; + +COMMENT + : ((OPEN_COMMENT COMMENT CLOSE_COMMENT) | (.)+? ) -> skip + ; + +CLOSE_COMMENT + : '*)' -> popMode + ; + +mode MULTILINE_STR; + +STRING_INNERLINE + : STRING_CONTENT* '\\\r\n' + ; + +STRING_LASTLINE + : STRING_CONTENT* '"' -> popMode + ; + +STRING_MULTILINE + : STRING_FIRSTLINE STRING_INNERLINE* STRING_LASTLINE + ; + +mode SIMPLE_STR; + +STRING_SIMPLE_CONTENT + : STRING_CONTENT+ + ; + +STRING_SIMPLE_STOP : + '"' -> popMode + ; + diff --git a/src/COOL.interp b/src/COOL.interp index 0a51d34e..656b83cd 100644 --- a/src/COOL.interp +++ b/src/COOL.interp @@ -78,8 +78,8 @@ OF NOT TRUE STRING -STRING_SIMPLE STRING_SIMPLE_START +STRING_SIMPLE STRING_FIRSTLINE INT TYPEID diff --git a/src/COOL.py b/src/COOL.py index 1e1ab864..98bb717d 100644 --- a/src/COOL.py +++ b/src/COOL.py @@ -129,7 +129,7 @@ class COOL ( Parser ): symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", "OF", "NOT", - "TRUE", "STRING", "STRING_SIMPLE", "STRING_SIMPLE_START", + "TRUE", "STRING", "STRING_SIMPLE_START", "STRING_SIMPLE", "STRING_FIRSTLINE", "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", @@ -170,8 +170,8 @@ class COOL ( Parser ): NOT=18 TRUE=19 STRING=20 - STRING_SIMPLE=21 - STRING_SIMPLE_START=22 + STRING_SIMPLE_START=21 + STRING_SIMPLE=22 STRING_FIRSTLINE=23 INT=24 TYPEID=25 diff --git a/src/COOL.tokens b/src/COOL.tokens index c7eacfe4..b0899aa4 100644 --- a/src/COOL.tokens +++ b/src/COOL.tokens @@ -18,8 +18,8 @@ OF=17 NOT=18 TRUE=19 STRING=20 -STRING_SIMPLE=21 -STRING_SIMPLE_START=22 +STRING_SIMPLE_START=21 +STRING_SIMPLE=22 STRING_FIRSTLINE=23 INT=24 TYPEID=25 diff --git a/src/COOLLexer.py b/src/COOLLexer.py index 62b3502f..fda56cf1 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -27,6 +27,8 @@ def notifyListeners(self, e:LexerNoViableAltException): msg = "String contains null character" elif self.inputStream.size == self.inputStream.index: msg = "EOF in string constant" + elif text in ['\r', '\n', '\0'] and self._input.getText(start-1, start-1) in ['\r', '\n', '\0']: + return; else: msg = "Unterminated string constant" else: diff --git a/src/COOL_LEX.interp b/src/COOL_LEX.interp index b7975eb6..d1000fee 100644 --- a/src/COOL_LEX.interp +++ b/src/COOL_LEX.interp @@ -78,8 +78,8 @@ OF NOT TRUE STRING -STRING_SIMPLE STRING_SIMPLE_START +STRING_SIMPLE STRING_FIRSTLINE INT TYPEID @@ -135,8 +135,8 @@ OF NOT TRUE STRING -STRING_SIMPLE STRING_SIMPLE_START +STRING_SIMPLE STRING_CONTENT STRING_FIRSTLINE INT @@ -203,4 +203,4 @@ MULTILINE_STR SIMPLE_STR atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 57, 471, 8, 1, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 254, 10, 21, 3, 22, 3, 22, 7, 22, 258, 10, 22, 12, 22, 14, 22, 261, 11, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 5, 24, 271, 10, 24, 3, 25, 3, 25, 7, 25, 275, 10, 25, 12, 25, 14, 25, 278, 11, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 6, 26, 287, 10, 26, 13, 26, 14, 26, 288, 3, 27, 3, 27, 7, 27, 293, 10, 27, 12, 27, 14, 27, 296, 11, 27, 3, 28, 3, 28, 7, 28, 300, 10, 28, 12, 28, 14, 28, 303, 11, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 5, 65, 383, 10, 65, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 6, 68, 394, 10, 68, 13, 68, 14, 68, 395, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 7, 69, 404, 10, 69, 12, 69, 14, 69, 407, 11, 69, 3, 69, 5, 69, 410, 10, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 424, 10, 71, 13, 71, 14, 71, 425, 5, 71, 428, 10, 71, 3, 71, 3, 71, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 438, 10, 73, 12, 73, 14, 73, 441, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 7, 74, 448, 10, 74, 12, 74, 14, 74, 451, 11, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 75, 3, 75, 7, 75, 459, 10, 75, 12, 75, 14, 75, 462, 11, 75, 3, 75, 3, 75, 3, 76, 3, 76, 3, 77, 3, 77, 3, 77, 3, 77, 3, 425, 2, 78, 6, 3, 8, 4, 10, 5, 12, 6, 14, 7, 16, 8, 18, 9, 20, 10, 22, 11, 24, 12, 26, 13, 28, 14, 30, 15, 32, 16, 34, 17, 36, 18, 38, 19, 40, 20, 42, 21, 44, 22, 46, 23, 48, 24, 50, 2, 52, 25, 54, 26, 56, 27, 58, 28, 60, 29, 62, 30, 64, 31, 66, 32, 68, 33, 70, 34, 72, 35, 74, 36, 76, 37, 78, 38, 80, 39, 82, 40, 84, 41, 86, 42, 88, 43, 90, 44, 92, 45, 94, 46, 96, 47, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 2, 132, 2, 134, 2, 136, 2, 138, 48, 140, 49, 142, 50, 144, 51, 146, 52, 148, 53, 150, 54, 152, 55, 154, 56, 156, 57, 6, 2, 3, 4, 5, 28, 6, 2, 2, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 462, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 90, 3, 2, 2, 2, 2, 92, 3, 2, 2, 2, 2, 94, 3, 2, 2, 2, 2, 96, 3, 2, 2, 2, 2, 138, 3, 2, 2, 2, 2, 140, 3, 2, 2, 2, 2, 142, 3, 2, 2, 2, 3, 144, 3, 2, 2, 2, 3, 146, 3, 2, 2, 2, 4, 148, 3, 2, 2, 2, 4, 150, 3, 2, 2, 2, 4, 152, 3, 2, 2, 2, 5, 154, 3, 2, 2, 2, 5, 156, 3, 2, 2, 2, 6, 158, 3, 2, 2, 2, 8, 164, 3, 2, 2, 2, 10, 169, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 178, 3, 2, 2, 2, 16, 181, 3, 2, 2, 2, 18, 184, 3, 2, 2, 2, 20, 193, 3, 2, 2, 2, 22, 200, 3, 2, 2, 2, 24, 204, 3, 2, 2, 2, 26, 209, 3, 2, 2, 2, 28, 214, 3, 2, 2, 2, 30, 219, 3, 2, 2, 2, 32, 225, 3, 2, 2, 2, 34, 230, 3, 2, 2, 2, 36, 235, 3, 2, 2, 2, 38, 239, 3, 2, 2, 2, 40, 242, 3, 2, 2, 2, 42, 246, 3, 2, 2, 2, 44, 253, 3, 2, 2, 2, 46, 255, 3, 2, 2, 2, 48, 264, 3, 2, 2, 2, 50, 270, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 286, 3, 2, 2, 2, 56, 290, 3, 2, 2, 2, 58, 297, 3, 2, 2, 2, 60, 304, 3, 2, 2, 2, 62, 307, 3, 2, 2, 2, 64, 310, 3, 2, 2, 2, 66, 312, 3, 2, 2, 2, 68, 314, 3, 2, 2, 2, 70, 316, 3, 2, 2, 2, 72, 318, 3, 2, 2, 2, 74, 320, 3, 2, 2, 2, 76, 323, 3, 2, 2, 2, 78, 325, 3, 2, 2, 2, 80, 327, 3, 2, 2, 2, 82, 329, 3, 2, 2, 2, 84, 331, 3, 2, 2, 2, 86, 333, 3, 2, 2, 2, 88, 335, 3, 2, 2, 2, 90, 337, 3, 2, 2, 2, 92, 339, 3, 2, 2, 2, 94, 341, 3, 2, 2, 2, 96, 343, 3, 2, 2, 2, 98, 345, 3, 2, 2, 2, 100, 347, 3, 2, 2, 2, 102, 349, 3, 2, 2, 2, 104, 351, 3, 2, 2, 2, 106, 353, 3, 2, 2, 2, 108, 355, 3, 2, 2, 2, 110, 357, 3, 2, 2, 2, 112, 359, 3, 2, 2, 2, 114, 361, 3, 2, 2, 2, 116, 363, 3, 2, 2, 2, 118, 365, 3, 2, 2, 2, 120, 367, 3, 2, 2, 2, 122, 369, 3, 2, 2, 2, 124, 371, 3, 2, 2, 2, 126, 373, 3, 2, 2, 2, 128, 375, 3, 2, 2, 2, 130, 377, 3, 2, 2, 2, 132, 379, 3, 2, 2, 2, 134, 384, 3, 2, 2, 2, 136, 390, 3, 2, 2, 2, 138, 393, 3, 2, 2, 2, 140, 399, 3, 2, 2, 2, 142, 413, 3, 2, 2, 2, 144, 427, 3, 2, 2, 2, 146, 431, 3, 2, 2, 2, 148, 439, 3, 2, 2, 2, 150, 449, 3, 2, 2, 2, 152, 456, 3, 2, 2, 2, 154, 465, 3, 2, 2, 2, 156, 467, 3, 2, 2, 2, 158, 159, 5, 100, 49, 2, 159, 160, 5, 112, 55, 2, 160, 161, 5, 98, 48, 2, 161, 162, 5, 122, 60, 2, 162, 163, 5, 122, 60, 2, 163, 7, 3, 2, 2, 2, 164, 165, 5, 104, 51, 2, 165, 166, 5, 112, 55, 2, 166, 167, 5, 122, 60, 2, 167, 168, 5, 104, 51, 2, 168, 9, 3, 2, 2, 2, 169, 170, 7, 104, 2, 2, 170, 171, 5, 98, 48, 2, 171, 172, 5, 112, 55, 2, 172, 173, 5, 122, 60, 2, 173, 174, 5, 104, 51, 2, 174, 11, 3, 2, 2, 2, 175, 176, 5, 106, 52, 2, 176, 177, 5, 110, 54, 2, 177, 13, 3, 2, 2, 2, 178, 179, 5, 110, 54, 2, 179, 180, 5, 106, 52, 2, 180, 15, 3, 2, 2, 2, 181, 182, 5, 110, 54, 2, 182, 183, 5, 114, 56, 2, 183, 17, 3, 2, 2, 2, 184, 185, 5, 110, 54, 2, 185, 186, 5, 114, 56, 2, 186, 187, 5, 108, 53, 2, 187, 188, 5, 104, 51, 2, 188, 189, 5, 120, 59, 2, 189, 190, 5, 110, 54, 2, 190, 191, 5, 124, 61, 2, 191, 192, 5, 122, 60, 2, 192, 19, 3, 2, 2, 2, 193, 194, 5, 110, 54, 2, 194, 195, 5, 122, 60, 2, 195, 196, 5, 128, 63, 2, 196, 197, 5, 116, 57, 2, 197, 198, 5, 110, 54, 2, 198, 199, 5, 102, 50, 2, 199, 21, 3, 2, 2, 2, 200, 201, 5, 112, 55, 2, 201, 202, 5, 104, 51, 2, 202, 203, 5, 124, 61, 2, 203, 23, 3, 2, 2, 2, 204, 205, 5, 112, 55, 2, 205, 206, 5, 116, 57, 2, 206, 207, 5, 116, 57, 2, 207, 208, 5, 118, 58, 2, 208, 25, 3, 2, 2, 2, 209, 210, 5, 118, 58, 2, 210, 211, 5, 116, 57, 2, 211, 212, 5, 116, 57, 2, 212, 213, 5, 112, 55, 2, 213, 27, 3, 2, 2, 2, 214, 215, 5, 124, 61, 2, 215, 216, 5, 108, 53, 2, 216, 217, 5, 104, 51, 2, 217, 218, 5, 114, 56, 2, 218, 29, 3, 2, 2, 2, 219, 220, 5, 130, 64, 2, 220, 221, 5, 108, 53, 2, 221, 222, 5, 110, 54, 2, 222, 223, 5, 112, 55, 2, 223, 224, 5, 104, 51, 2, 224, 31, 3, 2, 2, 2, 225, 226, 5, 100, 49, 2, 226, 227, 5, 98, 48, 2, 227, 228, 5, 122, 60, 2, 228, 229, 5, 104, 51, 2, 229, 33, 3, 2, 2, 2, 230, 231, 5, 104, 51, 2, 231, 232, 5, 122, 60, 2, 232, 233, 5, 98, 48, 2, 233, 234, 5, 100, 49, 2, 234, 35, 3, 2, 2, 2, 235, 236, 5, 114, 56, 2, 236, 237, 5, 104, 51, 2, 237, 238, 5, 130, 64, 2, 238, 37, 3, 2, 2, 2, 239, 240, 5, 116, 57, 2, 240, 241, 5, 106, 52, 2, 241, 39, 3, 2, 2, 2, 242, 243, 5, 114, 56, 2, 243, 244, 5, 116, 57, 2, 244, 245, 5, 124, 61, 2, 245, 41, 3, 2, 2, 2, 246, 247, 7, 118, 2, 2, 247, 248, 5, 120, 59, 2, 248, 249, 5, 126, 62, 2, 249, 250, 5, 104, 51, 2, 250, 43, 3, 2, 2, 2, 251, 254, 5, 46, 22, 2, 252, 254, 5, 152, 75, 2, 253, 251, 3, 2, 2, 2, 253, 252, 3, 2, 2, 2, 254, 45, 3, 2, 2, 2, 255, 259, 5, 48, 23, 2, 256, 258, 5, 154, 76, 2, 257, 256, 3, 2, 2, 2, 258, 261, 3, 2, 2, 2, 259, 257, 3, 2, 2, 2, 259, 260, 3, 2, 2, 2, 260, 262, 3, 2, 2, 2, 261, 259, 3, 2, 2, 2, 262, 263, 5, 156, 77, 2, 263, 47, 3, 2, 2, 2, 264, 265, 7, 36, 2, 2, 265, 266, 3, 2, 2, 2, 266, 267, 8, 23, 2, 2, 267, 49, 3, 2, 2, 2, 268, 271, 5, 132, 65, 2, 269, 271, 10, 2, 2, 2, 270, 268, 3, 2, 2, 2, 270, 269, 3, 2, 2, 2, 271, 51, 3, 2, 2, 2, 272, 276, 7, 36, 2, 2, 273, 275, 5, 50, 24, 2, 274, 273, 3, 2, 2, 2, 275, 278, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 279, 3, 2, 2, 2, 278, 276, 3, 2, 2, 2, 279, 280, 7, 94, 2, 2, 280, 281, 7, 15, 2, 2, 281, 282, 7, 12, 2, 2, 282, 283, 3, 2, 2, 2, 283, 284, 8, 25, 3, 2, 284, 53, 3, 2, 2, 2, 285, 287, 9, 3, 2, 2, 286, 285, 3, 2, 2, 2, 287, 288, 3, 2, 2, 2, 288, 286, 3, 2, 2, 2, 288, 289, 3, 2, 2, 2, 289, 55, 3, 2, 2, 2, 290, 294, 9, 4, 2, 2, 291, 293, 9, 5, 2, 2, 292, 291, 3, 2, 2, 2, 293, 296, 3, 2, 2, 2, 294, 292, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 57, 3, 2, 2, 2, 296, 294, 3, 2, 2, 2, 297, 301, 9, 6, 2, 2, 298, 300, 9, 5, 2, 2, 299, 298, 3, 2, 2, 2, 300, 303, 3, 2, 2, 2, 301, 299, 3, 2, 2, 2, 301, 302, 3, 2, 2, 2, 302, 59, 3, 2, 2, 2, 303, 301, 3, 2, 2, 2, 304, 305, 7, 62, 2, 2, 305, 306, 7, 47, 2, 2, 306, 61, 3, 2, 2, 2, 307, 308, 7, 63, 2, 2, 308, 309, 7, 64, 2, 2, 309, 63, 3, 2, 2, 2, 310, 311, 7, 45, 2, 2, 311, 65, 3, 2, 2, 2, 312, 313, 7, 47, 2, 2, 313, 67, 3, 2, 2, 2, 314, 315, 7, 44, 2, 2, 315, 69, 3, 2, 2, 2, 316, 317, 7, 49, 2, 2, 317, 71, 3, 2, 2, 2, 318, 319, 7, 62, 2, 2, 319, 73, 3, 2, 2, 2, 320, 321, 7, 62, 2, 2, 321, 322, 7, 63, 2, 2, 322, 75, 3, 2, 2, 2, 323, 324, 7, 63, 2, 2, 324, 77, 3, 2, 2, 2, 325, 326, 7, 128, 2, 2, 326, 79, 3, 2, 2, 2, 327, 328, 7, 42, 2, 2, 328, 81, 3, 2, 2, 2, 329, 330, 7, 43, 2, 2, 330, 83, 3, 2, 2, 2, 331, 332, 7, 125, 2, 2, 332, 85, 3, 2, 2, 2, 333, 334, 7, 127, 2, 2, 334, 87, 3, 2, 2, 2, 335, 336, 7, 66, 2, 2, 336, 89, 3, 2, 2, 2, 337, 338, 7, 48, 2, 2, 338, 91, 3, 2, 2, 2, 339, 340, 7, 46, 2, 2, 340, 93, 3, 2, 2, 2, 341, 342, 7, 60, 2, 2, 342, 95, 3, 2, 2, 2, 343, 344, 7, 61, 2, 2, 344, 97, 3, 2, 2, 2, 345, 346, 9, 7, 2, 2, 346, 99, 3, 2, 2, 2, 347, 348, 9, 8, 2, 2, 348, 101, 3, 2, 2, 2, 349, 350, 9, 9, 2, 2, 350, 103, 3, 2, 2, 2, 351, 352, 9, 10, 2, 2, 352, 105, 3, 2, 2, 2, 353, 354, 9, 11, 2, 2, 354, 107, 3, 2, 2, 2, 355, 356, 9, 12, 2, 2, 356, 109, 3, 2, 2, 2, 357, 358, 9, 13, 2, 2, 358, 111, 3, 2, 2, 2, 359, 360, 9, 14, 2, 2, 360, 113, 3, 2, 2, 2, 361, 362, 9, 15, 2, 2, 362, 115, 3, 2, 2, 2, 363, 364, 9, 16, 2, 2, 364, 117, 3, 2, 2, 2, 365, 366, 9, 17, 2, 2, 366, 119, 3, 2, 2, 2, 367, 368, 9, 18, 2, 2, 368, 121, 3, 2, 2, 2, 369, 370, 9, 19, 2, 2, 370, 123, 3, 2, 2, 2, 371, 372, 9, 20, 2, 2, 372, 125, 3, 2, 2, 2, 373, 374, 9, 21, 2, 2, 374, 127, 3, 2, 2, 2, 375, 376, 9, 22, 2, 2, 376, 129, 3, 2, 2, 2, 377, 378, 9, 23, 2, 2, 378, 131, 3, 2, 2, 2, 379, 382, 7, 94, 2, 2, 380, 383, 9, 24, 2, 2, 381, 383, 5, 134, 66, 2, 382, 380, 3, 2, 2, 2, 382, 381, 3, 2, 2, 2, 383, 133, 3, 2, 2, 2, 384, 385, 7, 119, 2, 2, 385, 386, 5, 136, 67, 2, 386, 387, 5, 136, 67, 2, 387, 388, 5, 136, 67, 2, 388, 389, 5, 136, 67, 2, 389, 135, 3, 2, 2, 2, 390, 391, 9, 25, 2, 2, 391, 137, 3, 2, 2, 2, 392, 394, 9, 26, 2, 2, 393, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 393, 3, 2, 2, 2, 395, 396, 3, 2, 2, 2, 396, 397, 3, 2, 2, 2, 397, 398, 8, 68, 4, 2, 398, 139, 3, 2, 2, 2, 399, 400, 7, 47, 2, 2, 400, 401, 7, 47, 2, 2, 401, 405, 3, 2, 2, 2, 402, 404, 10, 27, 2, 2, 403, 402, 3, 2, 2, 2, 404, 407, 3, 2, 2, 2, 405, 403, 3, 2, 2, 2, 405, 406, 3, 2, 2, 2, 406, 409, 3, 2, 2, 2, 407, 405, 3, 2, 2, 2, 408, 410, 7, 12, 2, 2, 409, 408, 3, 2, 2, 2, 409, 410, 3, 2, 2, 2, 410, 411, 3, 2, 2, 2, 411, 412, 8, 69, 4, 2, 412, 141, 3, 2, 2, 2, 413, 414, 7, 42, 2, 2, 414, 415, 7, 44, 2, 2, 415, 416, 3, 2, 2, 2, 416, 417, 8, 70, 5, 2, 417, 143, 3, 2, 2, 2, 418, 419, 5, 142, 70, 2, 419, 420, 5, 144, 71, 2, 420, 421, 5, 146, 72, 2, 421, 428, 3, 2, 2, 2, 422, 424, 11, 2, 2, 2, 423, 422, 3, 2, 2, 2, 424, 425, 3, 2, 2, 2, 425, 426, 3, 2, 2, 2, 425, 423, 3, 2, 2, 2, 426, 428, 3, 2, 2, 2, 427, 418, 3, 2, 2, 2, 427, 423, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 430, 8, 71, 4, 2, 430, 145, 3, 2, 2, 2, 431, 432, 7, 44, 2, 2, 432, 433, 7, 43, 2, 2, 433, 434, 3, 2, 2, 2, 434, 435, 8, 72, 6, 2, 435, 147, 3, 2, 2, 2, 436, 438, 5, 50, 24, 2, 437, 436, 3, 2, 2, 2, 438, 441, 3, 2, 2, 2, 439, 437, 3, 2, 2, 2, 439, 440, 3, 2, 2, 2, 440, 442, 3, 2, 2, 2, 441, 439, 3, 2, 2, 2, 442, 443, 7, 94, 2, 2, 443, 444, 7, 15, 2, 2, 444, 445, 7, 12, 2, 2, 445, 149, 3, 2, 2, 2, 446, 448, 5, 50, 24, 2, 447, 446, 3, 2, 2, 2, 448, 451, 3, 2, 2, 2, 449, 447, 3, 2, 2, 2, 449, 450, 3, 2, 2, 2, 450, 452, 3, 2, 2, 2, 451, 449, 3, 2, 2, 2, 452, 453, 7, 36, 2, 2, 453, 454, 3, 2, 2, 2, 454, 455, 8, 74, 6, 2, 455, 151, 3, 2, 2, 2, 456, 460, 5, 52, 25, 2, 457, 459, 5, 148, 73, 2, 458, 457, 3, 2, 2, 2, 459, 462, 3, 2, 2, 2, 460, 458, 3, 2, 2, 2, 460, 461, 3, 2, 2, 2, 461, 463, 3, 2, 2, 2, 462, 460, 3, 2, 2, 2, 463, 464, 5, 150, 74, 2, 464, 153, 3, 2, 2, 2, 465, 466, 5, 50, 24, 2, 466, 155, 3, 2, 2, 2, 467, 468, 7, 36, 2, 2, 468, 469, 3, 2, 2, 2, 469, 470, 8, 77, 6, 2, 470, 157, 3, 2, 2, 2, 22, 2, 3, 4, 5, 253, 259, 270, 276, 288, 294, 301, 382, 395, 405, 409, 425, 427, 439, 449, 460, 7, 7, 5, 2, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 57, 474, 8, 1, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 254, 10, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 5, 23, 267, 10, 23, 3, 24, 3, 24, 5, 24, 271, 10, 24, 3, 25, 3, 25, 7, 25, 275, 10, 25, 12, 25, 14, 25, 278, 11, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 6, 26, 287, 10, 26, 13, 26, 14, 26, 288, 3, 27, 3, 27, 7, 27, 293, 10, 27, 12, 27, 14, 27, 296, 11, 27, 3, 28, 3, 28, 7, 28, 300, 10, 28, 12, 28, 14, 28, 303, 11, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 5, 65, 383, 10, 65, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 6, 68, 394, 10, 68, 13, 68, 14, 68, 395, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 7, 69, 404, 10, 69, 12, 69, 14, 69, 407, 11, 69, 3, 69, 5, 69, 410, 10, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 424, 10, 71, 13, 71, 14, 71, 425, 5, 71, 428, 10, 71, 3, 71, 3, 71, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 438, 10, 73, 12, 73, 14, 73, 441, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 7, 74, 448, 10, 74, 12, 74, 14, 74, 451, 11, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 75, 3, 75, 7, 75, 459, 10, 75, 12, 75, 14, 75, 462, 11, 75, 3, 75, 3, 75, 3, 76, 6, 76, 467, 10, 76, 13, 76, 14, 76, 468, 3, 77, 3, 77, 3, 77, 3, 77, 3, 425, 2, 78, 6, 3, 8, 4, 10, 5, 12, 6, 14, 7, 16, 8, 18, 9, 20, 10, 22, 11, 24, 12, 26, 13, 28, 14, 30, 15, 32, 16, 34, 17, 36, 18, 38, 19, 40, 20, 42, 21, 44, 22, 46, 23, 48, 24, 50, 2, 52, 25, 54, 26, 56, 27, 58, 28, 60, 29, 62, 30, 64, 31, 66, 32, 68, 33, 70, 34, 72, 35, 74, 36, 76, 37, 78, 38, 80, 39, 82, 40, 84, 41, 86, 42, 88, 43, 90, 44, 92, 45, 94, 46, 96, 47, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 2, 132, 2, 134, 2, 136, 2, 138, 48, 140, 49, 142, 50, 144, 51, 146, 52, 148, 53, 150, 54, 152, 55, 154, 56, 156, 57, 6, 2, 3, 4, 5, 28, 6, 2, 2, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 466, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 90, 3, 2, 2, 2, 2, 92, 3, 2, 2, 2, 2, 94, 3, 2, 2, 2, 2, 96, 3, 2, 2, 2, 2, 138, 3, 2, 2, 2, 2, 140, 3, 2, 2, 2, 2, 142, 3, 2, 2, 2, 3, 144, 3, 2, 2, 2, 3, 146, 3, 2, 2, 2, 4, 148, 3, 2, 2, 2, 4, 150, 3, 2, 2, 2, 4, 152, 3, 2, 2, 2, 5, 154, 3, 2, 2, 2, 5, 156, 3, 2, 2, 2, 6, 158, 3, 2, 2, 2, 8, 164, 3, 2, 2, 2, 10, 169, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 178, 3, 2, 2, 2, 16, 181, 3, 2, 2, 2, 18, 184, 3, 2, 2, 2, 20, 193, 3, 2, 2, 2, 22, 200, 3, 2, 2, 2, 24, 204, 3, 2, 2, 2, 26, 209, 3, 2, 2, 2, 28, 214, 3, 2, 2, 2, 30, 219, 3, 2, 2, 2, 32, 225, 3, 2, 2, 2, 34, 230, 3, 2, 2, 2, 36, 235, 3, 2, 2, 2, 38, 239, 3, 2, 2, 2, 40, 242, 3, 2, 2, 2, 42, 246, 3, 2, 2, 2, 44, 253, 3, 2, 2, 2, 46, 255, 3, 2, 2, 2, 48, 266, 3, 2, 2, 2, 50, 270, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 286, 3, 2, 2, 2, 56, 290, 3, 2, 2, 2, 58, 297, 3, 2, 2, 2, 60, 304, 3, 2, 2, 2, 62, 307, 3, 2, 2, 2, 64, 310, 3, 2, 2, 2, 66, 312, 3, 2, 2, 2, 68, 314, 3, 2, 2, 2, 70, 316, 3, 2, 2, 2, 72, 318, 3, 2, 2, 2, 74, 320, 3, 2, 2, 2, 76, 323, 3, 2, 2, 2, 78, 325, 3, 2, 2, 2, 80, 327, 3, 2, 2, 2, 82, 329, 3, 2, 2, 2, 84, 331, 3, 2, 2, 2, 86, 333, 3, 2, 2, 2, 88, 335, 3, 2, 2, 2, 90, 337, 3, 2, 2, 2, 92, 339, 3, 2, 2, 2, 94, 341, 3, 2, 2, 2, 96, 343, 3, 2, 2, 2, 98, 345, 3, 2, 2, 2, 100, 347, 3, 2, 2, 2, 102, 349, 3, 2, 2, 2, 104, 351, 3, 2, 2, 2, 106, 353, 3, 2, 2, 2, 108, 355, 3, 2, 2, 2, 110, 357, 3, 2, 2, 2, 112, 359, 3, 2, 2, 2, 114, 361, 3, 2, 2, 2, 116, 363, 3, 2, 2, 2, 118, 365, 3, 2, 2, 2, 120, 367, 3, 2, 2, 2, 122, 369, 3, 2, 2, 2, 124, 371, 3, 2, 2, 2, 126, 373, 3, 2, 2, 2, 128, 375, 3, 2, 2, 2, 130, 377, 3, 2, 2, 2, 132, 379, 3, 2, 2, 2, 134, 384, 3, 2, 2, 2, 136, 390, 3, 2, 2, 2, 138, 393, 3, 2, 2, 2, 140, 399, 3, 2, 2, 2, 142, 413, 3, 2, 2, 2, 144, 427, 3, 2, 2, 2, 146, 431, 3, 2, 2, 2, 148, 439, 3, 2, 2, 2, 150, 449, 3, 2, 2, 2, 152, 456, 3, 2, 2, 2, 154, 466, 3, 2, 2, 2, 156, 470, 3, 2, 2, 2, 158, 159, 5, 100, 49, 2, 159, 160, 5, 112, 55, 2, 160, 161, 5, 98, 48, 2, 161, 162, 5, 122, 60, 2, 162, 163, 5, 122, 60, 2, 163, 7, 3, 2, 2, 2, 164, 165, 5, 104, 51, 2, 165, 166, 5, 112, 55, 2, 166, 167, 5, 122, 60, 2, 167, 168, 5, 104, 51, 2, 168, 9, 3, 2, 2, 2, 169, 170, 7, 104, 2, 2, 170, 171, 5, 98, 48, 2, 171, 172, 5, 112, 55, 2, 172, 173, 5, 122, 60, 2, 173, 174, 5, 104, 51, 2, 174, 11, 3, 2, 2, 2, 175, 176, 5, 106, 52, 2, 176, 177, 5, 110, 54, 2, 177, 13, 3, 2, 2, 2, 178, 179, 5, 110, 54, 2, 179, 180, 5, 106, 52, 2, 180, 15, 3, 2, 2, 2, 181, 182, 5, 110, 54, 2, 182, 183, 5, 114, 56, 2, 183, 17, 3, 2, 2, 2, 184, 185, 5, 110, 54, 2, 185, 186, 5, 114, 56, 2, 186, 187, 5, 108, 53, 2, 187, 188, 5, 104, 51, 2, 188, 189, 5, 120, 59, 2, 189, 190, 5, 110, 54, 2, 190, 191, 5, 124, 61, 2, 191, 192, 5, 122, 60, 2, 192, 19, 3, 2, 2, 2, 193, 194, 5, 110, 54, 2, 194, 195, 5, 122, 60, 2, 195, 196, 5, 128, 63, 2, 196, 197, 5, 116, 57, 2, 197, 198, 5, 110, 54, 2, 198, 199, 5, 102, 50, 2, 199, 21, 3, 2, 2, 2, 200, 201, 5, 112, 55, 2, 201, 202, 5, 104, 51, 2, 202, 203, 5, 124, 61, 2, 203, 23, 3, 2, 2, 2, 204, 205, 5, 112, 55, 2, 205, 206, 5, 116, 57, 2, 206, 207, 5, 116, 57, 2, 207, 208, 5, 118, 58, 2, 208, 25, 3, 2, 2, 2, 209, 210, 5, 118, 58, 2, 210, 211, 5, 116, 57, 2, 211, 212, 5, 116, 57, 2, 212, 213, 5, 112, 55, 2, 213, 27, 3, 2, 2, 2, 214, 215, 5, 124, 61, 2, 215, 216, 5, 108, 53, 2, 216, 217, 5, 104, 51, 2, 217, 218, 5, 114, 56, 2, 218, 29, 3, 2, 2, 2, 219, 220, 5, 130, 64, 2, 220, 221, 5, 108, 53, 2, 221, 222, 5, 110, 54, 2, 222, 223, 5, 112, 55, 2, 223, 224, 5, 104, 51, 2, 224, 31, 3, 2, 2, 2, 225, 226, 5, 100, 49, 2, 226, 227, 5, 98, 48, 2, 227, 228, 5, 122, 60, 2, 228, 229, 5, 104, 51, 2, 229, 33, 3, 2, 2, 2, 230, 231, 5, 104, 51, 2, 231, 232, 5, 122, 60, 2, 232, 233, 5, 98, 48, 2, 233, 234, 5, 100, 49, 2, 234, 35, 3, 2, 2, 2, 235, 236, 5, 114, 56, 2, 236, 237, 5, 104, 51, 2, 237, 238, 5, 130, 64, 2, 238, 37, 3, 2, 2, 2, 239, 240, 5, 116, 57, 2, 240, 241, 5, 106, 52, 2, 241, 39, 3, 2, 2, 2, 242, 243, 5, 114, 56, 2, 243, 244, 5, 116, 57, 2, 244, 245, 5, 124, 61, 2, 245, 41, 3, 2, 2, 2, 246, 247, 7, 118, 2, 2, 247, 248, 5, 120, 59, 2, 248, 249, 5, 126, 62, 2, 249, 250, 5, 104, 51, 2, 250, 43, 3, 2, 2, 2, 251, 254, 5, 48, 23, 2, 252, 254, 5, 152, 75, 2, 253, 251, 3, 2, 2, 2, 253, 252, 3, 2, 2, 2, 254, 45, 3, 2, 2, 2, 255, 256, 7, 36, 2, 2, 256, 257, 3, 2, 2, 2, 257, 258, 8, 22, 2, 2, 258, 47, 3, 2, 2, 2, 259, 260, 5, 46, 22, 2, 260, 261, 5, 154, 76, 2, 261, 262, 5, 156, 77, 2, 262, 267, 3, 2, 2, 2, 263, 264, 5, 46, 22, 2, 264, 265, 5, 156, 77, 2, 265, 267, 3, 2, 2, 2, 266, 259, 3, 2, 2, 2, 266, 263, 3, 2, 2, 2, 267, 49, 3, 2, 2, 2, 268, 271, 5, 132, 65, 2, 269, 271, 10, 2, 2, 2, 270, 268, 3, 2, 2, 2, 270, 269, 3, 2, 2, 2, 271, 51, 3, 2, 2, 2, 272, 276, 7, 36, 2, 2, 273, 275, 5, 50, 24, 2, 274, 273, 3, 2, 2, 2, 275, 278, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 279, 3, 2, 2, 2, 278, 276, 3, 2, 2, 2, 279, 280, 7, 94, 2, 2, 280, 281, 7, 15, 2, 2, 281, 282, 7, 12, 2, 2, 282, 283, 3, 2, 2, 2, 283, 284, 8, 25, 3, 2, 284, 53, 3, 2, 2, 2, 285, 287, 9, 3, 2, 2, 286, 285, 3, 2, 2, 2, 287, 288, 3, 2, 2, 2, 288, 286, 3, 2, 2, 2, 288, 289, 3, 2, 2, 2, 289, 55, 3, 2, 2, 2, 290, 294, 9, 4, 2, 2, 291, 293, 9, 5, 2, 2, 292, 291, 3, 2, 2, 2, 293, 296, 3, 2, 2, 2, 294, 292, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 57, 3, 2, 2, 2, 296, 294, 3, 2, 2, 2, 297, 301, 9, 6, 2, 2, 298, 300, 9, 5, 2, 2, 299, 298, 3, 2, 2, 2, 300, 303, 3, 2, 2, 2, 301, 299, 3, 2, 2, 2, 301, 302, 3, 2, 2, 2, 302, 59, 3, 2, 2, 2, 303, 301, 3, 2, 2, 2, 304, 305, 7, 62, 2, 2, 305, 306, 7, 47, 2, 2, 306, 61, 3, 2, 2, 2, 307, 308, 7, 63, 2, 2, 308, 309, 7, 64, 2, 2, 309, 63, 3, 2, 2, 2, 310, 311, 7, 45, 2, 2, 311, 65, 3, 2, 2, 2, 312, 313, 7, 47, 2, 2, 313, 67, 3, 2, 2, 2, 314, 315, 7, 44, 2, 2, 315, 69, 3, 2, 2, 2, 316, 317, 7, 49, 2, 2, 317, 71, 3, 2, 2, 2, 318, 319, 7, 62, 2, 2, 319, 73, 3, 2, 2, 2, 320, 321, 7, 62, 2, 2, 321, 322, 7, 63, 2, 2, 322, 75, 3, 2, 2, 2, 323, 324, 7, 63, 2, 2, 324, 77, 3, 2, 2, 2, 325, 326, 7, 128, 2, 2, 326, 79, 3, 2, 2, 2, 327, 328, 7, 42, 2, 2, 328, 81, 3, 2, 2, 2, 329, 330, 7, 43, 2, 2, 330, 83, 3, 2, 2, 2, 331, 332, 7, 125, 2, 2, 332, 85, 3, 2, 2, 2, 333, 334, 7, 127, 2, 2, 334, 87, 3, 2, 2, 2, 335, 336, 7, 66, 2, 2, 336, 89, 3, 2, 2, 2, 337, 338, 7, 48, 2, 2, 338, 91, 3, 2, 2, 2, 339, 340, 7, 46, 2, 2, 340, 93, 3, 2, 2, 2, 341, 342, 7, 60, 2, 2, 342, 95, 3, 2, 2, 2, 343, 344, 7, 61, 2, 2, 344, 97, 3, 2, 2, 2, 345, 346, 9, 7, 2, 2, 346, 99, 3, 2, 2, 2, 347, 348, 9, 8, 2, 2, 348, 101, 3, 2, 2, 2, 349, 350, 9, 9, 2, 2, 350, 103, 3, 2, 2, 2, 351, 352, 9, 10, 2, 2, 352, 105, 3, 2, 2, 2, 353, 354, 9, 11, 2, 2, 354, 107, 3, 2, 2, 2, 355, 356, 9, 12, 2, 2, 356, 109, 3, 2, 2, 2, 357, 358, 9, 13, 2, 2, 358, 111, 3, 2, 2, 2, 359, 360, 9, 14, 2, 2, 360, 113, 3, 2, 2, 2, 361, 362, 9, 15, 2, 2, 362, 115, 3, 2, 2, 2, 363, 364, 9, 16, 2, 2, 364, 117, 3, 2, 2, 2, 365, 366, 9, 17, 2, 2, 366, 119, 3, 2, 2, 2, 367, 368, 9, 18, 2, 2, 368, 121, 3, 2, 2, 2, 369, 370, 9, 19, 2, 2, 370, 123, 3, 2, 2, 2, 371, 372, 9, 20, 2, 2, 372, 125, 3, 2, 2, 2, 373, 374, 9, 21, 2, 2, 374, 127, 3, 2, 2, 2, 375, 376, 9, 22, 2, 2, 376, 129, 3, 2, 2, 2, 377, 378, 9, 23, 2, 2, 378, 131, 3, 2, 2, 2, 379, 382, 7, 94, 2, 2, 380, 383, 9, 24, 2, 2, 381, 383, 5, 134, 66, 2, 382, 380, 3, 2, 2, 2, 382, 381, 3, 2, 2, 2, 383, 133, 3, 2, 2, 2, 384, 385, 7, 119, 2, 2, 385, 386, 5, 136, 67, 2, 386, 387, 5, 136, 67, 2, 387, 388, 5, 136, 67, 2, 388, 389, 5, 136, 67, 2, 389, 135, 3, 2, 2, 2, 390, 391, 9, 25, 2, 2, 391, 137, 3, 2, 2, 2, 392, 394, 9, 26, 2, 2, 393, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 393, 3, 2, 2, 2, 395, 396, 3, 2, 2, 2, 396, 397, 3, 2, 2, 2, 397, 398, 8, 68, 4, 2, 398, 139, 3, 2, 2, 2, 399, 400, 7, 47, 2, 2, 400, 401, 7, 47, 2, 2, 401, 405, 3, 2, 2, 2, 402, 404, 10, 27, 2, 2, 403, 402, 3, 2, 2, 2, 404, 407, 3, 2, 2, 2, 405, 403, 3, 2, 2, 2, 405, 406, 3, 2, 2, 2, 406, 409, 3, 2, 2, 2, 407, 405, 3, 2, 2, 2, 408, 410, 7, 12, 2, 2, 409, 408, 3, 2, 2, 2, 409, 410, 3, 2, 2, 2, 410, 411, 3, 2, 2, 2, 411, 412, 8, 69, 4, 2, 412, 141, 3, 2, 2, 2, 413, 414, 7, 42, 2, 2, 414, 415, 7, 44, 2, 2, 415, 416, 3, 2, 2, 2, 416, 417, 8, 70, 5, 2, 417, 143, 3, 2, 2, 2, 418, 419, 5, 142, 70, 2, 419, 420, 5, 144, 71, 2, 420, 421, 5, 146, 72, 2, 421, 428, 3, 2, 2, 2, 422, 424, 11, 2, 2, 2, 423, 422, 3, 2, 2, 2, 424, 425, 3, 2, 2, 2, 425, 426, 3, 2, 2, 2, 425, 423, 3, 2, 2, 2, 426, 428, 3, 2, 2, 2, 427, 418, 3, 2, 2, 2, 427, 423, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 430, 8, 71, 4, 2, 430, 145, 3, 2, 2, 2, 431, 432, 7, 44, 2, 2, 432, 433, 7, 43, 2, 2, 433, 434, 3, 2, 2, 2, 434, 435, 8, 72, 6, 2, 435, 147, 3, 2, 2, 2, 436, 438, 5, 50, 24, 2, 437, 436, 3, 2, 2, 2, 438, 441, 3, 2, 2, 2, 439, 437, 3, 2, 2, 2, 439, 440, 3, 2, 2, 2, 440, 442, 3, 2, 2, 2, 441, 439, 3, 2, 2, 2, 442, 443, 7, 94, 2, 2, 443, 444, 7, 15, 2, 2, 444, 445, 7, 12, 2, 2, 445, 149, 3, 2, 2, 2, 446, 448, 5, 50, 24, 2, 447, 446, 3, 2, 2, 2, 448, 451, 3, 2, 2, 2, 449, 447, 3, 2, 2, 2, 449, 450, 3, 2, 2, 2, 450, 452, 3, 2, 2, 2, 451, 449, 3, 2, 2, 2, 452, 453, 7, 36, 2, 2, 453, 454, 3, 2, 2, 2, 454, 455, 8, 74, 6, 2, 455, 151, 3, 2, 2, 2, 456, 460, 5, 52, 25, 2, 457, 459, 5, 148, 73, 2, 458, 457, 3, 2, 2, 2, 459, 462, 3, 2, 2, 2, 460, 458, 3, 2, 2, 2, 460, 461, 3, 2, 2, 2, 461, 463, 3, 2, 2, 2, 462, 460, 3, 2, 2, 2, 463, 464, 5, 150, 74, 2, 464, 153, 3, 2, 2, 2, 465, 467, 5, 50, 24, 2, 466, 465, 3, 2, 2, 2, 467, 468, 3, 2, 2, 2, 468, 466, 3, 2, 2, 2, 468, 469, 3, 2, 2, 2, 469, 155, 3, 2, 2, 2, 470, 471, 7, 36, 2, 2, 471, 472, 3, 2, 2, 2, 472, 473, 8, 77, 6, 2, 473, 157, 3, 2, 2, 2, 23, 2, 3, 4, 5, 253, 266, 270, 276, 288, 294, 301, 382, 395, 405, 409, 425, 427, 439, 449, 460, 468, 7, 7, 5, 2, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file diff --git a/src/COOL_LEX.py b/src/COOL_LEX.py index 02c42de2..74921491 100644 --- a/src/COOL_LEX.py +++ b/src/COOL_LEX.py @@ -9,7 +9,7 @@ def serializedATN(): with StringIO() as buf: buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\29") - buf.write("\u01d7\b\1\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5") + buf.write("\u01da\b\1\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5") buf.write("\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f") buf.write("\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4") buf.write("\22\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27") @@ -28,190 +28,192 @@ def serializedATN(): buf.write("\r\3\16\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3") buf.write("\17\3\20\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\22") buf.write("\3\22\3\22\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24") - buf.write("\3\25\3\25\5\25\u00fe\n\25\3\26\3\26\7\26\u0102\n\26\f") - buf.write("\26\16\26\u0105\13\26\3\26\3\26\3\27\3\27\3\27\3\27\3") - buf.write("\30\3\30\5\30\u010f\n\30\3\31\3\31\7\31\u0113\n\31\f\31") - buf.write("\16\31\u0116\13\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32") - buf.write("\6\32\u011f\n\32\r\32\16\32\u0120\3\33\3\33\7\33\u0125") - buf.write("\n\33\f\33\16\33\u0128\13\33\3\34\3\34\7\34\u012c\n\34") - buf.write("\f\34\16\34\u012f\13\34\3\35\3\35\3\35\3\36\3\36\3\36") - buf.write("\3\37\3\37\3 \3 \3!\3!\3\"\3\"\3#\3#\3$\3$\3$\3%\3%\3") - buf.write("&\3&\3\'\3\'\3(\3(\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3") - buf.write(".\3/\3/\3\60\3\60\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3") - buf.write("\64\3\65\3\65\3\66\3\66\3\67\3\67\38\38\39\39\3:\3:\3") - buf.write(";\3;\3<\3<\3=\3=\3>\3>\3?\3?\3@\3@\3A\3A\3A\5A\u017f\n") - buf.write("A\3B\3B\3B\3B\3B\3B\3C\3C\3D\6D\u018a\nD\rD\16D\u018b") - buf.write("\3D\3D\3E\3E\3E\3E\7E\u0194\nE\fE\16E\u0197\13E\3E\5E") - buf.write("\u019a\nE\3E\3E\3F\3F\3F\3F\3F\3G\3G\3G\3G\3G\6G\u01a8") - buf.write("\nG\rG\16G\u01a9\5G\u01ac\nG\3G\3G\3H\3H\3H\3H\3H\3I\7") - buf.write("I\u01b6\nI\fI\16I\u01b9\13I\3I\3I\3I\3I\3J\7J\u01c0\n") - buf.write("J\fJ\16J\u01c3\13J\3J\3J\3J\3J\3K\3K\7K\u01cb\nK\fK\16") - buf.write("K\u01ce\13K\3K\3K\3L\3L\3M\3M\3M\3M\3\u01a9\2N\6\3\b\4") - buf.write("\n\5\f\6\16\7\20\b\22\t\24\n\26\13\30\f\32\r\34\16\36") - buf.write("\17 \20\"\21$\22&\23(\24*\25,\26.\27\60\30\62\2\64\31") - buf.write("\66\328\33:\34<\35>\36@\37B D!F\"H#J$L%N&P\'R(T)V*X+Z") - buf.write(",\\-^.`/b\2d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2|\2~\2") - buf.write("\u0080\2\u0082\2\u0084\2\u0086\2\u0088\2\u008a\60\u008c") - buf.write("\61\u008e\62\u0090\63\u0092\64\u0094\65\u0096\66\u0098") - buf.write("\67\u009a8\u009c9\6\2\3\4\5\34\6\2\2\2\f\f\17\17$$\3\2") - buf.write("\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEee\4\2F") - buf.write("Fff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2PPpp\4") - buf.write("\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4\2XXx") - buf.write("x\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2\13\f") - buf.write("\16\17\"\"\3\2\f\f\2\u01ce\2\6\3\2\2\2\2\b\3\2\2\2\2\n") - buf.write("\3\2\2\2\2\f\3\2\2\2\2\16\3\2\2\2\2\20\3\2\2\2\2\22\3") - buf.write("\2\2\2\2\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32\3\2") - buf.write("\2\2\2\34\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2\2\2") - buf.write("\2$\3\2\2\2\2&\3\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3\2\2") - buf.write("\2\2.\3\2\2\2\2\60\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\2") - buf.write("8\3\2\2\2\2:\3\2\2\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2\2\2") - buf.write("\2B\3\2\2\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3\2\2") - buf.write("\2\2L\3\2\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2") - buf.write("\2\2\2V\3\2\2\2\2X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2\2^\3") - buf.write("\2\2\2\2`\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2\2\u008e") - buf.write("\3\2\2\2\3\u0090\3\2\2\2\3\u0092\3\2\2\2\4\u0094\3\2\2") - buf.write("\2\4\u0096\3\2\2\2\4\u0098\3\2\2\2\5\u009a\3\2\2\2\5\u009c") - buf.write("\3\2\2\2\6\u009e\3\2\2\2\b\u00a4\3\2\2\2\n\u00a9\3\2\2") - buf.write("\2\f\u00af\3\2\2\2\16\u00b2\3\2\2\2\20\u00b5\3\2\2\2\22") - buf.write("\u00b8\3\2\2\2\24\u00c1\3\2\2\2\26\u00c8\3\2\2\2\30\u00cc") - buf.write("\3\2\2\2\32\u00d1\3\2\2\2\34\u00d6\3\2\2\2\36\u00db\3") - buf.write("\2\2\2 \u00e1\3\2\2\2\"\u00e6\3\2\2\2$\u00eb\3\2\2\2&") - buf.write("\u00ef\3\2\2\2(\u00f2\3\2\2\2*\u00f6\3\2\2\2,\u00fd\3") - buf.write("\2\2\2.\u00ff\3\2\2\2\60\u0108\3\2\2\2\62\u010e\3\2\2") - buf.write("\2\64\u0110\3\2\2\2\66\u011e\3\2\2\28\u0122\3\2\2\2:\u0129") - buf.write("\3\2\2\2<\u0130\3\2\2\2>\u0133\3\2\2\2@\u0136\3\2\2\2") - buf.write("B\u0138\3\2\2\2D\u013a\3\2\2\2F\u013c\3\2\2\2H\u013e\3") - buf.write("\2\2\2J\u0140\3\2\2\2L\u0143\3\2\2\2N\u0145\3\2\2\2P\u0147") - buf.write("\3\2\2\2R\u0149\3\2\2\2T\u014b\3\2\2\2V\u014d\3\2\2\2") - buf.write("X\u014f\3\2\2\2Z\u0151\3\2\2\2\\\u0153\3\2\2\2^\u0155") - buf.write("\3\2\2\2`\u0157\3\2\2\2b\u0159\3\2\2\2d\u015b\3\2\2\2") - buf.write("f\u015d\3\2\2\2h\u015f\3\2\2\2j\u0161\3\2\2\2l\u0163\3") - buf.write("\2\2\2n\u0165\3\2\2\2p\u0167\3\2\2\2r\u0169\3\2\2\2t\u016b") - buf.write("\3\2\2\2v\u016d\3\2\2\2x\u016f\3\2\2\2z\u0171\3\2\2\2") - buf.write("|\u0173\3\2\2\2~\u0175\3\2\2\2\u0080\u0177\3\2\2\2\u0082") - buf.write("\u0179\3\2\2\2\u0084\u017b\3\2\2\2\u0086\u0180\3\2\2\2") - buf.write("\u0088\u0186\3\2\2\2\u008a\u0189\3\2\2\2\u008c\u018f\3") - buf.write("\2\2\2\u008e\u019d\3\2\2\2\u0090\u01ab\3\2\2\2\u0092\u01af") - buf.write("\3\2\2\2\u0094\u01b7\3\2\2\2\u0096\u01c1\3\2\2\2\u0098") - buf.write("\u01c8\3\2\2\2\u009a\u01d1\3\2\2\2\u009c\u01d3\3\2\2\2") - buf.write("\u009e\u009f\5d\61\2\u009f\u00a0\5p\67\2\u00a0\u00a1\5") - buf.write("b\60\2\u00a1\u00a2\5z<\2\u00a2\u00a3\5z<\2\u00a3\7\3\2") - buf.write("\2\2\u00a4\u00a5\5h\63\2\u00a5\u00a6\5p\67\2\u00a6\u00a7") - buf.write("\5z<\2\u00a7\u00a8\5h\63\2\u00a8\t\3\2\2\2\u00a9\u00aa") - buf.write("\7h\2\2\u00aa\u00ab\5b\60\2\u00ab\u00ac\5p\67\2\u00ac") - buf.write("\u00ad\5z<\2\u00ad\u00ae\5h\63\2\u00ae\13\3\2\2\2\u00af") - buf.write("\u00b0\5j\64\2\u00b0\u00b1\5n\66\2\u00b1\r\3\2\2\2\u00b2") - buf.write("\u00b3\5n\66\2\u00b3\u00b4\5j\64\2\u00b4\17\3\2\2\2\u00b5") - buf.write("\u00b6\5n\66\2\u00b6\u00b7\5r8\2\u00b7\21\3\2\2\2\u00b8") - buf.write("\u00b9\5n\66\2\u00b9\u00ba\5r8\2\u00ba\u00bb\5l\65\2\u00bb") - buf.write("\u00bc\5h\63\2\u00bc\u00bd\5x;\2\u00bd\u00be\5n\66\2\u00be") - buf.write("\u00bf\5|=\2\u00bf\u00c0\5z<\2\u00c0\23\3\2\2\2\u00c1") - buf.write("\u00c2\5n\66\2\u00c2\u00c3\5z<\2\u00c3\u00c4\5\u0080?") - buf.write("\2\u00c4\u00c5\5t9\2\u00c5\u00c6\5n\66\2\u00c6\u00c7\5") - buf.write("f\62\2\u00c7\25\3\2\2\2\u00c8\u00c9\5p\67\2\u00c9\u00ca") - buf.write("\5h\63\2\u00ca\u00cb\5|=\2\u00cb\27\3\2\2\2\u00cc\u00cd") - buf.write("\5p\67\2\u00cd\u00ce\5t9\2\u00ce\u00cf\5t9\2\u00cf\u00d0") - buf.write("\5v:\2\u00d0\31\3\2\2\2\u00d1\u00d2\5v:\2\u00d2\u00d3") - buf.write("\5t9\2\u00d3\u00d4\5t9\2\u00d4\u00d5\5p\67\2\u00d5\33") - buf.write("\3\2\2\2\u00d6\u00d7\5|=\2\u00d7\u00d8\5l\65\2\u00d8\u00d9") - buf.write("\5h\63\2\u00d9\u00da\5r8\2\u00da\35\3\2\2\2\u00db\u00dc") - buf.write("\5\u0082@\2\u00dc\u00dd\5l\65\2\u00dd\u00de\5n\66\2\u00de") - buf.write("\u00df\5p\67\2\u00df\u00e0\5h\63\2\u00e0\37\3\2\2\2\u00e1") - buf.write("\u00e2\5d\61\2\u00e2\u00e3\5b\60\2\u00e3\u00e4\5z<\2\u00e4") - buf.write("\u00e5\5h\63\2\u00e5!\3\2\2\2\u00e6\u00e7\5h\63\2\u00e7") - buf.write("\u00e8\5z<\2\u00e8\u00e9\5b\60\2\u00e9\u00ea\5d\61\2\u00ea") - buf.write("#\3\2\2\2\u00eb\u00ec\5r8\2\u00ec\u00ed\5h\63\2\u00ed") - buf.write("\u00ee\5\u0082@\2\u00ee%\3\2\2\2\u00ef\u00f0\5t9\2\u00f0") - buf.write("\u00f1\5j\64\2\u00f1\'\3\2\2\2\u00f2\u00f3\5r8\2\u00f3") - buf.write("\u00f4\5t9\2\u00f4\u00f5\5|=\2\u00f5)\3\2\2\2\u00f6\u00f7") - buf.write("\7v\2\2\u00f7\u00f8\5x;\2\u00f8\u00f9\5~>\2\u00f9\u00fa") - buf.write("\5h\63\2\u00fa+\3\2\2\2\u00fb\u00fe\5.\26\2\u00fc\u00fe") - buf.write("\5\u0098K\2\u00fd\u00fb\3\2\2\2\u00fd\u00fc\3\2\2\2\u00fe") - buf.write("-\3\2\2\2\u00ff\u0103\5\60\27\2\u0100\u0102\5\u009aL\2") - buf.write("\u0101\u0100\3\2\2\2\u0102\u0105\3\2\2\2\u0103\u0101\3") - buf.write("\2\2\2\u0103\u0104\3\2\2\2\u0104\u0106\3\2\2\2\u0105\u0103") - buf.write("\3\2\2\2\u0106\u0107\5\u009cM\2\u0107/\3\2\2\2\u0108\u0109") - buf.write("\7$\2\2\u0109\u010a\3\2\2\2\u010a\u010b\b\27\2\2\u010b") - buf.write("\61\3\2\2\2\u010c\u010f\5\u0084A\2\u010d\u010f\n\2\2\2") - buf.write("\u010e\u010c\3\2\2\2\u010e\u010d\3\2\2\2\u010f\63\3\2") - buf.write("\2\2\u0110\u0114\7$\2\2\u0111\u0113\5\62\30\2\u0112\u0111") - buf.write("\3\2\2\2\u0113\u0116\3\2\2\2\u0114\u0112\3\2\2\2\u0114") - buf.write("\u0115\3\2\2\2\u0115\u0117\3\2\2\2\u0116\u0114\3\2\2\2") - buf.write("\u0117\u0118\7^\2\2\u0118\u0119\7\17\2\2\u0119\u011a\7") - buf.write("\f\2\2\u011a\u011b\3\2\2\2\u011b\u011c\b\31\3\2\u011c") - buf.write("\65\3\2\2\2\u011d\u011f\t\3\2\2\u011e\u011d\3\2\2\2\u011f") - buf.write("\u0120\3\2\2\2\u0120\u011e\3\2\2\2\u0120\u0121\3\2\2\2") - buf.write("\u0121\67\3\2\2\2\u0122\u0126\t\4\2\2\u0123\u0125\t\5") - buf.write("\2\2\u0124\u0123\3\2\2\2\u0125\u0128\3\2\2\2\u0126\u0124") - buf.write("\3\2\2\2\u0126\u0127\3\2\2\2\u01279\3\2\2\2\u0128\u0126") - buf.write("\3\2\2\2\u0129\u012d\t\6\2\2\u012a\u012c\t\5\2\2\u012b") - buf.write("\u012a\3\2\2\2\u012c\u012f\3\2\2\2\u012d\u012b\3\2\2\2") - buf.write("\u012d\u012e\3\2\2\2\u012e;\3\2\2\2\u012f\u012d\3\2\2") - buf.write("\2\u0130\u0131\7>\2\2\u0131\u0132\7/\2\2\u0132=\3\2\2") - buf.write("\2\u0133\u0134\7?\2\2\u0134\u0135\7@\2\2\u0135?\3\2\2") - buf.write("\2\u0136\u0137\7-\2\2\u0137A\3\2\2\2\u0138\u0139\7/\2") - buf.write("\2\u0139C\3\2\2\2\u013a\u013b\7,\2\2\u013bE\3\2\2\2\u013c") - buf.write("\u013d\7\61\2\2\u013dG\3\2\2\2\u013e\u013f\7>\2\2\u013f") - buf.write("I\3\2\2\2\u0140\u0141\7>\2\2\u0141\u0142\7?\2\2\u0142") - buf.write("K\3\2\2\2\u0143\u0144\7?\2\2\u0144M\3\2\2\2\u0145\u0146") - buf.write("\7\u0080\2\2\u0146O\3\2\2\2\u0147\u0148\7*\2\2\u0148Q") - buf.write("\3\2\2\2\u0149\u014a\7+\2\2\u014aS\3\2\2\2\u014b\u014c") - buf.write("\7}\2\2\u014cU\3\2\2\2\u014d\u014e\7\177\2\2\u014eW\3") - buf.write("\2\2\2\u014f\u0150\7B\2\2\u0150Y\3\2\2\2\u0151\u0152\7") - buf.write("\60\2\2\u0152[\3\2\2\2\u0153\u0154\7.\2\2\u0154]\3\2\2") - buf.write("\2\u0155\u0156\7<\2\2\u0156_\3\2\2\2\u0157\u0158\7=\2") - buf.write("\2\u0158a\3\2\2\2\u0159\u015a\t\7\2\2\u015ac\3\2\2\2\u015b") - buf.write("\u015c\t\b\2\2\u015ce\3\2\2\2\u015d\u015e\t\t\2\2\u015e") - buf.write("g\3\2\2\2\u015f\u0160\t\n\2\2\u0160i\3\2\2\2\u0161\u0162") - buf.write("\t\13\2\2\u0162k\3\2\2\2\u0163\u0164\t\f\2\2\u0164m\3") - buf.write("\2\2\2\u0165\u0166\t\r\2\2\u0166o\3\2\2\2\u0167\u0168") - buf.write("\t\16\2\2\u0168q\3\2\2\2\u0169\u016a\t\17\2\2\u016as\3") - buf.write("\2\2\2\u016b\u016c\t\20\2\2\u016cu\3\2\2\2\u016d\u016e") - buf.write("\t\21\2\2\u016ew\3\2\2\2\u016f\u0170\t\22\2\2\u0170y\3") - buf.write("\2\2\2\u0171\u0172\t\23\2\2\u0172{\3\2\2\2\u0173\u0174") - buf.write("\t\24\2\2\u0174}\3\2\2\2\u0175\u0176\t\25\2\2\u0176\177") - buf.write("\3\2\2\2\u0177\u0178\t\26\2\2\u0178\u0081\3\2\2\2\u0179") - buf.write("\u017a\t\27\2\2\u017a\u0083\3\2\2\2\u017b\u017e\7^\2\2") - buf.write("\u017c\u017f\t\30\2\2\u017d\u017f\5\u0086B\2\u017e\u017c") - buf.write("\3\2\2\2\u017e\u017d\3\2\2\2\u017f\u0085\3\2\2\2\u0180") - buf.write("\u0181\7w\2\2\u0181\u0182\5\u0088C\2\u0182\u0183\5\u0088") - buf.write("C\2\u0183\u0184\5\u0088C\2\u0184\u0185\5\u0088C\2\u0185") - buf.write("\u0087\3\2\2\2\u0186\u0187\t\31\2\2\u0187\u0089\3\2\2") - buf.write("\2\u0188\u018a\t\32\2\2\u0189\u0188\3\2\2\2\u018a\u018b") - buf.write("\3\2\2\2\u018b\u0189\3\2\2\2\u018b\u018c\3\2\2\2\u018c") - buf.write("\u018d\3\2\2\2\u018d\u018e\bD\4\2\u018e\u008b\3\2\2\2") - buf.write("\u018f\u0190\7/\2\2\u0190\u0191\7/\2\2\u0191\u0195\3\2") - buf.write("\2\2\u0192\u0194\n\33\2\2\u0193\u0192\3\2\2\2\u0194\u0197") - buf.write("\3\2\2\2\u0195\u0193\3\2\2\2\u0195\u0196\3\2\2\2\u0196") - buf.write("\u0199\3\2\2\2\u0197\u0195\3\2\2\2\u0198\u019a\7\f\2\2") - buf.write("\u0199\u0198\3\2\2\2\u0199\u019a\3\2\2\2\u019a\u019b\3") - buf.write("\2\2\2\u019b\u019c\bE\4\2\u019c\u008d\3\2\2\2\u019d\u019e") - buf.write("\7*\2\2\u019e\u019f\7,\2\2\u019f\u01a0\3\2\2\2\u01a0\u01a1") - buf.write("\bF\5\2\u01a1\u008f\3\2\2\2\u01a2\u01a3\5\u008eF\2\u01a3") - buf.write("\u01a4\5\u0090G\2\u01a4\u01a5\5\u0092H\2\u01a5\u01ac\3") - buf.write("\2\2\2\u01a6\u01a8\13\2\2\2\u01a7\u01a6\3\2\2\2\u01a8") - buf.write("\u01a9\3\2\2\2\u01a9\u01aa\3\2\2\2\u01a9\u01a7\3\2\2\2") - buf.write("\u01aa\u01ac\3\2\2\2\u01ab\u01a2\3\2\2\2\u01ab\u01a7\3") - buf.write("\2\2\2\u01ac\u01ad\3\2\2\2\u01ad\u01ae\bG\4\2\u01ae\u0091") - buf.write("\3\2\2\2\u01af\u01b0\7,\2\2\u01b0\u01b1\7+\2\2\u01b1\u01b2") - buf.write("\3\2\2\2\u01b2\u01b3\bH\6\2\u01b3\u0093\3\2\2\2\u01b4") - buf.write("\u01b6\5\62\30\2\u01b5\u01b4\3\2\2\2\u01b6\u01b9\3\2\2") - buf.write("\2\u01b7\u01b5\3\2\2\2\u01b7\u01b8\3\2\2\2\u01b8\u01ba") - buf.write("\3\2\2\2\u01b9\u01b7\3\2\2\2\u01ba\u01bb\7^\2\2\u01bb") - buf.write("\u01bc\7\17\2\2\u01bc\u01bd\7\f\2\2\u01bd\u0095\3\2\2") - buf.write("\2\u01be\u01c0\5\62\30\2\u01bf\u01be\3\2\2\2\u01c0\u01c3") - buf.write("\3\2\2\2\u01c1\u01bf\3\2\2\2\u01c1\u01c2\3\2\2\2\u01c2") - buf.write("\u01c4\3\2\2\2\u01c3\u01c1\3\2\2\2\u01c4\u01c5\7$\2\2") - buf.write("\u01c5\u01c6\3\2\2\2\u01c6\u01c7\bJ\6\2\u01c7\u0097\3") - buf.write("\2\2\2\u01c8\u01cc\5\64\31\2\u01c9\u01cb\5\u0094I\2\u01ca") - buf.write("\u01c9\3\2\2\2\u01cb\u01ce\3\2\2\2\u01cc\u01ca\3\2\2\2") - buf.write("\u01cc\u01cd\3\2\2\2\u01cd\u01cf\3\2\2\2\u01ce\u01cc\3") - buf.write("\2\2\2\u01cf\u01d0\5\u0096J\2\u01d0\u0099\3\2\2\2\u01d1") - buf.write("\u01d2\5\62\30\2\u01d2\u009b\3\2\2\2\u01d3\u01d4\7$\2") - buf.write("\2\u01d4\u01d5\3\2\2\2\u01d5\u01d6\bM\6\2\u01d6\u009d") - buf.write("\3\2\2\2\26\2\3\4\5\u00fd\u0103\u010e\u0114\u0120\u0126") - buf.write("\u012d\u017e\u018b\u0195\u0199\u01a9\u01ab\u01b7\u01c1") - buf.write("\u01cc\7\7\5\2\7\4\2\b\2\2\7\3\2\6\2\2") + buf.write("\3\25\3\25\5\25\u00fe\n\25\3\26\3\26\3\26\3\26\3\27\3") + buf.write("\27\3\27\3\27\3\27\3\27\3\27\5\27\u010b\n\27\3\30\3\30") + buf.write("\5\30\u010f\n\30\3\31\3\31\7\31\u0113\n\31\f\31\16\31") + buf.write("\u0116\13\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32\6\32\u011f") + buf.write("\n\32\r\32\16\32\u0120\3\33\3\33\7\33\u0125\n\33\f\33") + buf.write("\16\33\u0128\13\33\3\34\3\34\7\34\u012c\n\34\f\34\16\34") + buf.write("\u012f\13\34\3\35\3\35\3\35\3\36\3\36\3\36\3\37\3\37\3") + buf.write(" \3 \3!\3!\3\"\3\"\3#\3#\3$\3$\3$\3%\3%\3&\3&\3\'\3\'") + buf.write("\3(\3(\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60") + buf.write("\3\60\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65") + buf.write("\3\66\3\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<\3<\3=") + buf.write("\3=\3>\3>\3?\3?\3@\3@\3A\3A\3A\5A\u017f\nA\3B\3B\3B\3") + buf.write("B\3B\3B\3C\3C\3D\6D\u018a\nD\rD\16D\u018b\3D\3D\3E\3E") + buf.write("\3E\3E\7E\u0194\nE\fE\16E\u0197\13E\3E\5E\u019a\nE\3E") + buf.write("\3E\3F\3F\3F\3F\3F\3G\3G\3G\3G\3G\6G\u01a8\nG\rG\16G\u01a9") + buf.write("\5G\u01ac\nG\3G\3G\3H\3H\3H\3H\3H\3I\7I\u01b6\nI\fI\16") + buf.write("I\u01b9\13I\3I\3I\3I\3I\3J\7J\u01c0\nJ\fJ\16J\u01c3\13") + buf.write("J\3J\3J\3J\3J\3K\3K\7K\u01cb\nK\fK\16K\u01ce\13K\3K\3") + buf.write("K\3L\6L\u01d3\nL\rL\16L\u01d4\3M\3M\3M\3M\3\u01a9\2N\6") + buf.write("\3\b\4\n\5\f\6\16\7\20\b\22\t\24\n\26\13\30\f\32\r\34") + buf.write("\16\36\17 \20\"\21$\22&\23(\24*\25,\26.\27\60\30\62\2") + buf.write("\64\31\66\328\33:\34<\35>\36@\37B D!F\"H#J$L%N&P\'R(T") + buf.write(")V*X+Z,\\-^.`/b\2d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2") + buf.write("|\2~\2\u0080\2\u0082\2\u0084\2\u0086\2\u0088\2\u008a\60") + buf.write("\u008c\61\u008e\62\u0090\63\u0092\64\u0094\65\u0096\66") + buf.write("\u0098\67\u009a8\u009c9\6\2\3\4\5\34\6\2\2\2\f\f\17\17") + buf.write("$$\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEe") + buf.write("e\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2") + buf.write("PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4") + buf.write("\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2") + buf.write("\13\f\16\17\"\"\3\2\f\f\2\u01d2\2\6\3\2\2\2\2\b\3\2\2") + buf.write("\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16\3\2\2\2\2\20\3\2\2\2\2") + buf.write("\22\3\2\2\2\2\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32") + buf.write("\3\2\2\2\2\34\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2") + buf.write("\2\2\2$\3\2\2\2\2&\3\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3") + buf.write("\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2") + buf.write("\2\28\3\2\2\2\2:\3\2\2\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2") + buf.write("\2\2\2B\3\2\2\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3") + buf.write("\2\2\2\2L\3\2\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T") + buf.write("\3\2\2\2\2V\3\2\2\2\2X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2") + buf.write("\2^\3\2\2\2\2`\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2") + buf.write("\2\u008e\3\2\2\2\3\u0090\3\2\2\2\3\u0092\3\2\2\2\4\u0094") + buf.write("\3\2\2\2\4\u0096\3\2\2\2\4\u0098\3\2\2\2\5\u009a\3\2\2") + buf.write("\2\5\u009c\3\2\2\2\6\u009e\3\2\2\2\b\u00a4\3\2\2\2\n\u00a9") + buf.write("\3\2\2\2\f\u00af\3\2\2\2\16\u00b2\3\2\2\2\20\u00b5\3\2") + buf.write("\2\2\22\u00b8\3\2\2\2\24\u00c1\3\2\2\2\26\u00c8\3\2\2") + buf.write("\2\30\u00cc\3\2\2\2\32\u00d1\3\2\2\2\34\u00d6\3\2\2\2") + buf.write("\36\u00db\3\2\2\2 \u00e1\3\2\2\2\"\u00e6\3\2\2\2$\u00eb") + buf.write("\3\2\2\2&\u00ef\3\2\2\2(\u00f2\3\2\2\2*\u00f6\3\2\2\2") + buf.write(",\u00fd\3\2\2\2.\u00ff\3\2\2\2\60\u010a\3\2\2\2\62\u010e") + buf.write("\3\2\2\2\64\u0110\3\2\2\2\66\u011e\3\2\2\28\u0122\3\2") + buf.write("\2\2:\u0129\3\2\2\2<\u0130\3\2\2\2>\u0133\3\2\2\2@\u0136") + buf.write("\3\2\2\2B\u0138\3\2\2\2D\u013a\3\2\2\2F\u013c\3\2\2\2") + buf.write("H\u013e\3\2\2\2J\u0140\3\2\2\2L\u0143\3\2\2\2N\u0145\3") + buf.write("\2\2\2P\u0147\3\2\2\2R\u0149\3\2\2\2T\u014b\3\2\2\2V\u014d") + buf.write("\3\2\2\2X\u014f\3\2\2\2Z\u0151\3\2\2\2\\\u0153\3\2\2\2") + buf.write("^\u0155\3\2\2\2`\u0157\3\2\2\2b\u0159\3\2\2\2d\u015b\3") + buf.write("\2\2\2f\u015d\3\2\2\2h\u015f\3\2\2\2j\u0161\3\2\2\2l\u0163") + buf.write("\3\2\2\2n\u0165\3\2\2\2p\u0167\3\2\2\2r\u0169\3\2\2\2") + buf.write("t\u016b\3\2\2\2v\u016d\3\2\2\2x\u016f\3\2\2\2z\u0171\3") + buf.write("\2\2\2|\u0173\3\2\2\2~\u0175\3\2\2\2\u0080\u0177\3\2\2") + buf.write("\2\u0082\u0179\3\2\2\2\u0084\u017b\3\2\2\2\u0086\u0180") + buf.write("\3\2\2\2\u0088\u0186\3\2\2\2\u008a\u0189\3\2\2\2\u008c") + buf.write("\u018f\3\2\2\2\u008e\u019d\3\2\2\2\u0090\u01ab\3\2\2\2") + buf.write("\u0092\u01af\3\2\2\2\u0094\u01b7\3\2\2\2\u0096\u01c1\3") + buf.write("\2\2\2\u0098\u01c8\3\2\2\2\u009a\u01d2\3\2\2\2\u009c\u01d6") + buf.write("\3\2\2\2\u009e\u009f\5d\61\2\u009f\u00a0\5p\67\2\u00a0") + buf.write("\u00a1\5b\60\2\u00a1\u00a2\5z<\2\u00a2\u00a3\5z<\2\u00a3") + buf.write("\7\3\2\2\2\u00a4\u00a5\5h\63\2\u00a5\u00a6\5p\67\2\u00a6") + buf.write("\u00a7\5z<\2\u00a7\u00a8\5h\63\2\u00a8\t\3\2\2\2\u00a9") + buf.write("\u00aa\7h\2\2\u00aa\u00ab\5b\60\2\u00ab\u00ac\5p\67\2") + buf.write("\u00ac\u00ad\5z<\2\u00ad\u00ae\5h\63\2\u00ae\13\3\2\2") + buf.write("\2\u00af\u00b0\5j\64\2\u00b0\u00b1\5n\66\2\u00b1\r\3\2") + buf.write("\2\2\u00b2\u00b3\5n\66\2\u00b3\u00b4\5j\64\2\u00b4\17") + buf.write("\3\2\2\2\u00b5\u00b6\5n\66\2\u00b6\u00b7\5r8\2\u00b7\21") + buf.write("\3\2\2\2\u00b8\u00b9\5n\66\2\u00b9\u00ba\5r8\2\u00ba\u00bb") + buf.write("\5l\65\2\u00bb\u00bc\5h\63\2\u00bc\u00bd\5x;\2\u00bd\u00be") + buf.write("\5n\66\2\u00be\u00bf\5|=\2\u00bf\u00c0\5z<\2\u00c0\23") + buf.write("\3\2\2\2\u00c1\u00c2\5n\66\2\u00c2\u00c3\5z<\2\u00c3\u00c4") + buf.write("\5\u0080?\2\u00c4\u00c5\5t9\2\u00c5\u00c6\5n\66\2\u00c6") + buf.write("\u00c7\5f\62\2\u00c7\25\3\2\2\2\u00c8\u00c9\5p\67\2\u00c9") + buf.write("\u00ca\5h\63\2\u00ca\u00cb\5|=\2\u00cb\27\3\2\2\2\u00cc") + buf.write("\u00cd\5p\67\2\u00cd\u00ce\5t9\2\u00ce\u00cf\5t9\2\u00cf") + buf.write("\u00d0\5v:\2\u00d0\31\3\2\2\2\u00d1\u00d2\5v:\2\u00d2") + buf.write("\u00d3\5t9\2\u00d3\u00d4\5t9\2\u00d4\u00d5\5p\67\2\u00d5") + buf.write("\33\3\2\2\2\u00d6\u00d7\5|=\2\u00d7\u00d8\5l\65\2\u00d8") + buf.write("\u00d9\5h\63\2\u00d9\u00da\5r8\2\u00da\35\3\2\2\2\u00db") + buf.write("\u00dc\5\u0082@\2\u00dc\u00dd\5l\65\2\u00dd\u00de\5n\66") + buf.write("\2\u00de\u00df\5p\67\2\u00df\u00e0\5h\63\2\u00e0\37\3") + buf.write("\2\2\2\u00e1\u00e2\5d\61\2\u00e2\u00e3\5b\60\2\u00e3\u00e4") + buf.write("\5z<\2\u00e4\u00e5\5h\63\2\u00e5!\3\2\2\2\u00e6\u00e7") + buf.write("\5h\63\2\u00e7\u00e8\5z<\2\u00e8\u00e9\5b\60\2\u00e9\u00ea") + buf.write("\5d\61\2\u00ea#\3\2\2\2\u00eb\u00ec\5r8\2\u00ec\u00ed") + buf.write("\5h\63\2\u00ed\u00ee\5\u0082@\2\u00ee%\3\2\2\2\u00ef\u00f0") + buf.write("\5t9\2\u00f0\u00f1\5j\64\2\u00f1\'\3\2\2\2\u00f2\u00f3") + buf.write("\5r8\2\u00f3\u00f4\5t9\2\u00f4\u00f5\5|=\2\u00f5)\3\2") + buf.write("\2\2\u00f6\u00f7\7v\2\2\u00f7\u00f8\5x;\2\u00f8\u00f9") + buf.write("\5~>\2\u00f9\u00fa\5h\63\2\u00fa+\3\2\2\2\u00fb\u00fe") + buf.write("\5\60\27\2\u00fc\u00fe\5\u0098K\2\u00fd\u00fb\3\2\2\2") + buf.write("\u00fd\u00fc\3\2\2\2\u00fe-\3\2\2\2\u00ff\u0100\7$\2\2") + buf.write("\u0100\u0101\3\2\2\2\u0101\u0102\b\26\2\2\u0102/\3\2\2") + buf.write("\2\u0103\u0104\5.\26\2\u0104\u0105\5\u009aL\2\u0105\u0106") + buf.write("\5\u009cM\2\u0106\u010b\3\2\2\2\u0107\u0108\5.\26\2\u0108") + buf.write("\u0109\5\u009cM\2\u0109\u010b\3\2\2\2\u010a\u0103\3\2") + buf.write("\2\2\u010a\u0107\3\2\2\2\u010b\61\3\2\2\2\u010c\u010f") + buf.write("\5\u0084A\2\u010d\u010f\n\2\2\2\u010e\u010c\3\2\2\2\u010e") + buf.write("\u010d\3\2\2\2\u010f\63\3\2\2\2\u0110\u0114\7$\2\2\u0111") + buf.write("\u0113\5\62\30\2\u0112\u0111\3\2\2\2\u0113\u0116\3\2\2") + buf.write("\2\u0114\u0112\3\2\2\2\u0114\u0115\3\2\2\2\u0115\u0117") + buf.write("\3\2\2\2\u0116\u0114\3\2\2\2\u0117\u0118\7^\2\2\u0118") + buf.write("\u0119\7\17\2\2\u0119\u011a\7\f\2\2\u011a\u011b\3\2\2") + buf.write("\2\u011b\u011c\b\31\3\2\u011c\65\3\2\2\2\u011d\u011f\t") + buf.write("\3\2\2\u011e\u011d\3\2\2\2\u011f\u0120\3\2\2\2\u0120\u011e") + buf.write("\3\2\2\2\u0120\u0121\3\2\2\2\u0121\67\3\2\2\2\u0122\u0126") + buf.write("\t\4\2\2\u0123\u0125\t\5\2\2\u0124\u0123\3\2\2\2\u0125") + buf.write("\u0128\3\2\2\2\u0126\u0124\3\2\2\2\u0126\u0127\3\2\2\2") + buf.write("\u01279\3\2\2\2\u0128\u0126\3\2\2\2\u0129\u012d\t\6\2") + buf.write("\2\u012a\u012c\t\5\2\2\u012b\u012a\3\2\2\2\u012c\u012f") + buf.write("\3\2\2\2\u012d\u012b\3\2\2\2\u012d\u012e\3\2\2\2\u012e") + buf.write(";\3\2\2\2\u012f\u012d\3\2\2\2\u0130\u0131\7>\2\2\u0131") + buf.write("\u0132\7/\2\2\u0132=\3\2\2\2\u0133\u0134\7?\2\2\u0134") + buf.write("\u0135\7@\2\2\u0135?\3\2\2\2\u0136\u0137\7-\2\2\u0137") + buf.write("A\3\2\2\2\u0138\u0139\7/\2\2\u0139C\3\2\2\2\u013a\u013b") + buf.write("\7,\2\2\u013bE\3\2\2\2\u013c\u013d\7\61\2\2\u013dG\3\2") + buf.write("\2\2\u013e\u013f\7>\2\2\u013fI\3\2\2\2\u0140\u0141\7>") + buf.write("\2\2\u0141\u0142\7?\2\2\u0142K\3\2\2\2\u0143\u0144\7?") + buf.write("\2\2\u0144M\3\2\2\2\u0145\u0146\7\u0080\2\2\u0146O\3\2") + buf.write("\2\2\u0147\u0148\7*\2\2\u0148Q\3\2\2\2\u0149\u014a\7+") + buf.write("\2\2\u014aS\3\2\2\2\u014b\u014c\7}\2\2\u014cU\3\2\2\2") + buf.write("\u014d\u014e\7\177\2\2\u014eW\3\2\2\2\u014f\u0150\7B\2") + buf.write("\2\u0150Y\3\2\2\2\u0151\u0152\7\60\2\2\u0152[\3\2\2\2") + buf.write("\u0153\u0154\7.\2\2\u0154]\3\2\2\2\u0155\u0156\7<\2\2") + buf.write("\u0156_\3\2\2\2\u0157\u0158\7=\2\2\u0158a\3\2\2\2\u0159") + buf.write("\u015a\t\7\2\2\u015ac\3\2\2\2\u015b\u015c\t\b\2\2\u015c") + buf.write("e\3\2\2\2\u015d\u015e\t\t\2\2\u015eg\3\2\2\2\u015f\u0160") + buf.write("\t\n\2\2\u0160i\3\2\2\2\u0161\u0162\t\13\2\2\u0162k\3") + buf.write("\2\2\2\u0163\u0164\t\f\2\2\u0164m\3\2\2\2\u0165\u0166") + buf.write("\t\r\2\2\u0166o\3\2\2\2\u0167\u0168\t\16\2\2\u0168q\3") + buf.write("\2\2\2\u0169\u016a\t\17\2\2\u016as\3\2\2\2\u016b\u016c") + buf.write("\t\20\2\2\u016cu\3\2\2\2\u016d\u016e\t\21\2\2\u016ew\3") + buf.write("\2\2\2\u016f\u0170\t\22\2\2\u0170y\3\2\2\2\u0171\u0172") + buf.write("\t\23\2\2\u0172{\3\2\2\2\u0173\u0174\t\24\2\2\u0174}\3") + buf.write("\2\2\2\u0175\u0176\t\25\2\2\u0176\177\3\2\2\2\u0177\u0178") + buf.write("\t\26\2\2\u0178\u0081\3\2\2\2\u0179\u017a\t\27\2\2\u017a") + buf.write("\u0083\3\2\2\2\u017b\u017e\7^\2\2\u017c\u017f\t\30\2\2") + buf.write("\u017d\u017f\5\u0086B\2\u017e\u017c\3\2\2\2\u017e\u017d") + buf.write("\3\2\2\2\u017f\u0085\3\2\2\2\u0180\u0181\7w\2\2\u0181") + buf.write("\u0182\5\u0088C\2\u0182\u0183\5\u0088C\2\u0183\u0184\5") + buf.write("\u0088C\2\u0184\u0185\5\u0088C\2\u0185\u0087\3\2\2\2\u0186") + buf.write("\u0187\t\31\2\2\u0187\u0089\3\2\2\2\u0188\u018a\t\32\2") + buf.write("\2\u0189\u0188\3\2\2\2\u018a\u018b\3\2\2\2\u018b\u0189") + buf.write("\3\2\2\2\u018b\u018c\3\2\2\2\u018c\u018d\3\2\2\2\u018d") + buf.write("\u018e\bD\4\2\u018e\u008b\3\2\2\2\u018f\u0190\7/\2\2\u0190") + buf.write("\u0191\7/\2\2\u0191\u0195\3\2\2\2\u0192\u0194\n\33\2\2") + buf.write("\u0193\u0192\3\2\2\2\u0194\u0197\3\2\2\2\u0195\u0193\3") + buf.write("\2\2\2\u0195\u0196\3\2\2\2\u0196\u0199\3\2\2\2\u0197\u0195") + buf.write("\3\2\2\2\u0198\u019a\7\f\2\2\u0199\u0198\3\2\2\2\u0199") + buf.write("\u019a\3\2\2\2\u019a\u019b\3\2\2\2\u019b\u019c\bE\4\2") + buf.write("\u019c\u008d\3\2\2\2\u019d\u019e\7*\2\2\u019e\u019f\7") + buf.write(",\2\2\u019f\u01a0\3\2\2\2\u01a0\u01a1\bF\5\2\u01a1\u008f") + buf.write("\3\2\2\2\u01a2\u01a3\5\u008eF\2\u01a3\u01a4\5\u0090G\2") + buf.write("\u01a4\u01a5\5\u0092H\2\u01a5\u01ac\3\2\2\2\u01a6\u01a8") + buf.write("\13\2\2\2\u01a7\u01a6\3\2\2\2\u01a8\u01a9\3\2\2\2\u01a9") + buf.write("\u01aa\3\2\2\2\u01a9\u01a7\3\2\2\2\u01aa\u01ac\3\2\2\2") + buf.write("\u01ab\u01a2\3\2\2\2\u01ab\u01a7\3\2\2\2\u01ac\u01ad\3") + buf.write("\2\2\2\u01ad\u01ae\bG\4\2\u01ae\u0091\3\2\2\2\u01af\u01b0") + buf.write("\7,\2\2\u01b0\u01b1\7+\2\2\u01b1\u01b2\3\2\2\2\u01b2\u01b3") + buf.write("\bH\6\2\u01b3\u0093\3\2\2\2\u01b4\u01b6\5\62\30\2\u01b5") + buf.write("\u01b4\3\2\2\2\u01b6\u01b9\3\2\2\2\u01b7\u01b5\3\2\2\2") + buf.write("\u01b7\u01b8\3\2\2\2\u01b8\u01ba\3\2\2\2\u01b9\u01b7\3") + buf.write("\2\2\2\u01ba\u01bb\7^\2\2\u01bb\u01bc\7\17\2\2\u01bc\u01bd") + buf.write("\7\f\2\2\u01bd\u0095\3\2\2\2\u01be\u01c0\5\62\30\2\u01bf") + buf.write("\u01be\3\2\2\2\u01c0\u01c3\3\2\2\2\u01c1\u01bf\3\2\2\2") + buf.write("\u01c1\u01c2\3\2\2\2\u01c2\u01c4\3\2\2\2\u01c3\u01c1\3") + buf.write("\2\2\2\u01c4\u01c5\7$\2\2\u01c5\u01c6\3\2\2\2\u01c6\u01c7") + buf.write("\bJ\6\2\u01c7\u0097\3\2\2\2\u01c8\u01cc\5\64\31\2\u01c9") + buf.write("\u01cb\5\u0094I\2\u01ca\u01c9\3\2\2\2\u01cb\u01ce\3\2") + buf.write("\2\2\u01cc\u01ca\3\2\2\2\u01cc\u01cd\3\2\2\2\u01cd\u01cf") + buf.write("\3\2\2\2\u01ce\u01cc\3\2\2\2\u01cf\u01d0\5\u0096J\2\u01d0") + buf.write("\u0099\3\2\2\2\u01d1\u01d3\5\62\30\2\u01d2\u01d1\3\2\2") + buf.write("\2\u01d3\u01d4\3\2\2\2\u01d4\u01d2\3\2\2\2\u01d4\u01d5") + buf.write("\3\2\2\2\u01d5\u009b\3\2\2\2\u01d6\u01d7\7$\2\2\u01d7") + buf.write("\u01d8\3\2\2\2\u01d8\u01d9\bM\6\2\u01d9\u009d\3\2\2\2") + buf.write("\27\2\3\4\5\u00fd\u010a\u010e\u0114\u0120\u0126\u012d") + buf.write("\u017e\u018b\u0195\u0199\u01a9\u01ab\u01b7\u01c1\u01cc") + buf.write("\u01d4\7\7\5\2\7\4\2\b\2\2\7\3\2\6\2\2") return buf.getvalue() @@ -245,8 +247,8 @@ class COOL_LEX(Lexer): NOT = 18 TRUE = 19 STRING = 20 - STRING_SIMPLE = 21 - STRING_SIMPLE_START = 22 + STRING_SIMPLE_START = 21 + STRING_SIMPLE = 22 STRING_FIRSTLINE = 23 INT = 24 TYPEID = 25 @@ -294,7 +296,7 @@ class COOL_LEX(Lexer): symbolicNames = [ "", "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "NEW", - "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", "STRING_SIMPLE_START", + "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE_START", "STRING_SIMPLE", "STRING_FIRSTLINE", "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", @@ -305,8 +307,8 @@ class COOL_LEX(Lexer): ruleNames = [ "CLASS", "ELSE", "FALSE", "FI", "IF", "IN", "INHERITS", "ISVOID", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", - "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE", - "STRING_SIMPLE_START", "STRING_CONTENT", "STRING_FIRSTLINE", + "ESAC", "NEW", "OF", "NOT", "TRUE", "STRING", "STRING_SIMPLE_START", + "STRING_SIMPLE", "STRING_CONTENT", "STRING_FIRSTLINE", "INT", "TYPEID", "OBJECTID", "ASSIGNMENT", "CASE_ARROW", "ADD", "MINUS", "MULTIPLY", "DIVISION", "LESS_THAN", "LESS_EQUAL", "EQUAL", "INTEGER_NEGATIVE", "OPEN_ROUND", "CLOSE_ROUND", diff --git a/src/COOL_LEX.tokens b/src/COOL_LEX.tokens index c7eacfe4..b0899aa4 100644 --- a/src/COOL_LEX.tokens +++ b/src/COOL_LEX.tokens @@ -18,8 +18,8 @@ OF=17 NOT=18 TRUE=19 STRING=20 -STRING_SIMPLE=21 -STRING_SIMPLE_START=22 +STRING_SIMPLE_START=21 +STRING_SIMPLE=22 STRING_FIRSTLINE=23 INT=24 TYPEID=25 From 79b21c60d617866acb614b37933610e9f4fb8841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 16 Mar 2020 18:54:20 -0400 Subject: [PATCH 35/77] Se arreglo un bug de las cadenas simples --- src/COOLLexer.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/COOLLexer.py b/src/COOLLexer.py index fda56cf1..65fe0f15 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -30,6 +30,7 @@ def notifyListeners(self, e:LexerNoViableAltException): elif text in ['\r', '\n', '\0'] and self._input.getText(start-1, start-1) in ['\r', '\n', '\0']: return; else: + self.popMode() msg = "Unterminated string constant" else: msg = "'" + self.getErrorDisplay(text) + "'" @@ -52,15 +53,25 @@ def nextToken(self): continue elif self._currentToken.type == COOL_LEX.STRING_INNERLINE: continue + elif self._currentToken.type == COOL_LEX.STRING_SIMPLE_START: + continue + elif self._currentToken.type == COOL_LEX.STRING_SIMPLE_CONTENT: + continue else: break if self._currentToken.type == Token.EOF: - if lastToken != None and lastToken.type == COOL_LEX.OPEN_COMMENT: - self._hasErrors = True - listener = self.getErrorListenerDispatch() - listener.syntaxError(self, self._currentToken, self._currentToken.line, self._currentToken.column, - "EOF in comment", None) + if lastToken != None: + if lastToken.type == COOL_LEX.OPEN_COMMENT: + self._hasErrors = True + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, self._currentToken, self._currentToken.line, self._currentToken.column, + "EOF in comment", None) + elif lastToken.type == COOL_LEX.STRING_SIMPLE_START: + self._hasErrors = True + listener = self.getErrorListenerDispatch() + listener.syntaxError(self, self._currentToken, self._currentToken.line, self._currentToken.column, + "EOF in string constant", None) return self._currentToken; def reset(self): From 304a33b0b4cd2ade8a291ebe9a47d2be3f462ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 16 Mar 2020 19:24:18 -0400 Subject: [PATCH 36/77] Se arreglo otro bug --- src/COOLLexer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/COOLLexer.py b/src/COOLLexer.py index 65fe0f15..4df6933e 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -22,7 +22,7 @@ def notifyListeners(self, e:LexerNoViableAltException): start = self._tokenStartCharIndex stop = self._input.index text = self._input.getText(start, stop) - if self._currentToken.type in [COOL_LEX.STRING, COOL_LEX.STRING_FIRSTLINE, COOL_LEX.STRING_INNERLINE, COOL_LEX.STRING_SIMPLE_START, COOL_LEX.STRING_SIMPLE_CONTENT ] or text[0] == '"': + if self._currentToken.type in [COOL_LEX.STRING_FIRSTLINE, COOL_LEX.STRING_INNERLINE, COOL_LEX.STRING_SIMPLE_START, COOL_LEX.STRING_SIMPLE_CONTENT ] or text[0] == '"': if self._input.data[start] == 0: msg = "String contains null character" elif self.inputStream.size == self.inputStream.index: @@ -67,7 +67,7 @@ def nextToken(self): listener = self.getErrorListenerDispatch() listener.syntaxError(self, self._currentToken, self._currentToken.line, self._currentToken.column, "EOF in comment", None) - elif lastToken.type == COOL_LEX.STRING_SIMPLE_START: + elif lastToken.type in [COOL_LEX.STRING_SIMPLE_START, COOL_LEX.STRING_SIMPLE_CONTENT]: self._hasErrors = True listener = self.getErrorListenerDispatch() listener.syntaxError(self, self._currentToken, self._currentToken.line, self._currentToken.column, From 4cf80ad0717501a05ec28f9ba53af1b45ff5f9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 16 Mar 2020 19:38:21 -0400 Subject: [PATCH 37/77] =?UTF-8?q?Se=20arregl=C3=B3=20el=20mensaje=20de=20e?= =?UTF-8?q?rror=20del=20lexer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/COOLLexer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/COOLLexer.py b/src/COOLLexer.py index 4df6933e..40b9885b 100644 --- a/src/COOLLexer.py +++ b/src/COOLLexer.py @@ -33,7 +33,7 @@ def notifyListeners(self, e:LexerNoViableAltException): self.popMode() msg = "Unterminated string constant" else: - msg = "'" + self.getErrorDisplay(text) + "'" + msg = "ERROR \"" + self.getErrorDisplay(text) + "\"" if self._token == None: line = self.line col= self.column From 7e608c8eb3bc16f04aeed4db20ebee31a2d20c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 16 Mar 2020 20:01:37 -0400 Subject: [PATCH 38/77] =?UTF-8?q?Se=20arregl=C3=B3=20un=20bug=20relacionad?= =?UTF-8?q?o=20con=20la=20diferencia=20en=20el=20EOL=20entre=20Windows=20/?= =?UTF-8?q?=20Linux?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grammar/COOL_LEX.g4 | 4 +- src/COOL_LEX.interp | 2 +- src/COOL_LEX.py | 372 ++++++++++++++++++++++---------------------- 3 files changed, 191 insertions(+), 187 deletions(-) diff --git a/grammar/COOL_LEX.g4 b/grammar/COOL_LEX.g4 index ae23319b..eca3a6ed 100644 --- a/grammar/COOL_LEX.g4 +++ b/grammar/COOL_LEX.g4 @@ -97,7 +97,7 @@ STRING_CONTENT ; STRING_FIRSTLINE - : '"' STRING_CONTENT* '\\\r\n' -> pushMode(MULTILINE_STR) + : '"' STRING_CONTENT* ('\\\r\n' | '\\\n') -> pushMode(MULTILINE_STR) ; INT @@ -297,7 +297,7 @@ CLOSE_COMMENT mode MULTILINE_STR; STRING_INNERLINE - : STRING_CONTENT* '\\\r\n' + : STRING_CONTENT* ('\\\r\n' | '\\\n') ; STRING_LASTLINE diff --git a/src/COOL_LEX.interp b/src/COOL_LEX.interp index d1000fee..4bf1cb28 100644 --- a/src/COOL_LEX.interp +++ b/src/COOL_LEX.interp @@ -203,4 +203,4 @@ MULTILINE_STR SIMPLE_STR atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 57, 474, 8, 1, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 254, 10, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 5, 23, 267, 10, 23, 3, 24, 3, 24, 5, 24, 271, 10, 24, 3, 25, 3, 25, 7, 25, 275, 10, 25, 12, 25, 14, 25, 278, 11, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 6, 26, 287, 10, 26, 13, 26, 14, 26, 288, 3, 27, 3, 27, 7, 27, 293, 10, 27, 12, 27, 14, 27, 296, 11, 27, 3, 28, 3, 28, 7, 28, 300, 10, 28, 12, 28, 14, 28, 303, 11, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 5, 65, 383, 10, 65, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 6, 68, 394, 10, 68, 13, 68, 14, 68, 395, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 7, 69, 404, 10, 69, 12, 69, 14, 69, 407, 11, 69, 3, 69, 5, 69, 410, 10, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 424, 10, 71, 13, 71, 14, 71, 425, 5, 71, 428, 10, 71, 3, 71, 3, 71, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 438, 10, 73, 12, 73, 14, 73, 441, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 7, 74, 448, 10, 74, 12, 74, 14, 74, 451, 11, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 75, 3, 75, 7, 75, 459, 10, 75, 12, 75, 14, 75, 462, 11, 75, 3, 75, 3, 75, 3, 76, 6, 76, 467, 10, 76, 13, 76, 14, 76, 468, 3, 77, 3, 77, 3, 77, 3, 77, 3, 425, 2, 78, 6, 3, 8, 4, 10, 5, 12, 6, 14, 7, 16, 8, 18, 9, 20, 10, 22, 11, 24, 12, 26, 13, 28, 14, 30, 15, 32, 16, 34, 17, 36, 18, 38, 19, 40, 20, 42, 21, 44, 22, 46, 23, 48, 24, 50, 2, 52, 25, 54, 26, 56, 27, 58, 28, 60, 29, 62, 30, 64, 31, 66, 32, 68, 33, 70, 34, 72, 35, 74, 36, 76, 37, 78, 38, 80, 39, 82, 40, 84, 41, 86, 42, 88, 43, 90, 44, 92, 45, 94, 46, 96, 47, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 2, 132, 2, 134, 2, 136, 2, 138, 48, 140, 49, 142, 50, 144, 51, 146, 52, 148, 53, 150, 54, 152, 55, 154, 56, 156, 57, 6, 2, 3, 4, 5, 28, 6, 2, 2, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 466, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 90, 3, 2, 2, 2, 2, 92, 3, 2, 2, 2, 2, 94, 3, 2, 2, 2, 2, 96, 3, 2, 2, 2, 2, 138, 3, 2, 2, 2, 2, 140, 3, 2, 2, 2, 2, 142, 3, 2, 2, 2, 3, 144, 3, 2, 2, 2, 3, 146, 3, 2, 2, 2, 4, 148, 3, 2, 2, 2, 4, 150, 3, 2, 2, 2, 4, 152, 3, 2, 2, 2, 5, 154, 3, 2, 2, 2, 5, 156, 3, 2, 2, 2, 6, 158, 3, 2, 2, 2, 8, 164, 3, 2, 2, 2, 10, 169, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 178, 3, 2, 2, 2, 16, 181, 3, 2, 2, 2, 18, 184, 3, 2, 2, 2, 20, 193, 3, 2, 2, 2, 22, 200, 3, 2, 2, 2, 24, 204, 3, 2, 2, 2, 26, 209, 3, 2, 2, 2, 28, 214, 3, 2, 2, 2, 30, 219, 3, 2, 2, 2, 32, 225, 3, 2, 2, 2, 34, 230, 3, 2, 2, 2, 36, 235, 3, 2, 2, 2, 38, 239, 3, 2, 2, 2, 40, 242, 3, 2, 2, 2, 42, 246, 3, 2, 2, 2, 44, 253, 3, 2, 2, 2, 46, 255, 3, 2, 2, 2, 48, 266, 3, 2, 2, 2, 50, 270, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 286, 3, 2, 2, 2, 56, 290, 3, 2, 2, 2, 58, 297, 3, 2, 2, 2, 60, 304, 3, 2, 2, 2, 62, 307, 3, 2, 2, 2, 64, 310, 3, 2, 2, 2, 66, 312, 3, 2, 2, 2, 68, 314, 3, 2, 2, 2, 70, 316, 3, 2, 2, 2, 72, 318, 3, 2, 2, 2, 74, 320, 3, 2, 2, 2, 76, 323, 3, 2, 2, 2, 78, 325, 3, 2, 2, 2, 80, 327, 3, 2, 2, 2, 82, 329, 3, 2, 2, 2, 84, 331, 3, 2, 2, 2, 86, 333, 3, 2, 2, 2, 88, 335, 3, 2, 2, 2, 90, 337, 3, 2, 2, 2, 92, 339, 3, 2, 2, 2, 94, 341, 3, 2, 2, 2, 96, 343, 3, 2, 2, 2, 98, 345, 3, 2, 2, 2, 100, 347, 3, 2, 2, 2, 102, 349, 3, 2, 2, 2, 104, 351, 3, 2, 2, 2, 106, 353, 3, 2, 2, 2, 108, 355, 3, 2, 2, 2, 110, 357, 3, 2, 2, 2, 112, 359, 3, 2, 2, 2, 114, 361, 3, 2, 2, 2, 116, 363, 3, 2, 2, 2, 118, 365, 3, 2, 2, 2, 120, 367, 3, 2, 2, 2, 122, 369, 3, 2, 2, 2, 124, 371, 3, 2, 2, 2, 126, 373, 3, 2, 2, 2, 128, 375, 3, 2, 2, 2, 130, 377, 3, 2, 2, 2, 132, 379, 3, 2, 2, 2, 134, 384, 3, 2, 2, 2, 136, 390, 3, 2, 2, 2, 138, 393, 3, 2, 2, 2, 140, 399, 3, 2, 2, 2, 142, 413, 3, 2, 2, 2, 144, 427, 3, 2, 2, 2, 146, 431, 3, 2, 2, 2, 148, 439, 3, 2, 2, 2, 150, 449, 3, 2, 2, 2, 152, 456, 3, 2, 2, 2, 154, 466, 3, 2, 2, 2, 156, 470, 3, 2, 2, 2, 158, 159, 5, 100, 49, 2, 159, 160, 5, 112, 55, 2, 160, 161, 5, 98, 48, 2, 161, 162, 5, 122, 60, 2, 162, 163, 5, 122, 60, 2, 163, 7, 3, 2, 2, 2, 164, 165, 5, 104, 51, 2, 165, 166, 5, 112, 55, 2, 166, 167, 5, 122, 60, 2, 167, 168, 5, 104, 51, 2, 168, 9, 3, 2, 2, 2, 169, 170, 7, 104, 2, 2, 170, 171, 5, 98, 48, 2, 171, 172, 5, 112, 55, 2, 172, 173, 5, 122, 60, 2, 173, 174, 5, 104, 51, 2, 174, 11, 3, 2, 2, 2, 175, 176, 5, 106, 52, 2, 176, 177, 5, 110, 54, 2, 177, 13, 3, 2, 2, 2, 178, 179, 5, 110, 54, 2, 179, 180, 5, 106, 52, 2, 180, 15, 3, 2, 2, 2, 181, 182, 5, 110, 54, 2, 182, 183, 5, 114, 56, 2, 183, 17, 3, 2, 2, 2, 184, 185, 5, 110, 54, 2, 185, 186, 5, 114, 56, 2, 186, 187, 5, 108, 53, 2, 187, 188, 5, 104, 51, 2, 188, 189, 5, 120, 59, 2, 189, 190, 5, 110, 54, 2, 190, 191, 5, 124, 61, 2, 191, 192, 5, 122, 60, 2, 192, 19, 3, 2, 2, 2, 193, 194, 5, 110, 54, 2, 194, 195, 5, 122, 60, 2, 195, 196, 5, 128, 63, 2, 196, 197, 5, 116, 57, 2, 197, 198, 5, 110, 54, 2, 198, 199, 5, 102, 50, 2, 199, 21, 3, 2, 2, 2, 200, 201, 5, 112, 55, 2, 201, 202, 5, 104, 51, 2, 202, 203, 5, 124, 61, 2, 203, 23, 3, 2, 2, 2, 204, 205, 5, 112, 55, 2, 205, 206, 5, 116, 57, 2, 206, 207, 5, 116, 57, 2, 207, 208, 5, 118, 58, 2, 208, 25, 3, 2, 2, 2, 209, 210, 5, 118, 58, 2, 210, 211, 5, 116, 57, 2, 211, 212, 5, 116, 57, 2, 212, 213, 5, 112, 55, 2, 213, 27, 3, 2, 2, 2, 214, 215, 5, 124, 61, 2, 215, 216, 5, 108, 53, 2, 216, 217, 5, 104, 51, 2, 217, 218, 5, 114, 56, 2, 218, 29, 3, 2, 2, 2, 219, 220, 5, 130, 64, 2, 220, 221, 5, 108, 53, 2, 221, 222, 5, 110, 54, 2, 222, 223, 5, 112, 55, 2, 223, 224, 5, 104, 51, 2, 224, 31, 3, 2, 2, 2, 225, 226, 5, 100, 49, 2, 226, 227, 5, 98, 48, 2, 227, 228, 5, 122, 60, 2, 228, 229, 5, 104, 51, 2, 229, 33, 3, 2, 2, 2, 230, 231, 5, 104, 51, 2, 231, 232, 5, 122, 60, 2, 232, 233, 5, 98, 48, 2, 233, 234, 5, 100, 49, 2, 234, 35, 3, 2, 2, 2, 235, 236, 5, 114, 56, 2, 236, 237, 5, 104, 51, 2, 237, 238, 5, 130, 64, 2, 238, 37, 3, 2, 2, 2, 239, 240, 5, 116, 57, 2, 240, 241, 5, 106, 52, 2, 241, 39, 3, 2, 2, 2, 242, 243, 5, 114, 56, 2, 243, 244, 5, 116, 57, 2, 244, 245, 5, 124, 61, 2, 245, 41, 3, 2, 2, 2, 246, 247, 7, 118, 2, 2, 247, 248, 5, 120, 59, 2, 248, 249, 5, 126, 62, 2, 249, 250, 5, 104, 51, 2, 250, 43, 3, 2, 2, 2, 251, 254, 5, 48, 23, 2, 252, 254, 5, 152, 75, 2, 253, 251, 3, 2, 2, 2, 253, 252, 3, 2, 2, 2, 254, 45, 3, 2, 2, 2, 255, 256, 7, 36, 2, 2, 256, 257, 3, 2, 2, 2, 257, 258, 8, 22, 2, 2, 258, 47, 3, 2, 2, 2, 259, 260, 5, 46, 22, 2, 260, 261, 5, 154, 76, 2, 261, 262, 5, 156, 77, 2, 262, 267, 3, 2, 2, 2, 263, 264, 5, 46, 22, 2, 264, 265, 5, 156, 77, 2, 265, 267, 3, 2, 2, 2, 266, 259, 3, 2, 2, 2, 266, 263, 3, 2, 2, 2, 267, 49, 3, 2, 2, 2, 268, 271, 5, 132, 65, 2, 269, 271, 10, 2, 2, 2, 270, 268, 3, 2, 2, 2, 270, 269, 3, 2, 2, 2, 271, 51, 3, 2, 2, 2, 272, 276, 7, 36, 2, 2, 273, 275, 5, 50, 24, 2, 274, 273, 3, 2, 2, 2, 275, 278, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 279, 3, 2, 2, 2, 278, 276, 3, 2, 2, 2, 279, 280, 7, 94, 2, 2, 280, 281, 7, 15, 2, 2, 281, 282, 7, 12, 2, 2, 282, 283, 3, 2, 2, 2, 283, 284, 8, 25, 3, 2, 284, 53, 3, 2, 2, 2, 285, 287, 9, 3, 2, 2, 286, 285, 3, 2, 2, 2, 287, 288, 3, 2, 2, 2, 288, 286, 3, 2, 2, 2, 288, 289, 3, 2, 2, 2, 289, 55, 3, 2, 2, 2, 290, 294, 9, 4, 2, 2, 291, 293, 9, 5, 2, 2, 292, 291, 3, 2, 2, 2, 293, 296, 3, 2, 2, 2, 294, 292, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 57, 3, 2, 2, 2, 296, 294, 3, 2, 2, 2, 297, 301, 9, 6, 2, 2, 298, 300, 9, 5, 2, 2, 299, 298, 3, 2, 2, 2, 300, 303, 3, 2, 2, 2, 301, 299, 3, 2, 2, 2, 301, 302, 3, 2, 2, 2, 302, 59, 3, 2, 2, 2, 303, 301, 3, 2, 2, 2, 304, 305, 7, 62, 2, 2, 305, 306, 7, 47, 2, 2, 306, 61, 3, 2, 2, 2, 307, 308, 7, 63, 2, 2, 308, 309, 7, 64, 2, 2, 309, 63, 3, 2, 2, 2, 310, 311, 7, 45, 2, 2, 311, 65, 3, 2, 2, 2, 312, 313, 7, 47, 2, 2, 313, 67, 3, 2, 2, 2, 314, 315, 7, 44, 2, 2, 315, 69, 3, 2, 2, 2, 316, 317, 7, 49, 2, 2, 317, 71, 3, 2, 2, 2, 318, 319, 7, 62, 2, 2, 319, 73, 3, 2, 2, 2, 320, 321, 7, 62, 2, 2, 321, 322, 7, 63, 2, 2, 322, 75, 3, 2, 2, 2, 323, 324, 7, 63, 2, 2, 324, 77, 3, 2, 2, 2, 325, 326, 7, 128, 2, 2, 326, 79, 3, 2, 2, 2, 327, 328, 7, 42, 2, 2, 328, 81, 3, 2, 2, 2, 329, 330, 7, 43, 2, 2, 330, 83, 3, 2, 2, 2, 331, 332, 7, 125, 2, 2, 332, 85, 3, 2, 2, 2, 333, 334, 7, 127, 2, 2, 334, 87, 3, 2, 2, 2, 335, 336, 7, 66, 2, 2, 336, 89, 3, 2, 2, 2, 337, 338, 7, 48, 2, 2, 338, 91, 3, 2, 2, 2, 339, 340, 7, 46, 2, 2, 340, 93, 3, 2, 2, 2, 341, 342, 7, 60, 2, 2, 342, 95, 3, 2, 2, 2, 343, 344, 7, 61, 2, 2, 344, 97, 3, 2, 2, 2, 345, 346, 9, 7, 2, 2, 346, 99, 3, 2, 2, 2, 347, 348, 9, 8, 2, 2, 348, 101, 3, 2, 2, 2, 349, 350, 9, 9, 2, 2, 350, 103, 3, 2, 2, 2, 351, 352, 9, 10, 2, 2, 352, 105, 3, 2, 2, 2, 353, 354, 9, 11, 2, 2, 354, 107, 3, 2, 2, 2, 355, 356, 9, 12, 2, 2, 356, 109, 3, 2, 2, 2, 357, 358, 9, 13, 2, 2, 358, 111, 3, 2, 2, 2, 359, 360, 9, 14, 2, 2, 360, 113, 3, 2, 2, 2, 361, 362, 9, 15, 2, 2, 362, 115, 3, 2, 2, 2, 363, 364, 9, 16, 2, 2, 364, 117, 3, 2, 2, 2, 365, 366, 9, 17, 2, 2, 366, 119, 3, 2, 2, 2, 367, 368, 9, 18, 2, 2, 368, 121, 3, 2, 2, 2, 369, 370, 9, 19, 2, 2, 370, 123, 3, 2, 2, 2, 371, 372, 9, 20, 2, 2, 372, 125, 3, 2, 2, 2, 373, 374, 9, 21, 2, 2, 374, 127, 3, 2, 2, 2, 375, 376, 9, 22, 2, 2, 376, 129, 3, 2, 2, 2, 377, 378, 9, 23, 2, 2, 378, 131, 3, 2, 2, 2, 379, 382, 7, 94, 2, 2, 380, 383, 9, 24, 2, 2, 381, 383, 5, 134, 66, 2, 382, 380, 3, 2, 2, 2, 382, 381, 3, 2, 2, 2, 383, 133, 3, 2, 2, 2, 384, 385, 7, 119, 2, 2, 385, 386, 5, 136, 67, 2, 386, 387, 5, 136, 67, 2, 387, 388, 5, 136, 67, 2, 388, 389, 5, 136, 67, 2, 389, 135, 3, 2, 2, 2, 390, 391, 9, 25, 2, 2, 391, 137, 3, 2, 2, 2, 392, 394, 9, 26, 2, 2, 393, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 393, 3, 2, 2, 2, 395, 396, 3, 2, 2, 2, 396, 397, 3, 2, 2, 2, 397, 398, 8, 68, 4, 2, 398, 139, 3, 2, 2, 2, 399, 400, 7, 47, 2, 2, 400, 401, 7, 47, 2, 2, 401, 405, 3, 2, 2, 2, 402, 404, 10, 27, 2, 2, 403, 402, 3, 2, 2, 2, 404, 407, 3, 2, 2, 2, 405, 403, 3, 2, 2, 2, 405, 406, 3, 2, 2, 2, 406, 409, 3, 2, 2, 2, 407, 405, 3, 2, 2, 2, 408, 410, 7, 12, 2, 2, 409, 408, 3, 2, 2, 2, 409, 410, 3, 2, 2, 2, 410, 411, 3, 2, 2, 2, 411, 412, 8, 69, 4, 2, 412, 141, 3, 2, 2, 2, 413, 414, 7, 42, 2, 2, 414, 415, 7, 44, 2, 2, 415, 416, 3, 2, 2, 2, 416, 417, 8, 70, 5, 2, 417, 143, 3, 2, 2, 2, 418, 419, 5, 142, 70, 2, 419, 420, 5, 144, 71, 2, 420, 421, 5, 146, 72, 2, 421, 428, 3, 2, 2, 2, 422, 424, 11, 2, 2, 2, 423, 422, 3, 2, 2, 2, 424, 425, 3, 2, 2, 2, 425, 426, 3, 2, 2, 2, 425, 423, 3, 2, 2, 2, 426, 428, 3, 2, 2, 2, 427, 418, 3, 2, 2, 2, 427, 423, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 430, 8, 71, 4, 2, 430, 145, 3, 2, 2, 2, 431, 432, 7, 44, 2, 2, 432, 433, 7, 43, 2, 2, 433, 434, 3, 2, 2, 2, 434, 435, 8, 72, 6, 2, 435, 147, 3, 2, 2, 2, 436, 438, 5, 50, 24, 2, 437, 436, 3, 2, 2, 2, 438, 441, 3, 2, 2, 2, 439, 437, 3, 2, 2, 2, 439, 440, 3, 2, 2, 2, 440, 442, 3, 2, 2, 2, 441, 439, 3, 2, 2, 2, 442, 443, 7, 94, 2, 2, 443, 444, 7, 15, 2, 2, 444, 445, 7, 12, 2, 2, 445, 149, 3, 2, 2, 2, 446, 448, 5, 50, 24, 2, 447, 446, 3, 2, 2, 2, 448, 451, 3, 2, 2, 2, 449, 447, 3, 2, 2, 2, 449, 450, 3, 2, 2, 2, 450, 452, 3, 2, 2, 2, 451, 449, 3, 2, 2, 2, 452, 453, 7, 36, 2, 2, 453, 454, 3, 2, 2, 2, 454, 455, 8, 74, 6, 2, 455, 151, 3, 2, 2, 2, 456, 460, 5, 52, 25, 2, 457, 459, 5, 148, 73, 2, 458, 457, 3, 2, 2, 2, 459, 462, 3, 2, 2, 2, 460, 458, 3, 2, 2, 2, 460, 461, 3, 2, 2, 2, 461, 463, 3, 2, 2, 2, 462, 460, 3, 2, 2, 2, 463, 464, 5, 150, 74, 2, 464, 153, 3, 2, 2, 2, 465, 467, 5, 50, 24, 2, 466, 465, 3, 2, 2, 2, 467, 468, 3, 2, 2, 2, 468, 466, 3, 2, 2, 2, 468, 469, 3, 2, 2, 2, 469, 155, 3, 2, 2, 2, 470, 471, 7, 36, 2, 2, 471, 472, 3, 2, 2, 2, 472, 473, 8, 77, 6, 2, 473, 157, 3, 2, 2, 2, 23, 2, 3, 4, 5, 253, 266, 270, 276, 288, 294, 301, 382, 395, 405, 409, 425, 427, 439, 449, 460, 468, 7, 7, 5, 2, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 57, 480, 8, 1, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 254, 10, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 5, 23, 267, 10, 23, 3, 24, 3, 24, 5, 24, 271, 10, 24, 3, 25, 3, 25, 7, 25, 275, 10, 25, 12, 25, 14, 25, 278, 11, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 5, 25, 285, 10, 25, 3, 25, 3, 25, 3, 26, 6, 26, 290, 10, 26, 13, 26, 14, 26, 291, 3, 27, 3, 27, 7, 27, 296, 10, 27, 12, 27, 14, 27, 299, 11, 27, 3, 28, 3, 28, 7, 28, 303, 10, 28, 12, 28, 14, 28, 306, 11, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 5, 65, 386, 10, 65, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 6, 68, 397, 10, 68, 13, 68, 14, 68, 398, 3, 68, 3, 68, 3, 69, 3, 69, 3, 69, 3, 69, 7, 69, 407, 10, 69, 12, 69, 14, 69, 410, 11, 69, 3, 69, 5, 69, 413, 10, 69, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 427, 10, 71, 13, 71, 14, 71, 428, 5, 71, 431, 10, 71, 3, 71, 3, 71, 3, 72, 3, 72, 3, 72, 3, 72, 3, 72, 3, 73, 7, 73, 441, 10, 73, 12, 73, 14, 73, 444, 11, 73, 3, 73, 3, 73, 3, 73, 3, 73, 3, 73, 5, 73, 451, 10, 73, 3, 74, 7, 74, 454, 10, 74, 12, 74, 14, 74, 457, 11, 74, 3, 74, 3, 74, 3, 74, 3, 74, 3, 75, 3, 75, 7, 75, 465, 10, 75, 12, 75, 14, 75, 468, 11, 75, 3, 75, 3, 75, 3, 76, 6, 76, 473, 10, 76, 13, 76, 14, 76, 474, 3, 77, 3, 77, 3, 77, 3, 77, 3, 428, 2, 78, 6, 3, 8, 4, 10, 5, 12, 6, 14, 7, 16, 8, 18, 9, 20, 10, 22, 11, 24, 12, 26, 13, 28, 14, 30, 15, 32, 16, 34, 17, 36, 18, 38, 19, 40, 20, 42, 21, 44, 22, 46, 23, 48, 24, 50, 2, 52, 25, 54, 26, 56, 27, 58, 28, 60, 29, 62, 30, 64, 31, 66, 32, 68, 33, 70, 34, 72, 35, 74, 36, 76, 37, 78, 38, 80, 39, 82, 40, 84, 41, 86, 42, 88, 43, 90, 44, 92, 45, 94, 46, 96, 47, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 120, 2, 122, 2, 124, 2, 126, 2, 128, 2, 130, 2, 132, 2, 134, 2, 136, 2, 138, 48, 140, 49, 142, 50, 144, 51, 146, 52, 148, 53, 150, 54, 152, 55, 154, 56, 156, 57, 6, 2, 3, 4, 5, 28, 6, 2, 2, 2, 12, 12, 15, 15, 36, 36, 3, 2, 50, 59, 3, 2, 67, 92, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 99, 124, 4, 2, 67, 67, 99, 99, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 78, 78, 110, 110, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 11, 12, 14, 15, 34, 34, 3, 2, 12, 12, 2, 474, 2, 6, 3, 2, 2, 2, 2, 8, 3, 2, 2, 2, 2, 10, 3, 2, 2, 2, 2, 12, 3, 2, 2, 2, 2, 14, 3, 2, 2, 2, 2, 16, 3, 2, 2, 2, 2, 18, 3, 2, 2, 2, 2, 20, 3, 2, 2, 2, 2, 22, 3, 2, 2, 2, 2, 24, 3, 2, 2, 2, 2, 26, 3, 2, 2, 2, 2, 28, 3, 2, 2, 2, 2, 30, 3, 2, 2, 2, 2, 32, 3, 2, 2, 2, 2, 34, 3, 2, 2, 2, 2, 36, 3, 2, 2, 2, 2, 38, 3, 2, 2, 2, 2, 40, 3, 2, 2, 2, 2, 42, 3, 2, 2, 2, 2, 44, 3, 2, 2, 2, 2, 46, 3, 2, 2, 2, 2, 48, 3, 2, 2, 2, 2, 52, 3, 2, 2, 2, 2, 54, 3, 2, 2, 2, 2, 56, 3, 2, 2, 2, 2, 58, 3, 2, 2, 2, 2, 60, 3, 2, 2, 2, 2, 62, 3, 2, 2, 2, 2, 64, 3, 2, 2, 2, 2, 66, 3, 2, 2, 2, 2, 68, 3, 2, 2, 2, 2, 70, 3, 2, 2, 2, 2, 72, 3, 2, 2, 2, 2, 74, 3, 2, 2, 2, 2, 76, 3, 2, 2, 2, 2, 78, 3, 2, 2, 2, 2, 80, 3, 2, 2, 2, 2, 82, 3, 2, 2, 2, 2, 84, 3, 2, 2, 2, 2, 86, 3, 2, 2, 2, 2, 88, 3, 2, 2, 2, 2, 90, 3, 2, 2, 2, 2, 92, 3, 2, 2, 2, 2, 94, 3, 2, 2, 2, 2, 96, 3, 2, 2, 2, 2, 138, 3, 2, 2, 2, 2, 140, 3, 2, 2, 2, 2, 142, 3, 2, 2, 2, 3, 144, 3, 2, 2, 2, 3, 146, 3, 2, 2, 2, 4, 148, 3, 2, 2, 2, 4, 150, 3, 2, 2, 2, 4, 152, 3, 2, 2, 2, 5, 154, 3, 2, 2, 2, 5, 156, 3, 2, 2, 2, 6, 158, 3, 2, 2, 2, 8, 164, 3, 2, 2, 2, 10, 169, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 178, 3, 2, 2, 2, 16, 181, 3, 2, 2, 2, 18, 184, 3, 2, 2, 2, 20, 193, 3, 2, 2, 2, 22, 200, 3, 2, 2, 2, 24, 204, 3, 2, 2, 2, 26, 209, 3, 2, 2, 2, 28, 214, 3, 2, 2, 2, 30, 219, 3, 2, 2, 2, 32, 225, 3, 2, 2, 2, 34, 230, 3, 2, 2, 2, 36, 235, 3, 2, 2, 2, 38, 239, 3, 2, 2, 2, 40, 242, 3, 2, 2, 2, 42, 246, 3, 2, 2, 2, 44, 253, 3, 2, 2, 2, 46, 255, 3, 2, 2, 2, 48, 266, 3, 2, 2, 2, 50, 270, 3, 2, 2, 2, 52, 272, 3, 2, 2, 2, 54, 289, 3, 2, 2, 2, 56, 293, 3, 2, 2, 2, 58, 300, 3, 2, 2, 2, 60, 307, 3, 2, 2, 2, 62, 310, 3, 2, 2, 2, 64, 313, 3, 2, 2, 2, 66, 315, 3, 2, 2, 2, 68, 317, 3, 2, 2, 2, 70, 319, 3, 2, 2, 2, 72, 321, 3, 2, 2, 2, 74, 323, 3, 2, 2, 2, 76, 326, 3, 2, 2, 2, 78, 328, 3, 2, 2, 2, 80, 330, 3, 2, 2, 2, 82, 332, 3, 2, 2, 2, 84, 334, 3, 2, 2, 2, 86, 336, 3, 2, 2, 2, 88, 338, 3, 2, 2, 2, 90, 340, 3, 2, 2, 2, 92, 342, 3, 2, 2, 2, 94, 344, 3, 2, 2, 2, 96, 346, 3, 2, 2, 2, 98, 348, 3, 2, 2, 2, 100, 350, 3, 2, 2, 2, 102, 352, 3, 2, 2, 2, 104, 354, 3, 2, 2, 2, 106, 356, 3, 2, 2, 2, 108, 358, 3, 2, 2, 2, 110, 360, 3, 2, 2, 2, 112, 362, 3, 2, 2, 2, 114, 364, 3, 2, 2, 2, 116, 366, 3, 2, 2, 2, 118, 368, 3, 2, 2, 2, 120, 370, 3, 2, 2, 2, 122, 372, 3, 2, 2, 2, 124, 374, 3, 2, 2, 2, 126, 376, 3, 2, 2, 2, 128, 378, 3, 2, 2, 2, 130, 380, 3, 2, 2, 2, 132, 382, 3, 2, 2, 2, 134, 387, 3, 2, 2, 2, 136, 393, 3, 2, 2, 2, 138, 396, 3, 2, 2, 2, 140, 402, 3, 2, 2, 2, 142, 416, 3, 2, 2, 2, 144, 430, 3, 2, 2, 2, 146, 434, 3, 2, 2, 2, 148, 442, 3, 2, 2, 2, 150, 455, 3, 2, 2, 2, 152, 462, 3, 2, 2, 2, 154, 472, 3, 2, 2, 2, 156, 476, 3, 2, 2, 2, 158, 159, 5, 100, 49, 2, 159, 160, 5, 112, 55, 2, 160, 161, 5, 98, 48, 2, 161, 162, 5, 122, 60, 2, 162, 163, 5, 122, 60, 2, 163, 7, 3, 2, 2, 2, 164, 165, 5, 104, 51, 2, 165, 166, 5, 112, 55, 2, 166, 167, 5, 122, 60, 2, 167, 168, 5, 104, 51, 2, 168, 9, 3, 2, 2, 2, 169, 170, 7, 104, 2, 2, 170, 171, 5, 98, 48, 2, 171, 172, 5, 112, 55, 2, 172, 173, 5, 122, 60, 2, 173, 174, 5, 104, 51, 2, 174, 11, 3, 2, 2, 2, 175, 176, 5, 106, 52, 2, 176, 177, 5, 110, 54, 2, 177, 13, 3, 2, 2, 2, 178, 179, 5, 110, 54, 2, 179, 180, 5, 106, 52, 2, 180, 15, 3, 2, 2, 2, 181, 182, 5, 110, 54, 2, 182, 183, 5, 114, 56, 2, 183, 17, 3, 2, 2, 2, 184, 185, 5, 110, 54, 2, 185, 186, 5, 114, 56, 2, 186, 187, 5, 108, 53, 2, 187, 188, 5, 104, 51, 2, 188, 189, 5, 120, 59, 2, 189, 190, 5, 110, 54, 2, 190, 191, 5, 124, 61, 2, 191, 192, 5, 122, 60, 2, 192, 19, 3, 2, 2, 2, 193, 194, 5, 110, 54, 2, 194, 195, 5, 122, 60, 2, 195, 196, 5, 128, 63, 2, 196, 197, 5, 116, 57, 2, 197, 198, 5, 110, 54, 2, 198, 199, 5, 102, 50, 2, 199, 21, 3, 2, 2, 2, 200, 201, 5, 112, 55, 2, 201, 202, 5, 104, 51, 2, 202, 203, 5, 124, 61, 2, 203, 23, 3, 2, 2, 2, 204, 205, 5, 112, 55, 2, 205, 206, 5, 116, 57, 2, 206, 207, 5, 116, 57, 2, 207, 208, 5, 118, 58, 2, 208, 25, 3, 2, 2, 2, 209, 210, 5, 118, 58, 2, 210, 211, 5, 116, 57, 2, 211, 212, 5, 116, 57, 2, 212, 213, 5, 112, 55, 2, 213, 27, 3, 2, 2, 2, 214, 215, 5, 124, 61, 2, 215, 216, 5, 108, 53, 2, 216, 217, 5, 104, 51, 2, 217, 218, 5, 114, 56, 2, 218, 29, 3, 2, 2, 2, 219, 220, 5, 130, 64, 2, 220, 221, 5, 108, 53, 2, 221, 222, 5, 110, 54, 2, 222, 223, 5, 112, 55, 2, 223, 224, 5, 104, 51, 2, 224, 31, 3, 2, 2, 2, 225, 226, 5, 100, 49, 2, 226, 227, 5, 98, 48, 2, 227, 228, 5, 122, 60, 2, 228, 229, 5, 104, 51, 2, 229, 33, 3, 2, 2, 2, 230, 231, 5, 104, 51, 2, 231, 232, 5, 122, 60, 2, 232, 233, 5, 98, 48, 2, 233, 234, 5, 100, 49, 2, 234, 35, 3, 2, 2, 2, 235, 236, 5, 114, 56, 2, 236, 237, 5, 104, 51, 2, 237, 238, 5, 130, 64, 2, 238, 37, 3, 2, 2, 2, 239, 240, 5, 116, 57, 2, 240, 241, 5, 106, 52, 2, 241, 39, 3, 2, 2, 2, 242, 243, 5, 114, 56, 2, 243, 244, 5, 116, 57, 2, 244, 245, 5, 124, 61, 2, 245, 41, 3, 2, 2, 2, 246, 247, 7, 118, 2, 2, 247, 248, 5, 120, 59, 2, 248, 249, 5, 126, 62, 2, 249, 250, 5, 104, 51, 2, 250, 43, 3, 2, 2, 2, 251, 254, 5, 48, 23, 2, 252, 254, 5, 152, 75, 2, 253, 251, 3, 2, 2, 2, 253, 252, 3, 2, 2, 2, 254, 45, 3, 2, 2, 2, 255, 256, 7, 36, 2, 2, 256, 257, 3, 2, 2, 2, 257, 258, 8, 22, 2, 2, 258, 47, 3, 2, 2, 2, 259, 260, 5, 46, 22, 2, 260, 261, 5, 154, 76, 2, 261, 262, 5, 156, 77, 2, 262, 267, 3, 2, 2, 2, 263, 264, 5, 46, 22, 2, 264, 265, 5, 156, 77, 2, 265, 267, 3, 2, 2, 2, 266, 259, 3, 2, 2, 2, 266, 263, 3, 2, 2, 2, 267, 49, 3, 2, 2, 2, 268, 271, 5, 132, 65, 2, 269, 271, 10, 2, 2, 2, 270, 268, 3, 2, 2, 2, 270, 269, 3, 2, 2, 2, 271, 51, 3, 2, 2, 2, 272, 276, 7, 36, 2, 2, 273, 275, 5, 50, 24, 2, 274, 273, 3, 2, 2, 2, 275, 278, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 276, 277, 3, 2, 2, 2, 277, 284, 3, 2, 2, 2, 278, 276, 3, 2, 2, 2, 279, 280, 7, 94, 2, 2, 280, 281, 7, 15, 2, 2, 281, 285, 7, 12, 2, 2, 282, 283, 7, 94, 2, 2, 283, 285, 7, 12, 2, 2, 284, 279, 3, 2, 2, 2, 284, 282, 3, 2, 2, 2, 285, 286, 3, 2, 2, 2, 286, 287, 8, 25, 3, 2, 287, 53, 3, 2, 2, 2, 288, 290, 9, 3, 2, 2, 289, 288, 3, 2, 2, 2, 290, 291, 3, 2, 2, 2, 291, 289, 3, 2, 2, 2, 291, 292, 3, 2, 2, 2, 292, 55, 3, 2, 2, 2, 293, 297, 9, 4, 2, 2, 294, 296, 9, 5, 2, 2, 295, 294, 3, 2, 2, 2, 296, 299, 3, 2, 2, 2, 297, 295, 3, 2, 2, 2, 297, 298, 3, 2, 2, 2, 298, 57, 3, 2, 2, 2, 299, 297, 3, 2, 2, 2, 300, 304, 9, 6, 2, 2, 301, 303, 9, 5, 2, 2, 302, 301, 3, 2, 2, 2, 303, 306, 3, 2, 2, 2, 304, 302, 3, 2, 2, 2, 304, 305, 3, 2, 2, 2, 305, 59, 3, 2, 2, 2, 306, 304, 3, 2, 2, 2, 307, 308, 7, 62, 2, 2, 308, 309, 7, 47, 2, 2, 309, 61, 3, 2, 2, 2, 310, 311, 7, 63, 2, 2, 311, 312, 7, 64, 2, 2, 312, 63, 3, 2, 2, 2, 313, 314, 7, 45, 2, 2, 314, 65, 3, 2, 2, 2, 315, 316, 7, 47, 2, 2, 316, 67, 3, 2, 2, 2, 317, 318, 7, 44, 2, 2, 318, 69, 3, 2, 2, 2, 319, 320, 7, 49, 2, 2, 320, 71, 3, 2, 2, 2, 321, 322, 7, 62, 2, 2, 322, 73, 3, 2, 2, 2, 323, 324, 7, 62, 2, 2, 324, 325, 7, 63, 2, 2, 325, 75, 3, 2, 2, 2, 326, 327, 7, 63, 2, 2, 327, 77, 3, 2, 2, 2, 328, 329, 7, 128, 2, 2, 329, 79, 3, 2, 2, 2, 330, 331, 7, 42, 2, 2, 331, 81, 3, 2, 2, 2, 332, 333, 7, 43, 2, 2, 333, 83, 3, 2, 2, 2, 334, 335, 7, 125, 2, 2, 335, 85, 3, 2, 2, 2, 336, 337, 7, 127, 2, 2, 337, 87, 3, 2, 2, 2, 338, 339, 7, 66, 2, 2, 339, 89, 3, 2, 2, 2, 340, 341, 7, 48, 2, 2, 341, 91, 3, 2, 2, 2, 342, 343, 7, 46, 2, 2, 343, 93, 3, 2, 2, 2, 344, 345, 7, 60, 2, 2, 345, 95, 3, 2, 2, 2, 346, 347, 7, 61, 2, 2, 347, 97, 3, 2, 2, 2, 348, 349, 9, 7, 2, 2, 349, 99, 3, 2, 2, 2, 350, 351, 9, 8, 2, 2, 351, 101, 3, 2, 2, 2, 352, 353, 9, 9, 2, 2, 353, 103, 3, 2, 2, 2, 354, 355, 9, 10, 2, 2, 355, 105, 3, 2, 2, 2, 356, 357, 9, 11, 2, 2, 357, 107, 3, 2, 2, 2, 358, 359, 9, 12, 2, 2, 359, 109, 3, 2, 2, 2, 360, 361, 9, 13, 2, 2, 361, 111, 3, 2, 2, 2, 362, 363, 9, 14, 2, 2, 363, 113, 3, 2, 2, 2, 364, 365, 9, 15, 2, 2, 365, 115, 3, 2, 2, 2, 366, 367, 9, 16, 2, 2, 367, 117, 3, 2, 2, 2, 368, 369, 9, 17, 2, 2, 369, 119, 3, 2, 2, 2, 370, 371, 9, 18, 2, 2, 371, 121, 3, 2, 2, 2, 372, 373, 9, 19, 2, 2, 373, 123, 3, 2, 2, 2, 374, 375, 9, 20, 2, 2, 375, 125, 3, 2, 2, 2, 376, 377, 9, 21, 2, 2, 377, 127, 3, 2, 2, 2, 378, 379, 9, 22, 2, 2, 379, 129, 3, 2, 2, 2, 380, 381, 9, 23, 2, 2, 381, 131, 3, 2, 2, 2, 382, 385, 7, 94, 2, 2, 383, 386, 9, 24, 2, 2, 384, 386, 5, 134, 66, 2, 385, 383, 3, 2, 2, 2, 385, 384, 3, 2, 2, 2, 386, 133, 3, 2, 2, 2, 387, 388, 7, 119, 2, 2, 388, 389, 5, 136, 67, 2, 389, 390, 5, 136, 67, 2, 390, 391, 5, 136, 67, 2, 391, 392, 5, 136, 67, 2, 392, 135, 3, 2, 2, 2, 393, 394, 9, 25, 2, 2, 394, 137, 3, 2, 2, 2, 395, 397, 9, 26, 2, 2, 396, 395, 3, 2, 2, 2, 397, 398, 3, 2, 2, 2, 398, 396, 3, 2, 2, 2, 398, 399, 3, 2, 2, 2, 399, 400, 3, 2, 2, 2, 400, 401, 8, 68, 4, 2, 401, 139, 3, 2, 2, 2, 402, 403, 7, 47, 2, 2, 403, 404, 7, 47, 2, 2, 404, 408, 3, 2, 2, 2, 405, 407, 10, 27, 2, 2, 406, 405, 3, 2, 2, 2, 407, 410, 3, 2, 2, 2, 408, 406, 3, 2, 2, 2, 408, 409, 3, 2, 2, 2, 409, 412, 3, 2, 2, 2, 410, 408, 3, 2, 2, 2, 411, 413, 7, 12, 2, 2, 412, 411, 3, 2, 2, 2, 412, 413, 3, 2, 2, 2, 413, 414, 3, 2, 2, 2, 414, 415, 8, 69, 4, 2, 415, 141, 3, 2, 2, 2, 416, 417, 7, 42, 2, 2, 417, 418, 7, 44, 2, 2, 418, 419, 3, 2, 2, 2, 419, 420, 8, 70, 5, 2, 420, 143, 3, 2, 2, 2, 421, 422, 5, 142, 70, 2, 422, 423, 5, 144, 71, 2, 423, 424, 5, 146, 72, 2, 424, 431, 3, 2, 2, 2, 425, 427, 11, 2, 2, 2, 426, 425, 3, 2, 2, 2, 427, 428, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 428, 426, 3, 2, 2, 2, 429, 431, 3, 2, 2, 2, 430, 421, 3, 2, 2, 2, 430, 426, 3, 2, 2, 2, 431, 432, 3, 2, 2, 2, 432, 433, 8, 71, 4, 2, 433, 145, 3, 2, 2, 2, 434, 435, 7, 44, 2, 2, 435, 436, 7, 43, 2, 2, 436, 437, 3, 2, 2, 2, 437, 438, 8, 72, 6, 2, 438, 147, 3, 2, 2, 2, 439, 441, 5, 50, 24, 2, 440, 439, 3, 2, 2, 2, 441, 444, 3, 2, 2, 2, 442, 440, 3, 2, 2, 2, 442, 443, 3, 2, 2, 2, 443, 450, 3, 2, 2, 2, 444, 442, 3, 2, 2, 2, 445, 446, 7, 94, 2, 2, 446, 447, 7, 15, 2, 2, 447, 451, 7, 12, 2, 2, 448, 449, 7, 94, 2, 2, 449, 451, 7, 12, 2, 2, 450, 445, 3, 2, 2, 2, 450, 448, 3, 2, 2, 2, 451, 149, 3, 2, 2, 2, 452, 454, 5, 50, 24, 2, 453, 452, 3, 2, 2, 2, 454, 457, 3, 2, 2, 2, 455, 453, 3, 2, 2, 2, 455, 456, 3, 2, 2, 2, 456, 458, 3, 2, 2, 2, 457, 455, 3, 2, 2, 2, 458, 459, 7, 36, 2, 2, 459, 460, 3, 2, 2, 2, 460, 461, 8, 74, 6, 2, 461, 151, 3, 2, 2, 2, 462, 466, 5, 52, 25, 2, 463, 465, 5, 148, 73, 2, 464, 463, 3, 2, 2, 2, 465, 468, 3, 2, 2, 2, 466, 464, 3, 2, 2, 2, 466, 467, 3, 2, 2, 2, 467, 469, 3, 2, 2, 2, 468, 466, 3, 2, 2, 2, 469, 470, 5, 150, 74, 2, 470, 153, 3, 2, 2, 2, 471, 473, 5, 50, 24, 2, 472, 471, 3, 2, 2, 2, 473, 474, 3, 2, 2, 2, 474, 472, 3, 2, 2, 2, 474, 475, 3, 2, 2, 2, 475, 155, 3, 2, 2, 2, 476, 477, 7, 36, 2, 2, 477, 478, 3, 2, 2, 2, 478, 479, 8, 77, 6, 2, 479, 157, 3, 2, 2, 2, 25, 2, 3, 4, 5, 253, 266, 270, 276, 284, 291, 297, 304, 385, 398, 408, 412, 428, 430, 442, 450, 455, 466, 474, 7, 7, 5, 2, 7, 4, 2, 8, 2, 2, 7, 3, 2, 6, 2, 2] \ No newline at end of file diff --git a/src/COOL_LEX.py b/src/COOL_LEX.py index 74921491..9514ec13 100644 --- a/src/COOL_LEX.py +++ b/src/COOL_LEX.py @@ -9,7 +9,7 @@ def serializedATN(): with StringIO() as buf: buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\29") - buf.write("\u01da\b\1\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5") + buf.write("\u01e0\b\1\b\1\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5") buf.write("\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f") buf.write("\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4") buf.write("\22\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27") @@ -31,189 +31,193 @@ def serializedATN(): buf.write("\3\25\3\25\5\25\u00fe\n\25\3\26\3\26\3\26\3\26\3\27\3") buf.write("\27\3\27\3\27\3\27\3\27\3\27\5\27\u010b\n\27\3\30\3\30") buf.write("\5\30\u010f\n\30\3\31\3\31\7\31\u0113\n\31\f\31\16\31") - buf.write("\u0116\13\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32\6\32\u011f") - buf.write("\n\32\r\32\16\32\u0120\3\33\3\33\7\33\u0125\n\33\f\33") - buf.write("\16\33\u0128\13\33\3\34\3\34\7\34\u012c\n\34\f\34\16\34") - buf.write("\u012f\13\34\3\35\3\35\3\35\3\36\3\36\3\36\3\37\3\37\3") - buf.write(" \3 \3!\3!\3\"\3\"\3#\3#\3$\3$\3$\3%\3%\3&\3&\3\'\3\'") - buf.write("\3(\3(\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3/\3/\3\60") - buf.write("\3\60\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\65\3\65") - buf.write("\3\66\3\66\3\67\3\67\38\38\39\39\3:\3:\3;\3;\3<\3<\3=") - buf.write("\3=\3>\3>\3?\3?\3@\3@\3A\3A\3A\5A\u017f\nA\3B\3B\3B\3") - buf.write("B\3B\3B\3C\3C\3D\6D\u018a\nD\rD\16D\u018b\3D\3D\3E\3E") - buf.write("\3E\3E\7E\u0194\nE\fE\16E\u0197\13E\3E\5E\u019a\nE\3E") - buf.write("\3E\3F\3F\3F\3F\3F\3G\3G\3G\3G\3G\6G\u01a8\nG\rG\16G\u01a9") - buf.write("\5G\u01ac\nG\3G\3G\3H\3H\3H\3H\3H\3I\7I\u01b6\nI\fI\16") - buf.write("I\u01b9\13I\3I\3I\3I\3I\3J\7J\u01c0\nJ\fJ\16J\u01c3\13") - buf.write("J\3J\3J\3J\3J\3K\3K\7K\u01cb\nK\fK\16K\u01ce\13K\3K\3") - buf.write("K\3L\6L\u01d3\nL\rL\16L\u01d4\3M\3M\3M\3M\3\u01a9\2N\6") - buf.write("\3\b\4\n\5\f\6\16\7\20\b\22\t\24\n\26\13\30\f\32\r\34") - buf.write("\16\36\17 \20\"\21$\22&\23(\24*\25,\26.\27\60\30\62\2") - buf.write("\64\31\66\328\33:\34<\35>\36@\37B D!F\"H#J$L%N&P\'R(T") - buf.write(")V*X+Z,\\-^.`/b\2d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2") - buf.write("|\2~\2\u0080\2\u0082\2\u0084\2\u0086\2\u0088\2\u008a\60") - buf.write("\u008c\61\u008e\62\u0090\63\u0092\64\u0094\65\u0096\66") - buf.write("\u0098\67\u009a8\u009c9\6\2\3\4\5\34\6\2\2\2\f\f\17\17") - buf.write("$$\3\2\62;\3\2C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEe") - buf.write("e\4\2FFff\4\2GGgg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2") - buf.write("PPpp\4\2QQqq\4\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4") - buf.write("\2XXxx\4\2YYyy\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2") - buf.write("\13\f\16\17\"\"\3\2\f\f\2\u01d2\2\6\3\2\2\2\2\b\3\2\2") - buf.write("\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16\3\2\2\2\2\20\3\2\2\2\2") - buf.write("\22\3\2\2\2\2\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32") - buf.write("\3\2\2\2\2\34\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2") - buf.write("\2\2\2$\3\2\2\2\2&\3\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3") - buf.write("\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2") - buf.write("\2\28\3\2\2\2\2:\3\2\2\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2") - buf.write("\2\2\2B\3\2\2\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3") - buf.write("\2\2\2\2L\3\2\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T") - buf.write("\3\2\2\2\2V\3\2\2\2\2X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2") - buf.write("\2^\3\2\2\2\2`\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2") - buf.write("\2\u008e\3\2\2\2\3\u0090\3\2\2\2\3\u0092\3\2\2\2\4\u0094") - buf.write("\3\2\2\2\4\u0096\3\2\2\2\4\u0098\3\2\2\2\5\u009a\3\2\2") - buf.write("\2\5\u009c\3\2\2\2\6\u009e\3\2\2\2\b\u00a4\3\2\2\2\n\u00a9") - buf.write("\3\2\2\2\f\u00af\3\2\2\2\16\u00b2\3\2\2\2\20\u00b5\3\2") - buf.write("\2\2\22\u00b8\3\2\2\2\24\u00c1\3\2\2\2\26\u00c8\3\2\2") - buf.write("\2\30\u00cc\3\2\2\2\32\u00d1\3\2\2\2\34\u00d6\3\2\2\2") - buf.write("\36\u00db\3\2\2\2 \u00e1\3\2\2\2\"\u00e6\3\2\2\2$\u00eb") - buf.write("\3\2\2\2&\u00ef\3\2\2\2(\u00f2\3\2\2\2*\u00f6\3\2\2\2") - buf.write(",\u00fd\3\2\2\2.\u00ff\3\2\2\2\60\u010a\3\2\2\2\62\u010e") - buf.write("\3\2\2\2\64\u0110\3\2\2\2\66\u011e\3\2\2\28\u0122\3\2") - buf.write("\2\2:\u0129\3\2\2\2<\u0130\3\2\2\2>\u0133\3\2\2\2@\u0136") - buf.write("\3\2\2\2B\u0138\3\2\2\2D\u013a\3\2\2\2F\u013c\3\2\2\2") - buf.write("H\u013e\3\2\2\2J\u0140\3\2\2\2L\u0143\3\2\2\2N\u0145\3") - buf.write("\2\2\2P\u0147\3\2\2\2R\u0149\3\2\2\2T\u014b\3\2\2\2V\u014d") - buf.write("\3\2\2\2X\u014f\3\2\2\2Z\u0151\3\2\2\2\\\u0153\3\2\2\2") - buf.write("^\u0155\3\2\2\2`\u0157\3\2\2\2b\u0159\3\2\2\2d\u015b\3") - buf.write("\2\2\2f\u015d\3\2\2\2h\u015f\3\2\2\2j\u0161\3\2\2\2l\u0163") - buf.write("\3\2\2\2n\u0165\3\2\2\2p\u0167\3\2\2\2r\u0169\3\2\2\2") - buf.write("t\u016b\3\2\2\2v\u016d\3\2\2\2x\u016f\3\2\2\2z\u0171\3") - buf.write("\2\2\2|\u0173\3\2\2\2~\u0175\3\2\2\2\u0080\u0177\3\2\2") - buf.write("\2\u0082\u0179\3\2\2\2\u0084\u017b\3\2\2\2\u0086\u0180") - buf.write("\3\2\2\2\u0088\u0186\3\2\2\2\u008a\u0189\3\2\2\2\u008c") - buf.write("\u018f\3\2\2\2\u008e\u019d\3\2\2\2\u0090\u01ab\3\2\2\2") - buf.write("\u0092\u01af\3\2\2\2\u0094\u01b7\3\2\2\2\u0096\u01c1\3") - buf.write("\2\2\2\u0098\u01c8\3\2\2\2\u009a\u01d2\3\2\2\2\u009c\u01d6") - buf.write("\3\2\2\2\u009e\u009f\5d\61\2\u009f\u00a0\5p\67\2\u00a0") - buf.write("\u00a1\5b\60\2\u00a1\u00a2\5z<\2\u00a2\u00a3\5z<\2\u00a3") - buf.write("\7\3\2\2\2\u00a4\u00a5\5h\63\2\u00a5\u00a6\5p\67\2\u00a6") - buf.write("\u00a7\5z<\2\u00a7\u00a8\5h\63\2\u00a8\t\3\2\2\2\u00a9") - buf.write("\u00aa\7h\2\2\u00aa\u00ab\5b\60\2\u00ab\u00ac\5p\67\2") - buf.write("\u00ac\u00ad\5z<\2\u00ad\u00ae\5h\63\2\u00ae\13\3\2\2") - buf.write("\2\u00af\u00b0\5j\64\2\u00b0\u00b1\5n\66\2\u00b1\r\3\2") - buf.write("\2\2\u00b2\u00b3\5n\66\2\u00b3\u00b4\5j\64\2\u00b4\17") - buf.write("\3\2\2\2\u00b5\u00b6\5n\66\2\u00b6\u00b7\5r8\2\u00b7\21") - buf.write("\3\2\2\2\u00b8\u00b9\5n\66\2\u00b9\u00ba\5r8\2\u00ba\u00bb") - buf.write("\5l\65\2\u00bb\u00bc\5h\63\2\u00bc\u00bd\5x;\2\u00bd\u00be") - buf.write("\5n\66\2\u00be\u00bf\5|=\2\u00bf\u00c0\5z<\2\u00c0\23") - buf.write("\3\2\2\2\u00c1\u00c2\5n\66\2\u00c2\u00c3\5z<\2\u00c3\u00c4") - buf.write("\5\u0080?\2\u00c4\u00c5\5t9\2\u00c5\u00c6\5n\66\2\u00c6") - buf.write("\u00c7\5f\62\2\u00c7\25\3\2\2\2\u00c8\u00c9\5p\67\2\u00c9") - buf.write("\u00ca\5h\63\2\u00ca\u00cb\5|=\2\u00cb\27\3\2\2\2\u00cc") - buf.write("\u00cd\5p\67\2\u00cd\u00ce\5t9\2\u00ce\u00cf\5t9\2\u00cf") - buf.write("\u00d0\5v:\2\u00d0\31\3\2\2\2\u00d1\u00d2\5v:\2\u00d2") - buf.write("\u00d3\5t9\2\u00d3\u00d4\5t9\2\u00d4\u00d5\5p\67\2\u00d5") - buf.write("\33\3\2\2\2\u00d6\u00d7\5|=\2\u00d7\u00d8\5l\65\2\u00d8") - buf.write("\u00d9\5h\63\2\u00d9\u00da\5r8\2\u00da\35\3\2\2\2\u00db") - buf.write("\u00dc\5\u0082@\2\u00dc\u00dd\5l\65\2\u00dd\u00de\5n\66") - buf.write("\2\u00de\u00df\5p\67\2\u00df\u00e0\5h\63\2\u00e0\37\3") - buf.write("\2\2\2\u00e1\u00e2\5d\61\2\u00e2\u00e3\5b\60\2\u00e3\u00e4") - buf.write("\5z<\2\u00e4\u00e5\5h\63\2\u00e5!\3\2\2\2\u00e6\u00e7") - buf.write("\5h\63\2\u00e7\u00e8\5z<\2\u00e8\u00e9\5b\60\2\u00e9\u00ea") - buf.write("\5d\61\2\u00ea#\3\2\2\2\u00eb\u00ec\5r8\2\u00ec\u00ed") - buf.write("\5h\63\2\u00ed\u00ee\5\u0082@\2\u00ee%\3\2\2\2\u00ef\u00f0") - buf.write("\5t9\2\u00f0\u00f1\5j\64\2\u00f1\'\3\2\2\2\u00f2\u00f3") - buf.write("\5r8\2\u00f3\u00f4\5t9\2\u00f4\u00f5\5|=\2\u00f5)\3\2") - buf.write("\2\2\u00f6\u00f7\7v\2\2\u00f7\u00f8\5x;\2\u00f8\u00f9") - buf.write("\5~>\2\u00f9\u00fa\5h\63\2\u00fa+\3\2\2\2\u00fb\u00fe") - buf.write("\5\60\27\2\u00fc\u00fe\5\u0098K\2\u00fd\u00fb\3\2\2\2") - buf.write("\u00fd\u00fc\3\2\2\2\u00fe-\3\2\2\2\u00ff\u0100\7$\2\2") - buf.write("\u0100\u0101\3\2\2\2\u0101\u0102\b\26\2\2\u0102/\3\2\2") - buf.write("\2\u0103\u0104\5.\26\2\u0104\u0105\5\u009aL\2\u0105\u0106") - buf.write("\5\u009cM\2\u0106\u010b\3\2\2\2\u0107\u0108\5.\26\2\u0108") - buf.write("\u0109\5\u009cM\2\u0109\u010b\3\2\2\2\u010a\u0103\3\2") - buf.write("\2\2\u010a\u0107\3\2\2\2\u010b\61\3\2\2\2\u010c\u010f") - buf.write("\5\u0084A\2\u010d\u010f\n\2\2\2\u010e\u010c\3\2\2\2\u010e") - buf.write("\u010d\3\2\2\2\u010f\63\3\2\2\2\u0110\u0114\7$\2\2\u0111") - buf.write("\u0113\5\62\30\2\u0112\u0111\3\2\2\2\u0113\u0116\3\2\2") - buf.write("\2\u0114\u0112\3\2\2\2\u0114\u0115\3\2\2\2\u0115\u0117") - buf.write("\3\2\2\2\u0116\u0114\3\2\2\2\u0117\u0118\7^\2\2\u0118") - buf.write("\u0119\7\17\2\2\u0119\u011a\7\f\2\2\u011a\u011b\3\2\2") - buf.write("\2\u011b\u011c\b\31\3\2\u011c\65\3\2\2\2\u011d\u011f\t") - buf.write("\3\2\2\u011e\u011d\3\2\2\2\u011f\u0120\3\2\2\2\u0120\u011e") - buf.write("\3\2\2\2\u0120\u0121\3\2\2\2\u0121\67\3\2\2\2\u0122\u0126") - buf.write("\t\4\2\2\u0123\u0125\t\5\2\2\u0124\u0123\3\2\2\2\u0125") - buf.write("\u0128\3\2\2\2\u0126\u0124\3\2\2\2\u0126\u0127\3\2\2\2") - buf.write("\u01279\3\2\2\2\u0128\u0126\3\2\2\2\u0129\u012d\t\6\2") - buf.write("\2\u012a\u012c\t\5\2\2\u012b\u012a\3\2\2\2\u012c\u012f") - buf.write("\3\2\2\2\u012d\u012b\3\2\2\2\u012d\u012e\3\2\2\2\u012e") - buf.write(";\3\2\2\2\u012f\u012d\3\2\2\2\u0130\u0131\7>\2\2\u0131") - buf.write("\u0132\7/\2\2\u0132=\3\2\2\2\u0133\u0134\7?\2\2\u0134") - buf.write("\u0135\7@\2\2\u0135?\3\2\2\2\u0136\u0137\7-\2\2\u0137") - buf.write("A\3\2\2\2\u0138\u0139\7/\2\2\u0139C\3\2\2\2\u013a\u013b") - buf.write("\7,\2\2\u013bE\3\2\2\2\u013c\u013d\7\61\2\2\u013dG\3\2") - buf.write("\2\2\u013e\u013f\7>\2\2\u013fI\3\2\2\2\u0140\u0141\7>") - buf.write("\2\2\u0141\u0142\7?\2\2\u0142K\3\2\2\2\u0143\u0144\7?") - buf.write("\2\2\u0144M\3\2\2\2\u0145\u0146\7\u0080\2\2\u0146O\3\2") - buf.write("\2\2\u0147\u0148\7*\2\2\u0148Q\3\2\2\2\u0149\u014a\7+") - buf.write("\2\2\u014aS\3\2\2\2\u014b\u014c\7}\2\2\u014cU\3\2\2\2") - buf.write("\u014d\u014e\7\177\2\2\u014eW\3\2\2\2\u014f\u0150\7B\2") - buf.write("\2\u0150Y\3\2\2\2\u0151\u0152\7\60\2\2\u0152[\3\2\2\2") - buf.write("\u0153\u0154\7.\2\2\u0154]\3\2\2\2\u0155\u0156\7<\2\2") - buf.write("\u0156_\3\2\2\2\u0157\u0158\7=\2\2\u0158a\3\2\2\2\u0159") - buf.write("\u015a\t\7\2\2\u015ac\3\2\2\2\u015b\u015c\t\b\2\2\u015c") - buf.write("e\3\2\2\2\u015d\u015e\t\t\2\2\u015eg\3\2\2\2\u015f\u0160") - buf.write("\t\n\2\2\u0160i\3\2\2\2\u0161\u0162\t\13\2\2\u0162k\3") - buf.write("\2\2\2\u0163\u0164\t\f\2\2\u0164m\3\2\2\2\u0165\u0166") - buf.write("\t\r\2\2\u0166o\3\2\2\2\u0167\u0168\t\16\2\2\u0168q\3") - buf.write("\2\2\2\u0169\u016a\t\17\2\2\u016as\3\2\2\2\u016b\u016c") - buf.write("\t\20\2\2\u016cu\3\2\2\2\u016d\u016e\t\21\2\2\u016ew\3") - buf.write("\2\2\2\u016f\u0170\t\22\2\2\u0170y\3\2\2\2\u0171\u0172") - buf.write("\t\23\2\2\u0172{\3\2\2\2\u0173\u0174\t\24\2\2\u0174}\3") - buf.write("\2\2\2\u0175\u0176\t\25\2\2\u0176\177\3\2\2\2\u0177\u0178") - buf.write("\t\26\2\2\u0178\u0081\3\2\2\2\u0179\u017a\t\27\2\2\u017a") - buf.write("\u0083\3\2\2\2\u017b\u017e\7^\2\2\u017c\u017f\t\30\2\2") - buf.write("\u017d\u017f\5\u0086B\2\u017e\u017c\3\2\2\2\u017e\u017d") - buf.write("\3\2\2\2\u017f\u0085\3\2\2\2\u0180\u0181\7w\2\2\u0181") - buf.write("\u0182\5\u0088C\2\u0182\u0183\5\u0088C\2\u0183\u0184\5") - buf.write("\u0088C\2\u0184\u0185\5\u0088C\2\u0185\u0087\3\2\2\2\u0186") - buf.write("\u0187\t\31\2\2\u0187\u0089\3\2\2\2\u0188\u018a\t\32\2") - buf.write("\2\u0189\u0188\3\2\2\2\u018a\u018b\3\2\2\2\u018b\u0189") - buf.write("\3\2\2\2\u018b\u018c\3\2\2\2\u018c\u018d\3\2\2\2\u018d") - buf.write("\u018e\bD\4\2\u018e\u008b\3\2\2\2\u018f\u0190\7/\2\2\u0190") - buf.write("\u0191\7/\2\2\u0191\u0195\3\2\2\2\u0192\u0194\n\33\2\2") - buf.write("\u0193\u0192\3\2\2\2\u0194\u0197\3\2\2\2\u0195\u0193\3") - buf.write("\2\2\2\u0195\u0196\3\2\2\2\u0196\u0199\3\2\2\2\u0197\u0195") - buf.write("\3\2\2\2\u0198\u019a\7\f\2\2\u0199\u0198\3\2\2\2\u0199") - buf.write("\u019a\3\2\2\2\u019a\u019b\3\2\2\2\u019b\u019c\bE\4\2") - buf.write("\u019c\u008d\3\2\2\2\u019d\u019e\7*\2\2\u019e\u019f\7") - buf.write(",\2\2\u019f\u01a0\3\2\2\2\u01a0\u01a1\bF\5\2\u01a1\u008f") - buf.write("\3\2\2\2\u01a2\u01a3\5\u008eF\2\u01a3\u01a4\5\u0090G\2") - buf.write("\u01a4\u01a5\5\u0092H\2\u01a5\u01ac\3\2\2\2\u01a6\u01a8") - buf.write("\13\2\2\2\u01a7\u01a6\3\2\2\2\u01a8\u01a9\3\2\2\2\u01a9") - buf.write("\u01aa\3\2\2\2\u01a9\u01a7\3\2\2\2\u01aa\u01ac\3\2\2\2") - buf.write("\u01ab\u01a2\3\2\2\2\u01ab\u01a7\3\2\2\2\u01ac\u01ad\3") - buf.write("\2\2\2\u01ad\u01ae\bG\4\2\u01ae\u0091\3\2\2\2\u01af\u01b0") - buf.write("\7,\2\2\u01b0\u01b1\7+\2\2\u01b1\u01b2\3\2\2\2\u01b2\u01b3") - buf.write("\bH\6\2\u01b3\u0093\3\2\2\2\u01b4\u01b6\5\62\30\2\u01b5") - buf.write("\u01b4\3\2\2\2\u01b6\u01b9\3\2\2\2\u01b7\u01b5\3\2\2\2") - buf.write("\u01b7\u01b8\3\2\2\2\u01b8\u01ba\3\2\2\2\u01b9\u01b7\3") - buf.write("\2\2\2\u01ba\u01bb\7^\2\2\u01bb\u01bc\7\17\2\2\u01bc\u01bd") - buf.write("\7\f\2\2\u01bd\u0095\3\2\2\2\u01be\u01c0\5\62\30\2\u01bf") - buf.write("\u01be\3\2\2\2\u01c0\u01c3\3\2\2\2\u01c1\u01bf\3\2\2\2") - buf.write("\u01c1\u01c2\3\2\2\2\u01c2\u01c4\3\2\2\2\u01c3\u01c1\3") - buf.write("\2\2\2\u01c4\u01c5\7$\2\2\u01c5\u01c6\3\2\2\2\u01c6\u01c7") - buf.write("\bJ\6\2\u01c7\u0097\3\2\2\2\u01c8\u01cc\5\64\31\2\u01c9") - buf.write("\u01cb\5\u0094I\2\u01ca\u01c9\3\2\2\2\u01cb\u01ce\3\2") - buf.write("\2\2\u01cc\u01ca\3\2\2\2\u01cc\u01cd\3\2\2\2\u01cd\u01cf") - buf.write("\3\2\2\2\u01ce\u01cc\3\2\2\2\u01cf\u01d0\5\u0096J\2\u01d0") - buf.write("\u0099\3\2\2\2\u01d1\u01d3\5\62\30\2\u01d2\u01d1\3\2\2") - buf.write("\2\u01d3\u01d4\3\2\2\2\u01d4\u01d2\3\2\2\2\u01d4\u01d5") - buf.write("\3\2\2\2\u01d5\u009b\3\2\2\2\u01d6\u01d7\7$\2\2\u01d7") - buf.write("\u01d8\3\2\2\2\u01d8\u01d9\bM\6\2\u01d9\u009d\3\2\2\2") - buf.write("\27\2\3\4\5\u00fd\u010a\u010e\u0114\u0120\u0126\u012d") - buf.write("\u017e\u018b\u0195\u0199\u01a9\u01ab\u01b7\u01c1\u01cc") - buf.write("\u01d4\7\7\5\2\7\4\2\b\2\2\7\3\2\6\2\2") + buf.write("\u0116\13\31\3\31\3\31\3\31\3\31\3\31\5\31\u011d\n\31") + buf.write("\3\31\3\31\3\32\6\32\u0122\n\32\r\32\16\32\u0123\3\33") + buf.write("\3\33\7\33\u0128\n\33\f\33\16\33\u012b\13\33\3\34\3\34") + buf.write("\7\34\u012f\n\34\f\34\16\34\u0132\13\34\3\35\3\35\3\35") + buf.write("\3\36\3\36\3\36\3\37\3\37\3 \3 \3!\3!\3\"\3\"\3#\3#\3") + buf.write("$\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(\3)\3)\3*\3*\3+\3+\3") + buf.write(",\3,\3-\3-\3.\3.\3/\3/\3\60\3\60\3\61\3\61\3\62\3\62\3") + buf.write("\63\3\63\3\64\3\64\3\65\3\65\3\66\3\66\3\67\3\67\38\3") + buf.write("8\39\39\3:\3:\3;\3;\3<\3<\3=\3=\3>\3>\3?\3?\3@\3@\3A\3") + buf.write("A\3A\5A\u0182\nA\3B\3B\3B\3B\3B\3B\3C\3C\3D\6D\u018d\n") + buf.write("D\rD\16D\u018e\3D\3D\3E\3E\3E\3E\7E\u0197\nE\fE\16E\u019a") + buf.write("\13E\3E\5E\u019d\nE\3E\3E\3F\3F\3F\3F\3F\3G\3G\3G\3G\3") + buf.write("G\6G\u01ab\nG\rG\16G\u01ac\5G\u01af\nG\3G\3G\3H\3H\3H") + buf.write("\3H\3H\3I\7I\u01b9\nI\fI\16I\u01bc\13I\3I\3I\3I\3I\3I") + buf.write("\5I\u01c3\nI\3J\7J\u01c6\nJ\fJ\16J\u01c9\13J\3J\3J\3J") + buf.write("\3J\3K\3K\7K\u01d1\nK\fK\16K\u01d4\13K\3K\3K\3L\6L\u01d9") + buf.write("\nL\rL\16L\u01da\3M\3M\3M\3M\3\u01ac\2N\6\3\b\4\n\5\f") + buf.write("\6\16\7\20\b\22\t\24\n\26\13\30\f\32\r\34\16\36\17 \20") + buf.write("\"\21$\22&\23(\24*\25,\26.\27\60\30\62\2\64\31\66\328") + buf.write("\33:\34<\35>\36@\37B D!F\"H#J$L%N&P\'R(T)V*X+Z,\\-^.`") + buf.write("/b\2d\2f\2h\2j\2l\2n\2p\2r\2t\2v\2x\2z\2|\2~\2\u0080\2") + buf.write("\u0082\2\u0084\2\u0086\2\u0088\2\u008a\60\u008c\61\u008e") + buf.write("\62\u0090\63\u0092\64\u0094\65\u0096\66\u0098\67\u009a") + buf.write("8\u009c9\6\2\3\4\5\34\6\2\2\2\f\f\17\17$$\3\2\62;\3\2") + buf.write("C\\\6\2\62;C\\aac|\3\2c|\4\2CCcc\4\2EEee\4\2FFff\4\2G") + buf.write("Ggg\4\2HHhh\4\2JJjj\4\2KKkk\4\2NNnn\4\2PPpp\4\2QQqq\4") + buf.write("\2RRrr\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4\2XXxx\4\2YYy") + buf.write("y\n\2$$\61\61^^ddhhppttvv\5\2\62;CHch\5\2\13\f\16\17\"") + buf.write("\"\3\2\f\f\2\u01da\2\6\3\2\2\2\2\b\3\2\2\2\2\n\3\2\2\2") + buf.write("\2\f\3\2\2\2\2\16\3\2\2\2\2\20\3\2\2\2\2\22\3\2\2\2\2") + buf.write("\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32\3\2\2\2\2\34") + buf.write("\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2\2\2\2$\3\2\2") + buf.write("\2\2&\3\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3\2\2\2\2.\3\2") + buf.write("\2\2\2\60\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\28\3\2\2\2") + buf.write("\2:\3\2\2\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2\2\2\2B\3\2\2") + buf.write("\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3\2\2\2\2L\3\2") + buf.write("\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2\2\2\2V\3") + buf.write("\2\2\2\2X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2\2^\3\2\2\2\2") + buf.write("`\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2\2\u008e\3\2") + buf.write("\2\2\3\u0090\3\2\2\2\3\u0092\3\2\2\2\4\u0094\3\2\2\2\4") + buf.write("\u0096\3\2\2\2\4\u0098\3\2\2\2\5\u009a\3\2\2\2\5\u009c") + buf.write("\3\2\2\2\6\u009e\3\2\2\2\b\u00a4\3\2\2\2\n\u00a9\3\2\2") + buf.write("\2\f\u00af\3\2\2\2\16\u00b2\3\2\2\2\20\u00b5\3\2\2\2\22") + buf.write("\u00b8\3\2\2\2\24\u00c1\3\2\2\2\26\u00c8\3\2\2\2\30\u00cc") + buf.write("\3\2\2\2\32\u00d1\3\2\2\2\34\u00d6\3\2\2\2\36\u00db\3") + buf.write("\2\2\2 \u00e1\3\2\2\2\"\u00e6\3\2\2\2$\u00eb\3\2\2\2&") + buf.write("\u00ef\3\2\2\2(\u00f2\3\2\2\2*\u00f6\3\2\2\2,\u00fd\3") + buf.write("\2\2\2.\u00ff\3\2\2\2\60\u010a\3\2\2\2\62\u010e\3\2\2") + buf.write("\2\64\u0110\3\2\2\2\66\u0121\3\2\2\28\u0125\3\2\2\2:\u012c") + buf.write("\3\2\2\2<\u0133\3\2\2\2>\u0136\3\2\2\2@\u0139\3\2\2\2") + buf.write("B\u013b\3\2\2\2D\u013d\3\2\2\2F\u013f\3\2\2\2H\u0141\3") + buf.write("\2\2\2J\u0143\3\2\2\2L\u0146\3\2\2\2N\u0148\3\2\2\2P\u014a") + buf.write("\3\2\2\2R\u014c\3\2\2\2T\u014e\3\2\2\2V\u0150\3\2\2\2") + buf.write("X\u0152\3\2\2\2Z\u0154\3\2\2\2\\\u0156\3\2\2\2^\u0158") + buf.write("\3\2\2\2`\u015a\3\2\2\2b\u015c\3\2\2\2d\u015e\3\2\2\2") + buf.write("f\u0160\3\2\2\2h\u0162\3\2\2\2j\u0164\3\2\2\2l\u0166\3") + buf.write("\2\2\2n\u0168\3\2\2\2p\u016a\3\2\2\2r\u016c\3\2\2\2t\u016e") + buf.write("\3\2\2\2v\u0170\3\2\2\2x\u0172\3\2\2\2z\u0174\3\2\2\2") + buf.write("|\u0176\3\2\2\2~\u0178\3\2\2\2\u0080\u017a\3\2\2\2\u0082") + buf.write("\u017c\3\2\2\2\u0084\u017e\3\2\2\2\u0086\u0183\3\2\2\2") + buf.write("\u0088\u0189\3\2\2\2\u008a\u018c\3\2\2\2\u008c\u0192\3") + buf.write("\2\2\2\u008e\u01a0\3\2\2\2\u0090\u01ae\3\2\2\2\u0092\u01b2") + buf.write("\3\2\2\2\u0094\u01ba\3\2\2\2\u0096\u01c7\3\2\2\2\u0098") + buf.write("\u01ce\3\2\2\2\u009a\u01d8\3\2\2\2\u009c\u01dc\3\2\2\2") + buf.write("\u009e\u009f\5d\61\2\u009f\u00a0\5p\67\2\u00a0\u00a1\5") + buf.write("b\60\2\u00a1\u00a2\5z<\2\u00a2\u00a3\5z<\2\u00a3\7\3\2") + buf.write("\2\2\u00a4\u00a5\5h\63\2\u00a5\u00a6\5p\67\2\u00a6\u00a7") + buf.write("\5z<\2\u00a7\u00a8\5h\63\2\u00a8\t\3\2\2\2\u00a9\u00aa") + buf.write("\7h\2\2\u00aa\u00ab\5b\60\2\u00ab\u00ac\5p\67\2\u00ac") + buf.write("\u00ad\5z<\2\u00ad\u00ae\5h\63\2\u00ae\13\3\2\2\2\u00af") + buf.write("\u00b0\5j\64\2\u00b0\u00b1\5n\66\2\u00b1\r\3\2\2\2\u00b2") + buf.write("\u00b3\5n\66\2\u00b3\u00b4\5j\64\2\u00b4\17\3\2\2\2\u00b5") + buf.write("\u00b6\5n\66\2\u00b6\u00b7\5r8\2\u00b7\21\3\2\2\2\u00b8") + buf.write("\u00b9\5n\66\2\u00b9\u00ba\5r8\2\u00ba\u00bb\5l\65\2\u00bb") + buf.write("\u00bc\5h\63\2\u00bc\u00bd\5x;\2\u00bd\u00be\5n\66\2\u00be") + buf.write("\u00bf\5|=\2\u00bf\u00c0\5z<\2\u00c0\23\3\2\2\2\u00c1") + buf.write("\u00c2\5n\66\2\u00c2\u00c3\5z<\2\u00c3\u00c4\5\u0080?") + buf.write("\2\u00c4\u00c5\5t9\2\u00c5\u00c6\5n\66\2\u00c6\u00c7\5") + buf.write("f\62\2\u00c7\25\3\2\2\2\u00c8\u00c9\5p\67\2\u00c9\u00ca") + buf.write("\5h\63\2\u00ca\u00cb\5|=\2\u00cb\27\3\2\2\2\u00cc\u00cd") + buf.write("\5p\67\2\u00cd\u00ce\5t9\2\u00ce\u00cf\5t9\2\u00cf\u00d0") + buf.write("\5v:\2\u00d0\31\3\2\2\2\u00d1\u00d2\5v:\2\u00d2\u00d3") + buf.write("\5t9\2\u00d3\u00d4\5t9\2\u00d4\u00d5\5p\67\2\u00d5\33") + buf.write("\3\2\2\2\u00d6\u00d7\5|=\2\u00d7\u00d8\5l\65\2\u00d8\u00d9") + buf.write("\5h\63\2\u00d9\u00da\5r8\2\u00da\35\3\2\2\2\u00db\u00dc") + buf.write("\5\u0082@\2\u00dc\u00dd\5l\65\2\u00dd\u00de\5n\66\2\u00de") + buf.write("\u00df\5p\67\2\u00df\u00e0\5h\63\2\u00e0\37\3\2\2\2\u00e1") + buf.write("\u00e2\5d\61\2\u00e2\u00e3\5b\60\2\u00e3\u00e4\5z<\2\u00e4") + buf.write("\u00e5\5h\63\2\u00e5!\3\2\2\2\u00e6\u00e7\5h\63\2\u00e7") + buf.write("\u00e8\5z<\2\u00e8\u00e9\5b\60\2\u00e9\u00ea\5d\61\2\u00ea") + buf.write("#\3\2\2\2\u00eb\u00ec\5r8\2\u00ec\u00ed\5h\63\2\u00ed") + buf.write("\u00ee\5\u0082@\2\u00ee%\3\2\2\2\u00ef\u00f0\5t9\2\u00f0") + buf.write("\u00f1\5j\64\2\u00f1\'\3\2\2\2\u00f2\u00f3\5r8\2\u00f3") + buf.write("\u00f4\5t9\2\u00f4\u00f5\5|=\2\u00f5)\3\2\2\2\u00f6\u00f7") + buf.write("\7v\2\2\u00f7\u00f8\5x;\2\u00f8\u00f9\5~>\2\u00f9\u00fa") + buf.write("\5h\63\2\u00fa+\3\2\2\2\u00fb\u00fe\5\60\27\2\u00fc\u00fe") + buf.write("\5\u0098K\2\u00fd\u00fb\3\2\2\2\u00fd\u00fc\3\2\2\2\u00fe") + buf.write("-\3\2\2\2\u00ff\u0100\7$\2\2\u0100\u0101\3\2\2\2\u0101") + buf.write("\u0102\b\26\2\2\u0102/\3\2\2\2\u0103\u0104\5.\26\2\u0104") + buf.write("\u0105\5\u009aL\2\u0105\u0106\5\u009cM\2\u0106\u010b\3") + buf.write("\2\2\2\u0107\u0108\5.\26\2\u0108\u0109\5\u009cM\2\u0109") + buf.write("\u010b\3\2\2\2\u010a\u0103\3\2\2\2\u010a\u0107\3\2\2\2") + buf.write("\u010b\61\3\2\2\2\u010c\u010f\5\u0084A\2\u010d\u010f\n") + buf.write("\2\2\2\u010e\u010c\3\2\2\2\u010e\u010d\3\2\2\2\u010f\63") + buf.write("\3\2\2\2\u0110\u0114\7$\2\2\u0111\u0113\5\62\30\2\u0112") + buf.write("\u0111\3\2\2\2\u0113\u0116\3\2\2\2\u0114\u0112\3\2\2\2") + buf.write("\u0114\u0115\3\2\2\2\u0115\u011c\3\2\2\2\u0116\u0114\3") + buf.write("\2\2\2\u0117\u0118\7^\2\2\u0118\u0119\7\17\2\2\u0119\u011d") + buf.write("\7\f\2\2\u011a\u011b\7^\2\2\u011b\u011d\7\f\2\2\u011c") + buf.write("\u0117\3\2\2\2\u011c\u011a\3\2\2\2\u011d\u011e\3\2\2\2") + buf.write("\u011e\u011f\b\31\3\2\u011f\65\3\2\2\2\u0120\u0122\t\3") + buf.write("\2\2\u0121\u0120\3\2\2\2\u0122\u0123\3\2\2\2\u0123\u0121") + buf.write("\3\2\2\2\u0123\u0124\3\2\2\2\u0124\67\3\2\2\2\u0125\u0129") + buf.write("\t\4\2\2\u0126\u0128\t\5\2\2\u0127\u0126\3\2\2\2\u0128") + buf.write("\u012b\3\2\2\2\u0129\u0127\3\2\2\2\u0129\u012a\3\2\2\2") + buf.write("\u012a9\3\2\2\2\u012b\u0129\3\2\2\2\u012c\u0130\t\6\2") + buf.write("\2\u012d\u012f\t\5\2\2\u012e\u012d\3\2\2\2\u012f\u0132") + buf.write("\3\2\2\2\u0130\u012e\3\2\2\2\u0130\u0131\3\2\2\2\u0131") + buf.write(";\3\2\2\2\u0132\u0130\3\2\2\2\u0133\u0134\7>\2\2\u0134") + buf.write("\u0135\7/\2\2\u0135=\3\2\2\2\u0136\u0137\7?\2\2\u0137") + buf.write("\u0138\7@\2\2\u0138?\3\2\2\2\u0139\u013a\7-\2\2\u013a") + buf.write("A\3\2\2\2\u013b\u013c\7/\2\2\u013cC\3\2\2\2\u013d\u013e") + buf.write("\7,\2\2\u013eE\3\2\2\2\u013f\u0140\7\61\2\2\u0140G\3\2") + buf.write("\2\2\u0141\u0142\7>\2\2\u0142I\3\2\2\2\u0143\u0144\7>") + buf.write("\2\2\u0144\u0145\7?\2\2\u0145K\3\2\2\2\u0146\u0147\7?") + buf.write("\2\2\u0147M\3\2\2\2\u0148\u0149\7\u0080\2\2\u0149O\3\2") + buf.write("\2\2\u014a\u014b\7*\2\2\u014bQ\3\2\2\2\u014c\u014d\7+") + buf.write("\2\2\u014dS\3\2\2\2\u014e\u014f\7}\2\2\u014fU\3\2\2\2") + buf.write("\u0150\u0151\7\177\2\2\u0151W\3\2\2\2\u0152\u0153\7B\2") + buf.write("\2\u0153Y\3\2\2\2\u0154\u0155\7\60\2\2\u0155[\3\2\2\2") + buf.write("\u0156\u0157\7.\2\2\u0157]\3\2\2\2\u0158\u0159\7<\2\2") + buf.write("\u0159_\3\2\2\2\u015a\u015b\7=\2\2\u015ba\3\2\2\2\u015c") + buf.write("\u015d\t\7\2\2\u015dc\3\2\2\2\u015e\u015f\t\b\2\2\u015f") + buf.write("e\3\2\2\2\u0160\u0161\t\t\2\2\u0161g\3\2\2\2\u0162\u0163") + buf.write("\t\n\2\2\u0163i\3\2\2\2\u0164\u0165\t\13\2\2\u0165k\3") + buf.write("\2\2\2\u0166\u0167\t\f\2\2\u0167m\3\2\2\2\u0168\u0169") + buf.write("\t\r\2\2\u0169o\3\2\2\2\u016a\u016b\t\16\2\2\u016bq\3") + buf.write("\2\2\2\u016c\u016d\t\17\2\2\u016ds\3\2\2\2\u016e\u016f") + buf.write("\t\20\2\2\u016fu\3\2\2\2\u0170\u0171\t\21\2\2\u0171w\3") + buf.write("\2\2\2\u0172\u0173\t\22\2\2\u0173y\3\2\2\2\u0174\u0175") + buf.write("\t\23\2\2\u0175{\3\2\2\2\u0176\u0177\t\24\2\2\u0177}\3") + buf.write("\2\2\2\u0178\u0179\t\25\2\2\u0179\177\3\2\2\2\u017a\u017b") + buf.write("\t\26\2\2\u017b\u0081\3\2\2\2\u017c\u017d\t\27\2\2\u017d") + buf.write("\u0083\3\2\2\2\u017e\u0181\7^\2\2\u017f\u0182\t\30\2\2") + buf.write("\u0180\u0182\5\u0086B\2\u0181\u017f\3\2\2\2\u0181\u0180") + buf.write("\3\2\2\2\u0182\u0085\3\2\2\2\u0183\u0184\7w\2\2\u0184") + buf.write("\u0185\5\u0088C\2\u0185\u0186\5\u0088C\2\u0186\u0187\5") + buf.write("\u0088C\2\u0187\u0188\5\u0088C\2\u0188\u0087\3\2\2\2\u0189") + buf.write("\u018a\t\31\2\2\u018a\u0089\3\2\2\2\u018b\u018d\t\32\2") + buf.write("\2\u018c\u018b\3\2\2\2\u018d\u018e\3\2\2\2\u018e\u018c") + buf.write("\3\2\2\2\u018e\u018f\3\2\2\2\u018f\u0190\3\2\2\2\u0190") + buf.write("\u0191\bD\4\2\u0191\u008b\3\2\2\2\u0192\u0193\7/\2\2\u0193") + buf.write("\u0194\7/\2\2\u0194\u0198\3\2\2\2\u0195\u0197\n\33\2\2") + buf.write("\u0196\u0195\3\2\2\2\u0197\u019a\3\2\2\2\u0198\u0196\3") + buf.write("\2\2\2\u0198\u0199\3\2\2\2\u0199\u019c\3\2\2\2\u019a\u0198") + buf.write("\3\2\2\2\u019b\u019d\7\f\2\2\u019c\u019b\3\2\2\2\u019c") + buf.write("\u019d\3\2\2\2\u019d\u019e\3\2\2\2\u019e\u019f\bE\4\2") + buf.write("\u019f\u008d\3\2\2\2\u01a0\u01a1\7*\2\2\u01a1\u01a2\7") + buf.write(",\2\2\u01a2\u01a3\3\2\2\2\u01a3\u01a4\bF\5\2\u01a4\u008f") + buf.write("\3\2\2\2\u01a5\u01a6\5\u008eF\2\u01a6\u01a7\5\u0090G\2") + buf.write("\u01a7\u01a8\5\u0092H\2\u01a8\u01af\3\2\2\2\u01a9\u01ab") + buf.write("\13\2\2\2\u01aa\u01a9\3\2\2\2\u01ab\u01ac\3\2\2\2\u01ac") + buf.write("\u01ad\3\2\2\2\u01ac\u01aa\3\2\2\2\u01ad\u01af\3\2\2\2") + buf.write("\u01ae\u01a5\3\2\2\2\u01ae\u01aa\3\2\2\2\u01af\u01b0\3") + buf.write("\2\2\2\u01b0\u01b1\bG\4\2\u01b1\u0091\3\2\2\2\u01b2\u01b3") + buf.write("\7,\2\2\u01b3\u01b4\7+\2\2\u01b4\u01b5\3\2\2\2\u01b5\u01b6") + buf.write("\bH\6\2\u01b6\u0093\3\2\2\2\u01b7\u01b9\5\62\30\2\u01b8") + buf.write("\u01b7\3\2\2\2\u01b9\u01bc\3\2\2\2\u01ba\u01b8\3\2\2\2") + buf.write("\u01ba\u01bb\3\2\2\2\u01bb\u01c2\3\2\2\2\u01bc\u01ba\3") + buf.write("\2\2\2\u01bd\u01be\7^\2\2\u01be\u01bf\7\17\2\2\u01bf\u01c3") + buf.write("\7\f\2\2\u01c0\u01c1\7^\2\2\u01c1\u01c3\7\f\2\2\u01c2") + buf.write("\u01bd\3\2\2\2\u01c2\u01c0\3\2\2\2\u01c3\u0095\3\2\2\2") + buf.write("\u01c4\u01c6\5\62\30\2\u01c5\u01c4\3\2\2\2\u01c6\u01c9") + buf.write("\3\2\2\2\u01c7\u01c5\3\2\2\2\u01c7\u01c8\3\2\2\2\u01c8") + buf.write("\u01ca\3\2\2\2\u01c9\u01c7\3\2\2\2\u01ca\u01cb\7$\2\2") + buf.write("\u01cb\u01cc\3\2\2\2\u01cc\u01cd\bJ\6\2\u01cd\u0097\3") + buf.write("\2\2\2\u01ce\u01d2\5\64\31\2\u01cf\u01d1\5\u0094I\2\u01d0") + buf.write("\u01cf\3\2\2\2\u01d1\u01d4\3\2\2\2\u01d2\u01d0\3\2\2\2") + buf.write("\u01d2\u01d3\3\2\2\2\u01d3\u01d5\3\2\2\2\u01d4\u01d2\3") + buf.write("\2\2\2\u01d5\u01d6\5\u0096J\2\u01d6\u0099\3\2\2\2\u01d7") + buf.write("\u01d9\5\62\30\2\u01d8\u01d7\3\2\2\2\u01d9\u01da\3\2\2") + buf.write("\2\u01da\u01d8\3\2\2\2\u01da\u01db\3\2\2\2\u01db\u009b") + buf.write("\3\2\2\2\u01dc\u01dd\7$\2\2\u01dd\u01de\3\2\2\2\u01de") + buf.write("\u01df\bM\6\2\u01df\u009d\3\2\2\2\31\2\3\4\5\u00fd\u010a") + buf.write("\u010e\u0114\u011c\u0123\u0129\u0130\u0181\u018e\u0198") + buf.write("\u019c\u01ac\u01ae\u01ba\u01c2\u01c7\u01d2\u01da\7\7\5") + buf.write("\2\7\4\2\b\2\2\7\3\2\6\2\2") return buf.getvalue() From 24455b66406dee59829f8da3a5455dd8948e4b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 12 Oct 2020 01:44:54 -0400 Subject: [PATCH 39/77] =?UTF-8?q?Se=20agreg=C3=B3=20el=20an=C3=A1lisis=20s?= =?UTF-8?q?em=C3=A1ntico=20Se=20cre=C3=B3=20una=20versi=C3=B3n=20prelimina?= =?UTF-8?q?r=20(incompleto)=20de=20la=20generaci=C3=B3n=20de=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grammar/COOL.g4 | 1 + src/COOL.py | 186 ++ src/COOLCompiler.py | 20 +- src/COOLParser.py | 2 +- src/COOLVisitor.py | 1387 +++++++++++++++ src/Visitors.py | 3135 ++++++++++++++++++++++++++++++++++ tests/codegen/arith.cl | 16 +- tests/codegen/complex.cl | 30 +- tests/codegen/hello_world.cl | 7 +- 9 files changed, 4758 insertions(+), 26 deletions(-) create mode 100644 src/COOLVisitor.py create mode 100644 src/Visitors.py diff --git a/grammar/COOL.g4 b/grammar/COOL.g4 index 76a2f58f..7865fd05 100644 --- a/grammar/COOL.g4 +++ b/grammar/COOL.g4 @@ -2,6 +2,7 @@ parser grammar COOL; options { tokenVocab=COOL_LEX; + output=AST; } program diff --git a/src/COOL.py b/src/COOL.py index 98bb717d..d3628c54 100644 --- a/src/COOL.py +++ b/src/COOL.py @@ -239,6 +239,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitProgram" ): listener.exitProgram(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitProgram" ): + return visitor.visitProgram(self) + else: + return visitor.visitChildren(self) + @@ -300,6 +306,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitClasses" ): listener.exitClasses(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitClasses" ): + return visitor.visitClasses(self) + else: + return visitor.visitChildren(self) + def programBlocks(self): @@ -379,6 +391,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitClassDefine" ): listener.exitClassDefine(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitClassDefine" ): + return visitor.visitClassDefine(self) + else: + return visitor.visitChildren(self) + @@ -487,6 +505,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitMethod" ): listener.exitMethod(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitMethod" ): + return visitor.visitMethod(self) + else: + return visitor.visitChildren(self) + class PropertyContext(FeatureContext): @@ -514,6 +538,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitProperty" ): listener.exitProperty(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitProperty" ): + return visitor.visitProperty(self) + else: + return visitor.visitChildren(self) + def feature(self): @@ -625,6 +655,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitFormal" ): listener.exitFormal(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitFormal" ): + return visitor.visitFormal(self) + else: + return visitor.visitChildren(self) + @@ -714,6 +750,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitLetIn" ): listener.exitLetIn(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitLetIn" ): + return visitor.visitLetIn(self) + else: + return visitor.visitChildren(self) + class MinusContext(ExpressionContext): @@ -738,6 +780,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitMinus" ): listener.exitMinus(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitMinus" ): + return visitor.visitMinus(self) + else: + return visitor.visitChildren(self) + class StringContext(ExpressionContext): @@ -756,6 +804,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitString" ): listener.exitString(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitString" ): + return visitor.visitString(self) + else: + return visitor.visitChildren(self) + class IsvoidContext(ExpressionContext): @@ -777,6 +831,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitIsvoid" ): listener.exitIsvoid(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitIsvoid" ): + return visitor.visitIsvoid(self) + else: + return visitor.visitChildren(self) + class WhileContext(ExpressionContext): @@ -805,6 +865,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitWhile" ): listener.exitWhile(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitWhile" ): + return visitor.visitWhile(self) + else: + return visitor.visitChildren(self) + class DivisionContext(ExpressionContext): @@ -829,6 +895,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitDivision" ): listener.exitDivision(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitDivision" ): + return visitor.visitDivision(self) + else: + return visitor.visitChildren(self) + class NegativeContext(ExpressionContext): @@ -850,6 +922,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitNegative" ): listener.exitNegative(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitNegative" ): + return visitor.visitNegative(self) + else: + return visitor.visitChildren(self) + class BoolNotContext(ExpressionContext): @@ -871,6 +949,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitBoolNot" ): listener.exitBoolNot(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitBoolNot" ): + return visitor.visitBoolNot(self) + else: + return visitor.visitChildren(self) + class LessThanContext(ExpressionContext): @@ -895,6 +979,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitLessThan" ): listener.exitLessThan(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitLessThan" ): + return visitor.visitLessThan(self) + else: + return visitor.visitChildren(self) + class BlockContext(ExpressionContext): @@ -926,6 +1016,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitBlock" ): listener.exitBlock(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitBlock" ): + return visitor.visitBlock(self) + else: + return visitor.visitChildren(self) + class IdContext(ExpressionContext): @@ -944,6 +1040,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitId" ): listener.exitId(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitId" ): + return visitor.visitId(self) + else: + return visitor.visitChildren(self) + class MultiplyContext(ExpressionContext): @@ -968,6 +1070,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitMultiply" ): listener.exitMultiply(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitMultiply" ): + return visitor.visitMultiply(self) + else: + return visitor.visitChildren(self) + class IfContext(ExpressionContext): @@ -998,6 +1106,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitIf" ): listener.exitIf(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitIf" ): + return visitor.visitIf(self) + else: + return visitor.visitChildren(self) + class CaseContext(ExpressionContext): @@ -1051,6 +1165,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitCase" ): listener.exitCase(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitCase" ): + return visitor.visitCase(self) + else: + return visitor.visitChildren(self) + class OwnMethodCallContext(ExpressionContext): @@ -1084,6 +1204,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitOwnMethodCall" ): listener.exitOwnMethodCall(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitOwnMethodCall" ): + return visitor.visitOwnMethodCall(self) + else: + return visitor.visitChildren(self) + class AddContext(ExpressionContext): @@ -1108,6 +1234,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitAdd" ): listener.exitAdd(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitAdd" ): + return visitor.visitAdd(self) + else: + return visitor.visitChildren(self) + class NewContext(ExpressionContext): @@ -1128,6 +1260,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitNew" ): listener.exitNew(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitNew" ): + return visitor.visitNew(self) + else: + return visitor.visitChildren(self) + class ParenthesesContext(ExpressionContext): @@ -1151,6 +1289,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitParentheses" ): listener.exitParentheses(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitParentheses" ): + return visitor.visitParentheses(self) + else: + return visitor.visitChildren(self) + class AssignmentContext(ExpressionContext): @@ -1174,6 +1318,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitAssignment" ): listener.exitAssignment(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitAssignment" ): + return visitor.visitAssignment(self) + else: + return visitor.visitChildren(self) + class FalseContext(ExpressionContext): @@ -1192,6 +1342,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitFalse" ): listener.exitFalse(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitFalse" ): + return visitor.visitFalse(self) + else: + return visitor.visitChildren(self) + class IntContext(ExpressionContext): @@ -1210,6 +1366,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitInt" ): listener.exitInt(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitInt" ): + return visitor.visitInt(self) + else: + return visitor.visitChildren(self) + class EqualContext(ExpressionContext): @@ -1234,6 +1396,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitEqual" ): listener.exitEqual(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitEqual" ): + return visitor.visitEqual(self) + else: + return visitor.visitChildren(self) + class TrueContext(ExpressionContext): @@ -1252,6 +1420,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitTrue" ): listener.exitTrue(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitTrue" ): + return visitor.visitTrue(self) + else: + return visitor.visitChildren(self) + class LessEqualContext(ExpressionContext): @@ -1276,6 +1450,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitLessEqual" ): listener.exitLessEqual(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitLessEqual" ): + return visitor.visitLessEqual(self) + else: + return visitor.visitChildren(self) + class MethodCallContext(ExpressionContext): @@ -1315,6 +1495,12 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitMethodCall" ): listener.exitMethodCall(self) + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitMethodCall" ): + return visitor.visitMethodCall(self) + else: + return visitor.visitChildren(self) + def expression(self, _p:int=0): diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index b2d7beab..8e08f495 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -7,6 +7,10 @@ from COOLParser import COOLParser from COOLParserErrorListener import COOLParserErrorListener from COOLListener import COOLListener +from Visitors import TypeCOOLVisitor +from Visitors import SemanticCOOLVisitor +from Visitors import CodegenVisitor +from collections import deque def main(argv): if not os.path.isfile(argv[1]): @@ -24,16 +28,28 @@ def main(argv): token = lexer.nextToken() if lexer.hasErrors: return sys.exit(errno.EPERM) - lexer.reset(); stream = CommonTokenStream(lexer) parser = COOLParser(stream) parser.removeErrorListeners() parser.addErrorListener(COOLParserErrorListener()) - tree = parser.program() if parser.getNumberOfSyntaxErrors() > 0: return sys.exit(errno.EPERM) + visitor = TypeCOOLVisitor() + visitor.visitProgram(tree, argv[1]) + typeTree = visitor.TypeTable + consTble = visitor.ConstantTable + semanticAnalizer = SemanticCOOLVisitor(typeTree) + codegenerator = CodegenVisitor(typeTree, consTble, visitor.Counter) + semanticAnalizer.visitProgram(tree) + + outFilename = os.path.splitext(argv[1])[0] + ".s" + codegenerator.visitProgram(tree, outFilename) + none = typeTree["Object"] + + + if __name__ == '__main__': main(sys.argv) diff --git a/src/COOLParser.py b/src/COOLParser.py index 6decdd97..abab6507 100644 --- a/src/COOLParser.py +++ b/src/COOLParser.py @@ -2,13 +2,13 @@ from io import StringIO from typing.io import TextIO from antlr4 import * -from COOL import COOL from antlr4.CommonTokenFactory import CommonTokenFactory from antlr4.atn.LexerATNSimulator import LexerATNSimulator from antlr4.InputStream import InputStream from antlr4.Recognizer import Recognizer from antlr4.Token import Token from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException +from COOL import * class COOLParser(COOL): def __init__(self, input=None, output:TextIO = sys.stdout): diff --git a/src/COOLVisitor.py b/src/COOLVisitor.py new file mode 100644 index 00000000..665425e5 --- /dev/null +++ b/src/COOLVisitor.py @@ -0,0 +1,1387 @@ +# Generated from COOL.g4 by ANTLR 4.7.2 +from collections import deque +from antlr4 import * +# if __name__ is not None and "." in __name__: +# from .COOL import COOL +# else: +# from COOL import COOL + +from COOL import * + +from src import COOLParser + +# This class defines a complete generic visitor for a parse tree produced by COOL. +class COOLVisitor(ParseTreeVisitor): + + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx:COOL.ProgramContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx:COOL.ClassesContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx:COOL.ClassDefineContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx:COOL.MethodContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx:COOL.PropertyContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx:COOL.FormalContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx:COOL.LetInContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx:COOL.MinusContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx:COOL.StringContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx:COOL.IsvoidContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx:COOL.WhileContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx:COOL.DivisionContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx:COOL.NegativeContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx:COOL.BoolNotContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx:COOL.LessThanContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx:COOL.BlockContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx:COOL.IdContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx:COOL.MultiplyContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx:COOL.IfContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx:COOL.CaseContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx:COOL.AddContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx:COOL.NewContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx:COOL.ParenthesesContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx:COOL.AssignmentContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx:COOL.FalseContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx:COOL.IntContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx:COOL.EqualContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx:COOL.TrueContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx:COOL.LessEqualContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx:COOL.MethodCallContext): + return self.visitChildren(ctx) + +class SemanticCOOLVisitor(ParseTreeVisitor): + + def join(self, class1: str, class2: str): + if class1 == "None" or class2 == "None": + return "None" + if self.TypeTable[class1].Deep == self.TypeTable[class2].Deep: + if self.TypeTable[class1].Name == self.TypeTable[class2].Name: + return class1 + else: + return self.join(self.TypeTable[class1].Parent, self.TypeTable[class2].Parent) + elif self.TypeTable[class1].Deep > self.TypeTable[class2].Deep: + return self.join(self.TypeTable[class1].Parent, class2) + else: + return self.join(class1, self.TypeTable[class2].Parent) + + def calculateDeep(self, coolClass: COOLClass): + if self.TypeTable.keys().__contains__(coolClass.Parent): + if self.TypeTable[coolClass.Parent].Deep != -1: + coolClass.Deep = self.TypeTable[coolClass.Parent].Deep + 1 + else: + self.calculateDeep(self.TypeTable[coolClass.Parent]) + coolClass.Deep = self.TypeTable[coolClass.Parent].Deep + 1 + elif coolClass.Name == "Object": + coolClass.Deep = 0 + else: + coolClass.Deep = 1 + coolClass.Parent = "Object" + + def searchMethod(self, coolClass: str, methodName: str): + if coolClass == "None": + return False + elif self.TypeTable[coolClass].Methods.keys().__contains__(methodName): + return True + else: + return self.searchMethod(self.TypeTable[coolClass].Parent, methodName) + + def searchAtribute(self, coolClass: str, atributeName: str): + if coolClass == "None": + return False + elif self.TypeTable[coolClass].Atributes.keys().__contains__(atributeName): + return True + else: + return self.searchAtribute(self.TypeTable[coolClass].Parent, atributeName) + + def searchMethodInfo(self, coolClass: str, methodName: str): + for method in self.TypeTable[coolClass].Methods.keys(): + if method == methodName: + return self.TypeTable[coolClass].Methods[method] + return self.searchMethodInfo(self.TypeTable[coolClass].Parent, methodName) + + def searchAtributeInfo(self, coolClass: str, atributeName: str): + for atribute in self.TypeTable[coolClass].Atributes.keys(): + if atribute == atributeName: + return self.TypeTable[coolClass].Atributes[atribute] + return self.searchAtributeInfo(self.TypeTable[coolClass].Parent, atributeName) + + + def __init__(self, typeTable: dict): + self.TypeTable = typeTable + self.ScopeManager = COOLScopeManager() + self.actualClass = "Object" + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx:COOL.ProgramContext): + for className in self.TypeTable.keys(): + self.calculateDeep(self.TypeTable[className]) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx:COOL.ClassesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx:COOL.ClassDefineContext): + coolClass = ctx.getChild(1).symbol + if(self.TypeTable[coolClass.text].Created): + line = str(coolClass.line) + column = str(coolClass.column) + error = "(" + line + "," + column + "): this class name already exist" + print(error) + elif ctx.getChild(2).symbol.text == "inherits": + classParent = ctx.getChild(3).symbol + if (self.TypeTable.keys().__contains__(classParent.text)): + if self.TypeTable[classParent.text].Sealed: + line = str(classParent.line) + column = str(classParent.column) + error = "(" + line + "," + column + "): this class is sealed" + print(error) + else: + self.TypeTable[coolClass.text].Created = True + self.TypeTable[coolClass.text].Sealed = False + self.ScopeManager.addScope() + self.ScopeManager.addIdentifier("self", coolClass.text) + self.actualClass = coolClass.text + self.visitChildren(ctx) + self.ScopeManager.deleteScope() + return + else: + line = str(classParent.line) + column = str(classParent.column) + error = "(" + line + "," + column + "): this class doesn't exist" + print(error) + else: + self.TypeTable[coolClass.text].Created = True + self.TypeTable[coolClass.text].Sealed = False + self.ScopeManager.addScope() + self.actualClass = coolClass.text + self.ScopeManager.addIdentifier("self", coolClass.text) + self.visitChildren(ctx) + self.ScopeManager.deleteScope() + return + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx:COOL.MethodContext): + coolClass = ctx.parentCtx.getChild(1).symbol.text + methodName = ctx.getChild(0).symbol.text + methodType = ctx.getChild(len(ctx.children) - 4).symbol + if self.ScopeManager.searchScope(methodName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this method name already exist" + print(error) + elif self.TypeTable.keys().__contains__(self.TypeTable[coolClass].Methods[methodName].Type) or methodType.text == "SELF_TYPE": + self.ScopeManager.addIdentifier(methodName, methodType.text) + self.ScopeManager.addScope() + self.visitChildren(ctx) + self.ScopeManager.deleteScope() + return + else: + line = str(methodType.line) + column = str(methodType.column) + error = "(" + line + "," + column + "): this type doesn't exist" + print(error) + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx:COOL.PropertyContext): + atributeType = ctx.getChild(2).symbol.text + atributeName = ctx.getChild(0).symbol.text + if self.ScopeManager.searchScope(atributeName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this atribute name already exist" + print(error) + return "None" + elif not(self.TypeTable.keys().__contains__(atributeType) or atributeType == "SELF_TYPE"): + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column) + error = "(" + line + "," + column + "): this type doesn't exist" + print(error) + return "None" + elif len(ctx.children) == 5: + atributeValue = ctx.getChild(4).accept(self) + if self.join(atributeType, atributeValue) != atributeType: + line = str(ctx.getChild(4).start.line) + column = str(ctx.getChild(4).start.column) + error = "(" + line + "," + column + "): the type of the expression is diferent of the type of the atribute" + print(error) + return "None" + else: + self.ScopeManager.addIdentifier(atributeName, atributeType) + return atributeType + else: + self.ScopeManager.addIdentifier(atributeName, atributeType) + return atributeType + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx:COOL.FormalContext): + paramName = ctx.getChild(0).symbol.text + paramType = ctx.getChild(2).symbol.text + if self.ScopeManager.searchScope(paramName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this param name already exist" + print(error) + elif self.TypeTable.keys().__contains__(paramType): + self.ScopeManager.addIdentifier(paramName, paramType) + return self.visitChildren(ctx) + else: + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column) + error = "(" + line + "," + column + "): this type doesn't exist" + print(error) + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx: COOL.IntContext): + return "Int" + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx: COOL.StringContext): + return "String" + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx: COOL.FalseContext): + return "Bool" + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx: COOL.TrueContext): + return "Bool" + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx: COOL.AddContext): + addValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + addValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + addValue = "None" + return addValue + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx:COOL.MinusContext): + minusValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + minusValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + minusValue = "None" + return minusValue + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx: COOL.MultiplyContext): + mulValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + mulValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + mulValue = "None" + return mulValue + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx: COOL.DivisionContext): + divValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + divValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + divValue = "None" + return divValue + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx: COOL.NegativeContext): + expressValue = ctx.getChild(1).accept(self) + if expressValue == "Int": + return "Int" + return "None" + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx:COOL.IsvoidContext): + self.visitChildren(ctx) + return "Bool" + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx: COOL.BoolNotContext): + expressValue = ctx.getChild(1).accept(self) + if expressValue == "Bool": + return "Bool" + return "None" + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx:COOL.LessThanContext): + lessValue = "Bool" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessValue = "None" + return lessValue + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx:COOL.LessEqualContext): + lessEqualValue = "Bool" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessEqualValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessEqualValue = "None" + return lessEqualValue + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx: COOL.EqualContext): + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue == "None" or rightValue == "None": + return "None" + if leftValue == rightValue: + return "Bool" + if leftValue == "String" or leftValue == "Int" or leftValue == "Bool": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is incorrect" + print(error) + return "None" + if rightValue == "String" or rightValue == "Int" or rightValue == "Bool": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is incorrect" + print(error) + return "None" + return "Bool" + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx: COOL.AssignmentContext): + variableName = ctx.getChild(0).symbol.text + asignValue = ctx.getChild(2).accept(self) + variableType = self.ScopeManager.searchforType(variableName) + if variableType == "None": + if self.searchAtribute(self.actualClass, variableName): + variableType = self.searchAtributeInfo(self.actualClass, variableName) + else: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this identifier does not exist" + print(error) + return "None" + if variableType == "SELF_TYPE": + variableType = self.actualClass + if self.join(asignValue, variableType) != variableType: + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is diferent that the identifier" + print(error) + return "None" + return variableType + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx: COOL.ParenthesesContext): + return ctx.getChild(1).accept(self) + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx: COOL.IdContext): + IdValue = ctx.getChild(0).symbol.text + if self.ScopeManager.searchIdentifier(IdValue): + return self.ScopeManager.searchforType(IdValue) + elif self.searchAtribute(self.actualClass, IdValue): + return self.searchAtributeInfo(self.actualClass, IdValue) + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this identifier does not exist" + print(error) + return "None" + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx:COOL.IfContext): + ifValue = ctx.getChild(1).accept(self) + thenValue = ctx.getChild(3).accept(self) + elseValue = ctx.getChild(5).accept(self) + if ifValue == "None" or ifValue == "Bool": + return self.join(thenValue, elseValue) + else: + line = str(ctx.getChild(1).start.line) + column = str(ctx.getChild(1).start.column) + error = "(" + line + "," + column + "): this expression is not boolean" + print(error) + return self.join(thenValue, elseValue) + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx: COOL.WhileContext): + whileValue = ctx.getChild(3).accept(self) + whileValue = ctx.getChild(1).accept(self) + if whileValue == "None" or whileValue == "Bool": + return "Object" + else: + line = str(ctx.getChild(1).start.line) + column = str(ctx.getChild(1).start.column) + error = "(" + line + "," + column + "): this expression is not boolean" + print(error) + return "Object" + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx:COOL.BlockContext): + blockValue = "None" + count = 1 + lengt = len(ctx.children) - 1 + while lengt > count: + blockValue = ctx.getChild(count).accept(self) + count = count + 2 + return blockValue + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx:COOL.CaseContext): + ctx.getChild(1).accept(self) + lengt = len(ctx.children) - 1 + count = 3 + caseValue = "None" + while lengt > count: + idName = ctx.getChild(count).symbol.text + count = count + 2 + idType = ctx.getChild(count).symbol.text + count = count + 2 + self.ScopeManager.addScope() + self.ScopeManager.addIdentifier(idName, idType) + if (caseValue == "None"): + caseValue = ctx.getChild(count).accept(self) + else: + caseValue = self.join(caseValue, ctx.getChild(count).accept(self)) + count = count + 2 + self.ScopeManager.deleteScope() + return caseValue + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx: COOL.NewContext): + return ctx.getChild(1).symbol.text + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): + methodType = "None" + if self.searchMethod(self.actualClass, ctx.getChild(0).symbol.text): + methodInfo = self.searchMethodInfo(self.actualClass, ctx.getChild(0).symbol.text) + if(methodInfo.Type == "SELF_TYPE"): + methodType = self.actualClass + else: + methodType = methodInfo.Type + if methodInfo.ParamsNumber == 0 and len(ctx.children) != 3: + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + elif len(ctx.children) != methodInfo.ParamsNumber * 2 + 2 and methodInfo.ParamsNumber != 0: + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + else: + count = 2 + for param in methodInfo.Params: + (_,paramType) = param + requestType = ctx.getChild(count).accept(self) + if (self.join(requestType, paramType) != paramType): + line = str(ctx.getChild(count).start.line) + column = str(ctx.getChild(count).start.column) + error = "(" + line + "," + column + "): the type of this param in the call is incorrect" + print(error) + methodType = "None" + count = count + 2 + else: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this method not exist in " + self.actualClass + print(error) + return methodType + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx:COOL.MethodCallContext): + methodType = "None" + length = 5 + currentClass = ctx.getChild(0).accept(self) + if (ctx.getChild(1).symbol.text == "@"): + length = length + 2 + parent = ctx.getChild(2).symbol.text + if self.join(currentClass, parent) == parent: + currentClass = parent + else: + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column) + error = "(" + line + "," + column + "): this class is not parent of " + currentClass + print(error) + return methodType + if self.searchMethod(currentClass, ctx.getChild(length - 3).symbol.text): + methodInfo = self.searchMethodInfo(currentClass, ctx.getChild(length - 3).symbol.text) + if (methodInfo.Type == "SELF_TYPE"): + methodType = currentClass + else: + methodType = methodInfo.Type + if (methodInfo.ParamsNumber == 0 and len(ctx.children) != length): + line = str(ctx.getChild(length - 3).start.line) + column = str(ctx.getChild(length - 3).start.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + elif (len(ctx.children) != methodInfo.ParamsNumber * 2 + length - 1) and methodInfo.ParamsNumber > 0: + line = str(ctx.getChild(length - 3).start.line) + column = str(ctx.getChild(length - 3).start.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + else: + count = length - 1 + for param in methodInfo.Params: + (_, paramType) = param + requestType = ctx.getChild(count).accept(self) + if (self.join(requestType, paramType) != paramType): + line = str(ctx.getChild(count).start.line) + column = str(ctx.getChild(count).start.column) + error = "(" + line + "," + column + "): the type of this param in the call is incorrect" + print(error) + methodType = "None" + count = count + 2 + else: + line = str(ctx.getChild(length - 3).symbol.line) + column = str(ctx.getChild(length - 3).symbol.column) + error = "(" + line + "," + column + "): this method not exist in " + currentClass + print(error) + return methodType + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx: COOL.LetInContext): + self.ScopeManager.addScope() + count = 0 + while(ctx.getChild(count).symbol.text != "in"): + idName = ctx.getChild(count + 1).symbol.text + count = count + 2 + idType = ctx.getChild(count + 1).symbol.text + if not(self.TypeTable.keys().__contains__(idType)) and idType != "SELF_TYPE": + self.ScopeManager.deleteScope() + line = str(ctx.getChild(count + 1).symbol.line) + column = str(ctx.getChild(count + 1).symbol.column) + error = "(" + line + "," + column + "): this class does not exist " + print(error) + return "None" + self.ScopeManager.addIdentifier(idName, idType) + count = count + 2 + if ctx.getChild(count).symbol.text == "<-": + idValue = ctx.getChild(count + 1).accept(self) + count = count + 2 + if self.join(idType, idValue) != idType: + self.ScopeManager.deleteScope() + line = str(ctx.getChild(count -1).start.line) + column = str(ctx.getChild(count - 1).start.column) + error = "(" + line + "," + column + "): the type of the expression is diferent of the type of the identifier" + print(error) + return "None" + + return ctx.getChild(count + 1).accept(self) + +class TypeCOOLVisitor(ParseTreeVisitor): + + TypeTable = {} + + Counter = 0 + + ConstantTable = list() + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx: COOL.ProgramContext): + self.TypeTable["Object"] = COOLClass("Object", "None", True, False) + self.TypeTable["Object"].Methods["abort"] = COOLMethod("abort", "Object", 0, None) + self.TypeTable["Object"].Methods["type_name"] = COOLMethod("type_name", "String", 0, None) + self.TypeTable["Object"].Methods["copy"] = COOLMethod("copy", "SELF_TYPE", 0, None) + self.TypeTable["String"] = COOLClass("String", "Object", True, True) + self.TypeTable["String"].Methods["length"] = COOLMethod("length", "Int", 0, None) + self.TypeTable["String"].Methods["concat"] = COOLMethod("concat", "String", 1, None) + self.TypeTable["String"].Methods["concat"].Params.append(("s", "String")) + self.TypeTable["String"].Methods["substr"] = COOLMethod("substr", "String", 2, None) + self.TypeTable["String"].Methods["substr"].Params.append(("i", "Int")) + self.TypeTable["String"].Methods["substr"].Params.append(("l", "Int")) + self.TypeTable["Int"] = COOLClass("Int", "Object", True, True) + self.TypeTable["Bool"] = COOLClass("Bool", "Object", True, True) + self.TypeTable["IO"] = COOLClass("IO", "Object", True, False) + self.TypeTable["IO"].Methods["in_string"] = COOLMethod("in_string", "String", 0, None) + self.TypeTable["IO"].Methods["in_int"] = COOLMethod("in_int", "Int", 0, None) + self.TypeTable["IO"].Methods["out_string"] = COOLMethod("out_string", "SELF_TYPE", 1, None) + self.TypeTable["IO"].Methods["out_string"].Params.append(("x", "String")) + self.TypeTable["IO"].Methods["out_int"] = COOLMethod("out_int", "SELF_TYPE", 1, None) + self.TypeTable["IO"].Methods["out_int"].Params.append(("x", "Int")) + self.ConstantTable.append(("", "String", "string_const0")) + self.Counter = 1 + self.ConstantTable.append((0, "Int", "int_const0")) + self.ConstantTable.append(("false", "Bool", "bool_const0")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx: COOL.ClassesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx: COOL.ClassDefineContext): + coolClass = ctx.getChild(1).symbol + if self.TypeTable.keys().__contains__(coolClass.text): + return + if ctx.getChild(2).symbol.text == "inherits": + classParent = ctx.getChild(3).symbol + self.TypeTable[coolClass.text] = COOLClass(coolClass.text, classParent.text, False, False) + return self.visitChildren(ctx) + else: + self.TypeTable[coolClass.text] = COOLClass(coolClass.text, "Object", False, False) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx: COOL.MethodContext): + name = ctx.getChild(0).symbol.text + cclass = ctx.parentCtx.getChild(1).symbol.text + if self.TypeTable[cclass].Methods.keys().__contains__(name): + return + n = len(ctx.children) - 4 + if ctx.getChild(n).symbol.text == ":": + n = n + 1 + type = ctx.getChild(n).symbol.text + lengt = len(ctx.children) - 8 + paramsNumber = 0 + if lengt > 0: + paramsNumber = 1 + while lengt > 1: + lengt = lengt - 2 + paramsNumber = paramsNumber + 1 + self.TypeTable[cclass].Methods[name] = COOLMethod(name, type, paramsNumber, ctx.getChild(len(ctx.children) - 2)) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx: COOL.PropertyContext): + cclass = ctx.parentCtx.getChild(1).symbol.text + name = ctx.getChild(0).symbol.text + if self.TypeTable[cclass].Atributes.keys().__contains__(name): + return + type = ctx.getChild(2).symbol.text + self.TypeTable[cclass].Atributes[name] = type + if len(ctx.children) == 4: + self.TypeTable[cclass].AtributeAsign[name] = ctx.getChild(4) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx: COOL.FormalContext): + parent = ctx.parentCtx + + className = parent.parentCtx.getChild(1).symbol.text + methodName = parent.getChild(0).symbol.text + method = self.TypeTable[className].Methods[methodName] + for param in method.Params: + (paramName, paramType) = param + if (paramName == ctx.getChild(0).symbol.text): + return + method.Params.append((ctx.getChild(0).symbol.text, ctx.getChild(2).symbol.text)) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx: COOL.LetInContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx: COOL.MinusContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx: COOL.StringContext): + constantName = ctx.getChild(0).symbol.text[1:-1] + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == constantName and consType == "String": + return self.visitChildren(ctx) + + self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) + self.Counter = self.Counter + 1 + length = len(constantName) + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == length and consType == "Int": + return self.visitChildren(ctx) + self.ConstantTable.append((length, "Int", f"int_const{length}")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx: COOL.IsvoidContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx: COOL.WhileContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx: COOL.DivisionContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx: COOL.NegativeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx: COOL.BoolNotContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx: COOL.LessThanContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx: COOL.BlockContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx: COOL.IdContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx: COOL.MultiplyContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx: COOL.IfContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx: COOL.CaseContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx: COOL.AddContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx: COOL.NewContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx: COOL.ParenthesesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx: COOL.AssignmentContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx: COOL.FalseContext): + for cons in self.ConstantTable: + (consName, consType, _) = cons + if consName == "false" and consType == "Bool": + return self.visitChildren(ctx) + + self.ConstantTable.append(("false", "Bool", "bool_const0")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx: COOL.IntContext): + constantName = int(ctx.getChild(0).symbol.text) + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == constantName and consType == "Int": + return self.visitChildren(ctx) + + self.ConstantTable.append((constantName, "Int", f"int_const{constantName}")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx: COOL.EqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx: COOL.TrueContext): + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == "true" and consType == "Bool": + return self.visitChildren(ctx) + + self.ConstantTable.append(("true", "Bool","bool_const1")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx: COOL.LessEqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx: COOL.MethodCallContext): + return self.visitChildren(ctx) + +class CodegenVisitor(ParseTreeVisitor): + + def __init__(self, typeTable: dict, constantTable: list, counter: int): + self.TypeTable = typeTable + self.ConstantTable = constantTable + self.Counter = counter + + + def genGlobalClases(self): + sol = "\t.data\n\t.align 2\n\t.global class_nameTab\n" + for clasName in self.TypeTable.keys(): + protoName = "\t.global " + clasName + "_protoObj\n" + sol = sol + protoName + sol = sol + "_string_tag:\n\t.word 1\n_int_tag:\n\t.word 2\n_bool_tag :\n\t.word 3\n" + return sol + + def genConstant(self, sol: str): + for const in self.ConstantTable: + (constName, constType, constLabel) = const + if constType == "Bool": + sol = sol + \ + f"\t.word -1\n" \ + f"{constLabel}:\n" \ + f"\t.word 5\n" \ + f"\t.word 4\n" \ + f"\t.word Bool_dispTab\n" \ + f"\t.word {constLabel[-1:-1]}\n" + elif constType == "Int": + sol = sol + \ + f"\t.word -1\n{constLabel}:\n" \ + f"\t.word 3\n\t.word 4\n" \ + f"\t.word Int_dispTab\n" \ + f"\t.word {constName}\n" + else: + length = int(len(constName) / 4) + 3 + if len(constName) % 4 != 0: + length = length + 1 + sol = sol + \ + f"\t.word -1\n{constLabel}:\n" \ + f"\t.word 4\n\t.word {length}\n" \ + f"\t.word String_dispTab\n" \ + f"\t.word int_const{len(constName)}\n" \ + f"\t.ascii {constName}\n" \ + f"\t.byte 0\n" \ + f"\t.align 2\n" + return sol + + def findLabel(self, name: str): + for const in self.ConstantTable: + (constName, constType, constLabel) = const + if constName == name and constType == "String": + return constLabel + + def genMethodNames(self, coolClass: str, coolMethods: list, className: str): + if coolClass == "None": + return "" + temp = "" + for method in self.TypeTable[coolClass].Methods: + if not (coolMethods.__contains__(method)): + temp = temp + f"\t.word {coolClass}.{method}\n" + coolMethods.append(method) + + code = self.genMethodNames(self.TypeTable[coolClass].Parent, coolMethods, className) + return code + temp + + + + def genAtributeNames(self, coolClass: str, coolAtributes: list): + if coolClass == "None": + return "" + temp = "" + listAtributes = list() + for atribute in self.TypeTable[coolClass].Atributes: + listAtributes.append(atribute) + if not (coolAtributes.__contains__(atribute)): + value = self.TypeTable[coolClass].Atributes[atribute] + if value == "Int" or value == "String" or value == "Bool": + temp = temp + f"\t.word {value.lower()}_constant0\n" + else: + temp = temp + f"\t.word 0\n" + coolAtributes.append(atribute) + + code = self.genAtributeNames(self.TypeTable[coolClass].Parent, coolAtributes) + if coolClass != "Object": + self.TypeTable[coolClass].TagAtributes = self.TypeTable[self.TypeTable[coolClass].Parent].TagAtributes + listAtributes + return code + temp + + def genClassTable(self): + classNameTab = "class_nameTab:\n" + class_objTab = "class_objTab:\n" + methods = "" + atributes = "" + counter = 0 + for className in self.TypeTable: + classNameTab = classNameTab + f"\t.word {self.findLabel(className)}\n" + temp = self.genMethodNames(className, list(), className) + class_objTab = class_objTab + \ + f"\t.word {className}_protObj\n" \ + f"\t.word {className}_init\n" + methods = methods + f"{className}_dispTab:\n" + temp + if className == "Int" or className == "Bool": + atributes = atributes + \ + f"\t.word -1\n" \ + f"{className}_protObj:\n" \ + f"\t.word {counter}\n" \ + f"\t.word 4\n" \ + f"\t.word {className}_dispTab\n" \ + f"\t.word 0\n" + elif className == "String": + atributes = atributes + \ + f"\t.word -1\n" \ + f"{className}_protObj:\n" \ + f"\t.word {counter}\n" \ + f"\t.word 5\n" \ + f"\t.word {className}_dispTab\n" \ + f"\t.word int_constant0\n" \ + f"\t.word 0\n" + else: + atributeList = list() + temp = self.genAtributeNames(className, atributeList) + atributes = atributes + \ + f"\t.word -1\n" \ + f"{className}_protObj:\n" \ + f"\t.word {counter}\n" \ + f"\t.word {len(atributeList) + 3}\n" \ + f"\t.word {className}_dispTab\n" \ + f"" + temp + self.TypeTable[className].Tag = counter + counter = counter + 1 + return classNameTab + class_objTab + methods + atributes + + def genClassAtributes(self, className: str): + if className == "None": + return "" + code = self.genClassAtributes(self.TypeTable[className].Parent) + for atribute in self.TypeTable[className].AtributeAsign: + code = code + self.TypeTable[className].AtributeAsign[atribute].accept(self) + return code + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx: COOL.ProgramContext): + for className in self.TypeTable: + constantName = className + self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) + self.Counter = self.Counter + 1 + length = len(constantName) + contain = True + for cons in self.ConstantTable: + (consName, consType, _) = cons + if consName == length and consType == "Int": + contain = False + if contain: + self.ConstantTable.append((length, "Int", f"int_const{length}")) + self.ConstantTable.append(("SELF_TYPE", "String", f"str_const{self.Counter}")) + contain = True + length = len("SELF_TYPE") + for cons in self.ConstantTable: + (consName, consType, _) = cons + if consName == length and consType == "Int": + contain = False + if contain: + self.ConstantTable.append((length, "Int", f"int_const{length}")) + code = self.genGlobalClases() + code = self.genConstant(code) + code = code + self.genClassTable() + code = code + \ + "\t.global heap_start\n" \ + "heap_start:\n" \ + "\t.word 0\n" \ + "\t.text\n" \ + "\t.global Main_init\n" \ + "\t.global Int_init\n" \ + "\t.global String_init\n" \ + "\t.global Bool_init\n" \ + "\t.global Main.main\n" + for className in self.TypeTable: + code = code + f"{className}_init:\n" + temp = self.genClassAtributes(className) + if len(temp) != 0: + code = code + \ + "\taddiu $sp $sp -12\n" \ + "\tsw $fp 12($sp)\n" \ + "\tsw $s0 8($sp)\n" \ + "\tsw $ra 4($sp)\n" \ + "\taddiu $fp $sp 4\n" \ + "\tmove $s0 $a0\n" + code = code + temp + code = code + \ + "\tmove $a0 $s0\n" \ + "\tlw $fp 12($sp)\n" \ + "\tlw $s0 8($sp)\n" \ + "\tlw $ra 4($sp)\n" \ + "\taddiu $sp $sp 12\n" + code = code + "\tjr $ra\n" + for className in self.TypeTable: + if not(className == "Object" or className == "String" or className == "Int" or className == "Bool" or className == "IO"): + for methodName in self.TypeTable[className].Methods: + code = code + f"{className}.{methodName}:\n" + code = code + \ + "\taddiu $sp $sp -12\n" \ + "\tsw $fp 12($sp)\n" \ + "\tsw $s0 8($sp)\n" \ + "\tsw $ra 4($sp)\n" \ + "\taddiu $fp $sp 4\n" \ + "\tmove $s0 $a0\n" + code = code + self.TypeTable[className].Methods[methodName].InstructionSet.accept(self) + code = code + \ + "\tmove $a0 $s0\n" \ + "\tlw $fp 12($sp)\n" \ + "\tlw $s0 8($sp)\n" \ + "\tlw $ra 4($sp)\n" \ + "\taddiu $sp $sp 12\n" + code = code + "\tjr $ra\n" + print(code) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx: COOL.ClassesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx: COOL.ClassDefineContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx: COOL.MethodContext): + return "" + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx: COOL.PropertyContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx: COOL.FormalContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx: COOL.LetInContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx: COOL.MinusContext): + code = ctx.getChild(0).accept(self) + code = code + \ + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy" + \ + "\tlw $t1 4($sp)\n" + \ + "\tlw $t1 12($t1)\n" + \ + "\tlw $t2 12($a0)\n" + \ + "\tsub $t1 $t1 $t2\n" + \ + "\tsw $t1 12($a0)\n" + \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx: COOL.StringContext): + name = ctx.getChild(0).symbol.text[1:-1] + for const in self.ConstantTable: + (constName, constType, constTag) = const + if constType == "String" and constName == name: + return f"\tla $a0 {constTag}\n" + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx: COOL.IsvoidContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx: COOL.WhileContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx: COOL.DivisionContext): + code = ctx.getChild(0).accept(self) + code = code + \ + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy" \ + "\tlw $t1 4($sp)\n" \ + "\tlw $t1 12($t1)\n" \ + "\tlw $t2 12($a0)\n" \ + "\tdiv $t1 $t2\n" \ + "\tmflo $t1" \ + "\tsw $t1 12($a0)\n" \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx: COOL.NegativeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx: COOL.BoolNotContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx: COOL.LessThanContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx: COOL.BlockContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx: COOL.IdContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx: COOL.MultiplyContext): + code = ctx.getChild(0).accept(self) + code = code + \ + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy" + \ + "\tlw $t1 4($sp)\n" + \ + "\tlw $t1 12($t1)\n" + \ + "\tlw $t2 12($a0)\n" + \ + "\tmul $t1 $t1 $t2\n" + \ + "\tsw $t1 12($a0)\n" + \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx: COOL.IfContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx: COOL.CaseContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): + length = len(ctx.children) + code = "" + if length > 3: + count = 2 + while length != count: + param = ctx.getChild(count).accept(self) + code = code + param + f"\tsw $a0 0($sp)\n\taddiu $sp $sp -4\n" + count = count + 2 + code = code + "\tmove $a0 $s0\n" + return code + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx: COOL.AddContext): + code = ctx.getChild(0).accept(self) + code = code + \ + "\tsw $a0 0 ($sp)\n"+ \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy"+ \ + "\tlw $t1 4($sp)\n"+ \ + "\tlw $t1 12($t1)\n"+ \ + "\tlw $t2 12($a0)\n"+ \ + "\tadd $t1 $t1 $t2\n"+ \ + "\tsw $t1 12($a0)\n"+ \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx: COOL.NewContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx: COOL.ParenthesesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx: COOL.AssignmentContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx: COOL.FalseContext): + return f"\tla $a0 {bool_const0}\n" + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx: COOL.IntContext): + name = ctx.getChild(0).symbol.text[1:-1] + for const in self.ConstantTable: + (constName, constType, constTag) = const + if constType == "Int" and constName == name: + return f"\tla $a0 {constTag}\n" + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx: COOL.EqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx: COOL.TrueContext): + return f"\tla $a0 {bool_const1}\n" + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx: COOL.LessEqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx: COOL.MethodCallContext): + return self.visitChildren(ctx) diff --git a/src/Visitors.py b/src/Visitors.py new file mode 100644 index 00000000..0bcd390c --- /dev/null +++ b/src/Visitors.py @@ -0,0 +1,3135 @@ +from collections import deque +from antlr4 import * +from COOL import * +from src import COOLParser + +class COOLClass: + def __init__(self, name: str, parent: str, created: bool, sealed: bool): + self.Name = name + self.Parent = parent + self.Created = created + self.Sealed = sealed + self.Deep = -1 + self.Methods = {} + self.TagMethods = list() + self.Atributes = {} + self.Tag = 0 + self.TagAtributes = list() + self.AtributeAsign = {} + +class COOLMethod: + def __init__(self, name: str, type: str, paramNumber: int, instructionSet): + self.Name = name + self.Type = type + self.Params = list() + self.ParamsNumber= paramNumber + self.InstructionSet = instructionSet + +class COOLScopeManager: + def __init__(self): + self.Stack = deque() + + def addScope(self): + self.Stack.append({}) + + def addIdentifier(self, name: str, type: str): + scope = self.Stack.pop() + scope[name] = type + self.Stack.append(scope) + + def deleteScope(self): + self.Stack.pop() + + def searchScope(self, identifier: str): + scope = self.Stack.pop() + self.Stack.append(scope) + return scope.keys().__contains__(identifier) + + def searchIdentifier(self, identifier: str): + for scope in reversed(self.Stack): + if(scope.keys().__contains__(identifier)): + return True + return False + + def searchforType(self, identifier: str): + for scope in reversed(self.Stack): + if(scope.keys().__contains__(identifier)): + return scope[identifier] + return "None" + +class SemanticCOOLVisitor(ParseTreeVisitor): + + def join(self, class1: str, class2: str): + if class1 == "None" or class2 == "None": + return "None" + if self.TypeTable[class1].Deep == self.TypeTable[class2].Deep: + if self.TypeTable[class1].Name == self.TypeTable[class2].Name: + return class1 + else: + return self.join(self.TypeTable[class1].Parent, self.TypeTable[class2].Parent) + elif self.TypeTable[class1].Deep > self.TypeTable[class2].Deep: + return self.join(self.TypeTable[class1].Parent, class2) + else: + return self.join(class1, self.TypeTable[class2].Parent) + + def calculateDeep(self, coolClass: COOLClass): + if self.TypeTable.keys().__contains__(coolClass.Parent): + if self.TypeTable[coolClass.Parent].Deep != -1: + coolClass.Deep = self.TypeTable[coolClass.Parent].Deep + 1 + else: + self.calculateDeep(self.TypeTable[coolClass.Parent]) + coolClass.Deep = self.TypeTable[coolClass.Parent].Deep + 1 + elif coolClass.Name == "Object": + coolClass.Deep = 0 + else: + coolClass.Deep = 1 + coolClass.Parent = "Object" + + def searchMethod(self, coolClass: str, methodName: str): + if coolClass == "None": + return False + elif self.TypeTable[coolClass].Methods.keys().__contains__(methodName): + return True + else: + return self.searchMethod(self.TypeTable[coolClass].Parent, methodName) + + def searchAtribute(self, coolClass: str, atributeName: str): + if coolClass == "None": + return False + elif self.TypeTable[coolClass].Atributes.keys().__contains__(atributeName): + return True + else: + return self.searchAtribute(self.TypeTable[coolClass].Parent, atributeName) + + def searchMethodInfo(self, coolClass: str, methodName: str): + for method in self.TypeTable[coolClass].Methods.keys(): + if method == methodName: + return self.TypeTable[coolClass].Methods[method] + return self.searchMethodInfo(self.TypeTable[coolClass].Parent, methodName) + + def searchAtributeInfo(self, coolClass: str, atributeName: str): + for atribute in self.TypeTable[coolClass].Atributes.keys(): + if atribute == atributeName: + return self.TypeTable[coolClass].Atributes[atribute] + return self.searchAtributeInfo(self.TypeTable[coolClass].Parent, atributeName) + + + def __init__(self, typeTable: dict): + self.TypeTable = typeTable + self.ScopeManager = COOLScopeManager() + self.actualClass = "Object" + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx:COOL.ProgramContext): + for className in self.TypeTable.keys(): + self.calculateDeep(self.TypeTable[className]) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx:COOL.ClassesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx:COOL.ClassDefineContext): + coolClass = ctx.getChild(1).symbol + if(self.TypeTable[coolClass.text].Created): + line = str(coolClass.line) + column = str(coolClass.column) + error = "(" + line + "," + column + "): this class name already exist" + print(error) + elif ctx.getChild(2).symbol.text == "inherits": + classParent = ctx.getChild(3).symbol + if (self.TypeTable.keys().__contains__(classParent.text)): + if self.TypeTable[classParent.text].Sealed: + line = str(classParent.line) + column = str(classParent.column) + error = "(" + line + "," + column + "): this class is sealed" + print(error) + else: + self.TypeTable[coolClass.text].Created = True + self.TypeTable[coolClass.text].Sealed = False + self.ScopeManager.addScope() + self.ScopeManager.addIdentifier("self", coolClass.text) + self.actualClass = coolClass.text + self.visitChildren(ctx) + self.ScopeManager.deleteScope() + return + else: + line = str(classParent.line) + column = str(classParent.column) + error = "(" + line + "," + column + "): this class doesn't exist" + print(error) + else: + self.TypeTable[coolClass.text].Created = True + self.TypeTable[coolClass.text].Sealed = False + self.ScopeManager.addScope() + self.actualClass = coolClass.text + self.ScopeManager.addIdentifier("self", coolClass.text) + self.visitChildren(ctx) + self.ScopeManager.deleteScope() + return + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx:COOL.MethodContext): + coolClass = ctx.parentCtx.getChild(1).symbol.text + methodName = ctx.getChild(0).symbol.text + methodType = ctx.getChild(len(ctx.children) - 4).symbol + if self.ScopeManager.searchScope(methodName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this method name already exist" + print(error) + elif self.TypeTable.keys().__contains__(self.TypeTable[coolClass].Methods[methodName].Type) or methodType.text == "SELF_TYPE": + self.ScopeManager.addIdentifier(methodName, methodType.text) + self.ScopeManager.addScope() + self.visitChildren(ctx) + self.ScopeManager.deleteScope() + return + else: + line = str(methodType.line) + column = str(methodType.column) + error = "(" + line + "," + column + "): this type doesn't exist" + print(error) + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx:COOL.PropertyContext): + atributeType = ctx.getChild(2).symbol.text + atributeName = ctx.getChild(0).symbol.text + if self.ScopeManager.searchScope(atributeName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this atribute name already exist" + print(error) + return "None" + elif not(self.TypeTable.keys().__contains__(atributeType) or atributeType == "SELF_TYPE"): + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column) + error = "(" + line + "," + column + "): this type doesn't exist" + print(error) + return "None" + elif len(ctx.children) == 5: + atributeValue = ctx.getChild(4).accept(self) + if self.join(atributeType, atributeValue) != atributeType: + line = str(ctx.getChild(4).start.line) + column = str(ctx.getChild(4).start.column) + error = "(" + line + "," + column + "): the type of the expression is diferent of the type of the atribute" + print(error) + return "None" + else: + self.ScopeManager.addIdentifier(atributeName, atributeType) + return atributeType + else: + self.ScopeManager.addIdentifier(atributeName, atributeType) + return atributeType + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx:COOL.FormalContext): + paramName = ctx.getChild(0).symbol.text + paramType = ctx.getChild(2).symbol.text + if self.ScopeManager.searchScope(paramName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this param name already exist" + print(error) + elif self.TypeTable.keys().__contains__(paramType): + self.ScopeManager.addIdentifier(paramName, paramType) + return self.visitChildren(ctx) + else: + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column) + error = "(" + line + "," + column + "): this type doesn't exist" + print(error) + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx: COOL.IntContext): + return "Int" + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx: COOL.StringContext): + return "String" + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx: COOL.FalseContext): + return "Bool" + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx: COOL.TrueContext): + return "Bool" + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx: COOL.AddContext): + addValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + addValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + addValue = "None" + return addValue + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx:COOL.MinusContext): + minusValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + minusValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + minusValue = "None" + return minusValue + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx: COOL.MultiplyContext): + mulValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + mulValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + mulValue = "None" + return mulValue + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx: COOL.DivisionContext): + divValue = "Int" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + divValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + divValue = "None" + return divValue + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx: COOL.NegativeContext): + expressValue = ctx.getChild(1).accept(self) + if expressValue == "Int": + return "Int" + return "None" + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx:COOL.IsvoidContext): + self.visitChildren(ctx) + return "Bool" + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx: COOL.BoolNotContext): + expressValue = ctx.getChild(1).accept(self) + if expressValue == "Bool": + return "Bool" + return "None" + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx:COOL.LessThanContext): + lessValue = "Bool" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessValue = "None" + return lessValue + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx:COOL.LessEqualContext): + lessEqualValue = "Bool" + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue != "Int": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessEqualValue = "None" + if rightValue != "Int": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is not integer" + print(error) + lessEqualValue = "None" + return lessEqualValue + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx: COOL.EqualContext): + leftValue = ctx.getChild(0).accept(self) + rightValue = ctx.getChild(2).accept(self) + if leftValue == "None" or rightValue == "None": + return "None" + if leftValue == rightValue: + return "Bool" + if leftValue == "String" or leftValue == "Int" or leftValue == "Bool": + line = str(ctx.getChild(0).start.line) + column = str(ctx.getChild(0).start.column) + error = "(" + line + "," + column + "): the type of the expression is incorrect" + print(error) + return "None" + if rightValue == "String" or rightValue == "Int" or rightValue == "Bool": + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is incorrect" + print(error) + return "None" + return "Bool" + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx: COOL.AssignmentContext): + variableName = ctx.getChild(0).symbol.text + asignValue = ctx.getChild(2).accept(self) + variableType = self.ScopeManager.searchforType(variableName) + if variableType == "None": + if self.searchAtribute(self.actualClass, variableName): + variableType = self.searchAtributeInfo(self.actualClass, variableName) + else: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this identifier does not exist" + print(error) + return "None" + if variableType == "SELF_TYPE": + variableType = self.actualClass + if self.join(asignValue, variableType) != variableType: + line = str(ctx.getChild(2).start.line) + column = str(ctx.getChild(2).start.column) + error = "(" + line + "," + column + "): the type of the expression is diferent that the identifier" + print(error) + return "None" + return variableType + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx: COOL.ParenthesesContext): + return ctx.getChild(1).accept(self) + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx: COOL.IdContext): + IdValue = ctx.getChild(0).symbol.text + if self.ScopeManager.searchIdentifier(IdValue): + return self.ScopeManager.searchforType(IdValue) + elif self.searchAtribute(self.actualClass, IdValue): + return self.searchAtributeInfo(self.actualClass, IdValue) + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this identifier does not exist" + print(error) + return "None" + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx:COOL.IfContext): + ifValue = ctx.getChild(1).accept(self) + thenValue = ctx.getChild(3).accept(self) + elseValue = ctx.getChild(5).accept(self) + if ifValue == "None" or ifValue == "Bool": + return self.join(thenValue, elseValue) + else: + line = str(ctx.getChild(1).start.line) + column = str(ctx.getChild(1).start.column) + error = "(" + line + "," + column + "): this expression is not boolean" + print(error) + return self.join(thenValue, elseValue) + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx: COOL.WhileContext): + whileValue = ctx.getChild(3).accept(self) + whileValue = ctx.getChild(1).accept(self) + if whileValue == "None" or whileValue == "Bool": + return "Object" + else: + line = str(ctx.getChild(1).start.line) + column = str(ctx.getChild(1).start.column) + error = "(" + line + "," + column + "): this expression is not boolean" + print(error) + return "Object" + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx:COOL.BlockContext): + blockValue = "None" + count = 1 + lengt = len(ctx.children) - 1 + while lengt > count: + blockValue = ctx.getChild(count).accept(self) + count = count + 2 + return blockValue + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx:COOL.CaseContext): + ctx.getChild(1).accept(self) + lengt = len(ctx.children) - 1 + count = 3 + caseValue = "None" + while lengt > count: + idName = ctx.getChild(count).symbol.text + count = count + 2 + idType = ctx.getChild(count).symbol.text + count = count + 2 + self.ScopeManager.addScope() + self.ScopeManager.addIdentifier(idName, idType) + if (caseValue == "None"): + caseValue = ctx.getChild(count).accept(self) + else: + caseValue = self.join(caseValue, ctx.getChild(count).accept(self)) + count = count + 2 + self.ScopeManager.deleteScope() + return caseValue + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx: COOL.NewContext): + return ctx.getChild(1).symbol.text + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): + methodType = "None" + if self.searchMethod(self.actualClass, ctx.getChild(0).symbol.text): + methodInfo = self.searchMethodInfo(self.actualClass, ctx.getChild(0).symbol.text) + if(methodInfo.Type == "SELF_TYPE"): + methodType = self.actualClass + else: + methodType = methodInfo.Type + if methodInfo.ParamsNumber == 0 and len(ctx.children) != 3: + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + elif len(ctx.children) != methodInfo.ParamsNumber * 2 + 2 and methodInfo.ParamsNumber != 0: + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + else: + count = 2 + for param in methodInfo.Params: + (_,paramType) = param + requestType = ctx.getChild(count).accept(self) + if (self.join(requestType, paramType) != paramType): + line = str(ctx.getChild(count).start.line) + column = str(ctx.getChild(count).start.column) + error = "(" + line + "," + column + "): the type of this param in the call is incorrect" + print(error) + methodType = "None" + count = count + 2 + else: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column) + error = "(" + line + "," + column + "): this method not exist in " + self.actualClass + print(error) + return methodType + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx:COOL.MethodCallContext): + methodType = "None" + length = 5 + currentClass = ctx.getChild(0).accept(self) + if (ctx.getChild(1).symbol.text == "@"): + length = length + 2 + parent = ctx.getChild(2).symbol.text + if self.join(currentClass, parent) == parent: + currentClass = parent + else: + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column) + error = "(" + line + "," + column + "): this class is not parent of " + currentClass + print(error) + return methodType + if self.searchMethod(currentClass, ctx.getChild(length - 3).symbol.text): + methodInfo = self.searchMethodInfo(currentClass, ctx.getChild(length - 3).symbol.text) + if (methodInfo.Type == "SELF_TYPE"): + methodType = currentClass + else: + methodType = methodInfo.Type + if (methodInfo.ParamsNumber == 0 and len(ctx.children) != length): + line = str(ctx.getChild(length - 3).start.line) + column = str(ctx.getChild(length - 3).start.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + elif (len(ctx.children) != methodInfo.ParamsNumber * 2 + length - 1) and methodInfo.ParamsNumber > 0: + line = str(ctx.getChild(length - 3).start.line) + column = str(ctx.getChild(length - 3).start.column) + error = "(" + line + "," + column + "): the number of params in the call is incorrect" + print(error) + methodType = "None" + else: + count = length - 1 + for param in methodInfo.Params: + (_, paramType) = param + requestType = ctx.getChild(count).accept(self) + if (self.join(requestType, paramType) != paramType): + line = str(ctx.getChild(count).start.line) + column = str(ctx.getChild(count).start.column) + error = "(" + line + "," + column + "): the type of this param in the call is incorrect" + print(error) + methodType = "None" + count = count + 2 + else: + line = str(ctx.getChild(length - 3).symbol.line) + column = str(ctx.getChild(length - 3).symbol.column) + error = "(" + line + "," + column + "): this method not exist in " + currentClass + print(error) + return methodType + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx: COOL.LetInContext): + self.ScopeManager.addScope() + count = 0 + while(ctx.getChild(count).symbol.text != "in"): + idName = ctx.getChild(count + 1).symbol.text + count = count + 2 + idType = ctx.getChild(count + 1).symbol.text + if not(self.TypeTable.keys().__contains__(idType)) and idType != "SELF_TYPE": + self.ScopeManager.deleteScope() + line = str(ctx.getChild(count + 1).symbol.line) + column = str(ctx.getChild(count + 1).symbol.column) + error = "(" + line + "," + column + "): this class does not exist " + print(error) + return "None" + self.ScopeManager.addIdentifier(idName, idType) + count = count + 2 + if ctx.getChild(count).symbol.text == "<-": + idValue = ctx.getChild(count + 1).accept(self) + count = count + 2 + if self.join(idType, idValue) != idType: + self.ScopeManager.deleteScope() + line = str(ctx.getChild(count -1).start.line) + column = str(ctx.getChild(count - 1).start.column) + error = "(" + line + "," + column + "): the type of the expression is diferent of the type of the identifier" + print(error) + return "None" + + return ctx.getChild(count + 1).accept(self) + +class TypeCOOLVisitor(ParseTreeVisitor): + + TypeTable = {} + + Counter = 0 + + ConstantTable = list() + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx: COOL.ProgramContext, fileName: str): + self.TypeTable["Object"] = COOLClass("Object", "None", True, False) + self.TypeTable["Object"].Methods["abort"] = COOLMethod("abort", "Object", 0, None) + self.TypeTable["Object"].Methods["type_name"] = COOLMethod("type_name", "String", 0, None) + self.TypeTable["Object"].Methods["copy"] = COOLMethod("copy", "SELF_TYPE", 0, None) + self.TypeTable["String"] = COOLClass("String", "Object", True, True) + self.TypeTable["String"].Methods["length"] = COOLMethod("length", "Int", 0, None) + self.TypeTable["String"].Methods["concat"] = COOLMethod("concat", "String", 1, None) + self.TypeTable["String"].Methods["concat"].Params.append(("s", "String")) + self.TypeTable["String"].Methods["substr"] = COOLMethod("substr", "String", 2, None) + self.TypeTable["String"].Methods["substr"].Params.append(("i", "Int")) + self.TypeTable["String"].Methods["substr"].Params.append(("l", "Int")) + self.TypeTable["Int"] = COOLClass("Int", "Object", True, True) + self.TypeTable["Bool"] = COOLClass("Bool", "Object", True, True) + self.TypeTable["IO"] = COOLClass("IO", "Object", True, False) + self.TypeTable["IO"].Methods["in_string"] = COOLMethod("in_string", "String", 0, None) + self.TypeTable["IO"].Methods["in_int"] = COOLMethod("in_int", "Int", 0, None) + self.TypeTable["IO"].Methods["out_string"] = COOLMethod("out_string", "SELF_TYPE", 1, None) + self.TypeTable["IO"].Methods["out_string"].Params.append(("x", "String")) + self.TypeTable["IO"].Methods["out_int"] = COOLMethod("out_int", "SELF_TYPE", 1, None) + self.TypeTable["IO"].Methods["out_int"].Params.append(("x", "Int")) + self.ConstantTable.append(("", "String", "str_const0")) + self.ConstantTable.append((0, "Int", "int_const0")) + self.ConstantTable.append(("false", "Bool", "bool_const0")) + self.ConstantTable.append((fileName, "String", "str_const1")) + self.ConstantTable.append((len(fileName), "Int", F"int_const{len(fileName)}")) + self.Counter = 2 + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx: COOL.ClassesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx: COOL.ClassDefineContext): + coolClass = ctx.getChild(1).symbol + if self.TypeTable.keys().__contains__(coolClass.text): + return + if ctx.getChild(2).symbol.text == "inherits": + classParent = ctx.getChild(3).symbol + self.TypeTable[coolClass.text] = COOLClass(coolClass.text, classParent.text, False, False) + return self.visitChildren(ctx) + else: + self.TypeTable[coolClass.text] = COOLClass(coolClass.text, "Object", False, False) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx: COOL.MethodContext): + name = ctx.getChild(0).symbol.text + cclass = ctx.parentCtx.getChild(1).symbol.text + if self.TypeTable[cclass].Methods.keys().__contains__(name): + return + n = len(ctx.children) - 4 + if ctx.getChild(n).symbol.text == ":": + n = n + 1 + type = ctx.getChild(n).symbol.text + lengt = len(ctx.children) - 8 + paramsNumber = 0 + if lengt > 0: + paramsNumber = 1 + while lengt > 1: + lengt = lengt - 2 + paramsNumber = paramsNumber + 1 + self.TypeTable[cclass].Methods[name] = COOLMethod(name, type, paramsNumber, ctx.getChild(len(ctx.children) - 2)) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx: COOL.PropertyContext): + cclass = ctx.parentCtx.getChild(1).symbol.text + name = ctx.getChild(0).symbol.text + if self.TypeTable[cclass].Atributes.keys().__contains__(name): + return + type = ctx.getChild(2).symbol.text + self.TypeTable[cclass].Atributes[name] = type + if len(ctx.children) == 5: + self.TypeTable[cclass].AtributeAsign[name] = ctx.getChild(4) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx: COOL.FormalContext): + parent = ctx.parentCtx + + className = parent.parentCtx.getChild(1).symbol.text + methodName = parent.getChild(0).symbol.text + method = self.TypeTable[className].Methods[methodName] + for param in method.Params: + (paramName, paramType) = param + if (paramName == ctx.getChild(0).symbol.text): + return + method.Params.append((ctx.getChild(0).symbol.text, ctx.getChild(2).symbol.text)) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx: COOL.LetInContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx: COOL.MinusContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx: COOL.StringContext): + constantName = ctx.getChild(0).symbol.text[1:-1] + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == constantName and consType == "String": + return self.visitChildren(ctx) + + self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) + self.Counter = self.Counter + 1 + length = len(constantName) + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == length and consType == "Int": + return self.visitChildren(ctx) + self.ConstantTable.append((length, "Int", f"int_const{length}")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx: COOL.IsvoidContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx: COOL.WhileContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx: COOL.DivisionContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx: COOL.NegativeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx: COOL.BoolNotContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx: COOL.LessThanContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx: COOL.BlockContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx: COOL.IdContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx: COOL.MultiplyContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx: COOL.IfContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx: COOL.CaseContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx: COOL.AddContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx: COOL.NewContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx: COOL.ParenthesesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx: COOL.AssignmentContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx: COOL.FalseContext): + for cons in self.ConstantTable: + (consName, consType, _) = cons + if consName == "false" and consType == "Bool": + return self.visitChildren(ctx) + + self.ConstantTable.append(("false", "Bool", "bool_const0")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx: COOL.IntContext): + constantName = int(ctx.getChild(0).symbol.text) + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == constantName and consType == "Int": + return self.visitChildren(ctx) + + self.ConstantTable.append((constantName, "Int", f"int_const{constantName}")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx: COOL.EqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx: COOL.TrueContext): + for cons in self.ConstantTable: + (consName, consType,_) = cons + if consName == "true" and consType == "Bool": + return self.visitChildren(ctx) + + self.ConstantTable.append(("true", "Bool","bool_const1")) + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx: COOL.LessEqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx: COOL.MethodCallContext): + return self.visitChildren(ctx) + +class CodegenVisitor(ParseTreeVisitor): + + CurrentClass : COOLClass + + def __init__(self, typeTable: dict, constantTable: list, counter: int): + self.TypeTable = typeTable + self.ConstantTable = constantTable + self.Counter = counter + self.LabelCounter = 0 + + def genGlobalClases(self): + sol = "\t.data\n\t.align 2\n\t.globl class_nameTab\n" + for clasName in self.TypeTable.keys(): + protoName = "\t.globl " + clasName + "_protObj\n" + sol = sol + protoName + sol = sol + "_string_tag:\n\t.word 1\n_int_tag:\n\t.word 2\n_bool_tag :\n\t.word 3\n" + return sol + + def genConstant(self, sol: str): + for const in self.ConstantTable: + (constName, constType, constLabel) = const + if constType == "Bool": + sol = sol + \ + f"\t.word -1\n" \ + f"{constLabel}:\n" \ + f"\t.word 5\n" \ + f"\t.word 4\n" \ + f"\t.word Bool_dispTab\n" \ + f"\t.word {constLabel[-1]}\n" + elif constType == "Int": + sol = sol + \ + f"\t.word -1\n{constLabel}:\n" \ + f"\t.word 3\n\t.word 4\n" \ + f"\t.word Int_dispTab\n" \ + f"\t.word {constName}\n" + else: + length = int(len(constName) / 4) + 3 + if len(constName) % 4 != 0: + length = length + 1 + sol = sol + \ + f"\t.word -1\n{constLabel}:\n" \ + f"\t.word 4\n\t.word {length}\n" \ + f"\t.word String_dispTab\n" \ + f"\t.word int_const{len(constName)}\n" \ + f"\t.ascii \"{constName}\"\n" \ + f"\t.byte 0\n" \ + f"\t.align 2\n" + return sol + + def findLabel(self, name: str): + for const in self.ConstantTable: + (constName, constType, constLabel) = const + if constName == name and constType == "String": + return constLabel + + def genMethodNames(self, coolClass: str, coolMethods: list, className: str): + if coolClass == "None": + return "" + temp = "" + methodList = list() + for method in self.TypeTable[coolClass].Methods: + if not (coolMethods.__contains__(method)): + temp = temp + f"\t.word {coolClass}.{method}\n" + methodList.append(method) + coolMethods.append(method) + + code = self.genMethodNames(self.TypeTable[coolClass].Parent, coolMethods, className) + if coolClass != "Object": + self.TypeTable[coolClass].TagMethods = self.TypeTable[self.TypeTable[coolClass].Parent].TagMethods + methodList + else: + self.TypeTable[coolClass].TagMethods = methodList + return code + temp + + + + def genAtributeNames(self, coolClass: str, coolAtributes: list): + if coolClass == "None": + return "" + temp = "" + listAtributes = list() + for atribute in self.TypeTable[coolClass].Atributes: + if not (coolAtributes.__contains__(atribute)): + listAtributes.append(atribute) + value = self.TypeTable[coolClass].Atributes[atribute] + if value == "Int" or value == "String" or value == "Bool": + temp = temp + f"\t.word {value.lower()}_constant0\n" + else: + temp = temp + f"\t.word 0\n" + coolAtributes.append(atribute) + + code = self.genAtributeNames(self.TypeTable[coolClass].Parent, coolAtributes) + if coolClass != "Object": + self.TypeTable[coolClass].TagAtributes = self.TypeTable[self.TypeTable[coolClass].Parent].TagAtributes + listAtributes + return code + temp + + def genClassTable(self): + classNameTab = "class_nameTab:\n" + class_objTab = "class_objTab:\n" + methods = "" + atributes = "" + counter = 0 + for className in self.TypeTable: + classNameTab = classNameTab + f"\t.word {self.findLabel(className)}\n" + temp = self.genMethodNames(className, list(), className) + class_objTab = class_objTab + \ + f"\t.word {className}_protObj\n" \ + f"\t.word {className}_init\n" + methods = methods + f"{className}_dispTab:\n" + temp + if className == "Int" or className == "Bool": + atributes = atributes + \ + f"\t.word -1\n" \ + f"{className}_protObj:\n" \ + f"\t.word {counter}\n" \ + f"\t.word 4\n" \ + f"\t.word {className}_dispTab\n" \ + f"\t.word 0\n" + elif className == "String": + atributes = atributes + \ + f"\t.word -1\n" \ + f"{className}_protObj:\n" \ + f"\t.word {counter}\n" \ + f"\t.word 5\n" \ + f"\t.word {className}_dispTab\n" \ + f"\t.word int_constant0\n" \ + f"\t.word 0\n" + else: + atributeList = list() + temp = self.genAtributeNames(className, atributeList) + atributes = atributes + \ + f"\t.word -1\n" \ + f"{className}_protObj:\n" \ + f"\t.word {counter}\n" \ + f"\t.word {len(atributeList) + 3}\n" \ + f"\t.word {className}_dispTab\n" \ + f"" + temp + self.TypeTable[className].Tag = counter + counter = counter + 1 + return classNameTab + class_objTab + methods + atributes + + def genClassAtributes(self, className: str): + if className == "None": + return "" + code = self.genClassAtributes(self.TypeTable[className].Parent) + for atribute in self.TypeTable[className].AtributeAsign: + code = code + (self.TypeTable[className].AtributeAsign[atribute].accept(self) or "") + return code + + # Visit a parse tree produced by COOL#program. + def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): + for className in self.TypeTable: + constantName = className + self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) + self.Counter = self.Counter + 1 + length = len(constantName) + contain = True + for cons in self.ConstantTable: + (consName, consType, _) = cons + if consName == length and consType == "Int": + contain = False + if contain: + self.ConstantTable.append((length, "Int", f"int_const{length}")) + self.ConstantTable.append(("SELF_TYPE", "String", f"str_const{self.Counter}")) + contain = True + length = len("SELF_TYPE") + for cons in self.ConstantTable: + (consName, consType, _) = cons + if consName == length and consType == "Int": + contain = False + if contain: + self.ConstantTable.append((length, "Int", f"int_const{length}")) + code = self.genGlobalClases() + code = self.genConstant(code) + code = code + self.genClassTable() + code = code + \ + "\t.globl heap_start\n" \ + "heap_start:\n" \ + "\t.word 0\n" \ + "\t.text\n" \ + "\t.globl Main_init\n" \ + "\t.globl Int_init\n" \ + "\t.globl String_init\n" \ + "\t.globl Bool_init\n" \ + "\t.globl Main.main\n" + for className in self.TypeTable: + code = code + f"{className}_init:\n" + temp = self.genClassAtributes(className) + if len(temp) != 0: + code = code + \ + "\taddiu $sp $sp -12\n" \ + "\tsw $fp 12($sp)\n" \ + "\tsw $s0 8($sp)\n" \ + "\tsw $ra 4($sp)\n" \ + "\taddiu $fp $sp 4\n" \ + "\tmove $s0 $a0\n" + code = code + temp + code = code + \ + "\tmove $a0 $s0\n" \ + "\tlw $fp 12($sp)\n" \ + "\tlw $s0 8($sp)\n" \ + "\tlw $ra 4($sp)\n" \ + "\taddiu $sp $sp 12\n" + code = code + "\tjr $ra\n" + for className in self.TypeTable: + if not(className == "Object" or className == "String" or className == "Int" or className == "Bool" or className == "IO"): + self.CurrentClass = self.TypeTable[className] + for methodName in self.TypeTable[className].Methods: + code = code + f"{className}.{methodName}:\n" + code = code + \ + "\taddiu $sp $sp -12\n" \ + "\tsw $fp 12($sp)\n" \ + "\tsw $s0 8($sp)\n" \ + "\tsw $ra 4($sp)\n" \ + "\taddiu $fp $sp 4\n" \ + "\tmove $s0 $a0\n" + code = code + (self.TypeTable[className].Methods[methodName].InstructionSet.accept(self) or "") + code = code + \ + "\tmove $a0 $s0\n" \ + "\tlw $fp 12($sp)\n" \ + "\tlw $s0 8($sp)\n" \ + "\tlw $ra 4($sp)\n" \ + "\taddiu $sp $sp 12\n" + code = code + "\tjr $ra\n" + + code = self.RuntimeMessages + \ + "\n" + \ + self.MemManagerNoGCInit + \ + "\n" + \ + code + \ + "\n" + \ + self.RuntimeCode + \ + "\n" + \ + self.MemManagerNoGC + + outFile = open(outFilename, "w"); + outFile.write(code) + #print(code) + + return + + # Visit a parse tree produced by COOL#classes. + def visitClasses(self, ctx: COOL.ClassesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#classDefine. + def visitClassDefine(self, ctx: COOL.ClassDefineContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#method. + def visitMethod(self, ctx: COOL.MethodContext): + return "" + + # Visit a parse tree produced by COOL#property. + def visitProperty(self, ctx: COOL.PropertyContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#formal. + def visitFormal(self, ctx: COOL.FormalContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#letIn. + def visitLetIn(self, ctx: COOL.LetInContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#minus. + def visitMinus(self, ctx: COOL.MinusContext): + code = ctx.getChild(0).accept(self) + code = code + \ + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy\n" + \ + "\tlw $t1 4($sp)\n" + \ + "\tlw $t1 12($t1)\n" + \ + "\tlw $t2 12($a0)\n" + \ + "\tsub $t1 $t1 $t2\n" + \ + "\tsw $t1 12($a0)\n" + \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#string. + def visitString(self, ctx: COOL.StringContext): + name = ctx.getChild(0).symbol.text[1:-1] + for const in self.ConstantTable: + (constName, constType, constTag) = const + if constType == "String" and constName == name: + return f"\tla $a0 {constTag}\n" + + # Visit a parse tree produced by COOL#isvoid. + def visitIsvoid(self, ctx: COOL.IsvoidContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#while. + def visitWhile(self, ctx: COOL.WhileContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#division. + def visitDivision(self, ctx: COOL.DivisionContext): + code = ctx.getChild(0).accept(self) + code += \ + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code += ctx.getChild(2).accept(self) + code += \ + "\tjal Object.copy\n" \ + "\tlw $t1 4($sp)\n" \ + "\tlw $t1 12($t1)\n" \ + "\tlw $t2 12($a0)\n" \ + "\tdiv $t1 $t2\n" \ + "\tmflo $t1\n" \ + "\tsw $t1 12($a0)\n" \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#negative. + def visitNegative(self, ctx: COOL.NegativeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#boolNot. + def visitBoolNot(self, ctx: COOL.BoolNotContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#lessThan. + def visitLessThan(self, ctx: COOL.LessThanContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#block. + def visitBlock(self, ctx: COOL.BlockContext): + counter = 1 + length = len(ctx.children) - 1 + code = "" + while(counter < length ): + code += (ctx.getChild(counter).accept(self)) + counter += 2 + return code + + # Visit a parse tree produced by COOL#id. + def visitId(self, ctx: COOL.IdContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#multiply. + def visitMultiply(self, ctx: COOL.MultiplyContext): + code = ctx.getChild(0).accept(self) + code = code + \ + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy\n" + \ + "\tlw $t1 4($sp)\n" + \ + "\tlw $t1 12($t1)\n" + \ + "\tlw $t2 12($a0)\n" + \ + "\tmul $t1 $t1 $t2\n" + \ + "\tsw $t1 12($a0)\n" + \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#if. + def visitIf(self, ctx: COOL.IfContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#case. + def visitCase(self, ctx: COOL.CaseContext): + return "" + + # Visit a parse tree produced by COOL#ownMethodCall. + def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): + length = len(ctx.children) + code = "" + if length > 3: + count = 2 + while length != count: + param = (ctx.getChild(count).accept(self) or "") + code += param + \ + f"\tsw $a0 0($sp)\n" \ + f"\taddiu $sp $sp -4\n" + count = count + 2 + methodIdx = self.CurrentClass.TagMethods.index(ctx.getChild(0).symbol.text) + code += "\tmove $a0 $s0\n" \ + "\tlw $t1 8($a0)\n" \ + f"\tlw $t1 {methodIdx * 4}($t1)\n" \ + "\tjalr $t1\n" + return code + + # Visit a parse tree produced by COOL#add. + def visitAdd(self, ctx: COOL.AddContext): + code = ctx.getChild(0).accept(self) or "" + code = code + \ + "\tsw $a0 0 ($sp)\n"+ \ + "\taddiu $sp $sp -4\n" + code = code + ctx.getChild(2).accept(self) + code = code + \ + "\tjal Object.copy\n"+ \ + "\tlw $t1 4($sp)\n"+ \ + "\tlw $t1 12($t1)\n"+ \ + "\tlw $t2 12($a0)\n"+ \ + "\tadd $t1 $t1 $t2\n"+ \ + "\tsw $t1 12($a0)\n"+ \ + "\taddiu $sp $sp 4\n" + return code + + # Visit a parse tree produced by COOL#new. + def visitNew(self, ctx: COOL.NewContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#parentheses. + def visitParentheses(self, ctx: COOL.ParenthesesContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#assignment. + def visitAssignment(self, ctx: COOL.AssignmentContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#false. + def visitFalse(self, ctx: COOL.FalseContext): + return f"\tla $a0 {bool_const0}\n" + + # Visit a parse tree produced by COOL#int. + def visitInt(self, ctx: COOL.IntContext): + val = int(ctx.getChild(0).symbol.text) + for const in self.ConstantTable: + (constVal, constType, constTag) = const + if constType == "Int" and constVal == val: + return f"\tla $a0 {constTag}\n" + + # Visit a parse tree produced by COOL#equal. + def visitEqual(self, ctx: COOL.EqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#true. + def visitTrue(self, ctx: COOL.TrueContext): + return f"\tla $a0 {bool_const1}\n" + + # Visit a parse tree produced by COOL#lessEqual. + def visitLessEqual(self, ctx: COOL.LessEqualContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by COOL#methodCall. + def visitMethodCall(self, ctx: COOL.MethodCallContext): + # line = ctx.getChild(1).symbol.line + # f"\tbne $t2 $zero label{self.LabelCounter}\n" \ + # "\tla $a0 str_const1\n" \ + # f"\tli $t1 {line}\n" \ + # "\tjal _dispatch_abort\n" \ + # f"label{self.LabelCounter}:\n" \ + # self.LabelCounter += 1 + return "" + + RuntimeMessages = """ +# +# Messages for the Runtime +# + .data + +_abort_msg: .asciiz "Abort called from class " +_colon_msg: .asciiz ":" +_dispatch_msg: .asciiz ": Dispatch to void.\\n" +_cabort_msg: .asciiz "No match in case statement for Class " +_cabort_msg2: .asciiz "Match on void in case statement.\\n" +_nl: .asciiz "\\n" +_term_msg: .asciiz "\nCOOL program successfully executed\\n" +_sabort_msg1: .asciiz "Index to substr is negative\\n" +_sabort_msg2: .asciiz "Index to substr is too big\\n" +_sabort_msg3: .asciiz "Length to substr too long\\n" +_sabort_msg4: .asciiz "Length to substr is negative\\n" +_sabort_msg: .asciiz "Execution aborted.\\n" +_objcopy_msg: .asciiz "Object.copy: Invalid object size.\\n" +_gc_abort_msg: .asciiz "GC bug!\\n" + +# +# Messages for the GenGC garabge collector +# + +_GenGC_INITERROR: .asciiz "GenGC: Unable to initialize the garbage collector.\\n" +_GenGC_COLLECT: .asciiz "Garbage collecting ...\\n" +_GenGC_Major: .asciiz "Major ...\\n" +_GenGC_Minor: .asciiz "Minor ...\\n" +#_GenGC_COLLECT: .asciiz "" +_GenGC_MINORERROR: .asciiz "GenGC: Error during minor garbage collection.\\n" +_GenGC_MAJORERROR: .asciiz "GenGC: Error during major garbage collection.\\n" + +# +# Messages for the NoGC garabge collector +# + +_NoGC_COLLECT: .asciiz "Increasing heap...\\n" +#_NoGC_COLLECT: .asciiz "" +""" + + MemManagerNoGCInit = """ + .data + .align 2 + + .globl _MemMgr_INITIALIZER +_MemMgr_INITIALIZER: + .word _NoGC_Init + .globl _MemMgr_COLLECTOR +_MemMgr_COLLECTOR: + .word _NoGC_Collect + .globl _MemMgr_TEST +_MemMgr_TEST: + .word 0 +""" + + MemManagerGenGCInit = """ + .data + .align 2 + + .globl _MemMgr_INITIALIZER + _MemMgr_INITIALIZER: + .word _GenGC_Init + .globl _MemMgr_COLLECTOR + _MemMgr_COLLECTOR: + .word _GenGC_Collect + .globl _MemMgr_TEST + _MemMgr_TEST: + .word 0 + """ + + RuntimeCode = """ +# +# Define some constants +# + +obj_eyecatch=-4 # Unique id to verify any object +obj_tag=0 +obj_size=4 +obj_disp=8 +obj_attr=12 +int_slot=12 +bool_slot=12 +str_size=12 # This is a pointer to an Int object!!! +str_field=16 # The beginning of the ascii sequence +str_maxsize=1026 # the maximum string length + +# +# The REG mask tells the garbage collector which register(s) it +# should automatically update on a garbage collection. Note that +# this is (ANDed) with the ARU mask before the garbage collector +# reads it. Only the registers specified in the garbage collector's +# ARU mask can be automatically updated. +# +# BITS---------------------------- +# 3 2 1 0 +# 10987654321098765432109876543210 +# -------------------------------- +# +# 00000000011111110000000000000000 <- initial Register (REG) mask +# +--++--++--++--++--++--++--++--+ $s0-$s6 +# 0 0 7 F 0 0 0 0 ($16-$22) +# + +MemMgr_REG_MASK=0x007F0000 + + .text + .globl main +main: + li $v0 9 + move $a0 $zero + syscall # sbrk + move $a0 $sp # initialize the garbage collector + li $a1 MemMgr_REG_MASK + move $a2 $v0 + jal _MemMgr_Init # sets $gp and $s7 (limit) + la $a0 Main_protObj # create the Main object + jal Object.copy # Call copy + addiu $sp $sp -4 + sw $a0 4($sp) # save the Main object on the stack + move $s0 $a0 # set $s0 to point to self + jal Main_init # initialize the Main object + jal Main.main # Invoke main method + addiu $sp $sp 4 # restore the stack + la $a0 _term_msg # show terminal message + li $v0 4 + syscall + li $v0 10 + syscall # syscall 10 (exit) + +# +# Polymorphic equality testing function: +# Two objects are equal if they are +# - identical (pointer equality, inlined in code) +# - have same tag and are of type BOOL,STRING,INT and contain the +# same data +# +# INPUT: The two objects are passed in $t1 and $t2 +# OUTPUT: Initial value of $a0, if the objects are equal +# Initial value of $a1, otherwise +# +# The tags for Int,Bool,String are found in the global locations +# _int_tag, _bool_tag, _string_tag, which are initialized by the +# data part of the generated code. This removes a consistency problem +# between this file and the generated code. +# + + .globl equality_test +equality_test: # ops in $t1 $t2 + # true in A0, false in A1 + # assume $t1, $t2 are not equal + beq $t1 $zero _eq_false # $t2 can't also be void + beq $t2 $zero _eq_false # $t1 can't also be void + lw $v0 obj_tag($t1) # get tags + lw $v1 obj_tag($t2) + bne $v1 $v0 _eq_false # compare tags + lw $a2 _int_tag # load int tag + beq $v1 $a2 _eq_int # Integers + lw $a2 _bool_tag # load bool tag + beq $v1 $a2 _eq_int # Booleans + lw $a2 _string_tag # load string tag + bne $v1 $a2 _eq_false # Not a primitive type +_eq_str: # handle strings + lw $v0, str_size($t1) # get string size objs + lw $v1, str_size($t2) + lw $v0, int_slot($v0) # get string sizes + lw $v1, int_slot($v1) + bne $v1 $v0 _eq_false + beqz $v1 _eq_true # 0 length strings are equal + add $t1 str_field # Point to start of string + add $t2 str_field + move $t0 $v0 # Keep string length as counter +_eq_l1: + lbu $v0,0($t1) # get char + add $t1 1 + lbu $v1,0($t2) + add $t2 1 + bne $v1 $v0 _eq_false + addiu $t0 $t0 -1 # Decrement counter + bnez $t0 _eq_l1 + b _eq_true # end of strings + +_eq_int: # handles booleans and ints + lw $v0,int_slot($t1) # load values + lw $v1,int_slot($t2) + bne $v1 $v0 _eq_false +_eq_true: + jr $ra # return true +_eq_false: + move $a0 $a1 # move false into accumulator + jr $ra + +# +# _dispatch_abort +# +# filename in $a0 +# line number in $t1 +# +# Prints error message and exits. +# Called on dispatch to void. +# + .globl _dispatch_abort +_dispatch_abort: + sw $t1 0($sp) # save line number + addiu $sp $sp -4 + addiu $a0 $a0 str_field # adjust to beginning of string + li $v0 4 + syscall # print file name + la $a0 _colon_msg + li $v0 4 + syscall # print ":" + lw $a0 4($sp) # + li $v0 1 + syscall # print line number + li $v0 4 + la $a0 _dispatch_msg + syscall # print dispatch-to-void message + li $v0 10 + syscall # exit + + +# +# _case_abort2 +# +# filename in $a0 +# line number in $t1 +# +# Prints error message and exits. +# Called on case on void. +# + .globl _case_abort2 +_case_abort2: + sw $t1 0($sp) # save line number + addiu $sp $sp -4 + addiu $a0 $a0 str_field # adjust to beginning of string + li $v0 4 + syscall # print file name + la $a0 _colon_msg + li $v0 4 + syscall # print ":" + lw $a0 4($sp) # + li $v0 1 + syscall # print line number + li $v0 4 + la $a0 _cabort_msg2 + syscall # print case-on-void message + li $v0 10 + syscall # exit + +# +# +# _case_abort +# Is called when a case statement has no match +# +# INPUT: $a0 contains the object on which the case was +# performed +# +# Does not return! +# + .globl _case_abort +_case_abort: # $a0 contains case expression obj. + move $s0 $a0 # save the expression object + la $a0 _cabort_msg + li $v0 4 + syscall # print_str + la $t1 class_nameTab + lw $v0 obj_tag($s0) # Get object tag + sll $v0 $v0 2 # *4 + addu $t1 $t1 $v0 + lw $t1 0($t1) # Load class name string obj. + addiu $a0 $t1 str_field # Adjust to beginning of str + li $v0 4 # print_str + syscall + la $a0 _nl + li $v0 4 # print_str + syscall + li $v0 10 + syscall # Exit + + +# +# Copy method +# +# Copies an object and returns a pointer to a new object in +# the heap. Note that to increase performance, the stack frame +# is not set up unless it is absolutely needed. As a result, +# the frame is setup just before the call to "_MemMgr_Alloc" and +# is destroyed just after it. The increase in performance +# occurs becuase the calls to "_MemMgr_Alloc" happen very +# infrequently when the heap needs to be garbage collected. +# +# INPUT: $a0: object to be copied to free space in heap +# +# OUTPUT: $a0: points to the newly created copy. +# +# Registers modified: +# $t0, $t1, $t2, $v0, $v1, $a0, $a1, $a2, $gp, $s7 +# + + .globl Object.copy +Object.copy: + addiu $sp $sp -8 # create stack frame + sw $ra 8($sp) + sw $a0 4($sp) + + jal _MemMgr_Test # test GC area + + lw $a0 4($sp) # get object size + lw $a0 obj_size($a0) + blez $a0 _objcopy_error # check for invalid size + sll $a0 $a0 2 # convert words to bytes + addiu $a0 $a0 4 # account for eyecatcher + jal _MemMgr_Alloc # allocate storage + addiu $a1 $a0 4 # pointer to new object + + lw $a0 4($sp) # the self object + lw $ra 8($sp) # restore return address + addiu $sp $sp 8 # remove frame + lw $t0 obj_size($a0) # get size of object + sll $t0 $t0 2 # convert words to bytes + b _objcopy_allocated # get on with the copy + +# A faster version of Object.copy, for internal use (does not call +# _MemMgr_Test, and if possible not _MemMgr_Alloc) + +_quick_copy: + lw $t0 obj_size($a0) # get size of object to copy + blez $t0 _objcopy_error # check for invalid size + sll $t0 $t0 2 # convert words to bytes + addiu $t1 $t0 4 # account for eyecatcher + add $gp $gp $t1 # allocate memory + sub $a1 $gp $t0 # pointer to new object + blt $gp $s7 _objcopy_allocated # check allocation +_objcopy_allocate: + sub $gp $a1 4 # restore the original $gp + addiu $sp $sp -8 # frame size + sw $ra 8($sp) # save return address + sw $a0 4($sp) # save self + move $a0 $t1 # put bytes to allocate in $a0 + jal _MemMgr_Alloc # allocate storage + addiu $a1 $a0 4 # pointer to new object + lw $a0 4($sp) # the self object + lw $ra 8($sp) # restore return address + addiu $sp $sp 8 # remove frame + lw $t0 obj_size($a0) # get size of object + sll $t0 $t0 2 # convert words to bytes +_objcopy_allocated: + addiu $t1 $0 -1 + sw $t1 obj_eyecatch($a1) # store eyecatcher + add $t0 $t0 $a0 # find limit of copy + move $t1 $a1 # save source +_objcopy_loop: + lw $v0 0($a0) # copy word + sw $v0 0($t1) + addiu $a0 $a0 4 # update source + addiu $t1 $t1 4 # update destination + bne $a0 $t0 _objcopy_loop # loop +_objcopy_end: + move $a0 $a1 # put new object in $a0 + jr $ra # return +_objcopy_error: + la $a0 _objcopy_msg # show error message + li $v0 4 + syscall + li $v0 10 # exit + syscall + +# +# +# Object.abort +# +# The abort method for the object class (usually inherited by +# all other classes) +# +# INPUT: $a0 contains the object on which abort() was dispatched. +# + + .globl Object.abort +Object.abort: + move $s0 $a0 # save self + li $v0 4 + la $a0 _abort_msg + syscall # print_str + la $t1 class_nameTab + lw $v0 obj_tag($s0) # Get object tag + sll $v0 $v0 2 # *4 + addu $t1 $t1 $v0 + lw $t1 0($t1) # Load class name string obj. + addiu $a0 $t1 str_field # Adjust to beginning of str + li $v0 4 # print_str + syscall + la $a0 _nl + li $v0 4 + syscall # print new line + li $v0 10 + syscall # Exit + +# +# +# Object.type_name +# +# INPUT: $a0 object who's class name is desired +# OUTPUT: $a0 reference to class name string object +# + + .globl Object.type_name +Object.type_name: + la $t1 class_nameTab + lw $v0 obj_tag($a0) # Get object tag + sll $v0 $v0 2 # *4 + addu $t1 $t1 $v0 # index table + lw $a0 0($t1) # Load class name string obj. + jr $ra + +# +# +# IO.out_string +# +# Prints out the contents of a string object argument +# which is on top of the stack. +# +# $a0 is preserved! +# + + .globl IO.out_string +IO.out_string: + addiu $sp $sp -4 + sw $a0 4($sp) # save self + lw $a0 8($sp) # get arg + addiu $a0 $a0 str_field # Adjust to beginning of str + li $v0 4 # print_str + syscall + lw $a0 4($sp) # return self + addiu $sp $sp 8 # pop argument + jr $ra + +# +# +# IO.out_int +# +# Prints out the contents of an integer object on top of the +# stack. +# +# $a0 is preserved! +# + + .globl IO.out_int +IO.out_int: + addiu $sp $sp -4 + sw $a0 4($sp) # save self + lw $a0 8($sp) # get arg + lw $a0 int_slot($a0) # Fetch int + li $v0 1 # print_int + syscall + lw $a0 4($sp) # return self + addiu $sp $sp 8 # pop argument + jr $ra + +# +# +# IO.in_int +# +# Returns an integer object read from the terminal in $a0 +# + + .globl IO.in_int +IO.in_int: + addiu $sp $sp -4 + sw $ra 4($sp) # save return address + + la $a0 Int_protObj + jal _quick_copy # Call copy + jal Int_init + + addiu $sp $sp -4 + sw $a0 4($sp) # save new object + + li $v0, 5 # read int + syscall + + lw $a0 4($sp) + addiu $sp $sp 4 + + + sw $v0 int_slot($a0) # store int read into obj + lw $ra 4($sp) + addiu $sp $sp 4 + jr $ra + +# +# +# IO.in_string +# +# Returns a string object read from the terminal, removing the +# '\\n' +# +# OUTPUT: $a0 the read string object +# + + .globl IO.in_string +IO.in_string: + addiu $sp $sp -8 + sw $ra 8($sp) # save return address + sw $0 4($sp) # init GC area + + jal _MemMgr_Test # test GC area + + la $a0 Int_protObj # Int object for string size + jal _quick_copy + jal Int_init + sw $a0 4($sp) # save it + + li $a0 str_field # size of string obj. header + addiu $a0 $a0 str_maxsize # max size of string data + jal _MemMgr_QAlloc # make sure enough room + + la $a0 String_protObj # make string object + jal _quick_copy + jal String_init + lw $t0 4($sp) # get size object + sw $t0 str_size($a0) # store size object in string + sw $a0 4($sp) # save string object + + addiu $gp $gp -4 # overwrite last word + +_instr_ok: + li $a1 str_maxsize # largest string to read + move $a0 $gp + li $v0, 8 # read string + syscall + + move $t0 $gp # t0 to beginning of string +_instr_find_end: + lb $v0 0($gp) + addiu $gp $gp 1 + bnez $v0 _instr_find_end + + # $gp points just after the null byte + lb $v0 0($t0) # is first byte '\\0'? + bnez $v0 _instr_noteof + + # we read nothing. Return '\\n' (we don't have '\\0'!!!) + add $v0 $zero 10 # load '\\n' into $v0 + sb $v0 -1($gp) + sb $zero 0($gp) # terminate + addiu $gp $gp 1 + b _instr_nonl + +_instr_noteof: + # Check if there really is a '\\n' + lb $v0 -2($gp) + bne $v0 10 _instr_nonl + + # Write '\\0' over '\\n' + sb $zero -2($gp) # Set end of string where '\\n' was + addiu $gp $gp -1 # adjust for '\\n' + +_instr_nonl: + lw $a0 4($sp) # get pointer to new str obj + lw $t1 str_size($a0) # get pointer to int obj + + sub $t0 $gp $a0 + subu $t0 str_field # calc actual str size + addiu $t0 -1 # adjust for '\\0' + sw $t0 int_slot($t1) # store string size in int obj + addi $gp $gp 3 # was already 1 past '\\0' + and $gp $gp 0xfffffffc # word align $gp + + sub $t0 $gp $a0 # calc length + srl $t0 $t0 2 # divide by 4 + sw $t0 obj_size($a0) # set size field of obj + + lw $ra 8($sp) # restore return address + addiu $sp $sp 8 + jr $ra # return + +# +# +# String.length +# Returns Int Obj with string length of self +# +# INPUT: $a0 the string object +# OUTPUT: $a0 the int object which is the size of the string +# + + .globl String.length +String.length: + lw $a0 str_size($a0) # fetch attr + jr $ra # Return + +# +# String.concat +# +# Concatenates arg1 onto the end of self and returns a pointer +# to the new object. +# +# INPUT: $a0: the first string object (self) +# Top of stack: the second string object (arg1) +# +# OUTPUT: $a0 the new string object +# + + .globl String.concat +String.concat: + + addiu $sp $sp -16 + sw $ra 16($sp) # save return address + sw $a0 12($sp) # save self arg. + sw $0 8($sp) # init GC area + sw $0 4($sp) # init GC area + + jal _MemMgr_Test # test GC area + + lw $a0 12($sp) + lw $a0 str_size($a0) + jal _quick_copy # Call copy + sw $a0 8($sp) # save new size object + + lw $t1 20($sp) # load arg object + lw $t1 str_size($t1) # get size object + lw $t1 int_slot($t1) # arg string size + blez $t1 _strcat_argempty # nothing to add + lw $t0 12($sp) # load self object + lw $t0 str_size($t0) # get size object + lw $t0 int_slot($t0) # self string size + addu $t0 $t0 $t1 # new size + sw $t0 int_slot($a0) # store new size + + addiu $a0 $t0 str_field # size to allocate + addiu $a0 $a0 4 # include '\\0', +3 to align + and $a0 $a0 0xFFFFFFFC # align on word boundary + addiu $a0 $a0 1 # make size odd for GC <-| + sw $a0 4($sp) # save size in bytes | + addiu $a0 $a0 3 # include eyecatcher(4) -1 + jal _MemMgr_QAlloc # check memory + + lw $a0 12($sp) # copy self + jal _quick_copy # Call copy + lw $t0 8($sp) # get the Int object + sw $t0 str_size($a0) # store it in the str obj. + + sub $t1 $gp $a0 # bytes allocated by _quick_copy + lw $t0 4($sp) # get size in bytes (no eyecatcher) + sub $t0 $t0 1 # Remove extra 1 (was for GC) + sub $t1 $t0 $t1 # more memory needed + addu $gp $gp $t1 # allocate rest + srl $t0 $t0 2 # convert to words + sw $t0 obj_size($a0) # save new object size + + lw $t0 12($sp) # get original self object + lw $t0 str_size($t0) # get size object + lw $t0 int_slot($t0) # self string size + addiu $t1 $a0 str_field # points to start of string data + addu $t1 $t1 $t0 # points to end: '\\0' + lw $t0 20($sp) # load arg object + addiu $t2 $t0 str_field # points to start of arg data + lw $t0 str_size($t0) # get arg size + lw $t0 int_slot($t0) + addu $t0 $t0 $t2 # find limit of copy + +_strcat_copy: + lb $v0 0($t2) # load from source + sb $v0 0($t1) # save in destination + addiu $t2 $t2 1 # advance each index + addiu $t1 $t1 1 + bne $t2 $t0 _strcat_copy # check limit + sb $0 0($t1) # add '\\0' + + lw $ra 16($sp) # restore return address + addiu $sp $sp 20 # pop argument + jr $ra # return + +_strcat_argempty: + lw $a0 12($sp) # load original self + lw $ra 16($sp) # restore return address + addiu $sp $sp 20 # pop argument + jr $ra # return + +# +# +# String.substr(i,l) +# Returns the sub string of self from i with length l +# Offset starts at 0. +# +# INPUT: $a0 the string +# length int object on top of stack (-4) +# index int object below length on stack (-8) +# OUTPUT: The substring object in $a0 +# + + .globl String.substr +String.substr: + addiu $sp $sp -12 # frame + sw $ra 4($sp) # save return + sw $a0 12($sp) # save self + sw $0 8($sp) # init GC area + + jal _MemMgr_Test # test GC area + + lw $a0 12($sp) + lw $v0 obj_size($a0) + la $a0 Int_protObj # ask if enough room to allocate + lw $a0 obj_size($a0) # a string object, an int object, + add $a0 $a0 $v0 # and the string data + addiu $a0 $a0 2 # include 2 eyecatchers + sll $a0 $a0 2 + addi $a0 $a0 str_maxsize + jal _MemMgr_QAlloc + +_ss_ok: + la $a0 Int_protObj + jal _quick_copy + jal Int_init + sw $a0 8($sp) # save new length obj + la $a0 String_protObj + jal _quick_copy + jal String_init # new obj ptr in $a0 + move $a2 $a0 # use a2 to make copy + addiu $gp $gp -4 # backup alloc ptr + lw $a1 12($sp) # load orig + lw $t1 20($sp) # index obj + lw $t2 16($sp) # length obj + lw $t0 str_size($a1) + lw $v1 int_slot($t1) # index + lw $v0 int_slot($t0) # size of orig + bltz $v1 _ss_abort1 # index is smaller than 0 + bgt $v1 $v0 _ss_abort2 # index > orig + lw $t3 int_slot($t2) # sub length + add $v1 $v1 $t3 # index+sublength + bgt $v1 $v0 _ss_abort3 + bltz $t3 _ss_abort4 + lw $t4 8($sp) # load new length obj + sw $t3 int_slot($t4) # save new size + sw $t4 str_size($a0) # store size in string + lw $v1 int_slot($t1) # index + addiu $a1 $a1 str_field # advance src to str + add $a1 $a1 $v1 # advance to indexed char + addiu $a2 $a2 str_field # advance dst to str + beqz $t3 _ss_end # empty length +_ss_loop: + lb $v0 0($a1) + addiu $a1 $a1 1 # inc src + sb $v0 0($a2) + addiu $a2 $a2 1 # inc dst + addiu $t3 $t3 -1 # dec ctr + bnez $t3 _ss_loop +_ss_end: + sb $zero 0($a2) # null terminate + move $gp $a2 + addiu $gp $gp 4 # realign the heap ptr + and $gp $gp 0xfffffffc + + sub $t0 $gp $a0 # calc object size + srl $t0 $t0 2 # div by 4 + sw $t0 obj_size($a0) + + lw $ra 4($sp) + addiu $sp $sp 20 # pop arguments + jr $ra + +_ss_abort1: + la $a0 _sabort_msg1 + b _ss_abort +_ss_abort2: + la $a0 _sabort_msg2 + b _ss_abort +_ss_abort3: + la $a0 _sabort_msg3 + b _ss_abort +_ss_abort4: + la $a0 _sabort_msg4 +_ss_abort: + li $v0 4 + syscall + la $a0 _sabort_msg + li $v0 4 + syscall + li $v0 10 # exit + syscall + +# +# MemMgr Memory Manager +# +# The MemMgr functions give a consistent view of the garbage collectors. +# This allows multiple collectors to exist in one file and the easy +# selection of different collectors. It includes functions to initialize +# the collector and to reserve memory and query its status. +# +# The following assumptions are made: +# +# 1) The allocation of memory involves incrementing the $gp pointer. +# The $s7 pointer serves as a limit. The collector function is +# called before $s7 is exceeded by $gp. +# +# 2) The initialization functions all take the same arguments as +# defined in "_MemMgr_Init". +# +# 3) The garbage collector functions all take the arguments. "$a0" +# contains the end of the stack to check for pointers. "$a1" +# contains the size in bytes needed by the program and must be +# preserved across the function call. +# + +# +# Initialize the Memory Manager +# +# Call the initialization routine for the garbage collector. +# +# INPUT: +# $a0: start of stack +# $a1: initial Register mask +# $a2: end of heap +# heap_start: start of the heap +# +# OUTPUT: +# $gp: lower bound of the work area +# $s7: upper bound of the work area +# +# Registers modified: +# $t0, initializer function +# + + .globl _MemMgr_Init +_MemMgr_Init: + addiu $sp $sp -4 + sw $ra 4($sp) # save return address + la $t0 _MemMgr_INITIALIZER # pointer to initialization + lw $t0 0($t0) + jalr $t0 # initialize + lw $ra 4($sp) # restore return address + addiu $sp $sp 4 + jr $ra # return + +# +# Memory Allocation +# +# Allocates the requested amount of memory and returns a pointer +# to the start of the block. +# +# INPUT: +# $a0: size of allocation in bytes +# $s7: limit pointer of the work area +# $gp: current allocation pointer +# heap_start: start of heap +# +# OUTPUT: +# $a0: pointer to new memory block +# +# Registers modified: +# $t0, $a1, collector function +# + + .globl _MemMgr_Alloc +_MemMgr_Alloc: + add $gp $gp $a0 # attempt to allocate storage + blt $gp $s7 _MemMgr_Alloc_end # check allocation + sub $gp $gp $a0 # restore $gp + addiu $sp $sp -4 + sw $ra 4($sp) # save return address + move $a1 $a0 # size + addiu $a0 $sp 4 # end of stack to collect + la $t0 _MemMgr_COLLECTOR # pointer to collector function + lw $t0 0($t0) + jalr $t0 # garbage collect + lw $ra 4($sp) # restore return address + addiu $sp $sp 4 + move $a0 $a1 # put size into $a0 + add $gp $gp $a0 # allocate storage +_MemMgr_Alloc_end: + sub $a0 $gp $a0 + jr $ra # return + +# +# Query Memory Allocation +# +# Verifies that the requested amount of memory can be allocated +# within the work area. +# +# INPUT: +# $a0: size of allocation in bytes +# $s7: limit pointer of the work area +# $gp: current allocation pointer +# heap_start: start of heap +# +# OUTPUT: +# $a0: size of allocation in bytes (unchanged) +# +# Registers modified: +# $t0, $a1, collector function +# + + .globl _MemMgr_QAlloc +_MemMgr_QAlloc: + add $t0 $gp $a0 # attempt to allocate storage + blt $t0 $s7 _MemMgr_QAlloc_end # check allocation + addiu $sp $sp -4 + sw $ra 4($sp) # save return address + move $a1 $a0 # size + addiu $a0 $sp 4 # end of stack to collect + la $t0 _MemMgr_COLLECTOR # pointer to collector function + lw $t0 0($t0) + jalr $t0 # garbage collect + lw $ra 4($sp) # restore return address + addiu $sp $sp 4 + move $a0 $a1 # put size into $a0 +_MemMgr_QAlloc_end: + jr $ra # return + +# +# Test heap consistency +# +# Runs the garbage collector in the hope that this will help detect +# garbage collection bugs earlier. +# +# INPUT: (the usual GC stuff) +# $s7: limit pointer of the work area +# $gp: current allocation pointer +# heap_start: start of heap +# +# OUTPUT: +# none +# +# Registers modified: +# $t0, $a1, collector function + + .globl _MemMgr_Test +_MemMgr_Test: + la $t0 _MemMgr_TEST # Check if testing enabled + lw $t0 0($t0) + beqz $t0 _MemMgr_Test_end + +# Allocate 0 bytes + addiu $sp $sp -4 # Save return address + sw $ra 4($sp) + li $a1 0 # size = 0 + addiu $a0 $sp 4 # end of stack to collect + la $t0 _MemMgr_COLLECTOR # pointer to collector function + lw $t0 0($t0) + jalr $t0 # garbage collect + lw $ra 4($sp) # restore return address + addiu $sp $sp 4 + +_MemMgr_Test_end: + jr $ra +""" + + MemManagerNoGC = """ +# +# NoGC Garbage Collector +# +# NoGC does not attempt to do any garbage collection. +# It simply expands the heap if more memory is needed. +# + +# +# Some constants +# + +NoGC_EXPANDSIZE=0x10000 # size to expand heap + +# +# Initialization +# +# INPUT: +# none +# +# OUTPUT: +# $gp: lower bound of the work area +# $s7: upper bound of the work area +# +# Registers modified: +# $a0, $v0 +# + .globl _NoGC_Init +_NoGC_Init: + la $gp heap_start # set $gp to the start of the heap + li $v0 9 # get heap end + move $a0 $zero + syscall # sbrk + move $s7 $v0 # set limit pointer + jr $ra + +# +# Collection +# +# Expand the heap as necessary. +# +# INPUT: +# $a1: size will need to allocate in bytes +# $s7: limit pointer of thw work area +# $gp: current allocation pointer +# +# OUTPUT: +# $a1: size will need to allocate in bytes (unchanged) +# +# Registers modified: +# $t0, $a0, $v0, $gp, $s7 +# + + .globl _NoGC_Collect +_NoGC_Collect: + la $a0 _NoGC_COLLECT # show collection message + li $v0 4 + syscall +_NoGC_Collect_loop: + add $t0 $gp $a1 # test allocation + blt $t0 $s7 _NoGC_Collect_ok # stop if enough + li $v0 9 # expand heap + li $a0 NoGC_EXPANDSIZE # set the size to expand the heap + syscall # sbrk + li $v0 9 # get heap end + move $a0 $zero + syscall # sbrk + move $s7 $v0 # set limit pointer + b _NoGC_Collect_loop # loop +_NoGC_Collect_ok: + jr $ra # return +""" + + MemManagerGenGC = """ +# +# GenGC Generational Garbage Collector +# +# This is an implementation of a generational garbage collector +# as described in "Simple Generational Garbage Collection and Fast +# Allocation" by Andrew W. Appel [Princeton University, March 1988]. +# This is a two generation scheme which uses an assignment table +# to handle root pointers located in the older generation objects. +# +# When the work area is filled, a minor garbage collection takes place +# which moves all live objects into the reserve area. These objects +# are then incorporated into the old area. New reserve and work areas +# are setup and allocation can continue in the work area. If a break- +# point is reached in the size of the old area just after a minor +# collection, a major collection then takes place. All live objects in +# the old area are then copied into the new area, expanding the heap if +# necessary. The X and new areas are then block copied back L1-L0 +# bytes to form the next old area. +# +# The assignment table is implemented as a stack growing towards the +# allocation pointer ($gp) in the work area. If they cross, a minor +# collection is then carried out. This allows the garbage collector to +# to have to keep a fixed table of assignments. As a result, programs +# with many assignments will tend not to be bogged down with extra +# garbage collections. +# +# The unused area was implemented to help keep the garbage collector +# from continually expanding the heap. This buffer zone allows major +# garbage collections to happen earlier, reducing the risk of expansions +# due to too many live objects in the old area. The histories kept by +# the garbage collector in MAJOR0, MAJOR1, MINOR0, and MINOR1 also help +# to prevent unnecessary expansions of the heap. If many live objects +# were recently collected, the garbage collections will start to occur +# sooner. +# +# Note that during a minor collection, the work area is guaranteed to +# fit within the reserve area. However, during a major collection, the +# old area will not necessarily fit in the new area. If the latter occurs, +# "_GenGC_OfsCopy" will detect this and expand the heap. +# +# The heap is expanded on two different occasions: +# +# 1) After a major collection, the old area is set to be at most +# 1/(2^GenGC_OLDRATIO) of the usable heap (L0 to L3). Note that +# first L4 is checked to see if any of the unused memory between L3 +# and L4 is enough to satisfy this requirement. If not, then the +# heap will be expanded. If it is, the appropriate amount will be +# transfered from the unused area to the work/reserve area. +# +# 2) During a major collection, if the live objects in the old area +# do not fit within the new area, the heap is expanded and $s7 +# is updated to reflact this. This value later gets stored back +# into L4. +# +# During a normal allocation and minor collections, the heap has the +# following form: +# +# Header +# | +# | Older generation objects +# | | +# | | Minor garbage collection area +# | | | +# | | | Allocation area +# | | | | +# | | | | Assignment table +# | | | | | +# | | | | | Unused +# | | | | | | +# v v v v v v +# +----+--------------+-----------------+-------------+---+---------+ +# |XXXX| Old Area | Reserve Area | Work Area |XXX| Unused | +# +----+--------------+-----------------+-------------+---+---------+ +# ^ ^ ^ ^ ^ ^ ^ ^ +# | | | | |--> <--| | | +# | L0 L1 L2 $gp $s7 L3 L4 +# | +# heap_start +# +# $gp (allocation pointer): points to the next free word in the work +# area during normal allocation. During a minor garbage collection, +# it points to the next free work in the reserve area. +# +# $s7 (limit pointer): points to the limit that $gp can traverse. Between +# it and L3 sits the assignment table which grows towards $gp. +# +# During a Major collection, the heap has the following form: +# +# Header +# | +# | Older generation objects +# | | +# | | Objects surviving last minor garbage collection +# | | | +# | | | Major garbage collection area +# | | | | +# v v v v +# +----+------------------+----------+------------------------------+ +# |XXXX| Old Area | X | New Area | +# +----+------------------+----------+------------------------------+ +# ^ ^ ^ ^ ^ ^ ^ +# | | | | | |--> | +# | L0 L1 | L2 $gp L4, $s7 +# | | +# heap_start breakpoint +# +# $gp (allocation pointer): During a major collection, this points +# into the next free word in the new area. +# +# $s7 (limit pointer): During a major collection, the points to the +# limit of heap memory. $gp is not allowed to pass this value. +# If the objects in the live old area cannot fit in the new area, +# more memory is allocated and $s7 is adjusted accordingly. +# +# breakpoint: Point where a major collection will occur. It is +# calculated by the following formula: +# +# breakpoint = MIN(L3-MAX(MAJOR0,MAJOR1)-MAX(MINOR0,MINOR1), +# L3-(L3-L0)/2) +# +# where (variables stored in the header): +# MAJOR0 = total size of objects in the new area after last major +# collection. +# MAJOR1 = (MAJOR0+MAJOR1)/2 +# MINOR0 = total size of objects in the reserve area after last +# minor collection. +# MINOR1 = (MINOR0+MINOR1)/2 +# +# The following assumptions are made in the garbage collection +# process: +# +# 1) Pointers on the Stack: +# Every word on the stack that ends in 0 (i.e., is even) and is +# a valid address in the heap is assumed to point to an object +# in the heap. Even heap addresses on the stack that are actually +# something else (e.g., raw integers) will probably cause an +# garbage collection error. +# +# 2) Object Layout: +# Besides the Int, String, and Bool objects (which are handled +# separately), the garbage collector assumes that each attribute +# in an object is a pointer to another object. It, however, +# still does as much as possible to verify this before actually +# updating any fields. +# +# 3) Pointer tests: +# In order to be verified as an object, a pointer must undergo +# certain tests: +# +# a) The pointer must point within the correct storage area. +# b) The word before the pointer (obj_eyecatch) must be the +# word 0xFFFF FFFF +# c) The word at the pointer must not be 0xFFFF FFFF (i.e. +# -1 cannot be a class tag) +# +# These tests are performed whenever any data could be a pointer +# to keep any non-pointers from being updated accidentally. The +# functions "_GenGC_ChkCopy" and "_GenGC_OfsCopy" are responsible +# for these checks. +# +# 4) The size stored in the object does not include the word required +# to store the eyecatcher for the object in the heap. This allows +# the prototype objects to not require its own eyecatcher. Also, +# a size of 0 is invalid because it is used as a flag by the garbage +# collector to indicate a forwarding pointer in the "obj_disp" field. +# +# 5) Roots are contained in the following areas: the stack, registers +# specified in the REG mask, and the assignment table. +# + +# +# Constants +# + +# +# GenGC header offsets from "heap_start" +# + +GenGC_HDRSIZE=44 # size of GenGC header +GenGC_HDRL0=0 # pointers to GenGC areas +GenGC_HDRL1=4 +GenGC_HDRL2=8 +GenGC_HDRL3=12 +GenGC_HDRL4=16 +GenGC_HDRMAJOR0=20 # history of major collections +GenGC_HDRMAJOR1=24 +GenGC_HDRMINOR0=28 # history of minor collections +GenGC_HDRMINOR1=32 +GenGC_HDRSTK=36 # start of stack +GenGC_HDRREG=40 # current REG mask + +# +# Granularity of heap expansion +# +# The heap is always expanded in multiples of 2^k, where +# k is the granularity. +# + +GenGC_HEAPEXPGRAN=14 # 2^14=16K + +# +# Old to usable heap size ratio +# +# After a major collection, the ratio of size of old area to the usable +# size of the heap is at most 1/(2^k) where k is the value provided. +# + +GenGC_OLDRATIO=2 # 1/(2^2)=.25=25% + +# +# Mask to speficy which registers can be automatically updated +# when a garbage collection occurs. The Automatic Register Update +# (ARU) mask has a bit set for all possible registers the +# garbage collector is able to handle. The Register (REG) mask +# determines which register(s) are actually updated. +# +# BITS---------------------------- +# 3 2 1 0 +# 10987654321098765432109876543210 +# -------------------------------- +# +# 11000011011111110000000000000000 <- Auto Register Update (ARU) mask +# +--++--++--++--++--++--++--++--+ $s0-$s6, $t8-$t9, $fp, $ra +# C 3 7 F 0 0 0 0 ($16-$22, $24-$25, $30, $31) +# + +GenGC_ARU_MASK=0xC37F0000 + +# +# Functions +# + +# +# Initialization +# +# Sets up the header information block for the garbage collector. +# This block is located at the start of the heap ("heap_start") +# and includes information needed by the garbage collector. It +# also calculates the barrier for the reserve and work areas and +# sets the L2 pointer accordingly, rounding off in favor of the +# reserve area. +# +# INPUT: +# $a0: start of stack +# $a1: initial Register mask +# $a2: end of heap +# heap_start: start of the heap +# +# OUTPUT: +# $gp: lower bound of the work area +# $s7: upper bound of the work area +# +# Registers modified: +# $t0, $t1, $v0, $a0 +# + + .globl _GenGC_Init +_GenGC_Init: + la $t0 heap_start + addiu $t1 $t0 GenGC_HDRSIZE + sw $t1 GenGC_HDRL0($t0) # save start of old area + sw $t1 GenGC_HDRL1($t0) # save start of reserve area + sub $t1 $a2 $t1 # find reserve/work area barrier + srl $t1 $t1 1 + and $t1 $t1 0xFFFFFFFC + blez $t1 _GenGC_Init_error # heap initially to small + sub $gp $a2 $t1 + sw $gp GenGC_HDRL2($t0) # save start of work area + sw $a2 GenGC_HDRL3($t0) # save end of work area + move $s7 $a2 # set limit pointer + sw $0 GenGC_HDRMAJOR0($t0) # clear histories + sw $0 GenGC_HDRMAJOR1($t0) + sw $0 GenGC_HDRMINOR0($t0) + sw $0 GenGC_HDRMINOR1($t0) + sw $a0 GenGC_HDRSTK($t0) # save stack start + sw $a1 GenGC_HDRREG($t0) # save register mask + li $v0 9 # get heap end + move $a0 $zero + syscall # sbrk + sw $v0 GenGC_HDRL4($t0) # save heap limit + jr $ra # return +_GenGC_Init_error: + la $a0 _GenGC_INITERROR # show error message + li $v0 4 + syscall + li $v0 10 # exit + syscall + +# +# Record Assignment +# +# Records an assignment in the assignment table. Note that because +# $s7 is always greater than $gp, an assignment can always be +# recorded. +# +# INPUT: +# $a1: pointer to the pointer being modified +# $s7: limit pointer of the work area +# $gp: current allocation pointer +# heap_start: start of heap +# +# Registers modified: +# $t0, $t1, $t2, $v0, $v1, $a0, $a1, $a2, $gp, $s7 +# + + .globl _GenGC_Assign +_GenGC_Assign: + addiu $s7 $s7 -4 + sw $a1 0($s7) # save pointer to assignment + bgt $s7 $gp _GenGC_Assign_done + addiu $sp $sp -4 + sw $ra 4($sp) # save return address + move $a1 $0 # size + addiu $a0 $sp 4 # end of stack to collect + jal _GenGC_Collect + lw $ra 4($sp) # restore return address + addiu $sp $sp 4 +_GenGC_Assign_done: + jr $ra # return + + .globl _gc_check +_gc_check: + beqz $a1, _gc_ok # void is ok + lw $a2 obj_eyecatch($a1) # and check if it is valid + addiu $a2 $a2 1 + bnez $a2 _gc_abort +_gc_ok: + jr $ra + +_gc_abort: + la $a0 _gc_abort_msg + li $v0 4 + syscall # print gc message + li $v0 10 + syscall # exit + + +# +# Generational Garbage Collection +# +# This function implements the generational garbage collection. +# It first calls the minor collector, "_GenGC_MinorC", and then +# updates its history in the header. The breakpoint is then +# calculated. If the breakpoint is reached or there is still not +# enough room to allocate the requested size, a major garbage +# collection then takes place by calling "_GenGC_MajorC". After +# the major collection, the size of the old area is analyzed. If +# it is greater than 1/(2^GenGC_OLDRATIO) of the total usable heap +# size (L0 to L3), the heap is expanded. Also, if there is still not +# enough room to allocate the requested size, the heap is expanded +# further to make sure that the specified amount of memory can be +# allocated. If there is enough room in the unused area (L3 to L4), +# this memory is used and the heap is not expanded. The $s7 and $gp +# pointers are then set as well as the L2 pointer. If a major collection +# is not done, the X area is incorporated into the old area +# (i.e. the L2 pointer is moved into L1) and $s7, $gp, and L2 are +# then set. +# +# INPUT: +# $a0: end of stack +# $a1: size will need to allocate in bytes +# $s7: limit pointer of thw work area +# $gp: current allocation pointer +# heap_start: start of heap +# +# OUTPUT: +# $a1: size will need to allocate in bytes (unchanged) +# +# Registers modified: +# $t0, $t1, $t2, $t3, $t4, $v0, $v1, $a0, $a2, $gp, $s7 +# + + .globl _GenGC_Collect +_GenGC_Collect: + addiu $sp $sp -12 + sw $ra 12($sp) # save return address + sw $a0 8($sp) # save stack end + sw $a1 4($sp) # save size + la $a0 _GenGC_COLLECT # print collection message + li $v0 4 + syscall + lw $a0 8($sp) # restore stack end + jal _GenGC_MinorC # minor collection + la $a1 heap_start + lw $t1 GenGC_HDRMINOR1($a1) + addu $t1 $t1 $a0 + srl $t1 $t1 1 + sw $t1 GenGC_HDRMINOR1($a1) # update histories + sw $a0 GenGC_HDRMINOR0($a1) + move $t0 $t1 # set $t0 to max of minor + bgt $t1 $a0 _GenGC_Collect_maxmaj + move $t0 $a0 +_GenGC_Collect_maxmaj: + lw $t1 GenGC_HDRMAJOR0($a1) # set $t1 to max of major + lw $t2 GenGC_HDRMAJOR1($a1) + bgt $t1 $t2 _GenGC_Collect_maxdef + move $t1 $t2 +_GenGC_Collect_maxdef: + lw $t2 GenGC_HDRL3($a1) + sub $t0 $t2 $t0 # set $t0 to L3-$t0-$t1 + sub $t0 $t0 $t1 + lw $t1 GenGC_HDRL0($a1) # set $t1 to L3-(L3-L0)/2 + sub $t1 $t2 $t1 + srl $t1 $t1 1 + sub $t1 $t2 $t1 + blt $t0 $t1 _GenGC_Collect_breakpt # set $t0 to minimum of above + move $t0 $t1 +_GenGC_Collect_breakpt: + lw $t1 GenGC_HDRL1($a1) # get end of old area + bge $t1 $t0 _GenGC_Collect_major + lw $t0 GenGC_HDRL2($a1) + lw $t1 GenGC_HDRL3($a1) + lw $t2 4($sp) # load requested size into $t2 + sub $t0 $t1 $t0 # find reserve/work area barrier + srl $t0 $t0 1 + and $t0 $t0 0xFFFFFFFC + sub $t0 $t1 $t0 # reserve/work barrier + addu $t2 $t0 $t2 # test allocation + bge $t2 $t1 _GenGC_Collect_major # check if work area too small +_GenGC_Collect_nomajor: + lw $t1 GenGC_HDRL2($a1) + sw $t1 GenGC_HDRL1($a1) # expand old area + sw $t0 GenGC_HDRL2($a1) # set new reserve/work barrier + move $gp $t0 # set $gp + lw $s7 GenGC_HDRL3($a1) # load limit into $s7 + b _GenGC_Collect_done +_GenGC_Collect_major: + la $a0 _GenGC_Major # print collection message + li $v0 4 + syscall + lw $a0 8($sp) # restore stack end + jal _GenGC_MajorC # major collection + la $a1 heap_start + lw $t1 GenGC_HDRMAJOR1($a1) + addu $t1 $t1 $a0 + srl $t1 $t1 1 + sw $t1 GenGC_HDRMAJOR1($a1) # update histories + sw $a0 GenGC_HDRMAJOR0($a1) + lw $t1 GenGC_HDRL3($a1) # find ratio of the old area + lw $t0 GenGC_HDRL0($a1) + sub $t1 $t1 $t0 + srl $t1 $t1 GenGC_OLDRATIO + addu $t1 $t0 $t1 + lw $t0 GenGC_HDRL1($a1) + sub $t0 $t0 $t1 + sll $t0 $t0 GenGC_OLDRATIO # amount to expand in $t0 + lw $t1 GenGC_HDRL3($a1) # load L3 + lw $t2 GenGC_HDRL1($a1) # load L1 + sub $t2 $t1 $t2 + srl $t2 $t2 1 + and $t2 $t2 0xFFFFFFFC + sub $t1 $t1 $t2 # reserve/work barrier + lw $t2 4($sp) # restore size + addu $t1 $t1 $t2 + lw $t2 GenGC_HDRL3($a1) # load L3 + sub $t1 $t1 $t2 # test allocation + addiu $t1 $t1 4 # adjust for round off errors + sll $t1 $t1 1 # need to allocate $t1 memory + blt $t1 $t0 _GenGC_Collect_enough # put max of $t0, $t1 in $t0 + move $t0 $t1 +_GenGC_Collect_enough: + blez $t0 _GenGC_Collect_setL2 # no need to expand + addiu $t1 $0 1 # put 1 in $t1 + sll $t1 $t1 GenGC_HEAPEXPGRAN # get granularity of expansion + addiu $t1 $t1 -1 # align to granularity + addu $t0 $t0 $t1 + nor $t1 $t1 $t1 + and $t0 $t0 $t1 # total memory needed + lw $t1 GenGC_HDRL3($a1) # load L3 + lw $t2 GenGC_HDRL4($a1) # load L4 + sub $t1 $t2 $t1 + sub $t2 $t0 $t1 # actual amount to allocate + bgtz $t2 _GenGC_Collect_getmem # check if really need to allocate +_GenGC_Collect_xfermem: + lw $s7 GenGC_HDRL3($a1) # load L3 + addu $s7 $s7 $t0 # expand by $t0, set $s7 + sw $s7 GenGC_HDRL3($a1) # save L3 + b _GenGC_Collect_findL2 +_GenGC_Collect_getmem: + li $v0 9 # sbrk + move $a0 $t2 # set the size to expand the heap + syscall + li $v0 9 + move $a0 $zero + syscall # get new end of heap in $v0 + sw $v0 GenGC_HDRL4($a1) # save L4 + sw $v0 GenGC_HDRL3($a1) # save L3 + move $s7 $v0 # set $s7 + b _GenGC_Collect_findL2 +_GenGC_Collect_setL2: + lw $s7 GenGC_HDRL3($a1) # load L3 +_GenGC_Collect_findL2: + lw $t1 GenGC_HDRL1($a1) # load L1 + sub $t1 $s7 $t1 + srl $t1 $t1 1 + and $t1 $t1 0xFFFFFFFC + sub $gp $s7 $t1 # reserve/work barrier + sw $gp GenGC_HDRL2($a1) # save L2 +_GenGC_Collect_done: + +# Clear new generation to catch missing pointers + move $t0 $gp +_GenGC_Clear_loop: + sw $zero 0($t0) + addiu $t0 $t0 4 + blt $t0 $s7 _GenGC_Clear_loop + + lw $a1 4($sp) # restore size + lw $ra 12($sp) # restore return address + addiu $sp $sp 12 + jr $ra # return + +# +# Check and Copy an Object +# +# Checks that the input pointer points to an object is a heap +# object. If so, it then checks for a forwarding pointer by +# checking for an object size of 0. If found, the forwarding +# pointer is returned. If not found, the object is copied to $gp +# and a pointer to it is returned. The following tests are done to +# determine if the object is a heap object: +# +# 1) The pointer is within the specified limits +# 2) The pointer is even +# 3) The word before the pointer is the eye catcher 0xFFFF FFFF +# 4) The word at the pointer is a valid tag (i.e. not equal to +# 0xFFFF FFFF) +# +# INPUT: +# $a0: pointer to check and copy +# $a1: lower bound object should be within. +# $a2: upper bound object should be within. +# $gp: current allocation pointer +# +# OUTPUT: +# $a0: if input points to a heap object then it is set to the +# new location of object. If not, it is unchanged. +# $a1: lower bound object should be within. (unchanged) +# $a2: upper bound object should be within. (unchanged) +# +# Registers modified: +# $t0, $t1, $t2, $v0, $a0, $gp +# + + .globl _GenGC_ChkCopy +_GenGC_ChkCopy: + blt $a0 $a1 _GenGC_ChkCopy_done # check bounds + bge $a0 $a2 _GenGC_ChkCopy_done + andi $t2 $a0 1 # check if odd + bnez $t2 _GenGC_ChkCopy_done + addiu $t2 $0 -1 + lw $t1 obj_eyecatch($a0) # check eyecatcher + bne $t2 $t1 _gc_abort + lw $t1 obj_tag($a0) # check object tag + beq $t2 $t1 _GenGC_ChkCopy_done + lw $t1 obj_size($a0) # get size of object + beqz $t1 _GenGC_ChkCopy_forward # if size = 0, get forwarding pointer + move $t0 $a0 # save pointer to old object in $t0 + addiu $gp $gp 4 # allocate memory for eyecatcher + move $a0 $gp # get address of new object + sw $t2 obj_eyecatch($a0) # save eye catcher + sll $t1 $t1 2 # convert words to bytes + addu $t1 $t0 $t1 # set $t1 to limit of copy + move $t2 $t0 # set $t2 to old object +_GenGC_ChkCopy_loop: + lw $v0 0($t0) # copy + sw $v0 0($gp) + addiu $t0 $t0 4 # update each index + addiu $gp $gp 4 + bne $t0 $t1 _GenGC_ChkCopy_loop # check for limit of copy + sw $0 obj_size($t2) # set size to 0 + sw $a0 obj_disp($t2) # save forwarding pointer +_GenGC_ChkCopy_done: + jr $ra # return +_GenGC_ChkCopy_forward: + lw $a0 obj_disp($a0) # get forwarding pointer + jr $ra # return + + +# +# Minor Garbage Collection +# +# This garbage collector is run when ever the space in the work +# area is used up by objects and the assignment table. The live +# objects are found and copied to the reserve area. The L2 pointer +# is then set to the end of the live objects. The collector consists +# of six phases: +# +# 1) Set $gp into the reserve area and set the inputs for ChkCopy +# +# 2) Scan the stack for root pointers into the heap. The beginning +# of the stack is in the header and the end is an input to this +# function. Look for the appropriate stack flags and act +# accordingly. Use "_GenGC_ChkCopy" to validate the pointer and +# get the new pointer, and then update the stack entry. +# +# 3) Check the registers specified in the Register (REG) mask to +# automatically update. This mask is stored in the header. If +# bit #n in the mask is set, register #n will be passed to +# "_GenGC_ChkCopy" and updated with its result. "_GenGC_SetRegMask" +# can be used to update this mask. +# +# 4) The assignemnt table is now checked. $s7 is moved from its +# current position until it hits the L3 pointer. Each entry is a +# pointer to the pointer that must be checked. Again, +# "_GenGC_ChkCopy" is used and the pointer updated. +# +# 5) At this point, all root objects are in the reserve area. This +# area is now traversed object by object (from L1 to $gp). It +# results in a breadth first search of the live objects collected. +# All attributes of objects are treated as pointers except the +# "Int", "Bool", and "String" objects. The first two are skipped +# completely, and the first attribute of the string object is +# analyzed (should be a pointer to an "Int" object). +# +# 6) At this point, L2 is set to the end of the live objects in the +# reserve area. This is in preparation for a major collection. +# The size of all the live objects collected is then computed and +# returned. +# +# INPUT: +# $a0: end of stack +# $s7: limit pointer of this area of storage +# $gp: current allocation pointer +# heap_start: start of heap +# +# OUTPUT: +# $a0: size of all live objects collected +# +# Registers modified: +# $t0, $t1, $t2, $t3, $t4, $v0, $v1, $a0, $a1, $a2, $gp, $s7 +# + + .globl _GenGC_MinorC +_GenGC_MinorC: + addiu $sp $sp -20 + sw $ra 20($sp) # save return address + la $t0 heap_start + lw $a1 GenGC_HDRL2($t0) # set lower bound to work area + move $a2 $s7 # set upper bound for ChkCopy + lw $gp GenGC_HDRL1($t0) # set $gp into reserve area + sw $a0 16($sp) # save stack end + lw $t0 GenGC_HDRSTK($t0) # set $t0 to stack start + move $t1 $a0 # set $t1 to stack end + ble $t0 $t1 _GenGC_MinorC_stackend # check for empty stack +_GenGC_MinorC_stackloop: # $t1 stack end, $t0 index + addiu $t0 $t0 -4 # update index + sw $t0 12($sp) # save stack index + lw $a0 4($t0) # get stack item + jal _GenGC_ChkCopy # check and copy + lw $t0 12($sp) # load stack index + sw $a0 4($t0) + lw $t1 16($sp) # restore stack end + bgt $t0 $t1 _GenGC_MinorC_stackloop # loop +_GenGC_MinorC_stackend: + la $t0 heap_start + lw $t0 GenGC_HDRREG($t0) # get Register mask + sw $t0 16($sp) # save Register mask +_GenGC_MinorC_reg16: + srl $t0 $t0 16 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg17 # check if set + move $a0 $16 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $16 $a0 # update register +_GenGC_MinorC_reg17: + lw $t0 16($sp) # restore mask + srl $t0 $t0 17 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg18 # check if set + move $a0 $17 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $17 $a0 # update register +_GenGC_MinorC_reg18: + lw $t0 16($sp) # restore mask + srl $t0 $t0 18 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg19 # check if set + move $a0 $18 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $18 $a0 # update register +_GenGC_MinorC_reg19: + lw $t0 16($sp) # restore mask + srl $t0 $t0 19 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg20 # check if set + move $a0 $19 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $19 $a0 # update register +_GenGC_MinorC_reg20: + lw $t0 16($sp) # restore mask + srl $t0 $t0 20 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg21 # check if set + move $a0 $20 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $20 $a0 # update register +_GenGC_MinorC_reg21: + lw $t0 16($sp) # restore mask + srl $t0 $t0 21 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg22 # check if set + move $a0 $21 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $21 $a0 # update register +_GenGC_MinorC_reg22: + lw $t0 16($sp) # restore mask + srl $t0 $t0 22 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg24 # check if set + move $a0 $22 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $22 $a0 # update register +_GenGC_MinorC_reg24: + lw $t0 16($sp) # restore mask + srl $t0 $t0 24 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg25 # check if set + move $a0 $24 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $24 $a0 # update register +_GenGC_MinorC_reg25: + lw $t0 16($sp) # restore mask + srl $t0 $t0 25 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg30 # check if set + move $a0 $25 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $25 $a0 # update register +_GenGC_MinorC_reg30: + lw $t0 16($sp) # restore mask + srl $t0 $t0 30 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_reg31 # check if set + move $a0 $30 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $30 $a0 # update register +_GenGC_MinorC_reg31: + lw $t0 16($sp) # restore mask + srl $t0 $t0 31 # shift to proper bit + andi $t1 $t0 1 + beq $t1 $0 _GenGC_MinorC_regend # check if set + move $a0 $31 # set test pointer + jal _GenGC_ChkCopy # check and copy + move $31 $a0 # update register +_GenGC_MinorC_regend: + la $t0 heap_start + lw $t3 GenGC_HDRL0($t0) # lower limit of old area + lw $t4 GenGC_HDRL1($t0) # upper limit of old area + lw $t0 GenGC_HDRL3($t0) # get L3 + sw $t0 16($sp) # save index limit + bge $s7 $t0 _GenGC_MinorC_assnend # check for no assignments +_GenGC_MinorC_assnloop: # $s7 index, $t0 limit + lw $a0 0($s7) # get table entry + blt $a0 $t3 _GenGC_MinorC_assnnext # must point into old area + bge $a0 $t4 _GenGC_MinorC_assnnext + lw $a0 0($a0) # get pointer to check + jal _GenGC_ChkCopy # check and copy + lw $t0 0($s7) + sw $a0 0($t0) # update pointer + lw $t0 16($sp) # restore index limit +_GenGC_MinorC_assnnext: + addiu $s7 $s7 4 # update index + blt $s7 $t0 _GenGC_MinorC_assnloop # loop +_GenGC_MinorC_assnend: + la $t0 heap_start + lw $t0 GenGC_HDRL1($t0) # start of reserve area + bge $t0 $gp _GenGC_MinorC_heapend # check for no objects +_GenGC_MinorC_heaploop: # $t0: index, $gp: limit + addiu $t0 $t0 4 # skip over eyecatcher + addiu $t1 $0 -1 # check for eyecatcher + lw $t2 obj_eyecatch($t0) + bne $t1 $t2 _GenGC_MinorC_error # eyecatcher not found + lw $a0 obj_size($t0) # get object size + sll $a0 $a0 2 # words to bytes + lw $t1 obj_tag($t0) # get the object's tag + lw $t2 _int_tag # test for int object + beq $t1 $t2 _GenGC_MinorC_int + lw $t2 _bool_tag # test for bool object + beq $t1 $t2 _GenGC_MinorC_bool + lw $t2 _string_tag # test for string object + beq $t1 $t2 _GenGC_MinorC_string +_GenGC_MinorC_other: + addi $t1 $t0 obj_attr # start at first attribute + add $t2 $t0 $a0 # limit of attributes + bge $t1 $t2 _GenGC_MinorC_nextobj # check for no attributes + sw $t0 16($sp) # save pointer to object + sw $a0 12($sp) # save object size + sw $t2 4($sp) # save limit +_GenGC_MinorC_objloop: # $t1: index, $t2: limit + sw $t1 8($sp) # save index + lw $a0 0($t1) # set pointer to check + jal _GenGC_ChkCopy +""" diff --git a/tests/codegen/arith.cl b/tests/codegen/arith.cl index af5951cf..a1035961 100755 --- a/tests/codegen/arith.cl +++ b/tests/codegen/arith.cl @@ -158,14 +158,14 @@ class A2I { if char = "0" then 0 else if char = "1" then 1 else if char = "2" then 2 else - if char = "3" then 3 else - if char = "4" then 4 else - if char = "5" then 5 else - if char = "6" then 6 else - if char = "7" then 7 else - if char = "8" then 8 else - if char = "9" then 9 else - { abort(); 0; } (* the 0 is needed to satisfy the + if char = "3" then 3 else + if char = "4" then 4 else + if char = "5" then 5 else + if char = "6" then 6 else + if char = "7" then 7 else + if char = "8" then 8 else + if char = "9" then 9 else + { abort(); 0; } (* the 0 is needed to satisfy the typchecker *) fi fi fi fi fi fi fi fi fi fi }; diff --git a/tests/codegen/complex.cl b/tests/codegen/complex.cl index 0b7aa44e..bad142df 100755 --- a/tests/codegen/complex.cl +++ b/tests/codegen/complex.cl @@ -1,22 +1,11 @@ -class Main inherits IO { - main() : IO { - (let c : Complex <- (new Complex).init(1, 1) in - if c.reflect_X().reflect_Y() = c.reflect_0() - then out_string("=)\n") - else out_string("=(\n") - fi - ) - }; -}; - class Complex inherits IO { x : Int; y : Int; - init(a : Int, b : Int) : Complex { + init(a : Int, b : Int) : SELF_TYPE { { - x = a; - y = b; + x <- a; + y <- b; self; } }; @@ -50,3 +39,16 @@ class Complex inherits IO { } }; }; + +class Main inherits IO { + main() : IO { + (let c : Complex <- (new Complex).init(1, 1) in + if c.reflect_X().reflect_Y() = c.reflect_0() + then out_string("=)\n") + else out_string("=(\n") + fi + ) + }; +}; + + diff --git a/tests/codegen/hello_world.cl b/tests/codegen/hello_world.cl index 0c818f90..2055d2a7 100755 --- a/tests/codegen/hello_world.cl +++ b/tests/codegen/hello_world.cl @@ -1,5 +1,10 @@ class Main inherits IO { + x : Int <- 1; main(): IO { - out_string("Hello, World.\n") + { + out_string("Hello, World ("); + out_int(3*2-7*2*2); + out_string(").\n"); + } }; }; From a1775ad444a6d027c0f0bcf6463a14f23ba873e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Tue, 17 Nov 2020 18:32:22 -0500 Subject: [PATCH 40/77] =?UTF-8?q?Se=20agregaron=20los=20casos=20de=20prueb?= =?UTF-8?q?a=20par=20el=20an=C3=A1lisis=20sem=C3=A1ntico=20Se=20creo=20un?= =?UTF-8?q?=20FileStream=20nuevo=20para=20substituir=20los=20tabs=20por=20?= =?UTF-8?q?espacios=20Se=20arreglaron=20algunos=20errores=20en=20el=20an?= =?UTF-8?q?=C3=A1lisis=20sem=C3=A1ntico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + src/COOLCompiler.py | 10 +- src/NoTabsFileStream.py | 24 +++ src/Visitors.py | 383 +++++++++++++++++++++++++--------------- 4 files changed, 272 insertions(+), 148 deletions(-) create mode 100644 src/NoTabsFileStream.py diff --git a/.gitignore b/.gitignore index ebfe77c1..eb544d4e 100644 --- a/.gitignore +++ b/.gitignore @@ -409,3 +409,6 @@ dmypy.json # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) /.idea +/gen +/grammar/antlr_cool.bat +/tests/codegen/*.s diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 8e08f495..85bf37a8 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -11,14 +11,16 @@ from Visitors import SemanticCOOLVisitor from Visitors import CodegenVisitor from collections import deque +from NoTabsFileStream import NoTabsFileStream + def main(argv): if not os.path.isfile(argv[1]): print("invalid input filename: " + argv[1]) return sys.exit(errno.EPERM) - input = FileStream(argv[1]) - + input = NoTabsFileStream(argv[1]) + s = "" lexer = COOLLexer(input) lexer.removeErrorListeners() lexer.addErrorListener(COOLLexerErrorListener()) @@ -44,8 +46,8 @@ def main(argv): codegenerator = CodegenVisitor(typeTree, consTble, visitor.Counter) semanticAnalizer.visitProgram(tree) - outFilename = os.path.splitext(argv[1])[0] + ".s" - codegenerator.visitProgram(tree, outFilename) + # outFilename = os.path.splitext(argv[1])[0] + ".s" + # codegenerator.visitProgram(tree, outFilename) none = typeTree["Object"] diff --git a/src/NoTabsFileStream.py b/src/NoTabsFileStream.py new file mode 100644 index 00000000..cce514c0 --- /dev/null +++ b/src/NoTabsFileStream.py @@ -0,0 +1,24 @@ + +from antlr4.FileStream import FileStream + + +class NoTabsFileStream(FileStream): + + def __init__(self, fileName:str, tabSpaces: int = 4): + self.tabSpaces = tabSpaces + super().__init__(fileName) + + def readDataFrom(self, fileName:str, encoding:str, errors:str='strict'): + s = super().readDataFrom(fileName, encoding, errors) + r = "" + for t in s: + if t == '\t': + i = self.tabSpaces + while i > 0: + r += ' ' + i -= 1 + else: + r += t + return r + + diff --git a/src/Visitors.py b/src/Visitors.py index 0bcd390c..49ec5f34 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -11,6 +11,8 @@ def __init__(self, name: str, parent: str, created: bool, sealed: bool): self.Sealed = sealed self.Deep = -1 self.Methods = {} + self.VisitedMethods = list() + self.VisitedAtributes = list() self.TagMethods = list() self.Atributes = {} self.Tag = 0 @@ -72,12 +74,17 @@ def join(self, class1: str, class2: str): else: return self.join(class1, self.TypeTable[class2].Parent) - def calculateDeep(self, coolClass: COOLClass): - if self.TypeTable.keys().__contains__(coolClass.Parent): + def calculateDeep(self, coolClass: COOLClass, classList: list): + if coolClass.Deep != -1: + return + elif self.TypeTable.keys().__contains__(coolClass.Parent): if self.TypeTable[coolClass.Parent].Deep != -1: coolClass.Deep = self.TypeTable[coolClass.Parent].Deep + 1 + elif classList.__contains__(coolClass.Parent): + coolClass.Deep = 1 else: - self.calculateDeep(self.TypeTable[coolClass.Parent]) + classList.append(coolClass.Name) + self.calculateDeep(self.TypeTable[coolClass.Parent], classList) coolClass.Deep = self.TypeTable[coolClass.Parent].Deep + 1 elif coolClass.Name == "Object": coolClass.Deep = 0 @@ -122,7 +129,7 @@ def __init__(self, typeTable: dict): # Visit a parse tree produced by COOL#program. def visitProgram(self, ctx:COOL.ProgramContext): for className in self.TypeTable.keys(): - self.calculateDeep(self.TypeTable[className]) + self.calculateDeep(self.TypeTable[className], list()) return self.visitChildren(ctx) # Visit a parse tree produced by COOL#classes. @@ -134,16 +141,24 @@ def visitClassDefine(self, ctx:COOL.ClassDefineContext): coolClass = ctx.getChild(1).symbol if(self.TypeTable[coolClass.text].Created): line = str(coolClass.line) - column = str(coolClass.column) - error = "(" + line + "," + column + "): this class name already exist" + column = str(coolClass.column + 1) + if coolClass.text == "Bool" or coolClass.text == "Int" or coolClass.text == "String" or coolClass.text == "IO" or coolClass.text == "Object": + error = f"({line}, {column}) - SemanticError: Redefinition of basic class {coolClass.text}" + else: + error = f"({line}, {column}) - SemanticError: Classes may not be redefined" print(error) elif ctx.getChild(2).symbol.text == "inherits": classParent = ctx.getChild(3).symbol if (self.TypeTable.keys().__contains__(classParent.text)): if self.TypeTable[classParent.text].Sealed: line = str(classParent.line) - column = str(classParent.column) - error = "(" + line + "," + column + "): this class is sealed" + column = str(classParent.column + 1) + error = f"({line}, {column}) - SemanticError: Class {coolClass.text} cannot inherit class {classParent.text}" + print(error) + elif not (self.TypeTable[coolClass.text].Deep > self.TypeTable[classParent.text].Deep): + line = str(classParent.line) + column = str(classParent.column + 1) + error = f"({line}, {column}) - SemanticError: Class {coolClass.text}, or an ancestor of {coolClass.text}, is involved in an inheritance cycle." print(error) else: self.TypeTable[coolClass.text].Created = True @@ -156,8 +171,8 @@ def visitClassDefine(self, ctx:COOL.ClassDefineContext): return else: line = str(classParent.line) - column = str(classParent.column) - error = "(" + line + "," + column + "): this class doesn't exist" + column = str(classParent.column + 1) + error = f"({line}, {column}) - TypeError: Class {coolClass.text} inherits from an undefined class {classParent.text}." print(error) else: self.TypeTable[coolClass.text].Created = True @@ -173,71 +188,143 @@ def visitClassDefine(self, ctx:COOL.ClassDefineContext): def visitMethod(self, ctx:COOL.MethodContext): coolClass = ctx.parentCtx.getChild(1).symbol.text methodName = ctx.getChild(0).symbol.text - methodType = ctx.getChild(len(ctx.children) - 4).symbol - if self.ScopeManager.searchScope(methodName): + methodType = ctx.getChild(len(ctx.children) - 4).symbol + if self.TypeTable[coolClass].VisitedMethods.__contains__(methodName): line = str(ctx.getChild(0).symbol.line) - column = str(ctx.getChild(0).symbol.column) - error = "(" + line + "," + column + "): this method name already exist" + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Method {methodName} is multiply defined." print(error) - elif self.TypeTable.keys().__contains__(self.TypeTable[coolClass].Methods[methodName].Type) or methodType.text == "SELF_TYPE": + return + if self.searchMethod(self.TypeTable[coolClass].Parent, methodName): + ancestorMethod = self.searchMethodInfo(self.TypeTable[coolClass].Parent,methodName) + if ancestorMethod.ParamsNumber != self.TypeTable[coolClass].Methods[methodName].ParamsNumber: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) SemanticError: Incompatible number of formal parameters in redefined method {methodName}." + print(error) + return + if ancestorMethod.Type != methodType.text: + line = str(methodType.line) + column = str(methodType.column + 1) + error = f"({line}, {column}) SemanticError: In redefined method {methodName}, return type {methodType.text} is different from original return type {ancestorMethod.Type}." + print(error) + return + if self.TypeTable.keys().__contains__(self.TypeTable[coolClass].Methods[methodName].Type) or methodType.text == "SELF_TYPE": self.ScopeManager.addIdentifier(methodName, methodType.text) + self.TypeTable[coolClass].VisitedMethods.append(methodName) self.ScopeManager.addScope() - self.visitChildren(ctx) + i = 2 + while(i < len(ctx.children) - 4): + ctx.getChild(i).accept(self) + i += 2 + methodValue = ctx.getChild(len(ctx.children) - 2).accept(self) + if self.join(methodType.text, methodValue) != methodType.text: + line = str(ctx.getChild(len(ctx.children) - 2).start.line) + column = str(ctx.getChild(len(ctx.children) - 2).start.column + 1) + error = f"({line}, {column}) - TypeError: Inferred return type {methodValue} of method {methodName} does not conform to declared return type {methodType.text}." + print(error) self.ScopeManager.deleteScope() return else: line = str(methodType.line) - column = str(methodType.column) - error = "(" + line + "," + column + "): this type doesn't exist" + column = str(methodType.column + 1) + error = f"({line}, {column}) - TypeError: Undefined return type {methodType.text} in method {methodName}." print(error) # Visit a parse tree produced by COOL#property. def visitProperty(self, ctx:COOL.PropertyContext): atributeType = ctx.getChild(2).symbol.text + coolClass = ctx.parentCtx.getChild(1).symbol.text atributeName = ctx.getChild(0).symbol.text - if self.ScopeManager.searchScope(atributeName): + if self.TypeTable[coolClass].VisitedAtributes.__contains__(atributeName): line = str(ctx.getChild(0).symbol.line) - column = str(ctx.getChild(0).symbol.column) - error = "(" + line + "," + column + "): this atribute name already exist" + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Attribute {atributeName} is multiply defined in class." print(error) return "None" + elif atributeName == "self": + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: 'self' cannot be the name of an atribute." + print(error) + return elif not(self.TypeTable.keys().__contains__(atributeType) or atributeType == "SELF_TYPE"): line = str(ctx.getChild(2).symbol.line) - column = str(ctx.getChild(2).symbol.column) - error = "(" + line + "," + column + "): this type doesn't exist" + column = str(ctx.getChild(2).symbol.column + 1) + error = f"({line}, {column}) - TypeError: Class {atributeType} of attribute {atributeName} is undefined." + print(error) + return "None" + elif self.TypeTable[self.TypeTable[coolClass].Parent].Atributes.keys().__contains__(atributeName): + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Attribute {atributeName} is an attribute of an inherited class." print(error) return "None" elif len(ctx.children) == 5: atributeValue = ctx.getChild(4).accept(self) if self.join(atributeType, atributeValue) != atributeType: line = str(ctx.getChild(4).start.line) - column = str(ctx.getChild(4).start.column) - error = "(" + line + "," + column + "): the type of the expression is diferent of the type of the atribute" + column = str(ctx.getChild(4).start.column + 1) + error = f"({line}, {column}) - TypeError: Inferred type {atributeValue} of initialization of attribute {atributeName} does not conform to declared type {atributeType}." print(error) return "None" else: self.ScopeManager.addIdentifier(atributeName, atributeType) + self.TypeTable[coolClass].VisitedAtributes.append(atributeName) return atributeType else: self.ScopeManager.addIdentifier(atributeName, atributeType) + self.TypeTable[coolClass].VisitedAtributes.append(atributeName) return atributeType # Visit a parse tree produced by COOL#formal. def visitFormal(self, ctx:COOL.FormalContext): paramName = ctx.getChild(0).symbol.text paramType = ctx.getChild(2).symbol.text + method = ctx.parentCtx + coolClass = method.parentCtx.getChild(1).symbol.text + methodName = method.getChild(0).symbol.text + if paramName == "self": + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: 'self' cannot be the name of a formal parameter." + print(error) + return if self.ScopeManager.searchScope(paramName): line = str(ctx.getChild(0).symbol.line) - column = str(ctx.getChild(0).symbol.column) - error = "(" + line + "," + column + "): this param name already exist" + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Formal parameter {paramName} is multiply defined." print(error) - elif self.TypeTable.keys().__contains__(paramType): - self.ScopeManager.addIdentifier(paramName, paramType) - return self.visitChildren(ctx) + return + if self.searchMethod(self.TypeTable[coolClass].Parent, methodName): + ancestorMethod = self.searchMethodInfo(self.TypeTable[coolClass].Parent,methodName) + exist = False + i = 0 + for param in self.TypeTable[coolClass].Methods[methodName].Params: + (pName, pType) = param + if pName == paramName: + exist = True + (_, acType) = ancestorMethod.Params.__getitem__(i) + if paramType != acType: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: In redefined method {methodName}, parameter type {paramType} is different from original type {acType}." + print(error) + return + i += 1 + if not exist: + line = str(ctx.getChild(0).symbol.line) + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: In ancestor method {methodName}, dont exist param {paramName}." + print(error) + return + if self.TypeTable.keys().__contains__(paramType): + self.ScopeManager.addIdentifier(paramName, paramType) + return self.visitChildren(ctx) else: line = str(ctx.getChild(2).symbol.line) - column = str(ctx.getChild(2).symbol.column) - error = "(" + line + "," + column + "): this type doesn't exist" + column = str(ctx.getChild(2).symbol.column + 1) + error = f"({line}, {column}) - TypeError: Class {paramType} of formal parameter {paramName} is undefined." print(error) # Visit a parse tree produced by COOL#int. @@ -261,16 +348,10 @@ def visitAdd(self, ctx: COOL.AddContext): addValue = "Int" leftValue = ctx.getChild(0).accept(self) rightValue = ctx.getChild(2).accept(self) - if leftValue != "Int": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" - print(error) - addValue = "None" - if rightValue != "Int": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" + if leftValue != "Int" or rightValue != "Int": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} + {rightValue}" print(error) addValue = "None" return addValue @@ -280,16 +361,10 @@ def visitMinus(self, ctx:COOL.MinusContext): minusValue = "Int" leftValue = ctx.getChild(0).accept(self) rightValue = ctx.getChild(2).accept(self) - if leftValue != "Int": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" - print(error) - minusValue = "None" - if rightValue != "Int": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" + if leftValue != "Int" or rightValue != "Int": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} - {rightValue}" print(error) minusValue = "None" return minusValue @@ -299,16 +374,10 @@ def visitMultiply(self, ctx: COOL.MultiplyContext): mulValue = "Int" leftValue = ctx.getChild(0).accept(self) rightValue = ctx.getChild(2).accept(self) - if leftValue != "Int": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" - print(error) - mulValue = "None" - if rightValue != "Int": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" + if leftValue != "Int" or rightValue != "Int": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} * {rightValue}" print(error) mulValue = "None" return mulValue @@ -318,16 +387,10 @@ def visitDivision(self, ctx: COOL.DivisionContext): divValue = "Int" leftValue = ctx.getChild(0).accept(self) rightValue = ctx.getChild(2).accept(self) - if leftValue != "Int": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" - print(error) - divValue = "None" - if rightValue != "Int": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" + if leftValue != "Int" or rightValue != "Int": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} / {rightValue}" print(error) divValue = "None" return divValue @@ -337,7 +400,12 @@ def visitNegative(self, ctx: COOL.NegativeContext): expressValue = ctx.getChild(1).accept(self) if expressValue == "Int": return "Int" - return "None" + else: + line = str(ctx.getChild(1).start.line) + column = str(ctx.getChild(1).start.column) + error = f"({line}, {column}) - TypeError: Argument of '~' has type {expressValue} instead of Int." + print(error) + return "None" # Visit a parse tree produced by COOL#isvoid. def visitIsvoid(self, ctx:COOL.IsvoidContext): @@ -349,23 +417,22 @@ def visitBoolNot(self, ctx: COOL.BoolNotContext): expressValue = ctx.getChild(1).accept(self) if expressValue == "Bool": return "Bool" - return "None" + else: + line = str(ctx.getChild(1).start.line) + column = str(ctx.getChild(1).start.column + 1) + error = f"({line}, {column}) - TypeError: Argument of 'not' has type {expressValue} instead of Bool." + print(error) + return "None" # Visit a parse tree produced by COOL#lessThan. def visitLessThan(self, ctx:COOL.LessThanContext): lessValue = "Bool" leftValue = ctx.getChild(0).accept(self) rightValue = ctx.getChild(2).accept(self) - if leftValue != "Int": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" - print(error) - lessValue = "None" - if rightValue != "Int": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" + if leftValue != "Int" or rightValue != "Int": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} < {rightValue}" print(error) lessValue = "None" return lessValue @@ -375,16 +442,10 @@ def visitLessEqual(self, ctx:COOL.LessEqualContext): lessEqualValue = "Bool" leftValue = ctx.getChild(0).accept(self) rightValue = ctx.getChild(2).accept(self) - if leftValue != "Int": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" - print(error) - lessEqualValue = "None" - if rightValue != "Int": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is not integer" + if leftValue != "Int" or rightValue != "Int": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} <= {rightValue}" print(error) lessEqualValue = "None" return lessEqualValue @@ -395,21 +456,22 @@ def visitEqual(self, ctx: COOL.EqualContext): rightValue = ctx.getChild(2).accept(self) if leftValue == "None" or rightValue == "None": return "None" - if leftValue == rightValue: + elif leftValue == rightValue: return "Bool" - if leftValue == "String" or leftValue == "Int" or leftValue == "Bool": - line = str(ctx.getChild(0).start.line) - column = str(ctx.getChild(0).start.column) - error = "(" + line + "," + column + "): the type of the expression is incorrect" + elif leftValue == "String" or leftValue == "Int" or leftValue == "Bool": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: Illegal comparison with a basic type." print(error) return "None" - if rightValue == "String" or rightValue == "Int" or rightValue == "Bool": - line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is incorrect" + elif rightValue == "String" or rightValue == "Int" or rightValue == "Bool": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: Illegal comparison with a basic type." print(error) return "None" - return "Bool" + else: + return "Bool" # Visit a parse tree produced by COOL#assignment. def visitAssignment(self, ctx: COOL.AssignmentContext): @@ -421,19 +483,25 @@ def visitAssignment(self, ctx: COOL.AssignmentContext): variableType = self.searchAtributeInfo(self.actualClass, variableName) else: line = str(ctx.getChild(0).symbol.line) - column = str(ctx.getChild(0).symbol.column) - error = "(" + line + "," + column + "): this identifier does not exist" + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - NameError: Undeclared identifier {variableName}." print(error) return "None" if variableType == "SELF_TYPE": variableType = self.actualClass if self.join(asignValue, variableType) != variableType: line = str(ctx.getChild(2).start.line) - column = str(ctx.getChild(2).start.column) - error = "(" + line + "," + column + "): the type of the expression is diferent that the identifier" + column = str(ctx.getChild(2).start.column + 1) + error = f"({line}, {column}) - TypeError: Cannot assign {asignValue} expression to {variableType} identifier." + print(error) + return "None" + if variableName == "self": + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Cannot assign to 'self'." print(error) return "None" - return variableType + return asignValue # Visit a parse tree produced by COOL#parentheses. def visitParentheses(self, ctx: COOL.ParenthesesContext): @@ -447,8 +515,8 @@ def visitId(self, ctx: COOL.IdContext): elif self.searchAtribute(self.actualClass, IdValue): return self.searchAtributeInfo(self.actualClass, IdValue) line = str(ctx.getChild(0).symbol.line) - column = str(ctx.getChild(0).symbol.column) - error = "(" + line + "," + column + "): this identifier does not exist" + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) - NameError: Undeclared identifier {IdValue}." print(error) return "None" @@ -461,8 +529,8 @@ def visitIf(self, ctx:COOL.IfContext): return self.join(thenValue, elseValue) else: line = str(ctx.getChild(1).start.line) - column = str(ctx.getChild(1).start.column) - error = "(" + line + "," + column + "): this expression is not boolean" + column = str(ctx.getChild(1).start.column + 1) + error = f"({line}, {column}) - TypeError: Predicate of 'if' does not have type Bool." print(error) return self.join(thenValue, elseValue) @@ -474,8 +542,8 @@ def visitWhile(self, ctx: COOL.WhileContext): return "Object" else: line = str(ctx.getChild(1).start.line) - column = str(ctx.getChild(1).start.column) - error = "(" + line + "," + column + "): this expression is not boolean" + column = str(ctx.getChild(1).start.column + 1) + error = f"({line}, {column}) - TypeError: Loop condition does not have type Bool." print(error) return "Object" @@ -495,11 +563,23 @@ def visitCase(self, ctx:COOL.CaseContext): lengt = len(ctx.children) - 1 count = 3 caseValue = "None" + typeList = [] while lengt > count: idName = ctx.getChild(count).symbol.text count = count + 2 idType = ctx.getChild(count).symbol.text + if not (self.TypeTable.keys().__contains__(idType)): + line = str(ctx.getChild(count).symbol.line) + column = str(ctx.getChild(count).symbol.column + 1) + error = f"({line}, {column}) - TypeError: Class {idType} of case branch is undefined." + print(error) + if typeList.__contains__(idType): + line = str(ctx.getChild(count).symbol.line) + column = str(ctx.getChild(count).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Duplicate branch {idType} in case statement." + print(error) count = count + 2 + typeList.append(idType) self.ScopeManager.addScope() self.ScopeManager.addIdentifier(idName, idType) if (caseValue == "None"): @@ -512,7 +592,13 @@ def visitCase(self, ctx:COOL.CaseContext): # Visit a parse tree produced by COOL#new. def visitNew(self, ctx: COOL.NewContext): - return ctx.getChild(1).symbol.text + typeName = ctx.getChild(1).symbol.text + if not self.TypeTable.keys().__contains__(typeName): + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: 'new' used with undefined class {typeName}." + print(error) + return typeName # Visit a parse tree produced by COOL#ownMethodCall. def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): @@ -525,32 +611,32 @@ def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): methodType = methodInfo.Type if methodInfo.ParamsNumber == 0 and len(ctx.children) != 3: line = str(ctx.getChild(1).symbol.line) - column = str(ctx.getChild(1).symbol.column) - error = "(" + line + "," + column + "): the number of params in the call is incorrect" + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(1).symbol.text} called with wrong number of arguments." print(error) methodType = "None" elif len(ctx.children) != methodInfo.ParamsNumber * 2 + 2 and methodInfo.ParamsNumber != 0: line = str(ctx.getChild(1).symbol.line) - column = str(ctx.getChild(1).symbol.column) - error = "(" + line + "," + column + "): the number of params in the call is incorrect" + column = str(ctx.getChild(1).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(1).symbol.text} called with wrong number of arguments." print(error) methodType = "None" else: count = 2 for param in methodInfo.Params: - (_,paramType) = param + (paramName,paramType) = param requestType = ctx.getChild(count).accept(self) if (self.join(requestType, paramType) != paramType): line = str(ctx.getChild(count).start.line) - column = str(ctx.getChild(count).start.column) - error = "(" + line + "," + column + "): the type of this param in the call is incorrect" + column = str(ctx.getChild(count).start.column + 1) + error = f"({line}, {column}) - TypeError: In call of method {ctx.getChild(1).symbol.text}, type {requestType} of parameter {paramName} does not conform to declared type {paramType}." print(error) methodType = "None" count = count + 2 else: line = str(ctx.getChild(0).symbol.line) - column = str(ctx.getChild(0).symbol.column) - error = "(" + line + "," + column + "): this method not exist in " + self.actualClass + column = str(ctx.getChild(0).symbol.column + 1) + error = f"({line}, {column}) AttributeError: Dispatch to undefined method {ctx.getChild(0).symbol.text}." print(error) return methodType @@ -565,9 +651,9 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): if self.join(currentClass, parent) == parent: currentClass = parent else: - line = str(ctx.getChild(2).symbol.line) - column = str(ctx.getChild(2).symbol.column) - error = "(" + line + "," + column + "): this class is not parent of " + currentClass + line = str(ctx.getChild(1).symbol.line) + column = str(ctx.getChild(1).symbol.column) + error = f"({line}, {column}) - SemanticError: Expression type {currentClass} does not conform to declared static dispatch type {parent}." print(error) return methodType if self.searchMethod(currentClass, ctx.getChild(length - 3).symbol.text): @@ -577,33 +663,33 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): else: methodType = methodInfo.Type if (methodInfo.ParamsNumber == 0 and len(ctx.children) != length): - line = str(ctx.getChild(length - 3).start.line) - column = str(ctx.getChild(length - 3).start.column) - error = "(" + line + "," + column + "): the number of params in the call is incorrect" + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(2).symbol.text} called with wrong number of arguments." print(error) methodType = "None" elif (len(ctx.children) != methodInfo.ParamsNumber * 2 + length - 1) and methodInfo.ParamsNumber > 0: - line = str(ctx.getChild(length - 3).start.line) - column = str(ctx.getChild(length - 3).start.column) - error = "(" + line + "," + column + "): the number of params in the call is incorrect" + line = str(ctx.getChild(2).symbol.line) + column = str(ctx.getChild(2).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(2).symbol.text} called with wrong number of arguments." print(error) methodType = "None" else: count = length - 1 for param in methodInfo.Params: - (_, paramType) = param + (paramName, paramType) = param requestType = ctx.getChild(count).accept(self) if (self.join(requestType, paramType) != paramType): line = str(ctx.getChild(count).start.line) - column = str(ctx.getChild(count).start.column) - error = "(" + line + "," + column + "): the type of this param in the call is incorrect" + column = str(ctx.getChild(count).start.column + 1) + error = f"({line}, {column}) - TypeError: In call of method {ctx.getChild(2).symbol.text}, type {requestType} of parameter {paramName} does not conform to declared type {paramType}." print(error) methodType = "None" count = count + 2 else: line = str(ctx.getChild(length - 3).symbol.line) - column = str(ctx.getChild(length - 3).symbol.column) - error = "(" + line + "," + column + "): this method not exist in " + currentClass + column = str(ctx.getChild(length - 3).symbol.column + 1) + error = f"({line}, {column}) AttributeError: Dispatch to undefined method {ctx.getChild(length - 3).symbol.text}." print(error) return methodType @@ -613,13 +699,20 @@ def visitLetIn(self, ctx: COOL.LetInContext): count = 0 while(ctx.getChild(count).symbol.text != "in"): idName = ctx.getChild(count + 1).symbol.text + if idName == "self": + self.ScopeManager.deleteScope() + line = str(ctx.getChild(count + 1).symbol.line) + column = str(ctx.getChild(count + 1).symbol.column + 1) + error = f"({line}, {column}) - SemanticError: 'self' cannot be bound in a 'let' expression." + print(error) + return "None" count = count + 2 idType = ctx.getChild(count + 1).symbol.text if not(self.TypeTable.keys().__contains__(idType)) and idType != "SELF_TYPE": self.ScopeManager.deleteScope() line = str(ctx.getChild(count + 1).symbol.line) - column = str(ctx.getChild(count + 1).symbol.column) - error = "(" + line + "," + column + "): this class does not exist " + column = str(ctx.getChild(count + 1).symbol.column + 1) + error = f"({line}, {column}) - TypeError: Class {idType} of let-bound identifier {idName} is undefined." print(error) return "None" self.ScopeManager.addIdentifier(idName, idType) @@ -630,12 +723,14 @@ def visitLetIn(self, ctx: COOL.LetInContext): if self.join(idType, idValue) != idType: self.ScopeManager.deleteScope() line = str(ctx.getChild(count -1).start.line) - column = str(ctx.getChild(count - 1).start.column) - error = "(" + line + "," + column + "): the type of the expression is diferent of the type of the identifier" + column = str(ctx.getChild(count - 1).start.column + 1) + error = f"({line}, {column}) - TypeError: Inferred type of {idValue} initialization of {idName} does not conform to identifier's declared type {idType}." print(error) return "None" - return ctx.getChild(count + 1).accept(self) + temp = ctx.getChild(count + 1).accept(self) + self.ScopeManager.deleteScope() + return temp class TypeCOOLVisitor(ParseTreeVisitor): From fcada456e2b5e6823dac587cdd67c286e4900fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Wed, 18 Nov 2020 09:18:25 -0500 Subject: [PATCH 41/77] Se creo un metodo que impide la ejecucion de la generarcion de codigo si fallo el analisis semantico --- src/COOLCompiler.py | 6 ++--- src/Visitors.py | 53 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 85bf37a8..d4c37048 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -45,9 +45,9 @@ def main(argv): semanticAnalizer = SemanticCOOLVisitor(typeTree) codegenerator = CodegenVisitor(typeTree, consTble, visitor.Counter) semanticAnalizer.visitProgram(tree) - - # outFilename = os.path.splitext(argv[1])[0] + ".s" - # codegenerator.visitProgram(tree, outFilename) + if semanticAnalizer.hasNoError: + outFilename = os.path.splitext(argv[1])[0] + ".s" + codegenerator.visitProgram(tree, outFilename) none = typeTree["Object"] diff --git a/src/Visitors.py b/src/Visitors.py index 49ec5f34..2358ece1 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -125,6 +125,7 @@ def __init__(self, typeTable: dict): self.TypeTable = typeTable self.ScopeManager = COOLScopeManager() self.actualClass = "Object" + self.hasNoError = True # Visit a parse tree produced by COOL#program. def visitProgram(self, ctx:COOL.ProgramContext): @@ -147,6 +148,7 @@ def visitClassDefine(self, ctx:COOL.ClassDefineContext): else: error = f"({line}, {column}) - SemanticError: Classes may not be redefined" print(error) + self.hasNoError = False elif ctx.getChild(2).symbol.text == "inherits": classParent = ctx.getChild(3).symbol if (self.TypeTable.keys().__contains__(classParent.text)): @@ -155,11 +157,13 @@ def visitClassDefine(self, ctx:COOL.ClassDefineContext): column = str(classParent.column + 1) error = f"({line}, {column}) - SemanticError: Class {coolClass.text} cannot inherit class {classParent.text}" print(error) + self.hasNoError = False elif not (self.TypeTable[coolClass.text].Deep > self.TypeTable[classParent.text].Deep): line = str(classParent.line) column = str(classParent.column + 1) error = f"({line}, {column}) - SemanticError: Class {coolClass.text}, or an ancestor of {coolClass.text}, is involved in an inheritance cycle." print(error) + self.hasNoError = False else: self.TypeTable[coolClass.text].Created = True self.TypeTable[coolClass.text].Sealed = False @@ -174,6 +178,7 @@ def visitClassDefine(self, ctx:COOL.ClassDefineContext): column = str(classParent.column + 1) error = f"({line}, {column}) - TypeError: Class {coolClass.text} inherits from an undefined class {classParent.text}." print(error) + self.hasNoError = False else: self.TypeTable[coolClass.text].Created = True self.TypeTable[coolClass.text].Sealed = False @@ -194,6 +199,7 @@ def visitMethod(self, ctx:COOL.MethodContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Method {methodName} is multiply defined." print(error) + self.hasNoError = False return if self.searchMethod(self.TypeTable[coolClass].Parent, methodName): ancestorMethod = self.searchMethodInfo(self.TypeTable[coolClass].Parent,methodName) @@ -202,12 +208,14 @@ def visitMethod(self, ctx:COOL.MethodContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) SemanticError: Incompatible number of formal parameters in redefined method {methodName}." print(error) + self.hasNoError = False return if ancestorMethod.Type != methodType.text: line = str(methodType.line) column = str(methodType.column + 1) error = f"({line}, {column}) SemanticError: In redefined method {methodName}, return type {methodType.text} is different from original return type {ancestorMethod.Type}." print(error) + self.hasNoError = False return if self.TypeTable.keys().__contains__(self.TypeTable[coolClass].Methods[methodName].Type) or methodType.text == "SELF_TYPE": self.ScopeManager.addIdentifier(methodName, methodType.text) @@ -223,6 +231,7 @@ def visitMethod(self, ctx:COOL.MethodContext): column = str(ctx.getChild(len(ctx.children) - 2).start.column + 1) error = f"({line}, {column}) - TypeError: Inferred return type {methodValue} of method {methodName} does not conform to declared return type {methodType.text}." print(error) + self.hasNoError = False self.ScopeManager.deleteScope() return else: @@ -230,6 +239,7 @@ def visitMethod(self, ctx:COOL.MethodContext): column = str(methodType.column + 1) error = f"({line}, {column}) - TypeError: Undefined return type {methodType.text} in method {methodName}." print(error) + self.hasNoError = False # Visit a parse tree produced by COOL#property. def visitProperty(self, ctx:COOL.PropertyContext): @@ -241,24 +251,28 @@ def visitProperty(self, ctx:COOL.PropertyContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Attribute {atributeName} is multiply defined in class." print(error) + self.hasNoError = False return "None" elif atributeName == "self": line = str(ctx.getChild(0).symbol.line) column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: 'self' cannot be the name of an atribute." print(error) + self.hasNoError = False return elif not(self.TypeTable.keys().__contains__(atributeType) or atributeType == "SELF_TYPE"): line = str(ctx.getChild(2).symbol.line) column = str(ctx.getChild(2).symbol.column + 1) error = f"({line}, {column}) - TypeError: Class {atributeType} of attribute {atributeName} is undefined." print(error) + self.hasNoError = False return "None" elif self.TypeTable[self.TypeTable[coolClass].Parent].Atributes.keys().__contains__(atributeName): line = str(ctx.getChild(0).symbol.line) column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Attribute {atributeName} is an attribute of an inherited class." print(error) + self.hasNoError = False return "None" elif len(ctx.children) == 5: atributeValue = ctx.getChild(4).accept(self) @@ -267,6 +281,7 @@ def visitProperty(self, ctx:COOL.PropertyContext): column = str(ctx.getChild(4).start.column + 1) error = f"({line}, {column}) - TypeError: Inferred type {atributeValue} of initialization of attribute {atributeName} does not conform to declared type {atributeType}." print(error) + self.hasNoError = False return "None" else: self.ScopeManager.addIdentifier(atributeName, atributeType) @@ -289,12 +304,14 @@ def visitFormal(self, ctx:COOL.FormalContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: 'self' cannot be the name of a formal parameter." print(error) + self.hasNoError = False return if self.ScopeManager.searchScope(paramName): line = str(ctx.getChild(0).symbol.line) column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Formal parameter {paramName} is multiply defined." print(error) + self.hasNoError = False return if self.searchMethod(self.TypeTable[coolClass].Parent, methodName): ancestorMethod = self.searchMethodInfo(self.TypeTable[coolClass].Parent,methodName) @@ -310,6 +327,7 @@ def visitFormal(self, ctx:COOL.FormalContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: In redefined method {methodName}, parameter type {paramType} is different from original type {acType}." print(error) + self.hasNoError = False return i += 1 if not exist: @@ -317,6 +335,7 @@ def visitFormal(self, ctx:COOL.FormalContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - SemanticError: In ancestor method {methodName}, dont exist param {paramName}." print(error) + self.hasNoError = False return if self.TypeTable.keys().__contains__(paramType): self.ScopeManager.addIdentifier(paramName, paramType) @@ -326,6 +345,7 @@ def visitFormal(self, ctx:COOL.FormalContext): column = str(ctx.getChild(2).symbol.column + 1) error = f"({line}, {column}) - TypeError: Class {paramType} of formal parameter {paramName} is undefined." print(error) + self.hasNoError = False # Visit a parse tree produced by COOL#int. def visitInt(self, ctx: COOL.IntContext): @@ -353,6 +373,7 @@ def visitAdd(self, ctx: COOL.AddContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} + {rightValue}" print(error) + self.hasNoError = False addValue = "None" return addValue @@ -366,6 +387,7 @@ def visitMinus(self, ctx:COOL.MinusContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} - {rightValue}" print(error) + self.hasNoError = False minusValue = "None" return minusValue @@ -379,6 +401,7 @@ def visitMultiply(self, ctx: COOL.MultiplyContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} * {rightValue}" print(error) + self.hasNoError = False mulValue = "None" return mulValue @@ -392,6 +415,7 @@ def visitDivision(self, ctx: COOL.DivisionContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} / {rightValue}" print(error) + self.hasNoError = False divValue = "None" return divValue @@ -402,9 +426,10 @@ def visitNegative(self, ctx: COOL.NegativeContext): return "Int" else: line = str(ctx.getChild(1).start.line) - column = str(ctx.getChild(1).start.column) + column = str(ctx.getChild(1).start.column + 1) error = f"({line}, {column}) - TypeError: Argument of '~' has type {expressValue} instead of Int." print(error) + self.hasNoError = False return "None" # Visit a parse tree produced by COOL#isvoid. @@ -422,6 +447,7 @@ def visitBoolNot(self, ctx: COOL.BoolNotContext): column = str(ctx.getChild(1).start.column + 1) error = f"({line}, {column}) - TypeError: Argument of 'not' has type {expressValue} instead of Bool." print(error) + self.hasNoError = False return "None" # Visit a parse tree produced by COOL#lessThan. @@ -434,6 +460,7 @@ def visitLessThan(self, ctx:COOL.LessThanContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} < {rightValue}" print(error) + self.hasNoError = False lessValue = "None" return lessValue @@ -447,6 +474,7 @@ def visitLessEqual(self, ctx:COOL.LessEqualContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: non-Int arguments: {leftValue} <= {rightValue}" print(error) + self.hasNoError = False lessEqualValue = "None" return lessEqualValue @@ -463,12 +491,14 @@ def visitEqual(self, ctx: COOL.EqualContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: Illegal comparison with a basic type." print(error) + self.hasNoError = False return "None" elif rightValue == "String" or rightValue == "Int" or rightValue == "Bool": line = str(ctx.getChild(1).symbol.line) column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: Illegal comparison with a basic type." print(error) + self.hasNoError = False return "None" else: return "Bool" @@ -486,6 +516,7 @@ def visitAssignment(self, ctx: COOL.AssignmentContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - NameError: Undeclared identifier {variableName}." print(error) + self.hasNoError = False return "None" if variableType == "SELF_TYPE": variableType = self.actualClass @@ -494,12 +525,14 @@ def visitAssignment(self, ctx: COOL.AssignmentContext): column = str(ctx.getChild(2).start.column + 1) error = f"({line}, {column}) - TypeError: Cannot assign {asignValue} expression to {variableType} identifier." print(error) + self.hasNoError = False return "None" if variableName == "self": line = str(ctx.getChild(1).symbol.line) column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Cannot assign to 'self'." print(error) + self.hasNoError = False return "None" return asignValue @@ -518,6 +551,7 @@ def visitId(self, ctx: COOL.IdContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) - NameError: Undeclared identifier {IdValue}." print(error) + self.hasNoError = False return "None" # Visit a parse tree produced by COOL#if. @@ -532,6 +566,7 @@ def visitIf(self, ctx:COOL.IfContext): column = str(ctx.getChild(1).start.column + 1) error = f"({line}, {column}) - TypeError: Predicate of 'if' does not have type Bool." print(error) + self.hasNoError = False return self.join(thenValue, elseValue) # Visit a parse tree produced by COOL#while. @@ -545,6 +580,7 @@ def visitWhile(self, ctx: COOL.WhileContext): column = str(ctx.getChild(1).start.column + 1) error = f"({line}, {column}) - TypeError: Loop condition does not have type Bool." print(error) + self.hasNoError = False return "Object" # Visit a parse tree produced by COOL#block. @@ -573,11 +609,13 @@ def visitCase(self, ctx:COOL.CaseContext): column = str(ctx.getChild(count).symbol.column + 1) error = f"({line}, {column}) - TypeError: Class {idType} of case branch is undefined." print(error) + self.hasNoError = False if typeList.__contains__(idType): line = str(ctx.getChild(count).symbol.line) column = str(ctx.getChild(count).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Duplicate branch {idType} in case statement." print(error) + self.hasNoError = False count = count + 2 typeList.append(idType) self.ScopeManager.addScope() @@ -598,6 +636,7 @@ def visitNew(self, ctx: COOL.NewContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - TypeError: 'new' used with undefined class {typeName}." print(error) + self.hasNoError = False return typeName # Visit a parse tree produced by COOL#ownMethodCall. @@ -614,12 +653,14 @@ def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(1).symbol.text} called with wrong number of arguments." print(error) + self.hasNoError = False methodType = "None" elif len(ctx.children) != methodInfo.ParamsNumber * 2 + 2 and methodInfo.ParamsNumber != 0: line = str(ctx.getChild(1).symbol.line) column = str(ctx.getChild(1).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(1).symbol.text} called with wrong number of arguments." print(error) + self.hasNoError = False methodType = "None" else: count = 2 @@ -631,6 +672,7 @@ def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): column = str(ctx.getChild(count).start.column + 1) error = f"({line}, {column}) - TypeError: In call of method {ctx.getChild(1).symbol.text}, type {requestType} of parameter {paramName} does not conform to declared type {paramType}." print(error) + self.hasNoError = False methodType = "None" count = count + 2 else: @@ -638,6 +680,7 @@ def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): column = str(ctx.getChild(0).symbol.column + 1) error = f"({line}, {column}) AttributeError: Dispatch to undefined method {ctx.getChild(0).symbol.text}." print(error) + self.hasNoError = False return methodType # Visit a parse tree produced by COOL#methodCall. @@ -655,6 +698,7 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): column = str(ctx.getChild(1).symbol.column) error = f"({line}, {column}) - SemanticError: Expression type {currentClass} does not conform to declared static dispatch type {parent}." print(error) + self.hasNoError = False return methodType if self.searchMethod(currentClass, ctx.getChild(length - 3).symbol.text): methodInfo = self.searchMethodInfo(currentClass, ctx.getChild(length - 3).symbol.text) @@ -667,12 +711,14 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): column = str(ctx.getChild(2).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(2).symbol.text} called with wrong number of arguments." print(error) + self.hasNoError = False methodType = "None" elif (len(ctx.children) != methodInfo.ParamsNumber * 2 + length - 1) and methodInfo.ParamsNumber > 0: line = str(ctx.getChild(2).symbol.line) column = str(ctx.getChild(2).symbol.column + 1) error = f"({line}, {column}) - SemanticError: Method {ctx.getChild(2).symbol.text} called with wrong number of arguments." print(error) + self.hasNoError = False methodType = "None" else: count = length - 1 @@ -684,6 +730,7 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): column = str(ctx.getChild(count).start.column + 1) error = f"({line}, {column}) - TypeError: In call of method {ctx.getChild(2).symbol.text}, type {requestType} of parameter {paramName} does not conform to declared type {paramType}." print(error) + self.hasNoError = False methodType = "None" count = count + 2 else: @@ -691,6 +738,7 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): column = str(ctx.getChild(length - 3).symbol.column + 1) error = f"({line}, {column}) AttributeError: Dispatch to undefined method {ctx.getChild(length - 3).symbol.text}." print(error) + self.hasNoError = False return methodType # Visit a parse tree produced by COOL#letIn. @@ -705,6 +753,7 @@ def visitLetIn(self, ctx: COOL.LetInContext): column = str(ctx.getChild(count + 1).symbol.column + 1) error = f"({line}, {column}) - SemanticError: 'self' cannot be bound in a 'let' expression." print(error) + self.hasNoError = False return "None" count = count + 2 idType = ctx.getChild(count + 1).symbol.text @@ -714,6 +763,7 @@ def visitLetIn(self, ctx: COOL.LetInContext): column = str(ctx.getChild(count + 1).symbol.column + 1) error = f"({line}, {column}) - TypeError: Class {idType} of let-bound identifier {idName} is undefined." print(error) + self.hasNoError = False return "None" self.ScopeManager.addIdentifier(idName, idType) count = count + 2 @@ -726,6 +776,7 @@ def visitLetIn(self, ctx: COOL.LetInContext): column = str(ctx.getChild(count - 1).start.column + 1) error = f"({line}, {column}) - TypeError: Inferred type of {idValue} initialization of {idName} does not conform to identifier's declared type {idType}." print(error) + self.hasNoError = False return "None" temp = ctx.getChild(count + 1).accept(self) From cd7e20014a421dc42e345e680f5650b7dd2a4c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Thu, 26 Nov 2020 14:12:31 -0500 Subject: [PATCH 42/77] =?UTF-8?q?Ajustes=20en=20la=20generaci=C3=B3n=20de?= =?UTF-8?q?=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Visitors.py | 270 +++++++++++++++++++++++++++-------- tests/codegen/hello_world.cl | 12 +- 2 files changed, 222 insertions(+), 60 deletions(-) diff --git a/src/Visitors.py b/src/Visitors.py index 2358ece1..0c7dd42d 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -27,7 +27,7 @@ def __init__(self, name: str, type: str, paramNumber: int, instructionSet): self.ParamsNumber= paramNumber self.InstructionSet = instructionSet -class COOLScopeManager: +class SemanticScopeManager: def __init__(self): self.Stack = deque() @@ -59,8 +59,41 @@ def searchforType(self, identifier: str): return scope[identifier] return "None" -class SemanticCOOLVisitor(ParseTreeVisitor): +class GenScopeManager: + def __init__(self): + self.Stack = deque() + + def addScope(self): + self.Stack.append({}) + + def addIdentifier(self, name: str, type: str): + scope = self.Stack.pop() + scope[name] = type + self.Stack.append(scope) + + def deleteScope(self): + self.Stack.pop() + + def searchScope(self, identifier: str): + scope = self.Stack.pop() + self.Stack.append(scope) + return scope.keys().__contains__(identifier) + def searchIdentifier(self, identifier: str): + for scope in reversed(self.Stack): + if (len(scope) != 0): + if(scope.keys().__contains__(identifier)): + return self.Stack.index(scope) + return -1 + + def searchType(self, identifier: str): + for scope in reversed(self.Stack): + if (len(scope) != 0): + if(scope.keys().__contains__(identifier)): + return scope[identifier] + return "None" + +class SemanticCOOLVisitor(ParseTreeVisitor): def join(self, class1: str, class2: str): if class1 == "None" or class2 == "None": return "None" @@ -120,10 +153,9 @@ def searchAtributeInfo(self, coolClass: str, atributeName: str): return self.TypeTable[coolClass].Atributes[atribute] return self.searchAtributeInfo(self.TypeTable[coolClass].Parent, atributeName) - def __init__(self, typeTable: dict): self.TypeTable = typeTable - self.ScopeManager = COOLScopeManager() + self.ScopeManager = SemanticScopeManager() self.actualClass = "Object" self.hasNoError = True @@ -1021,11 +1053,28 @@ class CodegenVisitor(ParseTreeVisitor): CurrentClass : COOLClass + CurrentMethod: COOLMethod + + CurrentType: str + + def searchAtributeInfo(self, coolClass: str, atributeName: str): + for atribute in self.TypeTable[coolClass].Atributes.keys(): + if atribute == atributeName: + return self.TypeTable[coolClass].Atributes[atribute] + return self.searchAtributeInfo(self.TypeTable[coolClass].Parent, atributeName) + + def searchMethodInfo(self, coolClass: str, methodName: str): + for method in self.TypeTable[coolClass].Methods.keys(): + if method == methodName: + return self.TypeTable[coolClass].Methods[method].Type + return self.searchMethodInfo(self.TypeTable[coolClass].Parent, methodName) + def __init__(self, typeTable: dict, constantTable: list, counter: int): self.TypeTable = typeTable self.ConstantTable = constantTable self.Counter = counter self.LabelCounter = 0 + self.ScopeManager = GenScopeManager() def genGlobalClases(self): sol = "\t.data\n\t.align 2\n\t.globl class_nameTab\n" @@ -1090,8 +1139,6 @@ def genMethodNames(self, coolClass: str, coolMethods: list, className: str): self.TypeTable[coolClass].TagMethods = methodList return code + temp - - def genAtributeNames(self, coolClass: str, coolAtributes: list): if coolClass == "None": return "" @@ -1162,12 +1209,15 @@ def genClassAtributes(self, className: str): code = self.genClassAtributes(self.TypeTable[className].Parent) for atribute in self.TypeTable[className].AtributeAsign: code = code + (self.TypeTable[className].AtributeAsign[atribute].accept(self) or "") + pos = self.CurrentClass.TagAtributes.index(atribute) + code = code + f"\tsw $a0 {pos * 4 + 12}($s0)\n" return code # Visit a parse tree produced by COOL#program. def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): for className in self.TypeTable: constantName = className + self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) self.Counter = self.Counter + 1 length = len(constantName) @@ -1201,6 +1251,8 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): "\t.globl Bool_init\n" \ "\t.globl Main.main\n" for className in self.TypeTable: + self.CurrentClass = self.TypeTable[className] + self.CurrentType = className code = code + f"{className}_init:\n" temp = self.genClassAtributes(className) if len(temp) != 0: @@ -1222,7 +1274,16 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): for className in self.TypeTable: if not(className == "Object" or className == "String" or className == "Int" or className == "Bool" or className == "IO"): self.CurrentClass = self.TypeTable[className] - for methodName in self.TypeTable[className].Methods: + self.ScopeManager.addScope() + for atribute in self.CurrentClass.TagAtributes: + self.ScopeManager.addIdentifier(atribute,self.searchAtributeInfo(className, atribute)) + for methodName in self.CurrentClass.Methods: + self.CurrentMethod = self.CurrentClass.Methods[methodName] + self.CurrentType = self.CurrentMethod.Type + self.ScopeManager.addScope() + for param in self.CurrentClass.Methods[methodName].Params: + (paramName, paramType) = param + self.ScopeManager.addIdentifier(paramName, paramType) code = code + f"{className}.{methodName}:\n" code = code + \ "\taddiu $sp $sp -12\n" \ @@ -1239,6 +1300,9 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): "\tlw $ra 4($sp)\n" \ "\taddiu $sp $sp 12\n" code = code + "\tjr $ra\n" + self.ScopeManager.deleteScope() + + self.ScopeManager.deleteScope() code = self.RuntimeMessages + \ "\n" + \ @@ -1284,22 +1348,23 @@ def visitLetIn(self, ctx: COOL.LetInContext): def visitMinus(self, ctx: COOL.MinusContext): code = ctx.getChild(0).accept(self) code = code + \ - "\tsw $a0 0 ($sp)\n" + \ - "\taddiu $sp $sp -4\n" + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" code = code + ctx.getChild(2).accept(self) code = code + \ - "\tjal Object.copy\n" + \ - "\tlw $t1 4($sp)\n" + \ - "\tlw $t1 12($t1)\n" + \ - "\tlw $t2 12($a0)\n" + \ - "\tsub $t1 $t1 $t2\n" + \ - "\tsw $t1 12($a0)\n" + \ - "\taddiu $sp $sp 4\n" + "\tjal Object.copy\n" + \ + "\tlw $t1 4($sp)\n" + \ + "\tlw $t1 12($t1)\n" + \ + "\tlw $t2 12($a0)\n" + \ + "\tsub $t1 $t1 $t2\n" + \ + "\tsw $t1 12($a0)\n" + \ + "\taddiu $sp $sp 4\n" return code # Visit a parse tree produced by COOL#string. def visitString(self, ctx: COOL.StringContext): name = ctx.getChild(0).symbol.text[1:-1] + self.CurrentType = "String" for const in self.ConstantTable: (constName, constType, constTag) = const if constType == "String" and constName == name: @@ -1317,18 +1382,18 @@ def visitWhile(self, ctx: COOL.WhileContext): def visitDivision(self, ctx: COOL.DivisionContext): code = ctx.getChild(0).accept(self) code += \ - "\tsw $a0 0 ($sp)\n" + \ - "\taddiu $sp $sp -4\n" + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" code += ctx.getChild(2).accept(self) code += \ - "\tjal Object.copy\n" \ - "\tlw $t1 4($sp)\n" \ - "\tlw $t1 12($t1)\n" \ - "\tlw $t2 12($a0)\n" \ - "\tdiv $t1 $t2\n" \ - "\tmflo $t1\n" \ - "\tsw $t1 12($a0)\n" \ - "\taddiu $sp $sp 4\n" + "\tjal Object.copy\n" \ + "\tlw $t1 4($sp)\n" \ + "\tlw $t1 12($t1)\n" \ + "\tlw $t2 12($a0)\n" \ + "\tdiv $t1 $t2\n" \ + "\tmflo $t1\n" \ + "\tsw $t1 12($a0)\n" \ + "\taddiu $sp $sp 4\n" return code # Visit a parse tree produced by COOL#negative. @@ -1355,23 +1420,58 @@ def visitBlock(self, ctx: COOL.BlockContext): # Visit a parse tree produced by COOL#id. def visitId(self, ctx: COOL.IdContext): - return self.visitChildren(ctx) + varName = ctx.getChild(0).symbol.text + if varName == "self": + self.CurrentType = self.CurrentClass.Name + return "\tlw $a0 ($s0)\n" + self.CurrentType = self.ScopeManager.searchType(varName) + option = self.ScopeManager.searchIdentifier(varName) + if option == 0: + return self.propertyId(ctx) + elif option == 1: + return self.formalId(ctx) + else: + return self.variableId(ctx) + + def propertyId(self, ctx: COOL.AssignmentContext): + varName = ctx.getChild(0).symbol.text + pos = self.CurrentClass.TagAtributes.index(varName) + code = f"\tlw $a0 {pos * 4 + 12}($s0)\n" + return code + + def formalId(self, ctx: COOL.AssignmentContext): + varName = ctx.getChild(0).symbol.text + varType = self.ScopeManager.Stack[1][varName] + pos = self.CurrentMethod.Params.index((varName,varType)) + total = self.CurrentMethod.ParamsNumber + code = f"\tlw $a0 {(pos - (total + 2)) * 4}($fp)\n" + return code + + def variableId(self, ctx: COOL.AssignmentContext): + varName = ctx.getChild(0).symbol.text + scope = self.ScopeManager.searchIdentifier(varName) + pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) + total = 0 + for scope in self.ScopeManager.Stack [2 : pos]: + total += len(list(scope.keys())) + code = f"\tlw $a0 {(total + pos) * 4}($fp)\n" + return code # Visit a parse tree produced by COOL#multiply. def visitMultiply(self, ctx: COOL.MultiplyContext): code = ctx.getChild(0).accept(self) code = code + \ - "\tsw $a0 0 ($sp)\n" + \ - "\taddiu $sp $sp -4\n" + "\tsw $a0 0 ($sp)\n" + \ + "\taddiu $sp $sp -4\n" code = code + ctx.getChild(2).accept(self) code = code + \ - "\tjal Object.copy\n" + \ - "\tlw $t1 4($sp)\n" + \ - "\tlw $t1 12($t1)\n" + \ - "\tlw $t2 12($a0)\n" + \ - "\tmul $t1 $t1 $t2\n" + \ - "\tsw $t1 12($a0)\n" + \ - "\taddiu $sp $sp 4\n" + "\tjal Object.copy\n" + \ + "\tlw $t1 4($sp)\n" + \ + "\tlw $t1 12($t1)\n" + \ + "\tlw $t2 12($a0)\n" + \ + "\tmul $t1 $t1 $t2\n" + \ + "\tsw $t1 12($a0)\n" + \ + "\taddiu $sp $sp 4\n" return code # Visit a parse tree produced by COOL#if. @@ -1394,32 +1494,34 @@ def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): f"\tsw $a0 0($sp)\n" \ f"\taddiu $sp $sp -4\n" count = count + 2 - methodIdx = self.CurrentClass.TagMethods.index(ctx.getChild(0).symbol.text) - code += "\tmove $a0 $s0\n" \ - "\tlw $t1 8($a0)\n" \ - f"\tlw $t1 {methodIdx * 4}($t1)\n" \ - "\tjalr $t1\n" + methodIdx = self.CurrentClass.TagMethods.index(ctx.getChild(0).symbol.text) + self.CurrentType = self.searchMethodInfo(self.CurrentClass.Name, ctx.getChild(0).symbol.text) + code += "\tmove $a0 $s0\n" \ + "\tlw $t1 8($a0)\n" \ + f"\tlw $t1 {methodIdx * 4}($t1)\n" \ + "\tjalr $t1\n" return code # Visit a parse tree produced by COOL#add. def visitAdd(self, ctx: COOL.AddContext): code = ctx.getChild(0).accept(self) or "" code = code + \ - "\tsw $a0 0 ($sp)\n"+ \ - "\taddiu $sp $sp -4\n" + "\tsw $a0 0 ($sp)\n"+ \ + "\taddiu $sp $sp -4\n" code = code + ctx.getChild(2).accept(self) code = code + \ - "\tjal Object.copy\n"+ \ - "\tlw $t1 4($sp)\n"+ \ - "\tlw $t1 12($t1)\n"+ \ - "\tlw $t2 12($a0)\n"+ \ - "\tadd $t1 $t1 $t2\n"+ \ - "\tsw $t1 12($a0)\n"+ \ - "\taddiu $sp $sp 4\n" + "\tjal Object.copy\n"+ \ + "\tlw $t1 4($sp)\n"+ \ + "\tlw $t1 12($t1)\n"+ \ + "\tlw $t2 12($a0)\n"+ \ + "\tadd $t1 $t1 $t2\n"+ \ + "\tsw $t1 12($a0)\n"+ \ + "\taddiu $sp $sp 4\n" return code # Visit a parse tree produced by COOL#new. def visitNew(self, ctx: COOL.NewContext): + self.CurrentType = ctx.getChild(1).symbol.text return self.visitChildren(ctx) # Visit a parse tree produced by COOL#parentheses. @@ -1428,15 +1530,50 @@ def visitParentheses(self, ctx: COOL.ParenthesesContext): # Visit a parse tree produced by COOL#assignment. def visitAssignment(self, ctx: COOL.AssignmentContext): - return self.visitChildren(ctx) + varName = ctx.getChild(0).symbol.text + option = self.ScopeManager.searchIdentifier(varName) + if option == 0: + return self.propertyAssignament(ctx) + elif option == 1: + return self.formalAssignament(ctx) + else: + return self.variableAssignament(ctx) + + def propertyAssignament(self, ctx: COOL.AssignmentContext): + varName = ctx.getChild(0).symbol.text + code = ctx.getChild(2).accept(self) + pos = self.CurrentClass.TagAtributes.index(varName) + code = code + f"\tsw $a0 {pos * 4 + 12}($s0)\n" + return code + + def formalAssignament(self, ctx: COOL.AssignmentContext): + varName = ctx.getChild(0).symbol.text + code = ctx.getChild(2).accept(self) + varType = self.ScopeManager.Stack[1][varName] + pos = self.CurrentMethod.Params.index((varName, varType)) + total = self.CurrentMethod.ParamsNumber + code = code + f"\tsw $a0 {(pos - (total + 2)) * 4}($fp)\n" + return code + + def variableAssignament(self, ctx: COOL.AssignmentContext): + varName = ctx.getChild(0).symbol.text + scope = self.ScopeManager.searchIdentifier(varName) + pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) + total = 0 + for scope in self.ScopeManager.Stack[2: pos]: + total += len(list(scope.keys())) + code = f"\tsw $a0 {(total + pos) * 4}($fp)\n" + return code # Visit a parse tree produced by COOL#false. def visitFalse(self, ctx: COOL.FalseContext): + self.CurrentType = "Bool" return f"\tla $a0 {bool_const0}\n" # Visit a parse tree produced by COOL#int. def visitInt(self, ctx: COOL.IntContext): val = int(ctx.getChild(0).symbol.text) + self.CurrentType = "Int" for const in self.ConstantTable: (constVal, constType, constTag) = const if constType == "Int" and constVal == val: @@ -1448,7 +1585,8 @@ def visitEqual(self, ctx: COOL.EqualContext): # Visit a parse tree produced by COOL#true. def visitTrue(self, ctx: COOL.TrueContext): - return f"\tla $a0 {bool_const1}\n" + self.CurrentType = "Bool" + return f"\tla $a0 bool_const1\n" # Visit a parse tree produced by COOL#lessEqual. def visitLessEqual(self, ctx: COOL.LessEqualContext): @@ -1456,13 +1594,27 @@ def visitLessEqual(self, ctx: COOL.LessEqualContext): # Visit a parse tree produced by COOL#methodCall. def visitMethodCall(self, ctx: COOL.MethodCallContext): - # line = ctx.getChild(1).symbol.line - # f"\tbne $t2 $zero label{self.LabelCounter}\n" \ - # "\tla $a0 str_const1\n" \ - # f"\tli $t1 {line}\n" \ - # "\tjal _dispatch_abort\n" \ - # f"label{self.LabelCounter}:\n" \ - # self.LabelCounter += 1 + length = 5 + code = ctx.getChild(0).accept(self) or "" + classId = self.CurrentType + if ctx.getChild(1).symbol.text == "@": + length += 2 + classId = ctx.getChild(2).symbol.text + if len(ctx.children) > length: + count = length - 1 + while length != count: + param = (ctx.getChild(count).accept(self) or "") + code += param + \ + f"\tsw $a0 0($sp)\n" \ + f"\taddiu $sp $sp -4\n" + count = count + 2 + methodIdx = self.TypeTable[classId].TagMethods.index(ctx.getChild(length - 3).symbol.text) + self.CurrentType = self.searchMethodInfo(self.CurrentClass.Name, ctx.getChild(length - 3).symbol.text) + code += "\tmove $a0 $s0\n" \ + "\tlw $t1 8($a0)\n" \ + f"\tlw $t1 {methodIdx * 4}($t1)\n" \ + "\tjalr $t1\n" + return code return "" RuntimeMessages = """ diff --git a/tests/codegen/hello_world.cl b/tests/codegen/hello_world.cl index 2055d2a7..7cefd7a3 100755 --- a/tests/codegen/hello_world.cl +++ b/tests/codegen/hello_world.cl @@ -1,9 +1,19 @@ class Main inherits IO { x : Int <- 1; + + sqrt (x : Int) : Int + { + x * x + }; + main(): IO { { out_string("Hello, World ("); - out_int(3*2-7*2*2); + out_int(x * 2); + x <- 0 -7; + x <- sqrt(x); + out_string(", "); + out_int(x); out_string(").\n"); } }; From 00cc56cdedab7e5d997b8b3f33f98ae17f52a84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sat, 28 Nov 2020 18:58:57 -0500 Subject: [PATCH 43/77] =?UTF-8?q?Se=20resolvieron=20varios=20bugs=20de=20l?= =?UTF-8?q?a=20generaci=C3=B3n=20de=20c=C3=B3digo.=20Se=20modificaron=20va?= =?UTF-8?q?rios=20de=20los=20programas=20de=20prueba=20para=20probar=20el?= =?UTF-8?q?=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Visitors.py | 309 ++++++++++++++++++++++++++++------- tests/codegen/arith.cl | 10 +- tests/codegen/atoi.cl | 73 ++++++--- tests/codegen/hello_world.cl | 16 +- 4 files changed, 317 insertions(+), 91 deletions(-) diff --git a/src/Visitors.py b/src/Visitors.py index 0c7dd42d..9de9207e 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -80,11 +80,13 @@ def searchScope(self, identifier: str): return scope.keys().__contains__(identifier) def searchIdentifier(self, identifier: str): + index = len(self.Stack) - 1 for scope in reversed(self.Stack): if (len(scope) != 0): if(scope.keys().__contains__(identifier)): - return self.Stack.index(scope) - return -1 + return index + index -= 1 + return index def searchType(self, identifier: str): for scope in reversed(self.Stack): @@ -603,7 +605,7 @@ def visitIf(self, ctx:COOL.IfContext): # Visit a parse tree produced by COOL#while. def visitWhile(self, ctx: COOL.WhileContext): - whileValue = ctx.getChild(3).accept(self) + ctx.getChild(3).accept(self) #chequea semanticamente el cuerpo whileValue = ctx.getChild(1).accept(self) if whileValue == "None" or whileValue == "Bool": return "Object" @@ -848,6 +850,7 @@ def visitProgram(self, ctx: COOL.ProgramContext, fileName: str): self.ConstantTable.append(("", "String", "str_const0")) self.ConstantTable.append((0, "Int", "int_const0")) self.ConstantTable.append(("false", "Bool", "bool_const0")) + self.ConstantTable.append(("true", "Bool", "bool_const1")) self.ConstantTable.append((fileName, "String", "str_const1")) self.ConstantTable.append((len(fileName), "Int", F"int_const{len(fileName)}")) self.Counter = 2 @@ -905,7 +908,6 @@ def visitProperty(self, ctx: COOL.PropertyContext): # Visit a parse tree produced by COOL#formal. def visitFormal(self, ctx: COOL.FormalContext): parent = ctx.parentCtx - className = parent.parentCtx.getChild(1).symbol.text methodName = parent.getChild(0).symbol.text method = self.TypeTable[className].Methods[methodName] @@ -1057,6 +1059,23 @@ class CodegenVisitor(ParseTreeVisitor): CurrentType: str + def join(self, class1: str, class2: str): + if class1 == "None" or class2 == "None": + return "None" + if class1 == "SELF_TYPE": + class1 = self.CurrentClass.Name + if class2 == "SELF_TYPE": + class2 = self.CurrentClass.Name + if self.TypeTable[class1].Deep == self.TypeTable[class2].Deep: + if self.TypeTable[class1].Name == self.TypeTable[class2].Name: + return class1 + else: + return self.join(self.TypeTable[class1].Parent, self.TypeTable[class2].Parent) + elif self.TypeTable[class1].Deep > self.TypeTable[class2].Deep: + return self.join(self.TypeTable[class1].Parent, class2) + else: + return self.join(class1, self.TypeTable[class2].Parent) + def searchAtributeInfo(self, coolClass: str, atributeName: str): for atribute in self.TypeTable[coolClass].Atributes.keys(): if atribute == atributeName: @@ -1091,14 +1110,14 @@ def genConstant(self, sol: str): sol = sol + \ f"\t.word -1\n" \ f"{constLabel}:\n" \ - f"\t.word 5\n" \ + f"\t.word 3\n" \ f"\t.word 4\n" \ f"\t.word Bool_dispTab\n" \ f"\t.word {constLabel[-1]}\n" elif constType == "Int": sol = sol + \ f"\t.word -1\n{constLabel}:\n" \ - f"\t.word 3\n\t.word 4\n" \ + f"\t.word 2\n\t.word 4\n" \ f"\t.word Int_dispTab\n" \ f"\t.word {constName}\n" else: @@ -1107,7 +1126,7 @@ def genConstant(self, sol: str): length = length + 1 sol = sol + \ f"\t.word -1\n{constLabel}:\n" \ - f"\t.word 4\n\t.word {length}\n" \ + f"\t.word 1\n\t.word {length}\n" \ f"\t.word String_dispTab\n" \ f"\t.word int_const{len(constName)}\n" \ f"\t.ascii \"{constName}\"\n" \ @@ -1125,20 +1144,23 @@ def genMethodNames(self, coolClass: str, coolMethods: list, className: str): if coolClass == "None": return "" temp = "" - methodList = list() for method in self.TypeTable[coolClass].Methods: if not (coolMethods.__contains__(method)): temp = temp + f"\t.word {coolClass}.{method}\n" - methodList.append(method) coolMethods.append(method) code = self.genMethodNames(self.TypeTable[coolClass].Parent, coolMethods, className) - if coolClass != "Object": - self.TypeTable[coolClass].TagMethods = self.TypeTable[self.TypeTable[coolClass].Parent].TagMethods + methodList - else: - self.TypeTable[coolClass].TagMethods = methodList return code + temp + def genMethodTags(self, coolClass: str, coolMethods: list, className: str): + if coolClass == "None": + return coolMethods + coolMethods = self.genMethodTags(self.TypeTable[coolClass].Parent, coolMethods, className) + for method in self.TypeTable[coolClass].Methods: + if not (coolMethods.__contains__(method)): + coolMethods.append(method) + return coolMethods + def genAtributeNames(self, coolClass: str, coolAtributes: list): if coolClass == "None": return "" @@ -1149,7 +1171,7 @@ def genAtributeNames(self, coolClass: str, coolAtributes: list): listAtributes.append(atribute) value = self.TypeTable[coolClass].Atributes[atribute] if value == "Int" or value == "String" or value == "Bool": - temp = temp + f"\t.word {value.lower()}_constant0\n" + temp = temp + f"\t.word {value.lower()}_const0\n" else: temp = temp + f"\t.word 0\n" coolAtributes.append(atribute) @@ -1187,7 +1209,7 @@ def genClassTable(self): f"\t.word {counter}\n" \ f"\t.word 5\n" \ f"\t.word {className}_dispTab\n" \ - f"\t.word int_constant0\n" \ + f"\t.word int_const0\n" \ f"\t.word 0\n" else: atributeList = list() @@ -1217,7 +1239,6 @@ def genClassAtributes(self, className: str): def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): for className in self.TypeTable: constantName = className - self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) self.Counter = self.Counter + 1 length = len(constantName) @@ -1228,6 +1249,7 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): contain = False if contain: self.ConstantTable.append((length, "Int", f"int_const{length}")) + self.TypeTable[className].TagMethods = self.genMethodTags(className,list(),className) self.ConstantTable.append(("SELF_TYPE", "String", f"str_const{self.Counter}")) contain = True length = len("SELF_TYPE") @@ -1253,6 +1275,7 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): for className in self.TypeTable: self.CurrentClass = self.TypeTable[className] self.CurrentType = className + self.CurrentMethod = "None" code = code + f"{className}_init:\n" temp = self.genClassAtributes(className) if len(temp) != 0: @@ -1293,12 +1316,12 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): "\taddiu $fp $sp 4\n" \ "\tmove $s0 $a0\n" code = code + (self.TypeTable[className].Methods[methodName].InstructionSet.accept(self) or "") + # "\tmove $a0 $s0\n" \ code = code + \ - "\tmove $a0 $s0\n" \ "\tlw $fp 12($sp)\n" \ "\tlw $s0 8($sp)\n" \ "\tlw $ra 4($sp)\n" \ - "\taddiu $sp $sp 12\n" + f"\taddiu $sp $sp {12+4*self.CurrentClass.Methods[methodName].ParamsNumber}\n" code = code + "\tjr $ra\n" self.ScopeManager.deleteScope() @@ -1342,7 +1365,31 @@ def visitFormal(self, ctx: COOL.FormalContext): # Visit a parse tree produced by COOL#letIn. def visitLetIn(self, ctx: COOL.LetInContext): - return self.visitChildren(ctx) + self.ScopeManager.addScope() + count = 0 + varNumber = 0 + code = "" + while (ctx.getChild(count).symbol.text != "in"): + idName = ctx.getChild(count + 1).symbol.text + varNumber += 1 + count = count + 2 + idType = ctx.getChild(count + 1).symbol.text + count = count + 2 + if ctx.getChild(count).symbol.text == "<-": + code += ctx.getChild(count + 1).accept(self) + count = count + 2 + else: + if idType == "String" or idType == "Int" or idType == "Bool": + code += f"\tla $a0 {idType.lower()}_const0\n" + else: + code += "li $a0 0\n" + code += f"\tsw $a0 0($sp)\n" \ + f"\taddiu $sp $sp -4\n" + self.ScopeManager.addIdentifier(idName, idType) + code += ctx.getChild(count + 1).accept(self) + code += f"\taddiu $sp $sp {varNumber * 4}\n" + self.ScopeManager.deleteScope() + return code # Visit a parse tree produced by COOL#minus. def visitMinus(self, ctx: COOL.MinusContext): @@ -1372,17 +1419,35 @@ def visitString(self, ctx: COOL.StringContext): # Visit a parse tree produced by COOL#isvoid. def visitIsvoid(self, ctx: COOL.IsvoidContext): - return self.visitChildren(ctx) + code = ctx.getChild(1).accept(self) + code += \ + "\tla $t1 bool_const0\n" \ + "\tla $t2 bool_const1\n" \ + "\tmovz $t1 $t2 $a0\n" \ + "\tmove $a0 $t1\n" + self.CurrentType = "Bool" + return code # Visit a parse tree produced by COOL#while. def visitWhile(self, ctx: COOL.WhileContext): - return self.visitChildren(ctx) + code = f"while_label{self.Counter}:\n" + code += ctx.getChild(1).accept(self) + code += "\tlw $t1 12($a0)\n" + \ + f"\tbgtz $t1 loop_label{self.Counter}\n" + \ + f"\tb pool_label{self.Counter}\n" + \ + f"loop_label{self.Counter}:\n" + code += ctx.getChild(3).accept(self) + code += f"\tb while_label{self.Counter}\n" + \ + f"pool_label{self.Counter}:\n" + self.CurrentType = "None" + self.Counter += 1 + return code # Visit a parse tree produced by COOL#division. def visitDivision(self, ctx: COOL.DivisionContext): code = ctx.getChild(0).accept(self) code += \ - "\tsw $a0 0 ($sp)\n" + \ + "\tsw $a0 0($sp)\n" + \ "\taddiu $sp $sp -4\n" code += ctx.getChild(2).accept(self) code += \ @@ -1398,15 +1463,48 @@ def visitDivision(self, ctx: COOL.DivisionContext): # Visit a parse tree produced by COOL#negative. def visitNegative(self, ctx: COOL.NegativeContext): - return self.visitChildren(ctx) + self.CurrentType = "Int" + code = ctx.getChild(1).accept(self) + code += \ + "\tjal Object.copy\n" \ + "\tlw $t1 12($a0)\n" \ + "\tnegu $t1 $t1\n" \ + "\tsw $t1 12($a0)\n" \ + "\tsw $a0 0($sp)\n" + return code # Visit a parse tree produced by COOL#boolNot. def visitBoolNot(self, ctx: COOL.BoolNotContext): - return self.visitChildren(ctx) + self.CurrentType = "Bool" + code = ctx.getChild(1).accept(self) + code += \ + "\tjal Object.copy\n" \ + "\tlw $t1 12($a0)\n" \ + "\tnegu $t2 $t1\n" \ + "\taddiu $t3 $t2 1\n"\ + "\tsw $t3 12($a0)\n" \ + "\tsw $a0 0($sp)\n" + return code # Visit a parse tree produced by COOL#lessThan. def visitLessThan(self, ctx: COOL.LessThanContext): - return self.visitChildren(ctx) + self.CurrentType = "Bool" + code = ctx.getChild(0).accept(self) + code += \ + "\tsw $a0 0($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code += ctx.getChild(2).accept(self) + code += \ + "\tjal Object.copy\n" \ + "\tlw $t0 4($sp)\n" \ + "\tlw $t1 12($t0)\n" \ + "\tlw $t2 12($a0)\n" \ + "\tslt $t3 $t1 $t2\n" \ + "\tla $a0 bool_const0\n" \ + "\tjal Object.copy\n" \ + "\tsw $t3 12($a0)\n" \ + "\taddiu $sp $sp 4\n" + return code # Visit a parse tree produced by COOL#block. def visitBlock(self, ctx: COOL.BlockContext): @@ -1426,9 +1524,9 @@ def visitId(self, ctx: COOL.IdContext): return "\tlw $a0 ($s0)\n" self.CurrentType = self.ScopeManager.searchType(varName) option = self.ScopeManager.searchIdentifier(varName) - if option == 0: + if option == 0 and self.CurrentMethod != "None": return self.propertyId(ctx) - elif option == 1: + elif option == 1 and self.CurrentMethod != "None": return self.formalId(ctx) else: return self.variableId(ctx) @@ -1444,17 +1542,19 @@ def formalId(self, ctx: COOL.AssignmentContext): varType = self.ScopeManager.Stack[1][varName] pos = self.CurrentMethod.Params.index((varName,varType)) total = self.CurrentMethod.ParamsNumber - code = f"\tlw $a0 {(pos - (total + 2)) * 4}($fp)\n" + code = f"\tlw $a0 {((total + 2) - pos) * 4}($fp)\n" return code def variableId(self, ctx: COOL.AssignmentContext): varName = ctx.getChild(0).symbol.text scope = self.ScopeManager.searchIdentifier(varName) - pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) - total = 0 - for scope in self.ScopeManager.Stack [2 : pos]: - total += len(list(scope.keys())) - code = f"\tlw $a0 {(total + pos) * 4}($fp)\n" + pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) + 1 + init = 2 + if self.CurrentMethod == "None": + init = 0 + for scope in list(self.ScopeManager.Stack)[init : scope]: + pos += len(list(scope.keys())) + code = f"\tlw $a0 {-(pos * 4)}($fp)\n" return code # Visit a parse tree produced by COOL#multiply. @@ -1476,11 +1576,67 @@ def visitMultiply(self, ctx: COOL.MultiplyContext): # Visit a parse tree produced by COOL#if. def visitIf(self, ctx: COOL.IfContext): - return self.visitChildren(ctx) + code = ctx.getChild(1).accept(self) + counter = self.Counter + self.Counter += 1 + code = code + \ + "\tlw $t1 12($a0)\n" + \ + f"\tbgtz $t1 then_label{counter}\n" + \ + f"\tb else_label{counter}\n" + \ + f"then_label{counter}:\n" + code = code +\ + ctx.getChild(3).accept(self) + \ + f"\tb fi_label{counter}\n" + \ + f"else_label{counter}:\n" + tempType = self.CurrentType + code = code +\ + ctx.getChild(5).accept(self) + \ + f"\tb fi_label{counter}\n" + \ + f"fi_label{counter}:\n" + self.CurrentType = self.join(tempType, self.CurrentType) + return code # Visit a parse tree produced by COOL#case. def visitCase(self, ctx: COOL.CaseContext): - return "" + counter = self.Counter + self.Counter += 1 + code = ctx.getChild(1).accept(self) +\ + "\tli $t1 0\n" \ + f"\tbeq $a0 $t1 abort{counter}\n" + lengt = len(ctx.children) - 1 + tempCode = f"abort{counter}:\n" \ + "\tjal _case_abort2\n" + count = 3 + while lengt > count: + idName = ctx.getChild(count).symbol.text + count = count + 2 + idType = ctx.getChild(count).symbol.text + count = count + 2 + self.ScopeManager.addScope() + self.ScopeManager.addIdentifier(idName, idType) + code += \ + f"\tlw $t1 0($a0)\n" \ + f"\tli $t2 {self.TypeTable[idType].Tag}\n" \ + f"\tbeq $t1 $t2 {idType}_case{counter}\n" + scope = self.ScopeManager.searchIdentifier(idName) + pos = list(self.ScopeManager.Stack[scope].keys()).index(idName) + 1 + init = 2 + if self.CurrentMethod == "None": + init = 0 + for scope in list(self.ScopeManager.Stack)[init: scope]: + pos += len(list(scope.keys())) + tempCode +=\ + f"{idType}_case{counter}:\n" \ + f"\tsw $a0 -{pos * 4}($fp)\n" + tempCode += ctx.getChild(count).accept(self) + tempCode += f"\tb esac{counter}\n" + self.ScopeManager.deleteScope() + count = count + 2 + code = code + \ + "\tjal _case_abort\n" + code += tempCode +\ + f"esac{counter}:\n" + return code # Visit a parse tree produced by COOL#ownMethodCall. def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): @@ -1522,19 +1678,21 @@ def visitAdd(self, ctx: COOL.AddContext): # Visit a parse tree produced by COOL#new. def visitNew(self, ctx: COOL.NewContext): self.CurrentType = ctx.getChild(1).symbol.text - return self.visitChildren(ctx) + return f"\tla $a0 {self.CurrentType}_protObj\n"\ + "\tjal Object.copy\n" \ + f"\tjal {self.CurrentType}_init\n" # Visit a parse tree produced by COOL#parentheses. def visitParentheses(self, ctx: COOL.ParenthesesContext): - return self.visitChildren(ctx) + return ctx.getChild(1).accept(self) # Visit a parse tree produced by COOL#assignment. def visitAssignment(self, ctx: COOL.AssignmentContext): varName = ctx.getChild(0).symbol.text option = self.ScopeManager.searchIdentifier(varName) - if option == 0: + if option == 0 and self.CurrentMethod != "None": return self.propertyAssignament(ctx) - elif option == 1: + elif option == 1 and self.CurrentMethod != "None": return self.formalAssignament(ctx) else: return self.variableAssignament(ctx) @@ -1558,17 +1716,20 @@ def formalAssignament(self, ctx: COOL.AssignmentContext): def variableAssignament(self, ctx: COOL.AssignmentContext): varName = ctx.getChild(0).symbol.text scope = self.ScopeManager.searchIdentifier(varName) - pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) - total = 0 - for scope in self.ScopeManager.Stack[2: pos]: - total += len(list(scope.keys())) - code = f"\tsw $a0 {(total + pos) * 4}($fp)\n" + pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) + 1 + init = 2 + if self.CurrentMethod == "None": + init = 0 + for scope in list(self.ScopeManager.Stack)[init: scope]: + pos += len(list(scope.keys())) + code = ctx.getChild(2).accept(self) + code += f"\tsw $a0 -{pos * 4}($fp)\n" return code # Visit a parse tree produced by COOL#false. def visitFalse(self, ctx: COOL.FalseContext): self.CurrentType = "Bool" - return f"\tla $a0 {bool_const0}\n" + return "\tla $a0 bool_const0\n" # Visit a parse tree produced by COOL#int. def visitInt(self, ctx: COOL.IntContext): @@ -1581,41 +1742,75 @@ def visitInt(self, ctx: COOL.IntContext): # Visit a parse tree produced by COOL#equal. def visitEqual(self, ctx: COOL.EqualContext): - return self.visitChildren(ctx) + code = ctx.getChild(0).accept(self) + code += \ + "\tsw $a0 0($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code += ctx.getChild(2).accept(self) + code += \ + "\tmove $t2 $a0\n" \ + "\tlw $t1 4($sp)\n" \ + "\taddiu $sp $sp 4\n" \ + "\tla $a0 bool_const1\n" \ + "\tla $a1 bool_const0\n" \ + "\tjal equality_test\n" + self.CurrentType = "Bool" + return code # Visit a parse tree produced by COOL#true. def visitTrue(self, ctx: COOL.TrueContext): self.CurrentType = "Bool" - return f"\tla $a0 bool_const1\n" + return "\tla $a0 bool_const1\n" # Visit a parse tree produced by COOL#lessEqual. def visitLessEqual(self, ctx: COOL.LessEqualContext): - return self.visitChildren(ctx) + code = ctx.getChild(0).accept(self) + code += \ + "\tsw $a0 0($sp)\n" + \ + "\taddiu $sp $sp -4\n" + code += ctx.getChild(2).accept(self) + code += \ + "\tjal Object.copy\n" \ + "\tlw $t0 4($sp)\n" \ + "\tlw $t1 12($t0)\n" \ + "\tlw $t2 12($a0)\n" \ + "\tslt $t3 $t2 $t1\n" \ + "\tnegu $t4 $t3\n" \ + "\taddiu $t5 $t4 1\n" \ + "\tla $a0 bool_const0\n" \ + "\tjal Object.copy\n" \ + "\tsw $t5 12($a0)\n" \ + "\taddiu $sp $sp 4\n" + self.CurrentType = "Bool" + return code # Visit a parse tree produced by COOL#methodCall. def visitMethodCall(self, ctx: COOL.MethodCallContext): length = 5 - code = ctx.getChild(0).accept(self) or "" + methodPos = 2 + objCode = ctx.getChild(0).accept(self) + code = "" classId = self.CurrentType if ctx.getChild(1).symbol.text == "@": length += 2 + methodPos += 2 classId = ctx.getChild(2).symbol.text + count = methodPos + 2 if len(ctx.children) > length: - count = length - 1 + length = len(ctx.children) while length != count: param = (ctx.getChild(count).accept(self) or "") code += param + \ f"\tsw $a0 0($sp)\n" \ f"\taddiu $sp $sp -4\n" count = count + 2 - methodIdx = self.TypeTable[classId].TagMethods.index(ctx.getChild(length - 3).symbol.text) - self.CurrentType = self.searchMethodInfo(self.CurrentClass.Name, ctx.getChild(length - 3).symbol.text) - code += "\tmove $a0 $s0\n" \ - "\tlw $t1 8($a0)\n" \ - f"\tlw $t1 {methodIdx * 4}($t1)\n" \ - "\tjalr $t1\n" + methodIdx = self.TypeTable[classId].TagMethods.index(ctx.getChild(methodPos).symbol.text) + self.CurrentType = self.searchMethodInfo(classId, ctx.getChild(methodPos).symbol.text) + code += objCode + \ + "\tlw $t1 8($a0)\n" \ + f"\tlw $t1 {methodIdx * 4}($t1)\n" \ + "\tjalr $t1\n" return code - return "" RuntimeMessages = """ # diff --git a/tests/codegen/arith.cl b/tests/codegen/arith.cl index a1035961..9e7ce2c4 100755 --- a/tests/codegen/arith.cl +++ b/tests/codegen/arith.cl @@ -338,7 +338,13 @@ class Main inherits IO { main() : Object { { - avar <- (new A); + --avar <- (new A); + + avar <- (new C)@A.method5(avar.value()); + + -- print(avar); + +(* while flag loop { -- avar <- (new A).set_var(get_int()); @@ -423,7 +429,9 @@ class Main inherits IO { fi fi fi fi fi fi fi fi fi fi; } pool; +*) } + }; }; diff --git a/tests/codegen/atoi.cl b/tests/codegen/atoi.cl index fd8b2ea4..1ace1efb 100644 --- a/tests/codegen/atoi.cl +++ b/tests/codegen/atoi.cl @@ -13,9 +13,9 @@ something of type A2I, or simpl write (new A2I).method(argument). class A2I { c2i(char : String) : Int { - if char = "0" then 0 else - if char = "1" then 1 else - if char = "2" then 2 else + if char = "0" then 0 else + if char = "1" then 1 else + if char = "2" then 2 else if char = "3" then 3 else if char = "4" then 4 else if char = "5" then 5 else @@ -54,9 +54,13 @@ overflow. *) a2i(s : String) : Int { - if s.length() = 0 then 0 else - if s.substr(0,1) = "-" then ~a2i_aux(s.substr(1,s.length()-1)) else - if s.substr(0,1) = "+" then a2i_aux(s.substr(1,s.length()-1)) else + if s.length() = 0 then + 0 + else if s.substr(0,1) = "-" then + ~a2i_aux(s.substr(1,s.length()-1)) + else if s.substr(0,1) = "+" then + a2i_aux(s.substr(1,s.length()-1)) + else a2i_aux(s) fi fi fi }; @@ -66,21 +70,17 @@ overflow. example, this method is written iteratively. *) a2i_aux(s : String) : Int { - (let int : Int <- 0 in - { - (let j : Int <- s.length() in - (let i : Int <- 0 in - while i < j loop - { - int <- int * 10 + c2i(s.substr(i,1)); - i <- i + 1; - } - pool - ) - ); - int; - } - ) + (let int : Int <- 0 in { + (let j : Int <- s.length() in + (let i : Int <- 0 in + while i < j loop { + int <- int * 10 + c2i(s.substr(i,1)); + i <- i + 1; + } pool + ) + ); + int; + }) }; (* @@ -108,14 +108,35 @@ numbers are handled correctly. }; class Main inherits IO { - main () : Object { - let a : Int <- (new A2I).a2i("678987"), - b : String <- (new A2I).i2a(678987) in + + c2i(char : String) : Int { + if char = "0" then 0 else + if char = "1" then 1 else + if char = "2" then 2 else + if char = "3" then 3 else + if char = "4" then 4 else + if char = "5" then 5 else + if char = "6" then 6 else + if char = "7" then 7 else + if char = "8" then 8 else + if char = "9" then 9 else + { abort(); 0; } -- the 0 is needed to satisfy the typchecker + fi fi fi fi fi fi fi fi fi fi + }; + + counter : Int <- 0; + + main () : Object { { + + let a : Int <- (new A2I).a2i("678987"), + b : String <- (new A2I).i2a(678987) in { out_int(a) ; out_string(" == ") ; out_string(b) ; - out_string("\n"); - } + out_string("\n"); + }; + + } } ; } ; diff --git a/tests/codegen/hello_world.cl b/tests/codegen/hello_world.cl index 7cefd7a3..ce2679b0 100755 --- a/tests/codegen/hello_world.cl +++ b/tests/codegen/hello_world.cl @@ -1,6 +1,7 @@ class Main inherits IO { - x : Int <- 1; + x : Int <- let x : Int <- 5, y : Int <- 4 in (x + y); + y : Bool <- true; sqrt (x : Int) : Int { x * x @@ -8,13 +9,14 @@ class Main inherits IO { main(): IO { { - out_string("Hello, World ("); - out_int(x * 2); - x <- 0 -7; - x <- sqrt(x); - out_string(", "); + (*while x < 10 loop{ out_int(x); - out_string(").\n"); + out_string("\n"); + x <- x + 1; + } pool;*) + case x of y : Int => y <- 10 ;esac; + out_int(x); + } }; }; From 0b9b099e6d7a8487856d2d5760ac204834c2d498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 02:10:16 -0500 Subject: [PATCH 44/77] Se depuro la generacion de codigo usando los ejemplos de la definicion de COOL que cubren todo el espectro de instrucciones --- src/Visitors.py | 118 +++++++++++++++++------------- tests/codegen/arith.cl | 151 ++++++++++++++++++--------------------- tests/codegen/complex.cl | 8 +-- 3 files changed, 141 insertions(+), 136 deletions(-) diff --git a/src/Visitors.py b/src/Visitors.py index 9de9207e..ceb20b22 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -13,7 +13,7 @@ def __init__(self, name: str, parent: str, created: bool, sealed: bool): self.Methods = {} self.VisitedMethods = list() self.VisitedAtributes = list() - self.TagMethods = list() + self.TagMethods = {} self.Atributes = {} self.Tag = 0 self.TagAtributes = list() @@ -260,7 +260,10 @@ def visitMethod(self, ctx:COOL.MethodContext): ctx.getChild(i).accept(self) i += 2 methodValue = ctx.getChild(len(ctx.children) - 2).accept(self) - if self.join(methodType.text, methodValue) != methodType.text: + mType = methodType.text + if mType == "SELF_TYPE": + mType = coolClass + if self.join(mType, methodValue) !=mType: line = str(ctx.getChild(len(ctx.children) - 2).start.line) column = str(ctx.getChild(len(ctx.children) - 2).start.column + 1) error = f"({line}, {column}) - TypeError: Inferred return type {methodValue} of method {methodName} does not conform to declared return type {methodType.text}." @@ -847,11 +850,11 @@ def visitProgram(self, ctx: COOL.ProgramContext, fileName: str): self.TypeTable["IO"].Methods["out_string"].Params.append(("x", "String")) self.TypeTable["IO"].Methods["out_int"] = COOLMethod("out_int", "SELF_TYPE", 1, None) self.TypeTable["IO"].Methods["out_int"].Params.append(("x", "Int")) - self.ConstantTable.append(("", "String", "str_const0")) + self.ConstantTable.append(("", "String", "string_const0")) self.ConstantTable.append((0, "Int", "int_const0")) self.ConstantTable.append(("false", "Bool", "bool_const0")) self.ConstantTable.append(("true", "Bool", "bool_const1")) - self.ConstantTable.append((fileName, "String", "str_const1")) + self.ConstantTable.append((fileName, "String", "string_const1")) self.ConstantTable.append((len(fileName), "Int", F"int_const{len(fileName)}")) self.Counter = 2 return self.visitChildren(ctx) @@ -934,7 +937,7 @@ def visitString(self, ctx: COOL.StringContext): if consName == constantName and consType == "String": return self.visitChildren(ctx) - self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) + self.ConstantTable.append((constantName, "String", f"string_const{self.Counter}")) self.Counter = self.Counter + 1 length = len(constantName) for cons in self.ConstantTable: @@ -1140,25 +1143,19 @@ def findLabel(self, name: str): if constName == name and constType == "String": return constLabel - def genMethodNames(self, coolClass: str, coolMethods: list, className: str): - if coolClass == "None": - return "" - temp = "" - for method in self.TypeTable[coolClass].Methods: - if not (coolMethods.__contains__(method)): - temp = temp + f"\t.word {coolClass}.{method}\n" - coolMethods.append(method) + def genMethodNames(self, coolClass: str): + code = "" + for method in self.TypeTable[coolClass].TagMethods.values(): + code += f"\t.word {method}\n" - code = self.genMethodNames(self.TypeTable[coolClass].Parent, coolMethods, className) - return code + temp + return code - def genMethodTags(self, coolClass: str, coolMethods: list, className: str): + def genMethodTags(self, coolClass: str, coolMethods: dict): if coolClass == "None": return coolMethods - coolMethods = self.genMethodTags(self.TypeTable[coolClass].Parent, coolMethods, className) + coolMethods = self.genMethodTags(self.TypeTable[coolClass].Parent, coolMethods,) for method in self.TypeTable[coolClass].Methods: - if not (coolMethods.__contains__(method)): - coolMethods.append(method) + coolMethods[method] = f"{coolClass}.{method}" return coolMethods def genAtributeNames(self, coolClass: str, coolAtributes: list): @@ -1189,7 +1186,7 @@ def genClassTable(self): counter = 0 for className in self.TypeTable: classNameTab = classNameTab + f"\t.word {self.findLabel(className)}\n" - temp = self.genMethodNames(className, list(), className) + temp = self.genMethodNames(className) class_objTab = class_objTab + \ f"\t.word {className}_protObj\n" \ f"\t.word {className}_init\n" @@ -1239,7 +1236,7 @@ def genClassAtributes(self, className: str): def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): for className in self.TypeTable: constantName = className - self.ConstantTable.append((constantName, "String", f"str_const{self.Counter}")) + self.ConstantTable.append((constantName, "String", f"string_const{self.Counter}")) self.Counter = self.Counter + 1 length = len(constantName) contain = True @@ -1249,8 +1246,8 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): contain = False if contain: self.ConstantTable.append((length, "Int", f"int_const{length}")) - self.TypeTable[className].TagMethods = self.genMethodTags(className,list(),className) - self.ConstantTable.append(("SELF_TYPE", "String", f"str_const{self.Counter}")) + self.TypeTable[className].TagMethods = self.genMethodTags(className,{}) + self.ConstantTable.append(("SELF_TYPE", "String", f"string_const{self.Counter}")) contain = True length = len("SELF_TYPE") for cons in self.ConstantTable: @@ -1276,6 +1273,10 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): self.CurrentClass = self.TypeTable[className] self.CurrentType = className self.CurrentMethod = "None" + self.CurrentClass = self.TypeTable[className] + self.ScopeManager.addScope() + for atribute in self.CurrentClass.TagAtributes: + self.ScopeManager.addIdentifier(atribute, self.searchAtributeInfo(className, atribute)) code = code + f"{className}_init:\n" temp = self.genClassAtributes(className) if len(temp) != 0: @@ -1294,12 +1295,13 @@ def visitProgram(self, ctx: COOL.ProgramContext, outFilename: str): "\tlw $ra 4($sp)\n" \ "\taddiu $sp $sp 12\n" code = code + "\tjr $ra\n" + self.ScopeManager.deleteScope() for className in self.TypeTable: if not(className == "Object" or className == "String" or className == "Int" or className == "Bool" or className == "IO"): self.CurrentClass = self.TypeTable[className] self.ScopeManager.addScope() for atribute in self.CurrentClass.TagAtributes: - self.ScopeManager.addIdentifier(atribute,self.searchAtributeInfo(className, atribute)) + self.ScopeManager.addIdentifier(atribute, self.searchAtributeInfo(className, atribute)) for methodName in self.CurrentClass.Methods: self.CurrentMethod = self.CurrentClass.Methods[methodName] self.CurrentType = self.CurrentMethod.Type @@ -1430,17 +1432,18 @@ def visitIsvoid(self, ctx: COOL.IsvoidContext): # Visit a parse tree produced by COOL#while. def visitWhile(self, ctx: COOL.WhileContext): - code = f"while_label{self.Counter}:\n" + labelCounter = self.Counter + self.Counter += 1 + code = f"while_label{labelCounter}:\n" code += ctx.getChild(1).accept(self) code += "\tlw $t1 12($a0)\n" + \ - f"\tbgtz $t1 loop_label{self.Counter}\n" + \ - f"\tb pool_label{self.Counter}\n" + \ - f"loop_label{self.Counter}:\n" + f"\tbgtz $t1 loop_label{labelCounter}\n" + \ + f"\tb pool_label{labelCounter}\n" + \ + f"loop_label{labelCounter}:\n" code += ctx.getChild(3).accept(self) - code += f"\tb while_label{self.Counter}\n" + \ - f"pool_label{self.Counter}:\n" + code += f"\tb while_label{labelCounter}\n" + \ + f"pool_label{labelCounter}:\n" self.CurrentType = "None" - self.Counter += 1 return code # Visit a parse tree produced by COOL#division. @@ -1469,21 +1472,19 @@ def visitNegative(self, ctx: COOL.NegativeContext): "\tjal Object.copy\n" \ "\tlw $t1 12($a0)\n" \ "\tnegu $t1 $t1\n" \ - "\tsw $t1 12($a0)\n" \ - "\tsw $a0 0($sp)\n" + "\tsw $t1 12($a0)\n" return code # Visit a parse tree produced by COOL#boolNot. def visitBoolNot(self, ctx: COOL.BoolNotContext): - self.CurrentType = "Bool" code = ctx.getChild(1).accept(self) code += \ "\tjal Object.copy\n" \ "\tlw $t1 12($a0)\n" \ "\tnegu $t2 $t1\n" \ - "\taddiu $t3 $t2 1\n"\ - "\tsw $t3 12($a0)\n" \ - "\tsw $a0 0($sp)\n" + "\taddiu $t1 $t2 1\n" \ + "\tsw $t1 12($a0)\n" + self.CurrentType = "Bool" return code # Visit a parse tree produced by COOL#lessThan. @@ -1521,10 +1522,10 @@ def visitId(self, ctx: COOL.IdContext): varName = ctx.getChild(0).symbol.text if varName == "self": self.CurrentType = self.CurrentClass.Name - return "\tlw $a0 ($s0)\n" + return "\tmove $a0 $s0\n" self.CurrentType = self.ScopeManager.searchType(varName) option = self.ScopeManager.searchIdentifier(varName) - if option == 0 and self.CurrentMethod != "None": + if option == 0: return self.propertyId(ctx) elif option == 1 and self.CurrentMethod != "None": return self.formalId(ctx) @@ -1588,6 +1589,8 @@ def visitIf(self, ctx: COOL.IfContext): ctx.getChild(3).accept(self) + \ f"\tb fi_label{counter}\n" + \ f"else_label{counter}:\n" + if self.CurrentType == "SELF_TYPE": + self.CurrentType = self.CurrentClass.Name tempType = self.CurrentType code = code +\ ctx.getChild(5).accept(self) + \ @@ -1614,6 +1617,8 @@ def visitCase(self, ctx: COOL.CaseContext): count = count + 2 self.ScopeManager.addScope() self.ScopeManager.addIdentifier(idName, idType) + if idType == "Object": + code += f"\tb {idType}_case{counter}\n" code += \ f"\tlw $t1 0($a0)\n" \ f"\tli $t2 {self.TypeTable[idType].Tag}\n" \ @@ -1650,7 +1655,7 @@ def visitOwnMethodCall(self, ctx: COOL.OwnMethodCallContext): f"\tsw $a0 0($sp)\n" \ f"\taddiu $sp $sp -4\n" count = count + 2 - methodIdx = self.CurrentClass.TagMethods.index(ctx.getChild(0).symbol.text) + methodIdx = list(self.CurrentClass.TagMethods).index(ctx.getChild(0).symbol.text) self.CurrentType = self.searchMethodInfo(self.CurrentClass.Name, ctx.getChild(0).symbol.text) code += "\tmove $a0 $s0\n" \ "\tlw $t1 8($a0)\n" \ @@ -1690,7 +1695,7 @@ def visitParentheses(self, ctx: COOL.ParenthesesContext): def visitAssignment(self, ctx: COOL.AssignmentContext): varName = ctx.getChild(0).symbol.text option = self.ScopeManager.searchIdentifier(varName) - if option == 0 and self.CurrentMethod != "None": + if option == 0: return self.propertyAssignament(ctx) elif option == 1 and self.CurrentMethod != "None": return self.formalAssignament(ctx) @@ -1710,7 +1715,7 @@ def formalAssignament(self, ctx: COOL.AssignmentContext): varType = self.ScopeManager.Stack[1][varName] pos = self.CurrentMethod.Params.index((varName, varType)) total = self.CurrentMethod.ParamsNumber - code = code + f"\tsw $a0 {(pos - (total + 2)) * 4}($fp)\n" + code = code + f"\tsw $a0 {((total + 2) - pos) * 4}($fp)\n" return code def variableAssignament(self, ctx: COOL.AssignmentContext): @@ -1750,10 +1755,15 @@ def visitEqual(self, ctx: COOL.EqualContext): code += \ "\tmove $t2 $a0\n" \ "\tlw $t1 4($sp)\n" \ - "\taddiu $sp $sp 4\n" \ + "\taddiu $sp $sp 4\n"\ "\tla $a0 bool_const1\n" \ - "\tla $a1 bool_const0\n" \ - "\tjal equality_test\n" + "\tla $a1 bool_const0\n" + if self.CurrentType == "String" or self.CurrentType == "Int" or self.CurrentType == "Bool": + code += "\tjal equality_test\n" + else: + code += \ + "\tsub $t3 $t2 $t1\n"\ + "\tmovn $a0 $a1 $t3\n" self.CurrentType = "Bool" return code @@ -1790,6 +1800,8 @@ def visitMethodCall(self, ctx: COOL.MethodCallContext): methodPos = 2 objCode = ctx.getChild(0).accept(self) code = "" + if self.CurrentType == "SELF_TYPE": + self.CurrentType = self.CurrentClass.Name classId = self.CurrentType if ctx.getChild(1).symbol.text == "@": length += 2 @@ -1804,12 +1816,18 @@ def visitMethodCall(self, ctx: COOL.MethodCallContext): f"\tsw $a0 0($sp)\n" \ f"\taddiu $sp $sp -4\n" count = count + 2 - methodIdx = self.TypeTable[classId].TagMethods.index(ctx.getChild(methodPos).symbol.text) + methodIdx = list(self.TypeTable[classId].TagMethods).index(ctx.getChild(methodPos).symbol.text) self.CurrentType = self.searchMethodInfo(classId, ctx.getChild(methodPos).symbol.text) - code += objCode + \ - "\tlw $t1 8($a0)\n" \ - f"\tlw $t1 {methodIdx * 4}($t1)\n" \ - "\tjalr $t1\n" + if ctx.getChild(1).symbol.text == "@": + code += objCode + \ + f"\tla $t1 {classId}_dispTab\n" \ + f"\tlw $t1 {methodIdx * 4}($t1)\n" \ + "\tjalr $t1\n" + else: + code += objCode + \ + f"\tlw $t1 8($a0)\n" \ + f"\tlw $t1 {methodIdx * 4}($t1)\n" \ + "\tjalr $t1\n" return code RuntimeMessages = """ diff --git a/tests/codegen/arith.cl b/tests/codegen/arith.cl index 9e7ce2c4..91f08cfc 100755 --- a/tests/codegen/arith.cl +++ b/tests/codegen/arith.cl @@ -318,12 +318,12 @@ class Main inherits IO { class_type(var : A) : IO { case var of - a : A => out_string("Class type is now A\n"); - b : B => out_string("Class type is now B\n"); - c : C => out_string("Class type is now C\n"); - d : D => out_string("Class type is now D\n"); - e : E => out_string("Class type is now E\n"); - o : Object => out_string("Oooops\n"); + a : A => out_string("Class type is now A\n"); + b : B => out_string("Class type is now B\n"); + c : C => out_string("Class type is now C\n"); + d : D => out_string("Class type is now D\n"); + e : E => out_string("Class type is now E\n"); + o : Object => out_string("Oooops\n"); esac }; @@ -338,16 +338,10 @@ class Main inherits IO { main() : Object { { - --avar <- (new A); + avar <- (new A); - avar <- (new C)@A.method5(avar.value()); + while flag loop { - -- print(avar); - -(* - while flag loop - { - -- avar <- (new A).set_var(get_int()); out_string("number "); print(avar); if is_even(avar.value()) then @@ -355,83 +349,76 @@ class Main inherits IO { else out_string("is odd!\n") fi; - -- print(avar); -- prints out answer + class_type(avar); + char <- menu(); - if char = "a" then -- add - { - a_var <- (new A).set_var(get_int()); - avar <- (new B).method2(avar.value(), a_var.value()); - } else - if char = "b" then -- negate - case avar of - c : C => avar <- c.method6(c.value()); - a : A => avar <- a.method3(a.value()); - o : Object => { - out_string("Oooops\n"); - abort(); 0; - }; - esac else - if char = "c" then -- diff - { - a_var <- (new A).set_var(get_int()); - avar <- (new D).method4(avar.value(), a_var.value()); - } else - if char = "d" then avar <- (new C)@A.method5(avar.value()) else - -- factorial - if char = "e" then avar <- (new C)@B.method5(avar.value()) else - -- square - if char = "f" then avar <- (new C)@C.method5(avar.value()) else - -- cube - if char = "g" then -- multiple of 3? - if ((new D).method7(avar.value())) - then -- avar <- (new A).method1(avar.value()) + if char = "a" then -- add + { + a_var <- (new A).set_var(get_int()); + avar <- (new B).method2(avar.value(), a_var.value()); + } + else if char = "b" then -- negate + case avar of + c : C => avar <- c.method6(c.value()); + a : A => avar <- a.method3(a.value()); + o : Object => { + out_string("Oooops\n"); + abort(); 0; + }; + esac + else if char = "c" then -- diff + { + a_var <- (new A).set_var(get_int()); + avar <- (new D).method4(avar.value(), a_var.value()); + } + else if char = "d" then + avar <- (new C)@A.method5(avar.value()) -- factorial + else if char = "e" then + avar <- (new C)@B.method5(avar.value()) -- square + else if char = "f" then + avar <- (new C)@C.method5(avar.value()) -- cube + else if char = "g" then -- multiple of 3? + if ((new D).method7(avar.value())) then { - out_string("number "); - print(avar); - out_string("is divisible by 3.\n"); + out_string("number "); + print(avar); + out_string("is divisible by 3.\n"); } - else -- avar <- (new A).set_var(0) + else { - out_string("number "); - print(avar); - out_string("is not divisible by 3.\n"); - } - fi else - if char = "h" then - (let x : A in - { - x <- (new E).method6(avar.value()); + out_string("number "); + print(avar); + out_string("is not divisible by 3.\n"); + } fi + else if char = "h" then + (let x : A in { + x <- (new E).method6(avar.value()); (let r : Int <- (avar.value() - (x.value() * 8)) in - { - out_string("number "); - print(avar); - out_string("is equal to "); - print(x); - out_string("times 8 with a remainder of "); - (let a : A2I <- new A2I in - { - out_string(a.i2a(r)); - out_string("\n"); - } - ); -- end let a: - } - ); -- end let r: + { + out_string("number "); + print(avar); + out_string("is equal to "); + print(x); + out_string("times 8 with a remainder of "); + (let a : A2I <- new A2I in + { + out_string(a.i2a(r)); + out_string("\n"); + }); -- end let a: + }); -- end let r: avar <- x; - } - ) -- end let x: - else - if char = "j" then avar <- (new A) - else - if char = "q" then flag <- false - else - avar <- (new A).method1(avar.value()) -- divide/8 - fi fi fi fi fi fi fi fi fi fi; - } + }) -- end let x: + else if char = "j" then + avar <- (new A) + else if char = "q" then + flag <- false + else + avar <- (new A).method1(avar.value()) -- divide/8 + fi fi fi fi fi fi fi fi fi fi; + } pool; -*) } - }; }; diff --git a/tests/codegen/complex.cl b/tests/codegen/complex.cl index bad142df..20c0e7d4 100755 --- a/tests/codegen/complex.cl +++ b/tests/codegen/complex.cl @@ -19,22 +19,22 @@ class Complex inherits IO { reflect_0() : Complex { { - x = ~x; - y = ~y; + x <- ~x; + y <- ~y; self; } }; reflect_X() : Complex { { - y = ~y; + y <- ~y; self; } }; reflect_Y() : Complex { { - x = ~x; + x <- ~x; self; } }; From 6411caec8b406dfc1d9145587b7a9554ab02d313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 05:26:48 -0500 Subject: [PATCH 45/77] Se hicieron modificaciones para que las pruebas (test) se ejecuten localmente (Windows) --- .gitignore | 1 + src/COOLCompiler.py | 14 ++++++++++++-- src/Visitors.py | 4 ++-- tests/codegen_test.py | 6 +++--- tests/semantic_test.py | 4 ++-- tests/utils/utils.py | 4 ++-- 6 files changed, 22 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index eb544d4e..fd0a4a46 100644 --- a/.gitignore +++ b/.gitignore @@ -412,3 +412,4 @@ dmypy.json /gen /grammar/antlr_cool.bat /tests/codegen/*.s +/tests/codegen/*.mips diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index d4c37048..07ee00ec 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -15,8 +15,12 @@ def main(argv): + if len(argv) < 2: + print("ERROR: no input filename") + return sys.exit(errno.EPERM) + if not os.path.isfile(argv[1]): - print("invalid input filename: " + argv[1]) + print("ERROR: invalid input filename: " + argv[1]) return sys.exit(errno.EPERM) input = NoTabsFileStream(argv[1]) @@ -46,8 +50,14 @@ def main(argv): codegenerator = CodegenVisitor(typeTree, consTble, visitor.Counter) semanticAnalizer.visitProgram(tree) if semanticAnalizer.hasNoError: - outFilename = os.path.splitext(argv[1])[0] + ".s" + if len(argv) > 2: + outFilename = argv[2] + else: + outFilename = os.path.splitext(argv[1])[0] + ".s" codegenerator.visitProgram(tree, outFilename) + else: + return sys.exit(errno.EPERM) + none = typeTree["Object"] diff --git a/src/Visitors.py b/src/Visitors.py index ceb20b22..a08bee50 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -240,14 +240,14 @@ def visitMethod(self, ctx:COOL.MethodContext): if ancestorMethod.ParamsNumber != self.TypeTable[coolClass].Methods[methodName].ParamsNumber: line = str(ctx.getChild(0).symbol.line) column = str(ctx.getChild(0).symbol.column + 1) - error = f"({line}, {column}) SemanticError: Incompatible number of formal parameters in redefined method {methodName}." + error = f"({line}, {column}) - SemanticError: Incompatible number of formal parameters in redefined method {methodName}." print(error) self.hasNoError = False return if ancestorMethod.Type != methodType.text: line = str(methodType.line) column = str(methodType.column + 1) - error = f"({line}, {column}) SemanticError: In redefined method {methodName}, return type {methodType.text} is different from original return type {ancestorMethod.Type}." + error = f"({line}, {column}) - SemanticError: In redefined method {methodName}, return type {methodType.text} is different from original return type {ancestorMethod.Type}." print(error) self.hasNoError = False return diff --git a/tests/codegen_test.py b/tests/codegen_test.py index 48df768f..a419742b 100644 --- a/tests/codegen_test.py +++ b/tests/codegen_test.py @@ -2,7 +2,7 @@ import os from utils import compare_outputs -tests_dir = __file__.rpartition('/')[0] + '/codegen/' +tests_dir = os.path.join(__file__.rpartition(os.path.sep)[0], 'codegen') tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] # @pytest.mark.lexer @@ -13,5 +13,5 @@ @pytest.mark.run(order=4) @pytest.mark.parametrize("cool_file", tests) def test_codegen(compiler_path, cool_file): - compare_outputs(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ - tests_dir + cool_file[:-3] + '_output.txt') \ No newline at end of file + compare_outputs(compiler_path, os.path.join(tests_dir, cool_file), os.path.join(tests_dir, cool_file[:-3] + '_input.txt'), \ + os.path.join(tests_dir, cool_file[:-3] + '_output.txt')) diff --git a/tests/semantic_test.py b/tests/semantic_test.py index cac9cd78..d074c263 100644 --- a/tests/semantic_test.py +++ b/tests/semantic_test.py @@ -2,7 +2,7 @@ import os from utils import compare_errors, first_error_only_line -tests_dir = __file__.rpartition('/')[0] + '/semantic/' +tests_dir = os.path.join(__file__.rpartition(os.path.sep)[0], 'semantic') tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] @pytest.mark.semantic @@ -10,5 +10,5 @@ @pytest.mark.run(order=3) @pytest.mark.parametrize("cool_file", tests) def test_semantic_errors(compiler_path, cool_file): - compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt', \ + compare_errors(compiler_path, os.path.join(tests_dir, cool_file), os.path.join(tests_dir, cool_file[:-3] + '_error.txt'), \ cmp=first_error_only_line) \ No newline at end of file diff --git a/tests/utils/utils.py b/tests/utils/utils.py index 961cf7cb..ca446a55 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -45,7 +45,7 @@ def get_file_name(path: str): def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str, cmp=first_error, timeout=100): try: - sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + sp = subprocess.run(['sh', compiler_path, cool_file_path], capture_output=True, timeout=timeout) return_code, output = sp.returncode, sp.stdout.decode() except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT @@ -67,7 +67,7 @@ def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str (?:Loaded: .+\n)*''' def compare_outputs(compiler_path: str, cool_file_path: str, input_file_path: str, output_file_path: str, timeout=100): try: - sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + sp = subprocess.run(['sh', compiler_path, cool_file_path], capture_output=True, timeout=timeout) assert sp.returncode == 0, TEST_MUST_COMPILE % get_file_name(cool_file_path) except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT From 205007236fa16f07c9e917a6a3c60be455e08455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 05:44:20 -0500 Subject: [PATCH 46/77] Se restablecio el uso de BASH en lugar de SH para los test --- tests/utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/utils/utils.py b/tests/utils/utils.py index ca446a55..961cf7cb 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -45,7 +45,7 @@ def get_file_name(path: str): def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str, cmp=first_error, timeout=100): try: - sp = subprocess.run(['sh', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) return_code, output = sp.returncode, sp.stdout.decode() except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT @@ -67,7 +67,7 @@ def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str (?:Loaded: .+\n)*''' def compare_outputs(compiler_path: str, cool_file_path: str, input_file_path: str, output_file_path: str, timeout=100): try: - sp = subprocess.run(['sh', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) assert sp.returncode == 0, TEST_MUST_COMPILE % get_file_name(cool_file_path) except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT From 442c88bc921d9b216ba19fe84d699e17a2be593b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 13:11:04 -0500 Subject: [PATCH 47/77] =?UTF-8?q?Se=20arregl=C3=B3=20el=20formato=20de=20a?= =?UTF-8?q?lgunos=20errores?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 2 ++ src/Visitors.py | 4 ++-- tests/utils/utils.py | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index 9eb0cad1..6d4fcad9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ pytest pytest-ordering +antlr4-python3-runtime==4.7.2 + diff --git a/src/Visitors.py b/src/Visitors.py index a08bee50..f8b88f14 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -715,7 +715,7 @@ def visitOwnMethodCall(self, ctx:COOL.OwnMethodCallContext): else: line = str(ctx.getChild(0).symbol.line) column = str(ctx.getChild(0).symbol.column + 1) - error = f"({line}, {column}) AttributeError: Dispatch to undefined method {ctx.getChild(0).symbol.text}." + error = f"({line}, {column}) - AttributeError: Dispatch to undefined method {ctx.getChild(0).symbol.text}." print(error) self.hasNoError = False return methodType @@ -773,7 +773,7 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): else: line = str(ctx.getChild(length - 3).symbol.line) column = str(ctx.getChild(length - 3).symbol.column + 1) - error = f"({line}, {column}) AttributeError: Dispatch to undefined method {ctx.getChild(length - 3).symbol.text}." + error = f"({line}, {column}) - AttributeError: Dispatch to undefined method {ctx.getChild(length - 3).symbol.text}." print(error) self.hasNoError = False return methodType diff --git a/tests/utils/utils.py b/tests/utils/utils.py index 961cf7cb..ca446a55 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -45,7 +45,7 @@ def get_file_name(path: str): def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str, cmp=first_error, timeout=100): try: - sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + sp = subprocess.run(['sh', compiler_path, cool_file_path], capture_output=True, timeout=timeout) return_code, output = sp.returncode, sp.stdout.decode() except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT @@ -67,7 +67,7 @@ def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str (?:Loaded: .+\n)*''' def compare_outputs(compiler_path: str, cool_file_path: str, input_file_path: str, output_file_path: str, timeout=100): try: - sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + sp = subprocess.run(['sh', compiler_path, cool_file_path], capture_output=True, timeout=timeout) assert sp.returncode == 0, TEST_MUST_COMPILE % get_file_name(cool_file_path) except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT From fe810c24cfee0df45b67d1c2b081b3c38c42faeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 13:14:48 -0500 Subject: [PATCH 48/77] =?UTF-8?q?Se=20restaur=C3=B3=20el=20uso=20de=20bash?= =?UTF-8?q?=20en=20lugar=20de=20sh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/utils/utils.py b/tests/utils/utils.py index ca446a55..961cf7cb 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -45,7 +45,7 @@ def get_file_name(path: str): def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str, cmp=first_error, timeout=100): try: - sp = subprocess.run(['sh', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) return_code, output = sp.returncode, sp.stdout.decode() except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT @@ -67,7 +67,7 @@ def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str (?:Loaded: .+\n)*''' def compare_outputs(compiler_path: str, cool_file_path: str, input_file_path: str, output_file_path: str, timeout=100): try: - sp = subprocess.run(['sh', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) assert sp.returncode == 0, TEST_MUST_COMPILE % get_file_name(cool_file_path) except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT From d9a2855727b341b88f52db34a02eb8b5ba1f3001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 13:32:11 -0500 Subject: [PATCH 49/77] =?UTF-8?q?Prueba=20para=20ver=20por=20qu=C3=A9=20lo?= =?UTF-8?q?s=20test=20fallan=20en=20GitHub?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/utils/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/utils/utils.py b/tests/utils/utils.py index 961cf7cb..b25ca3e7 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -6,8 +6,9 @@ SPIM_TIMEOUT = 'El spim tarda mucho en responder.' TEST_MUST_FAIL = 'El test %s debe fallar al compilar' TEST_MUST_COMPILE = 'El test %s debe compilar' -BAD_ERROR_FORMAT = '''El error no esta en formato: (,) - : - o no se encuentra en la 3ra linea\n\n%s''' +# BAD_ERROR_FORMAT = '''El error no esta en formato: (,) - : +# o no se encuentra en la 3ra linea\n\n%s''' +BAD_ERROR_FORMAT = '''El error no esta en formato: [%s]''' UNEXPECTED_ERROR = 'Se esperaba un %s en (%d, %d). Su error fue un %s en (%d, %d)' UNEXPECTED_OUTPUT = 'La salida de %s no es la esperada:\n%s\nEsperada:\n%s' From e832d7b834633e39e8a70bddf9edfb8c1d654782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 13:38:53 -0500 Subject: [PATCH 50/77] =?UTF-8?q?Prueba=20para=20ver=20por=20qu=C3=A9=20lo?= =?UTF-8?q?s=20test=20fallan=20en=20GitHub=20(2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coolc.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coolc.sh b/src/coolc.sh index bfea5d60..738f4bf0 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -6,6 +6,7 @@ OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto echo "COOLCompiler 1.0.2" echo "Copyright (C) 2019-2020: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" +echo "3ra línea" # Llamar al compilador #echo "Compiling $INPUT_FILE into $OUTPUT_FILE" From 535d4ede1d955600c3635e18a36315d9db956e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 13:43:51 -0500 Subject: [PATCH 51/77] =?UTF-8?q?Prueba=20para=20ver=20por=20qu=C3=A9=20lo?= =?UTF-8?q?s=20test=20fallan=20en=20GitHub=20(3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/COOLCompiler.py | 4 ++++ src/coolc.sh | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 07ee00ec..33c280cc 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -15,6 +15,10 @@ def main(argv): + print("COOLCompiler 1.0.3") + print("Copyright (C) 2019-2020: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado") + print("3ra linea") + if len(argv) < 2: print("ERROR: no input filename") return sys.exit(errno.EPERM) diff --git a/src/coolc.sh b/src/coolc.sh index 738f4bf0..5b4c44f7 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,9 +4,6 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "COOLCompiler 1.0.2" -echo "Copyright (C) 2019-2020: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" -echo "3ra línea" # Llamar al compilador #echo "Compiling $INPUT_FILE into $OUTPUT_FILE" From 7e5a87116156049fb2397c28031c4fff68b867f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 14:04:05 -0500 Subject: [PATCH 52/77] =?UTF-8?q?Prueba=20para=20ver=20por=20qu=C3=A9=20lo?= =?UTF-8?q?s=20test=20fallan=20en=20GitHub=20(4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/COOLCompiler.py | 1 - src/coolc.sh | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 33c280cc..e3c8e105 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -17,7 +17,6 @@ def main(argv): print("COOLCompiler 1.0.3") print("Copyright (C) 2019-2020: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado") - print("3ra linea") if len(argv) < 2: print("ERROR: no input filename") diff --git a/src/coolc.sh b/src/coolc.sh index 5b4c44f7..402cb676 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,6 +4,8 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto +echo "COOLCompiler 1.0.3" +echo "Copyright (C) 2019-2020: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" # Llamar al compilador #echo "Compiling $INPUT_FILE into $OUTPUT_FILE" From f5c53046c31a5e7d1c05f054537af4621a652416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 14:30:53 -0500 Subject: [PATCH 53/77] =?UTF-8?q?Prueba=20para=20ver=20por=20qu=C3=A9=20lo?= =?UTF-8?q?s=20test=20fallan=20en=20GitHub=20(5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/COOLCompiler.py | 2 -- src/coolc.sh | 4 ++-- tests/utils/utils.py | 5 ++--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index e3c8e105..6fe5d617 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -6,11 +6,9 @@ from COOLLexerErrorListener import COOLLexerErrorListener from COOLParser import COOLParser from COOLParserErrorListener import COOLParserErrorListener -from COOLListener import COOLListener from Visitors import TypeCOOLVisitor from Visitors import SemanticCOOLVisitor from Visitors import CodegenVisitor -from collections import deque from NoTabsFileStream import NoTabsFileStream diff --git a/src/coolc.sh b/src/coolc.sh index 402cb676..dfcc065a 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,8 +4,8 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "COOLCompiler 1.0.3" -echo "Copyright (C) 2019-2020: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" +# echo "COOLCompiler 1.0.3" +# echo "Copyright (C) 2019-2020: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado" # Llamar al compilador #echo "Compiling $INPUT_FILE into $OUTPUT_FILE" diff --git a/tests/utils/utils.py b/tests/utils/utils.py index b25ca3e7..7d97db98 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -6,9 +6,8 @@ SPIM_TIMEOUT = 'El spim tarda mucho en responder.' TEST_MUST_FAIL = 'El test %s debe fallar al compilar' TEST_MUST_COMPILE = 'El test %s debe compilar' -# BAD_ERROR_FORMAT = '''El error no esta en formato: (,) - : -# o no se encuentra en la 3ra linea\n\n%s''' -BAD_ERROR_FORMAT = '''El error no esta en formato: [%s]''' +BAD_ERROR_FORMAT = '''El error no esta en formato: (,) - : + o no se encuentra en la 3ra linea\n\n%s''' UNEXPECTED_ERROR = 'Se esperaba un %s en (%d, %d). Su error fue un %s en (%d, %d)' UNEXPECTED_OUTPUT = 'La salida de %s no es la esperada:\n%s\nEsperada:\n%s' From 3012fb32df440413b60ae98d54f83335f83f80df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 21:53:11 -0500 Subject: [PATCH 54/77] =?UTF-8?q?Se=20ajustaron=20errores=20en=20la=20gene?= =?UTF-8?q?raci=C3=B3n=20de=20c=C3=B3digo=20Se=20ajust=C3=B3=20la=20lectur?= =?UTF-8?q?a=20de=20los=20archivos=20en=20UTF-8=20para=20evitar=20diferenc?= =?UTF-8?q?ias=20en=20los=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/NoTabsFileStream.py | 4 +-- src/Visitors.py | 58 ++++++++++++++++++++++++------------ tests/codegen/hello_world.cl | 17 +---------- 3 files changed, 42 insertions(+), 37 deletions(-) diff --git a/src/NoTabsFileStream.py b/src/NoTabsFileStream.py index cce514c0..38ddadd2 100644 --- a/src/NoTabsFileStream.py +++ b/src/NoTabsFileStream.py @@ -4,9 +4,9 @@ class NoTabsFileStream(FileStream): - def __init__(self, fileName:str, tabSpaces: int = 4): + def __init__(self, fileName:str, tabSpaces: int = 1): self.tabSpaces = tabSpaces - super().__init__(fileName) + super().__init__(fileName, "utf-8") def readDataFrom(self, fileName:str, encoding:str, errors:str='strict'): s = super().readDataFrom(fileName, encoding, errors) diff --git a/src/Visitors.py b/src/Visitors.py index f8b88f14..91c427fa 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -733,7 +733,7 @@ def visitMethodCall(self, ctx:COOL.MethodCallContext): else: line = str(ctx.getChild(1).symbol.line) column = str(ctx.getChild(1).symbol.column) - error = f"({line}, {column}) - SemanticError: Expression type {currentClass} does not conform to declared static dispatch type {parent}." + error = f"({line}, {column}) - TypeError: Expression type {currentClass} does not conform to declared static dispatch type {parent}." print(error) self.hasNoError = False return methodType @@ -1062,6 +1062,16 @@ class CodegenVisitor(ParseTreeVisitor): CurrentType: str + def getTagChildren(self, className: str, classList: list): + tagList = list() + for coolClass in self.TypeTable.values(): + if coolClass.Parent == className and not classList.__contains__(coolClass.Name): + tagList += self.getTagChildren(coolClass.Name, classList) + if not classList.__contains__(className): + tagList.append(self.TypeTable[className].Tag) + return tagList + + def join(self, class1: str, class2: str): if class1 == "None" or class2 == "None": return "None" @@ -1124,8 +1134,9 @@ def genConstant(self, sol: str): f"\t.word Int_dispTab\n" \ f"\t.word {constName}\n" else: - length = int(len(constName) / 4) + 3 - if len(constName) % 4 != 0: + l = len(constName)+1 + length = int(l / 4) + 4 + if l % 4 != 0: length = length + 1 sol = sol + \ f"\t.word -1\n{constLabel}:\n" \ @@ -1153,7 +1164,7 @@ def genMethodNames(self, coolClass: str): def genMethodTags(self, coolClass: str, coolMethods: dict): if coolClass == "None": return coolMethods - coolMethods = self.genMethodTags(self.TypeTable[coolClass].Parent, coolMethods,) + coolMethods = self.genMethodTags(self.TypeTable[coolClass].Parent, coolMethods) for method in self.TypeTable[coolClass].Methods: coolMethods[method] = f"{coolClass}.{method}" return coolMethods @@ -1610,37 +1621,46 @@ def visitCase(self, ctx: COOL.CaseContext): tempCode = f"abort{counter}:\n" \ "\tjal _case_abort2\n" count = 3 + idTypeList = list() while lengt > count: idName = ctx.getChild(count).symbol.text count = count + 2 idType = ctx.getChild(count).symbol.text + idTypeList.append(idType) count = count + 2 self.ScopeManager.addScope() self.ScopeManager.addIdentifier(idName, idType) - if idType == "Object": - code += f"\tb {idType}_case{counter}\n" - code += \ - f"\tlw $t1 0($a0)\n" \ - f"\tli $t2 {self.TypeTable[idType].Tag}\n" \ - f"\tbeq $t1 $t2 {idType}_case{counter}\n" - scope = self.ScopeManager.searchIdentifier(idName) - pos = list(self.ScopeManager.Stack[scope].keys()).index(idName) + 1 - init = 2 - if self.CurrentMethod == "None": - init = 0 - for scope in list(self.ScopeManager.Stack)[init: scope]: - pos += len(list(scope.keys())) + code += "\tlw $t1 0($a0)\n" \ + f"\tli $t2 {self.TypeTable[idType].Tag}\n" \ + f"\tbeq $t1 $t2 {idType}_case{counter}\n" tempCode +=\ f"{idType}_case{counter}:\n" \ - f"\tsw $a0 -{pos * 4}($fp)\n" + f"\tsw $a0 0($sp)\n" \ + f"\taddiu $sp $sp -4\n" tempCode += ctx.getChild(count).accept(self) tempCode += f"\tb esac{counter}\n" self.ScopeManager.deleteScope() count = count + 2 + count = 5 + objCase = "" + while lengt > count: + idType = ctx.getChild(count).symbol.text + count = count + 6 + if idType == "Object": + objCase = f"\tb Object_case{counter}\n" + else: + tagList = self.getTagChildren(idType, idTypeList) + for tag in tagList: + code += \ + "\tlw $t1 0($a0)\n"\ + f"\tli $t2 {tag}\n" \ + f"\tbeq $t1 $t2 {idType}_case{counter}\n" + code += objCase code = code + \ "\tjal _case_abort\n" code += tempCode +\ - f"esac{counter}:\n" + f"esac{counter}:\n" \ + "\taddiu $sp $sp 4\n" return code # Visit a parse tree produced by COOL#ownMethodCall. diff --git a/tests/codegen/hello_world.cl b/tests/codegen/hello_world.cl index ce2679b0..52bd2397 100755 --- a/tests/codegen/hello_world.cl +++ b/tests/codegen/hello_world.cl @@ -1,22 +1,7 @@ class Main inherits IO { - x : Int <- let x : Int <- 5, y : Int <- 4 in (x + y); - - y : Bool <- true; - sqrt (x : Int) : Int - { - x * x - }; - main(): IO { { - (*while x < 10 loop{ - out_int(x); - out_string("\n"); - x <- x + 1; - } pool;*) - case x of y : Int => y <- 10 ;esac; - out_int(x); - + out_string("Hello".concat("World")); } }; }; From bc61c3cd04f984e7cae2d4925c2184611000189f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 22:04:21 -0500 Subject: [PATCH 55/77] Pruebas para encontrar el problema de los test en GitHub --- src/MockCompiler.py | 13 +++++++++++++ src/coolc.sh | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 src/MockCompiler.py diff --git a/src/MockCompiler.py b/src/MockCompiler.py new file mode 100644 index 00000000..f3f0ad6b --- /dev/null +++ b/src/MockCompiler.py @@ -0,0 +1,13 @@ +import sys +import errno + +def main(argv): + print("COOLCompiler 1.0.3") + print("Copyright (C) 2019-2020: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado") + + print("3rd line") + + return sys.exit(errno.EPERM) + +if __name__ == '__main__': + main(sys.argv) diff --git a/src/coolc.sh b/src/coolc.sh index dfcc065a..6e6d3a2d 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -9,4 +9,4 @@ OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Llamar al compilador #echo "Compiling $INPUT_FILE into $OUTPUT_FILE" -python COOLCompiler.py $INPUT_FILE $OUTPUT_FILE +python MockCompiler.py $INPUT_FILE $OUTPUT_FILE From 08563259f04392fc610d20fe6c82fe7cbe70f97a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 22:17:21 -0500 Subject: [PATCH 56/77] Pruebas para encontrar el problema de los test en GitHub (2) --- src/MockCompiler.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/MockCompiler.py b/src/MockCompiler.py index f3f0ad6b..b11e6d9f 100644 --- a/src/MockCompiler.py +++ b/src/MockCompiler.py @@ -1,10 +1,21 @@ import sys import errno +import os.path def main(argv): print("COOLCompiler 1.0.3") print("Copyright (C) 2019-2020: Liset Silva Oropesa, Pablo A. de Armas Suárez, Yenli Gil Machado") + if len(argv) < 2: + print("ERROR: no input filename") + return sys.exit(errno.EPERM) + + if not os.path.isfile(argv[1]): + print("ERROR: invalid input filename: " + argv[1]) + return sys.exit(errno.EPERM) + + input = NoTabsFileStream(argv[1]) + print("3rd line") return sys.exit(errno.EPERM) From 24947a4648d1da4ea80a42af24dccc7cbba80b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 22:26:17 -0500 Subject: [PATCH 57/77] Pruebas para encontrar el problema de los test en GitHub (3) --- src/MockCompiler.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MockCompiler.py b/src/MockCompiler.py index b11e6d9f..1f74c246 100644 --- a/src/MockCompiler.py +++ b/src/MockCompiler.py @@ -1,6 +1,7 @@ import sys import errno import os.path +from NoTabsFileStream import NoTabsFileStream def main(argv): print("COOLCompiler 1.0.3") From aca693799111574d42b1d80669fc9f597f9169d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 22:32:40 -0500 Subject: [PATCH 58/77] Pruebas para encontrar el problema de los test en GitHub (4) --- src/COOLCompiler.py | 3 +-- src/coolc.sh | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 6fe5d617..eafb9b3b 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -9,7 +9,7 @@ from Visitors import TypeCOOLVisitor from Visitors import SemanticCOOLVisitor from Visitors import CodegenVisitor -from NoTabsFileStream import NoTabsFileStream +import NoTabsFileStream def main(argv): @@ -59,7 +59,6 @@ def main(argv): else: return sys.exit(errno.EPERM) - none = typeTree["Object"] diff --git a/src/coolc.sh b/src/coolc.sh index 6e6d3a2d..dfcc065a 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -9,4 +9,4 @@ OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Llamar al compilador #echo "Compiling $INPUT_FILE into $OUTPUT_FILE" -python MockCompiler.py $INPUT_FILE $OUTPUT_FILE +python COOLCompiler.py $INPUT_FILE $OUTPUT_FILE From 9816cd8b732620c46712339cf0f59d160011ff5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 22:48:35 -0500 Subject: [PATCH 59/77] Pruebas para encontrar el problema de los test en GitHub (5) --- src/COOLCompiler.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index eafb9b3b..ebbf7b42 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -9,7 +9,7 @@ from Visitors import TypeCOOLVisitor from Visitors import SemanticCOOLVisitor from Visitors import CodegenVisitor -import NoTabsFileStream +from NoTabsFileStream import NoTabsFileStream def main(argv): @@ -59,9 +59,7 @@ def main(argv): else: return sys.exit(errno.EPERM) - - - + return 0 if __name__ == '__main__': main(sys.argv) From e4de63c2cb7754057beb04fe839416ecd1f5e157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 22:54:11 -0500 Subject: [PATCH 60/77] Pruebas para encontrar el problema de los test en GitHub (6) --- src/COOLCompiler.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index ebbf7b42..b6483779 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -9,7 +9,7 @@ from Visitors import TypeCOOLVisitor from Visitors import SemanticCOOLVisitor from Visitors import CodegenVisitor -from NoTabsFileStream import NoTabsFileStream + def main(argv): @@ -24,8 +24,7 @@ def main(argv): print("ERROR: invalid input filename: " + argv[1]) return sys.exit(errno.EPERM) - input = NoTabsFileStream(argv[1]) - s = "" + input = FileStream(argv[1], "utf-8") lexer = COOLLexer(input) lexer.removeErrorListeners() lexer.addErrorListener(COOLLexerErrorListener()) From b8053b6389d128256d2213d0b8153d2e28ff3ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 22:56:26 -0500 Subject: [PATCH 61/77] Pruebas para encontrar el problema de los test en GitHub (6) --- src/COOLCompiler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index b6483779..c38ebe43 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -34,7 +34,7 @@ def main(argv): token = lexer.nextToken() if lexer.hasErrors: return sys.exit(errno.EPERM) - lexer.reset(); + lexer.reset() stream = CommonTokenStream(lexer) parser = COOLParser(stream) parser.removeErrorListeners() From 779795a8c4abb7cdf2e3451e0bdc551e353235cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 23:00:00 -0500 Subject: [PATCH 62/77] Pruebas para encontrar el problema de los test en GitHub (7) --- src/COOLCompiler.py | 67 +++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index c38ebe43..6dc7b1ad 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -24,39 +24,40 @@ def main(argv): print("ERROR: invalid input filename: " + argv[1]) return sys.exit(errno.EPERM) - input = FileStream(argv[1], "utf-8") - lexer = COOLLexer(input) - lexer.removeErrorListeners() - lexer.addErrorListener(COOLLexerErrorListener()) - token = lexer.nextToken() - while token.type != Token.EOF: - #print(token.type) - token = lexer.nextToken() - if lexer.hasErrors: - return sys.exit(errno.EPERM) - lexer.reset() - stream = CommonTokenStream(lexer) - parser = COOLParser(stream) - parser.removeErrorListeners() - parser.addErrorListener(COOLParserErrorListener()) - tree = parser.program() - if parser.getNumberOfSyntaxErrors() > 0: - return sys.exit(errno.EPERM) - visitor = TypeCOOLVisitor() - visitor.visitProgram(tree, argv[1]) - typeTree = visitor.TypeTable - consTble = visitor.ConstantTable - semanticAnalizer = SemanticCOOLVisitor(typeTree) - codegenerator = CodegenVisitor(typeTree, consTble, visitor.Counter) - semanticAnalizer.visitProgram(tree) - if semanticAnalizer.hasNoError: - if len(argv) > 2: - outFilename = argv[2] - else: - outFilename = os.path.splitext(argv[1])[0] + ".s" - codegenerator.visitProgram(tree, outFilename) - else: - return sys.exit(errno.EPERM) + + # input = FileStream(argv[1], "utf-8") + # lexer = COOLLexer(input) + # lexer.removeErrorListeners() + # lexer.addErrorListener(COOLLexerErrorListener()) + # token = lexer.nextToken() + # while token.type != Token.EOF: + # #print(token.type) + # token = lexer.nextToken() + # if lexer.hasErrors: + # return sys.exit(errno.EPERM) + # lexer.reset() + # stream = CommonTokenStream(lexer) + # parser = COOLParser(stream) + # parser.removeErrorListeners() + # parser.addErrorListener(COOLParserErrorListener()) + # tree = parser.program() + # if parser.getNumberOfSyntaxErrors() > 0: + # return sys.exit(errno.EPERM) + # visitor = TypeCOOLVisitor() + # visitor.visitProgram(tree, argv[1]) + # typeTree = visitor.TypeTable + # consTble = visitor.ConstantTable + # semanticAnalizer = SemanticCOOLVisitor(typeTree) + # codegenerator = CodegenVisitor(typeTree, consTble, visitor.Counter) + # semanticAnalizer.visitProgram(tree) + # if semanticAnalizer.hasNoError: + # if len(argv) > 2: + # outFilename = argv[2] + # else: + # outFilename = os.path.splitext(argv[1])[0] + ".s" + # codegenerator.visitProgram(tree, outFilename) + # else: + # return sys.exit(errno.EPERM) return 0 From 20b83f34f7aa1288d04576081a968111149714d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 23:02:02 -0500 Subject: [PATCH 63/77] Pruebas para encontrar el problema de los test en GitHub (8) --- src/COOLCompiler.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 6dc7b1ad..f11cdfa8 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -1,14 +1,14 @@ import sys import os.path import errno -from antlr4 import * -from COOLLexer import COOLLexer -from COOLLexerErrorListener import COOLLexerErrorListener -from COOLParser import COOLParser -from COOLParserErrorListener import COOLParserErrorListener -from Visitors import TypeCOOLVisitor -from Visitors import SemanticCOOLVisitor -from Visitors import CodegenVisitor +# from antlr4 import * +# from COOLLexer import COOLLexer +# from COOLLexerErrorListener import COOLLexerErrorListener +# from COOLParser import COOLParser +# from COOLParserErrorListener import COOLParserErrorListener +# from Visitors import TypeCOOLVisitor +# from Visitors import SemanticCOOLVisitor +# from Visitors import CodegenVisitor From 59d7b827dc307ab88df03a18a13c713ca73cce6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 23:04:34 -0500 Subject: [PATCH 64/77] Pruebas para encontrar el problema de los test en GitHub (9) --- src/COOLCompiler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index f11cdfa8..e43f071d 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -1,7 +1,7 @@ import sys import os.path import errno -# from antlr4 import * +from antlr4 import * # from COOLLexer import COOLLexer # from COOLLexerErrorListener import COOLLexerErrorListener # from COOLParser import COOLParser @@ -25,7 +25,7 @@ def main(argv): return sys.exit(errno.EPERM) - # input = FileStream(argv[1], "utf-8") + input = FileStream(argv[1], "utf-8") # lexer = COOLLexer(input) # lexer.removeErrorListeners() # lexer.addErrorListener(COOLLexerErrorListener()) From d75b3ec765f809d240a140d14ee8a49375293294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 23:06:54 -0500 Subject: [PATCH 65/77] Pruebas para encontrar el problema de los test en GitHub (10) --- src/COOLCompiler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index e43f071d..34946702 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -2,7 +2,7 @@ import os.path import errno from antlr4 import * -# from COOLLexer import COOLLexer +from COOLLexer import COOLLexer # from COOLLexerErrorListener import COOLLexerErrorListener # from COOLParser import COOLParser # from COOLParserErrorListener import COOLParserErrorListener @@ -26,7 +26,7 @@ def main(argv): input = FileStream(argv[1], "utf-8") - # lexer = COOLLexer(input) + lexer = COOLLexer(input) # lexer.removeErrorListeners() # lexer.addErrorListener(COOLLexerErrorListener()) # token = lexer.nextToken() From 9b507009a007c01d8eb86b49fd2cd04d30ed7b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 23:09:23 -0500 Subject: [PATCH 66/77] test en GitHub (11) --- src/COOLCompiler.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 34946702..8efdb4ae 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -3,7 +3,7 @@ import errno from antlr4 import * from COOLLexer import COOLLexer -# from COOLLexerErrorListener import COOLLexerErrorListener +from COOLLexerErrorListener import COOLLexerErrorListener # from COOLParser import COOLParser # from COOLParserErrorListener import COOLParserErrorListener # from Visitors import TypeCOOLVisitor @@ -27,8 +27,8 @@ def main(argv): input = FileStream(argv[1], "utf-8") lexer = COOLLexer(input) - # lexer.removeErrorListeners() - # lexer.addErrorListener(COOLLexerErrorListener()) + lexer.removeErrorListeners() + lexer.addErrorListener(COOLLexerErrorListener()) # token = lexer.nextToken() # while token.type != Token.EOF: # #print(token.type) From 62839a95afc39548605d280b6ae70903b6313864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 23:12:13 -0500 Subject: [PATCH 67/77] test en GitHub (12) --- src/COOLCompiler.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 8efdb4ae..0f04fb6a 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -29,12 +29,11 @@ def main(argv): lexer = COOLLexer(input) lexer.removeErrorListeners() lexer.addErrorListener(COOLLexerErrorListener()) - # token = lexer.nextToken() - # while token.type != Token.EOF: - # #print(token.type) - # token = lexer.nextToken() - # if lexer.hasErrors: - # return sys.exit(errno.EPERM) + token = lexer.nextToken() + while token.type != Token.EOF: + token = lexer.nextToken() + if lexer.hasErrors: + return sys.exit(errno.EPERM) # lexer.reset() # stream = CommonTokenStream(lexer) # parser = COOLParser(stream) From 51352a88a83f34a47daef9ffe7ceb70390d0e52f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 23:15:24 -0500 Subject: [PATCH 68/77] test en GitHub (12) --- src/COOLCompiler.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 0f04fb6a..2ab99c85 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -4,8 +4,8 @@ from antlr4 import * from COOLLexer import COOLLexer from COOLLexerErrorListener import COOLLexerErrorListener -# from COOLParser import COOLParser -# from COOLParserErrorListener import COOLParserErrorListener +from COOLParser import COOLParser +from COOLParserErrorListener import COOLParserErrorListener # from Visitors import TypeCOOLVisitor # from Visitors import SemanticCOOLVisitor # from Visitors import CodegenVisitor @@ -34,14 +34,14 @@ def main(argv): token = lexer.nextToken() if lexer.hasErrors: return sys.exit(errno.EPERM) - # lexer.reset() - # stream = CommonTokenStream(lexer) - # parser = COOLParser(stream) - # parser.removeErrorListeners() - # parser.addErrorListener(COOLParserErrorListener()) - # tree = parser.program() - # if parser.getNumberOfSyntaxErrors() > 0: - # return sys.exit(errno.EPERM) + lexer.reset() + stream = CommonTokenStream(lexer) + parser = COOLParser(stream) + parser.removeErrorListeners() + parser.addErrorListener(COOLParserErrorListener()) + tree = parser.program() + if parser.getNumberOfSyntaxErrors() > 0: + return sys.exit(errno.EPERM) # visitor = TypeCOOLVisitor() # visitor.visitProgram(tree, argv[1]) # typeTree = visitor.TypeTable From 8dda8b348564209938cf040485d75817e13d24cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 23:19:06 -0500 Subject: [PATCH 69/77] test en GitHub (13) --- src/COOLCompiler.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 2ab99c85..9d5846b7 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -6,9 +6,9 @@ from COOLLexerErrorListener import COOLLexerErrorListener from COOLParser import COOLParser from COOLParserErrorListener import COOLParserErrorListener -# from Visitors import TypeCOOLVisitor -# from Visitors import SemanticCOOLVisitor -# from Visitors import CodegenVisitor +from Visitors import TypeCOOLVisitor +from Visitors import SemanticCOOLVisitor +from Visitors import CodegenVisitor @@ -42,11 +42,11 @@ def main(argv): tree = parser.program() if parser.getNumberOfSyntaxErrors() > 0: return sys.exit(errno.EPERM) - # visitor = TypeCOOLVisitor() - # visitor.visitProgram(tree, argv[1]) - # typeTree = visitor.TypeTable - # consTble = visitor.ConstantTable - # semanticAnalizer = SemanticCOOLVisitor(typeTree) + visitor = TypeCOOLVisitor() + visitor.visitProgram(tree, argv[1]) + typeTree = visitor.TypeTable + consTble = visitor.ConstantTable + semanticAnalizer = SemanticCOOLVisitor(typeTree) # codegenerator = CodegenVisitor(typeTree, consTble, visitor.Counter) # semanticAnalizer.visitProgram(tree) # if semanticAnalizer.hasNoError: From 805b31bfc7aa9d601be010a1c48563775c904a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 23:22:43 -0500 Subject: [PATCH 70/77] test en GitHub (14) --- src/Visitors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Visitors.py b/src/Visitors.py index 91c427fa..6c798cc0 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -1,7 +1,7 @@ from collections import deque from antlr4 import * from COOL import * -from src import COOLParser + class COOLClass: def __init__(self, name: str, parent: str, created: bool, sealed: bool): From 199d7def7b31541fa94ca24620218c6c2a97e2dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 23:25:56 -0500 Subject: [PATCH 71/77] test en GitHub (15) --- src/COOLCompiler.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/COOLCompiler.py b/src/COOLCompiler.py index 9d5846b7..0d636685 100644 --- a/src/COOLCompiler.py +++ b/src/COOLCompiler.py @@ -47,16 +47,16 @@ def main(argv): typeTree = visitor.TypeTable consTble = visitor.ConstantTable semanticAnalizer = SemanticCOOLVisitor(typeTree) - # codegenerator = CodegenVisitor(typeTree, consTble, visitor.Counter) - # semanticAnalizer.visitProgram(tree) - # if semanticAnalizer.hasNoError: - # if len(argv) > 2: - # outFilename = argv[2] - # else: - # outFilename = os.path.splitext(argv[1])[0] + ".s" - # codegenerator.visitProgram(tree, outFilename) - # else: - # return sys.exit(errno.EPERM) + codegenerator = CodegenVisitor(typeTree, consTble, visitor.Counter) + semanticAnalizer.visitProgram(tree) + if semanticAnalizer.hasNoError: + if len(argv) > 2: + outFilename = argv[2] + else: + outFilename = os.path.splitext(argv[1])[0] + ".s" + codegenerator.visitProgram(tree, outFilename) + else: + return sys.exit(errno.EPERM) return 0 From d530a64b2ba133dc9de2ec3d1e3229fe91dd70fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Sun, 29 Nov 2020 23:37:19 -0500 Subject: [PATCH 72/77] =?UTF-8?q?Arreglo=20a=20la=20generaci=C3=B3n=20de?= =?UTF-8?q?=20c=C3=B3digo=20(quitar=20mensaje=20final=20de=20la=20consola)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Visitors.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Visitors.py b/src/Visitors.py index 6c798cc0..70b0e001 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -1974,9 +1974,6 @@ def visitMethodCall(self, ctx: COOL.MethodCallContext): jal Main_init # initialize the Main object jal Main.main # Invoke main method addiu $sp $sp 4 # restore the stack - la $a0 _term_msg # show terminal message - li $v0 4 - syscall li $v0 10 syscall # syscall 10 (exit) From cf342c23bed4a8894662751182f499a7822341c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 30 Nov 2020 01:04:13 -0500 Subject: [PATCH 73/77] =?UTF-8?q?Arreglo=20a=20la=20generaci=C3=B3n=20de?= =?UTF-8?q?=20c=C3=B3digo=20(quitar=20mensaje=20del=20GC)=20Se=20retorn?= =?UTF-8?q?=C3=B3=20el=20Hello=20World=20a=20la=20versi=C3=B3n=20original?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Visitors.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Visitors.py b/src/Visitors.py index 70b0e001..6dfec9fa 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -1862,7 +1862,8 @@ def visitMethodCall(self, ctx: COOL.MethodCallContext): _cabort_msg: .asciiz "No match in case statement for Class " _cabort_msg2: .asciiz "Match on void in case statement.\\n" _nl: .asciiz "\\n" -_term_msg: .asciiz "\nCOOL program successfully executed\\n" +#_term_msg: .asciiz "\nCOOL program successfully executed\\n" +_term_msg: .asciiz "" _sabort_msg1: .asciiz "Index to substr is negative\\n" _sabort_msg2: .asciiz "Index to substr is too big\\n" _sabort_msg3: .asciiz "Length to substr too long\\n" @@ -1887,8 +1888,8 @@ def visitMethodCall(self, ctx: COOL.MethodCallContext): # Messages for the NoGC garabge collector # -_NoGC_COLLECT: .asciiz "Increasing heap...\\n" -#_NoGC_COLLECT: .asciiz "" +#_NoGC_COLLECT: .asciiz "Increasing heap...\\n" +_NoGC_COLLECT: .asciiz "" """ MemManagerNoGCInit = """ @@ -1974,6 +1975,9 @@ def visitMethodCall(self, ctx: COOL.MethodCallContext): jal Main_init # initialize the Main object jal Main.main # Invoke main method addiu $sp $sp 4 # restore the stack + #la $a0 _term_msg # show terminal message + li $v0 4 + syscall li $v0 10 syscall # syscall 10 (exit) From f8da25a5be7a94be76f5dd2ade2d2c4b02cbc614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 30 Nov 2020 01:10:28 -0500 Subject: [PATCH 74/77] Se eliminaron errores que se introdujeron en el commit anterior --- src/Visitors.py | 2 +- tests/codegen/hello_world.cl | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Visitors.py b/src/Visitors.py index 6dfec9fa..94865c8a 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -1975,7 +1975,7 @@ def visitMethodCall(self, ctx: COOL.MethodCallContext): jal Main_init # initialize the Main object jal Main.main # Invoke main method addiu $sp $sp 4 # restore the stack - #la $a0 _term_msg # show terminal message + la $a0 _term_msg # show terminal message li $v0 4 syscall li $v0 10 diff --git a/tests/codegen/hello_world.cl b/tests/codegen/hello_world.cl index 52bd2397..0c818f90 100755 --- a/tests/codegen/hello_world.cl +++ b/tests/codegen/hello_world.cl @@ -1,7 +1,5 @@ class Main inherits IO { main(): IO { - { - out_string("Hello".concat("World")); - } + out_string("Hello, World.\n") }; }; From b1850bdb44275a9cdc168bb45b8c87d304fb0e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 30 Nov 2020 01:25:52 -0500 Subject: [PATCH 75/77] Se eliminaron errores que se introdujeron en el commit anterior (cont) --- src/Visitors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Visitors.py b/src/Visitors.py index 94865c8a..f68d7fd0 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -1862,7 +1862,7 @@ def visitMethodCall(self, ctx: COOL.MethodCallContext): _cabort_msg: .asciiz "No match in case statement for Class " _cabort_msg2: .asciiz "Match on void in case statement.\\n" _nl: .asciiz "\\n" -#_term_msg: .asciiz "\nCOOL program successfully executed\\n" +#_term_msg: .asciiz "\\nCOOL program successfully executed\\n" _term_msg: .asciiz "" _sabort_msg1: .asciiz "Index to substr is negative\\n" _sabort_msg2: .asciiz "Index to substr is too big\\n" @@ -1888,7 +1888,7 @@ def visitMethodCall(self, ctx: COOL.MethodCallContext): # Messages for the NoGC garabge collector # -#_NoGC_COLLECT: .asciiz "Increasing heap...\\n" +# _NoGC_COLLECT: .asciiz "Increasing heap...\\n" _NoGC_COLLECT: .asciiz "" """ From 3519a33c54ff228a9584c0bdffabc4c6872e2a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Antonio=20de=20Armas=20Su=C3=A1rez?= Date: Mon, 30 Nov 2020 09:58:36 -0500 Subject: [PATCH 76/77] Se arreglo un error relacionado con la ejecucion de uno de los programas de prueba --- src/Visitors.py | 4 ++-- tests/codegen/graph_input.txt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Visitors.py b/src/Visitors.py index f68d7fd0..d94017e5 100644 --- a/src/Visitors.py +++ b/src/Visitors.py @@ -1563,7 +1563,7 @@ def variableId(self, ctx: COOL.AssignmentContext): pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) + 1 init = 2 if self.CurrentMethod == "None": - init = 0 + init = 1 for scope in list(self.ScopeManager.Stack)[init : scope]: pos += len(list(scope.keys())) code = f"\tlw $a0 {-(pos * 4)}($fp)\n" @@ -1744,7 +1744,7 @@ def variableAssignament(self, ctx: COOL.AssignmentContext): pos = list(self.ScopeManager.Stack[scope].keys()).index(varName) + 1 init = 2 if self.CurrentMethod == "None": - init = 0 + init = 1 for scope in list(self.ScopeManager.Stack)[init: scope]: pos += len(list(scope.keys())) code = ctx.getChild(2).accept(self) diff --git a/tests/codegen/graph_input.txt b/tests/codegen/graph_input.txt index b67d9021..939229b0 100644 --- a/tests/codegen/graph_input.txt +++ b/tests/codegen/graph_input.txt @@ -3,3 +3,4 @@ 3 2,10 4 3,55 5,100 5 1,1 2,2 3,3 4,4 5,5 + From fc866919708ed5f666176e240d7feb3a89321000 Mon Sep 17 00:00:00 2001 From: LSilvaO Date: Mon, 30 Nov 2020 23:05:01 -0500 Subject: [PATCH 77/77] Se termino el informe --- doc/Informe/Informe.pdf | Bin 0 -> 268522 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/Informe/Informe.pdf diff --git a/doc/Informe/Informe.pdf b/doc/Informe/Informe.pdf new file mode 100644 index 0000000000000000000000000000000000000000..65503264609e4ed11f9fb96fa6e51f6ee6a8051c GIT binary patch literal 268522 zcmd3ubzD_j*Qn`kknZliVbfiLq(~zjn-bV`NrQ9=BHbm_cklbh1^KPD=9)3)m~)LW*E8mlK~+YUgNu_F6OExB`h$taMGd5enA%{XiHHC+ zJRQIQX%iO{TZkn<)x;9)OwA3wtp-psvA1Lf+jD5Dvrq%nU7TFaTr`}(U^NKDg&M?v zpGDck>6yH}1q52n-6`0d8k!9(2K~WA1KXS5H*r_lU)s8F10W4?wTIRNP_#C8)}sd9 zRY%QzUn@0;=kCgY`qx_SGW=65P;s5W&{}?zR}Jh8adk2SJ42CIhMYpy~XA+|YDsXdj@xbEdvm2SCmV;_3hu>VCZLF97NQ z4JQ+OXNNm2n0W%E)d4bKH)}Jnnw%80aSanwXK0q+M(#IFIa33FRq9>EKb0zLZR-Md z0?67zyDkGZgP4N>N??0S7b|KWARp+il(UNy*u)MK%_DtCUlB4Vi`S0+$#2P#aXV*f z$RYs)!^G|!7GOI?Cal9=^PD)E`Nj0;p!p;4%GE5n^9P!JyT^K(*TzSq@w_(hT*l$C zjHN9tTcz6Sqy4QL2P+BumX(m7USVQ{bR@iJ*hn|GF+ zHs)LImfTvYtTqv`3;R&=fP6MtB7QHVQWGnC-$mFh*4;o5I{HGTNPGejj9Up!($Lx|Mus-3JZ?Yh9 z{dRfSghQNjrVZB@Y^_~X+oTTSUh)zReLbq|=ATEp$s|5A#OwRSif``2`PsrMBALdz~yRXboa8B^y(xUX8sCB}g z`#?1B0DG}+;SwT^m4i+MzLo;8zm9pyGIMqG#^&&l|J~_(K}Cy$2Z2N^r$+1OImhkR zkbPDb{Wb)Xc$&HghPI{x9hrd6=AJS=0bRQTPJ`~}!QuJ!2N5ce_pBru%p{h+d8F(w z%yXmE-G{kzjnm5cO9yqkeBUlQd+nXpZ5m6R0*o= z=@QMcr$|`CI37UuAS32Q5|)ubs6);%I5+k;1M7R(*;J8gImok{zeA&}4a{bjPo^50 zf>*c0ZUCPPeiC)u$tTu zY2D%(YX=H~wtgS`iQ^?(m+cAqHvl}jD-HvJ{p(~cFJi$okQhE1e^8($uJhWY#3z-p zPG+>w6r7L`S0GmhG|)7BsSus7jQ%Nu!()Vb+;oA0l%6;CeQ@m47l5_#LVqPzXF(kTwhSs{57+g)#ZtP#@f9fR#Npu;hoe1p(tqz! zZ!LLw=KtV)=PMGHHk(M9IK`Y9iF2ohb8k=AGWa`Jj!3jRRfaHwk%%gOvK+pQmNAv- zhml6)k>^S%A_e<65rkGVacd?zErLMiRp|ltj{-+e5c~_axKDPKzB^T8B37{DbFGVg zUS{2jOOU5Ztnf!5i8lTy2`P4JeKcKG?*67-1sB(FR5x{O#r+MjE289>uV)*^YupE( z>952J{SXd`6ErFGE^RckR!CExb_jV>h zJCU$2rQu^8aQV z{X?C#I)g3XNuS1T@CbInv{ewo7_4z?)%lk<3nRLObFAuwM=qokaS%p@a$qtSUG5vD zAo~Yqa#hADh?*f6E29*zPcqPA806JpRU}2lYIWi8M4c9%n=#lSlQ^yj&lJc5%XTdg2AFr)>ptivf1);LH$|XieKh456qvrtp=v9p7@wws-ijX zp}lVWR*1ejOpUHir)Aml}NF&`s;O2!dQl+J35&I^tXF%{A zZp~xe^bA^U+R3Ej^6!X8+N`OcU>J9Y z(IrDNtA;Q9zDyViiPf3U$Tt%1F5%)QEFU!YmQi_Sqcrkm_%&2ivBR$Ny!sxsKBZ%< z8FtCW7c(ZTzo%xiS4iG}<_s^hHNi0CJWfi#s69kS(2FoamY6K>yg=hRUzZ4i4|+SW zufj6KkpC@jy!NPVET-7dgak=jk+4>=9<<+ro@vTkUY0B>9mk&+EF5NUG?a0oZE9FS z^)kD*d&pqfb_3uN5qd+LFn@u|RZ4j=9sV#$9-uvZEbY@MZ9+Xy-a@CFjJVxqw*PUQ zX{D@zk$KuTKr?}SJF-U;R4pF5WZhxo%MIJY`fk#q?p{%191tKc#Op{{p1*7+jFxZ(^<~S%P`!1YWZ3Zhl1M5jmW$J+ z`w<;^R4@oRuF>LM@RP%LxguG7k4QnqMAhBO!I--((AwsIxuHR(bbixR^&G|@ROy{}0 zaxe_%e$LR+$MX2=*PFrpDzYF9ki6Kc?w)zbe8d6VIn z6HH?hJ%i$Xf&_5YcLu|^sb-_tPHM*m$Xf3TEnauWOY(h9n--yGAR%gw{Tx71B`<{- zS-S(OH?>7J;qM}jjKdI*A=^t-VBjst3`NsGLn$o?HEfb72o`wgQPM=|O;deSBZ&>% zUz{K-m8@{rHRp3d*zR1PQ^N)$ycv@jkw4=N^1iD4)%Uv9DTRyf z)D&1X5EU-}G_@)gDWBuZ_ug~P5c@hp)RMIPp^4_tkk{sA5K*b8ia$`uzbqx95^q+N z-g;DcF<)9JuD^w7^K@?7oi^NBtw`zp;Q5wwOZY4^@#9W0!^6sa&Ilz*&%@a_J3m4y zo&?}jV`jPT^Ymso;cwFv!HvK8;$AHp@kE%>(x81>@xu)wt)-!SYF$$Cbhdu+Hpbfa%LLm16&W)J;fbB;L~>u}E3-E|6z+&2 z(V-P7mE`fWG^X=~u*h}%&hu^0C`%?M)5b}OBu|Pt8&uw#wT-jeuGdWNZrey)Fl-xN zGDhtuV045MYkR;w=`v6?WF;a@M0uexvrwlqd7i%|^kzS&v_{C2uy7OE@+s_Cb{E_X zsl(*EoDh1^gGZCEBz`D9pBkUi;!*P%&qdRmo6c0emJQ{@ac-dB(bE`yvobJd8cv*O zq2at)^F^(Q{#g(O@xqu6`;$JS5+<`UOav`BEj44H?$e?Wd%^hi<;f6xK z8mtC&Snlw*`;LM-CqAyaG-=Q4Twxo8^bK46ZQiyNPd=Zm=Xvf+N-2h}d4$id0$Mb` zfiu01JVceKRadJY^)oxEonKUKa;vTnLT0N&LU?JQ=seS!6QQdu)hT^a0Dw8fi1UwK zFO_KjWW>RIG~MbwiB@B$^tk7;u;OtmPSL_x%j^>?;@hk)%?n~5urv|%Rn6=GWZXm$FnBk(5AqPf&3NE8e|F>O^Yt~D|v>@8YBtEiz1)TZzwhV;9nF@Lc zDzJe7n^q!KY44{3?bmZQXfJ5IPymBBX|k0KYH>)nWr||0SBV#{ryzw6&BJa_2CmQF zIWh`M$tsijx&f^QBt5Z_rm1t!Ej#E$?BRul)W=s-l~#ymAGzXxt%^)!P|q?vReF<3 zR#ltR(DEQ)cg;+ko`OIBsq(O4@3TOKb!^FE&Zp%lb*_qfo!h&8Ui*v}VILG-cU;G) zll9d^PL0R{_DaL%l=2!YK2g#la%qyQ+2m5spFY|h-kKmfw}}YINLmpul{yWXeU?^m zam3f2A3OH;E%*mxo`xn-<-&maLJv)S4&V1L@ z4OC(r>M)red&XN%o9JoDzB4Y@aYV0XN0lj7>ReusdK9J#eX;w2G8$OY%@^;DcAJGT zbJ;_DEgHXhZbJT2e%;K`!1LvcT8_F|Zpm_|j#3`owuPxt0WL@IX*5QIy~h?RL4D7z z&k4Q=iWN$BTq5DYVg6;9d*0#9i&nwpOjkI40r;bkq;{?Kn%e`G!)hLS*K%`9VBDOV z6~00Qs&+72*3#BWNR^1F!`WQZQ784Q<57$WbIyn94-8q|g{G^Frfj(2AO8sW(w2gH zDVS?fXgmgUL2hw_tzTXYxF1=j~lLUdhP>}N5IR`fv5K6}!9)Ybbtz4-2xdi}{ZkG3g zQ1kF`L9v&|Zx`Hre7yI~X#bXz2M7e{{9fu#b|tXMoeHQyASjUm+i5{d-)EP)CqEp} z($sftL6H;?c-PEd@z))N`b+=*z*GP!Wq=CA$quS!GZSjAUzKtPto~ymY01A9xQF$XeFvEU zveY~P$)C7N(#*vgVh@E;nriZQf6R6!P}~F&^5nF%wv_-oySPFT7?gH7bK04>m_h6~ zU9C9HTv_fA+OPQPuae&5w7(M-1Qiu39G?KE0QA7k#VN@1yWsy9qS|sgTid#s{4a#% z{&g(wq2J#L%gxQn%T3J-Rj(jaz0fN@=+(XG{};kKaGF48g!BJG*n7hF^J%|FlYb*D zmmoi0 zTMlS~gS9Q#iGv%+4gBZH!1EXV{u3bnI}64A4;G4D3Sw*iKQ>cbzX92QW2bmPf7+?v zq4J+F{J!W<&HiCX|E;0=O|Jivwc;22)mlLf*`0=dw^scB(OU8U#aeL-{GGMB2kigU z%Rk)()Mo(yVFdnEzPvfq23xy$ayDnXMqAae3D$|eqgpE3eu zw4qcVsypaSbx&ugUB8QlP(uymy(9apcjLN`0zl0p7tehl;4jnnS6ltq$sFti^%cxN zn}Nn()WDY3P^aw4ED4ROfbRk_t_}{iV7ohi^%tgp-^xGf{@>29JK+ESzbm|-d(a34 z_%4iduf|`McOS+1r!N0F-Tt~d;rWM|$Nt+I;Li#89~LRx_lu8zvr6IO{$-VNA8`7M zp#KziyPH}6c5Hr1_AiHsgNyrLuUCKq|D*K^mjFNCuNL5cxnALgK3h<`EC3x3UcrA} zuiS^z{$@!2!2(E0%RGF@CT(J83SBSKaRZf2T&(^ake`pizpx10zXkPvu?Rf(#`!N= z|HC!tQFGtl{naAer~H)kPmAy`CHn7K2=3oQkbfC|YVP0c+nt5DKl@8BeqDn9KUs+T zR(|&Q?|sm})WW}DF$L@KOES1 z-gZi3sa54pKaLOQ>iX_MPVZ1f_D&v466X_nc@kMP41w`|+4G=qsy&u)+rssHeYN-D@lff&M$eI@ ze0pbx{s-ppvP5ugmKr%kKFk8CnH!`Xh>h z@bJW#g@vX|-^(H%uf--y*}Vg1bh!>_0Z8O6`z>YLH8j8W_i#V&n;n8rDPiiOaM3vM z*@|Kk%@G9*u=7W-c;Qh;QE)D`dRq_c^ikWIE*uRwwVfOr-HRe-G6spZqc0y3Egt01 zfk|i6rHU4=>s~okbDjyy#-+qKKMc6Sq|4TSKcVVRt0Hj@FLU*PiaJr?b3v9s?#32& z(i0w4jIRW}O9I-%)`)5SQ%a8KSUQb56=S)axhGCwB5}?aEA#^D3thL*-N)I5*101Sm(zA+wMcedm1ZY`9w9e*g`sUm*Bh1{r z`?ryJui5Fp6h@^{?SE7>ZY?*fo{jOo^lMUIY)w>Ve>3#C9Kw85P3PF$yhK~J!tzq> zQ7w*E*2B;(dX-w#?n*aik4XvUe66~%6#VZsUX4n~mT~QRepWTvt^-tWVzZyR-&{RG z;8P!VwTP$Q_elw3^Es&ckvft;g@MFUwn>0g;+2sv^c(^G`PN(cmwl`SYr9+&uQM?W z8LL$ZJj|nz1oJF2YThJS93%=qbJU#~uIfb?-8sq#l@8EwlpUJ*dN>PN6bY2{Wi5I2 z!Bjf_<7m$mY+~xHo9@+KT$mfRE!B+hg?jmkY5WWI5I4tK4Z{P$hed4yv?v4*E%%A5 zr*<3|_ba@#bIW01CgtR}%c_$cSeVvn!cbRJ(J115>c79juF?!fqZ}Ep7e19XLHT`QK#3Q<}&2gOZ$)>6yujD{Y>etGoL zZLMKGc>E!z+r~)dFy*ugsn#nNp@Is5#FiP|vvAtt$elpE?H7}?ajvT>JCr>;=IHWz zm}^Jurm>$_&3mM0d4_kST~I*;w&91N;J8k&_2v%)rC>a|AqH8gVG;(>=SaFRJCUy` zTy>zaVXTTAfv|}P)_|9O8-iq^m8&^T!RvM2yP0vqur64-yDTU`U92 z9^&QHyI!6qL|l`H#^0kJmT(fhYr;FT1Zd%@7&Px8GwzP=Ynqy+B*mm7yR^Spj}b--#WJK()13gSkWUt1HYzH;0MGL&hIM~oG~N3 zk9Q5&Xa*Eu*5w;AH5?xfR}Zf@Icey06~4iD5JL$Aw{dnJR!;ALiZZy-NN1Dh-cZkW%)C1N2&f(WJFrfsHV1#F0-^kgr+0z$)v4 zsnNCjF>6WTyLf|rp3F=8#Ct!O9jn!X9ytV@TZoOVjSaOtm>X_9t>6(c zS+q#K*zu?fFbmz{#y97(SowX}(Lf9z7$SfUGB@lUi@9+!a#iEyE6Cbph^S1|C7 z?U!`_z<@2wV5JM}?$$9Q3}D%OXc4m#g!=dZp?^Vw|GM zIZ`^_YU(E|8pO#>G?u4IXz*{=FnK#v%uu!|t~tBT#Mx(XrmGV<^S4Vry-AhJFR#%J zdLUf9hFeY>2r(bBrQj&2e27Z}T1^I4>$2B$0`=^SlU`qHOxv<_KZdp7o^ zg#e*IMfW^%`C@IfMlAylTgJzMCs8T(Kl2j8u zax~irJuplQ^>-6K{#bfbZ2Nwljau7B4v8HPd9$dS1LP}~(I08eRAv(-gy*ay*ZrFN z<#5c0lIjEI>DpJH*n(V_*SmgjoS(CIXn{=3ilUJq$#OmN>R646 zwh;VLi$E$;x1t=050`bDbRMMq>e|`KhIdwtETY+QVNg;RbxH~97mdb-!DA()I36YcnB4L~=5hb^w zqL8559h0bwB!3xhotRIO@G^mH{hgYB6XujI^XNxW^=acSc~@^Q7c?z}WcT<8LA^mq zi)z|s3HMixZ?SirwG{O~ttb(Yks}`PJ7wc61{h<71k4hD+FpQv66Hvlf`THE?&p+q zJ5-Kzyz{Z&xEW7duxar~?Mt)hQaG?n9UH^NQCGham8)^EX}n<>E{)WxtT0hJ=A+3$ z2U$brIC&JnG<{Df4>6r5PpGvQWAd54>0-U$a-u8JO5u+wqz%ykp(BJHx`gN0m_+*( z56H7lR%Xb=zcWo`74=BYYNEvLNiAKcqYITZsAGByta>N>z_E|}&LiX0{6;VMV>ZB= z@XG(ztl_Gj&ru<&;p9l}+D$o2M^e4d6U(cUE=Syc<7?}RNoAaYw+zI~V2?{p$m3MM zabpy}WKM?lR7puZ!iB^4qLaS97~6VYe#$*AU7Dk z2(&UHgh!S^e>}WzH_nSue*7W4Ye@b=?81axA(}!)RPAkMx?P$+tkqWashw;rF&)sZ z$LtNbim*l!p}7MtN`ovzuU=H1!qNjRI4%c|L$^JyW%3litTk>_cp^Pb^Yk^0FDJN? zhij@g&2UMarY*)~0M`iuN_O4e)>VgVqcNWuKqP}dZHnOGGn zWB(Bjgys(_#xGgC+8?J##R3*#5+k>`w7#kEZwz*Ff)S*h9;W3)C0absR7HVY+mWF? zX~O>K2^1^2d5y6UX3Oa95wkSJPJOyGME;5iWkFTr8`c7jLngb2baaBKhcu=JiTES( zoyp>%=?h>sv)pV^@*sxu=VNN4vxQ+@Q$F8XdMWy5xEVD8P{LP|c08&aOp*C$LoKT>WE_haH55jlPb>1BtJy9c9(aY^3WQ=%IL8Im{IUUk-P4Yd2EJ#2c zZqu-1whI81XF77+viruEGkH;+mfi4ei_N=<^dhPOv1#}7Q{`>Eyv7N>n0e~!vmhgv zC7)BKIoQIZhQ}c^HYtk-C=MZ)Y0HEh;3W0!vahDV?_I=MzNa!V{MA-rEh4 zLQz-SPu|;(o%hX(#m;!)IoQO-AHzm|AX+kYfKM?tqUkqfXK8nG4+cJBP76xeqfHnM z9iTaT)GFZxg1BYbm$jYe4o;RG#4N6seR zYQkg>igAR3eCkK2ij$GwQ4}Y?aJrE|lz+G;frz+X0{7sXKr{Ss*Uq4FE3=CP z&KedJ4h+{8w-wAEnCxA1;<33%|5fIDTDBaWXKPQrLT z>%~dUF8S%UNvlYMs9laz_)sB;q=|xnHL4*7pj`C+s-)aUf45hMR9@*!+t#OmyCE>J zyU-F39%4_M9Zcbd^%cOJbX|emu3koCw6NmZ2)Jb~op&oq5hl{$1S<8&l;~!~yZ6Au z3RejB%d>l@`$ZB=xqR60^eEc->V?9VMg#f<~aj z$!y=&KQb)wQD|H--a&O9B}(lSpg~+f+*sLMUsgC}TiIy?ITIb%jFD5t~l zW09N0+nWy*mf&|}ELaW8I}4QW>PJCartJ4hjCn{UFPesJ__QS(~b~l*iDiuLt?{TEJ#l}(v@?bL67l~Vb_=?Xf&hMHxA*ayUs2S3p8Lk3q33(>{wuq^Px&d@AMEyb z5&nCy7WCWqC4Xi0&_Mn@f4hUV{}hq9FY!~b|0h^`-^$OL{ub8$-tE7qv(RAGU-mZe z{eoxt1VMl9ZQz3jwf@-Kz{SM{`XAs~;4gR@jsy1dvy7ialYg7 zf9dA`49)%lWdCHeKY=Vj_9vu;?jrbOyTpIvtDgUeWjO?xmQdzqkB4uP|>T?=q<$U`_yIB52gQvC^ zaNr$dn9lKO*Cl>Q#*bU-Ng%zxrtA{~C8iGFP`5Ark=vW!zA;FCa=dmFq5(2XUc5AZ zNt>82u(IKW9%R_2X*J&&Y-N|Jc6MwdBuO1ywBdCwmMd_BX>iMvk>2x8{4vw}XPpx8 zVq={se1{8i8v-mY>907Kl7_^QRtFSj1i| zM#oQ3M&&xEV+^M-NLv_-nM-z`7qK`56zX<-eigl4?`6A^Qa5k0B&I_1IarF?cnuZ0@+(Xrm=Q?QTH!A1j6blUvUqJxIf`amYd<6XcyFTH%Mu@d?dqbR&lU58qiIg* zgoqgOzKrMl%q9;GgmwNi0vyT;0{++9!w(wVaKbC(pydQ7C7sdpRk$3&mB>%U%Bji*!xXSd&{2eDO%yb*A<^oe56#cIAqECidw$}|@@S>*t7Kv%yw_-hncc+%4qNYoa=ZMIw__|G!-%Bfu=jQZ%TE>bl6V^-D6qeR zBU5jGcPPy)B?Bt+{(vIanoQ$P$+Dh0_T8Th=9;F&%y6ik?flc5N5@?Jt_v={5ZRgy z=l3;prP21x7bT~waS)fGMvjLpNN_@dvKoZ*#5YgM&2Y!h`P>h;Om%%f&Aev&R6&X| zkwCWmc%WZj7l)v<+9=JbagTY;$p|hs@wKLn9Y+a!oq9cHFh&^Ipiyb4Znw0nctlQj z6Fy`~$HEZ4W#4M|4QG7Evj-n@CuW?#WVsZxm@c%x4E-8R+oON}3S$+GQIN5lX|*C+ zN6aByx)n=@B+_c5d>rRsU;jI4(2EN!<`XAft=1Sh{^5W#i|;8vYGG2lZftiDLM=;Y zl?^togGar_J^P5I!wot#TW@K3d^&@GWsA^_OgVEex-m6Bj}?bTcRfYyvpogb)S6(? z8elyo#F;HrW%K!4tQBAHQUHHIp6v@dx+TmSboK0(>$&__;IB1AY+bzx)=)`oC3?{G}4Sk!M+nD6(BL3e3LLqC~>?rdbf zxrI@Nv4$~&ae{%sI79y|U|e7-V5niVq32F8=Fl^47$6K64ByW}(EV~U&`&X$WrXf_ zKSA9nkQ@4s7svtRWdZ`3pxKlm=KmoF^h;H9S2OVcuK8cxGS45O^PfBU9-G>zyVwC# z?zX-Bwg-Y*fD5{j;NN~d%Eb#5xU2FPSEMs*PaufnBlnf+3VD9Dl_9u}JsaHo5ET!b zjWQ&ke=uGt&xE#Xaj%5aojbLumC2$YF}LY`h5FfH0egv-ZYep-HbMPU-O3Lnt4|B` z2A>sVs3(6a0kfLP3zpiFy;AO!0n@#%cam&Qex>+vR?G7WF_z?ki)yCEqoqwvb6pjN z2x@f}fmP8+MCHzn=tI>Ylp|a-`WGypk&d3eG%3jjb%toY6_PBl6l5^!6|B_LK(I3QbLaNwj^hUWmA7iUOylYLtUWxBv&4K|5P~VO zMzKSaY3acqrW?oCC~fE=hHPmx@coyTewloG;Z75pQ)N?XSn)Yazfb zL;$biS#GfKgGq5>b`^ZJJarwl<6}@LMPe?Eo**W; zK042M(VNSn`#B|PU;w=8 zQxW_3G6D!Q)6t^485N-)s+d1(hesvQu4CgLNKTaY)#o4)Jd-G4JQ@J^Lwa5aBs(b_ zNjq}lTwSFf(szg_<-dMrs=MWK^&`5KzFuErKusMy0ltl;BylZ6b!e_5l31-Vgh@nC zNP|`U&M}GNj%_io_@$(7$*`vWJG(ZcJLq*3dlFNl_*!(?FwL7G65(o=jo!45j41-1 zA+nO8{5Nxly75BL#B)$UtHKvG>xsq|p_6yvc~1DI+6&^ZVIW6vD-6y!8KK75om&Z{*{ z{7u5|?P?4hxdKA{pfF^SHi~8HIzP;1j$JYs!Lv*WL zld@nLtX_51tpu4hLL+Glug`K~LTEgWcYF}@r&Hqya$5Rt#cI> zX-V4yX?96=KJL!f6s^Q(!^nVGQFYOV?}JlfHD>VLjzK;jKIioKlD#?~q|~dy)3ol7 zF_79+UgKQ0n`EtAbr})G2~foT)=?7sI6_mr@X<|Cj!v3s&D+A)iesx>NjhnS3KJBs zY=xMo^;1`xhp-0aW(==eoUX-uj{zs%_%r{~P5!o5^FP14fVlqQ)#ZhnqJ0n$Xa17F zurLxuDchPp_*I;&>1eEi7mOKpNr5T*3VV}JG*f{cYyE4Owv;n2N;z)XkKKYs_BgQrLMg-*8FcHh9{}NbaEv3-o9jOFi96$Dkk<4hV`8Q*5hbsQ_7;pi( z1-L=K{|69U)F44Ve*S+Lm7NS!V>0cGTR)-oR~9aMq2({Z)79hyF&R@aEA%lG!lAP~ zB^hHX>QyWB%CS6~uys}F(;T9z0f?_T3^t@p6mRF9G*nt!jhveve<7pPx;Y{nq zvDu|T(?Ye`bxNL|xYM#C4Bg_pL#hlBpyNiY-pn3y-cZ!+?bmO!m7m%j_ROddR^nsf zbO6)t8&~iKSton}Puj>N6f(pe&uR9h5oYxQcT3idyvN%k4Sy^l0UM03LuXF+1RcO; zyLS9=JF|!(v-XP}?xrKP(!!Joz&WLc4l4Zg-F7mE>(C~{#@o&Z+NAAMCqk!Z3jPap zM7wP}@y7?pFv;DQTz1D_gA(xlE?l}{`?RZXM&m+>0A@bBoeOM?N{u>< z`yL`nr)Tlu@Xz=3YS-0`Bj%9fh(%oX57|CDHsM|lBpilv&OYDxBIkQ43=BDi`M@D@ z!$*E&o#`36TCOmn=p9D@|6?!#(-H6HN84l3vyT~-8I^DynA(U>GyQ2A*G@P-Rd%zv zw;!rJI26>~F=AkeiS05`UB&TO0oHrFvkfB&eeK|A9 z8tvDMiXXS7PmYzQ^`X-DvN(2<$+U2kd#4b_9*t}Dm76|gPXTfgMH9l|Dj+o6 zwuxeZlFqd{T6(&{>O<&qHdyY0cL1wt^blsJXElNNHtJlyX}$#yYw4m~XU|Y1Tu7e8 zc3XCv!U4Y|@;o8=R31aFdaj789eumrVg>FDc0U1!h^>%6vr0Uvh-%~%0^*$f%GY2j z5H^5g|K)`V73U-grT;c2cD{JfIdS)R)AjZvA*I8`XVcL-G6?O);}qAIT1_7bC`6ThhgpX8S1iOT`<%mmpm7Mh%3d9AXL^ z8hLUz$_+Q?UhAMPemH&q^iyNe?r{&Gkc8N5Zkj3`K0H@^MsV*(^Z4~ZRd$A)HI zIS%j^xAgkBjSYPQZvuayPwx{IHE7qGwUfK0q*qP6eZZHBY{FXs7+B}+d`fDFNcXK( zol(4u^@p#fUc0{H+H;9D_b#`AYloaw+~m5q7>%fD%X}CRJ`$5eFvXmW0qV-yfH6+& zmrEr;kE<;1Lg=n7mpx+Zxk3};A{G1N!w&~MMiJI~L1}|VK?ZA!#vV9Cl=d}sOBaz2 z3Cr#d37bw<^k5~UzGGzItsq8{$xVRm4`(G|n6x3**Ov_5Q*Ws}wu#4#_1>PF>hIuW z9tju-DK2yko^?7IXNe_`Jm*Z1yKs~e-5JoI6-_bjsJK+LkF5p*7hvmOEKYX!YR5IQ zkTtAJsb#+F*Wq*}GapRSz*>JnYt5h3lF@-+9wU^vyB_2BeF_9smKoR54`NFov6$tM zPe1Qb?Q1`xRn*?2ov@XShP3r$uw{us zRtqv**+R;dhle3^7kQOLh7ZfVI$wTz8uufF+j+^&QcC)zNQ@1sAx9>r)-&r_V-4nq zBN6-tuegu}1_s@U?gy4RFh_z&Jh6rf9q({OJ7mx_`REZD#_%pAn-xM61`hn7^)WgI{I(k)r)Txp}#7gK|eohWD3^*2vNB_Khd% zhHEy@`dr*{L97J$=4&XC{W5E)#Wf;K^T>cB>!pCl9awNEo0AdE6JAPCnVG{H!Dd4tn$sG9!7hD*Y>c@@U8dZDLY7VBN>?U5 zkKj|BR)QrdzC}_+d7?zDbW7QwDvHjRZT}*=c-C0`0#P7s3ur4#5s-6yR7Ei?GcS2U zJ{2g0W?7IG#5EPsf`8&EK-6I3O@xt`iA+}v$+^&)%Je1dGeO=$NDpcuJ8=i1niW4c zX4*0oAabSJQ4oh;SD(jT&oP97$lnrj20KO>$()!bONhd>a$Vyk%ZNTY!P$|&MdEzX zR-DvzUYw-f26tNIhY1NnS6##+%58@~v2McSlxjo6%5KN!l=LAQ?+6Sk_QMQSUBpZ( z%nCeH6~#!(yTQ~CxM>ydpVc7aNO}=Due8fiUOq1$s+$l2z=BCl+?W@ z(-poAnpn8diwlqdT$WTDy1ir@nOMRN%N5&|^Tm@N{BLft8gnUMjO0=V&8qI@Trf0I zoDA#(HnTdlm$1fev%LV`SSMmXM7I38iBvn#jAX7!=TdICyeZU*&w4a2O;^TaiRW$bZca3yI8#F0=pT=Ptl*Y28x)oM%F%#hHMffyGf$s)(co?YfRu-l zqBnZZYx$URklz`NWt)DPU5icbEjqbn4k3OYf@Bpsq2baempp>6%L( zoGV$lPmVY?VNZtk5yK(vSxgz5?Ie;TIEC+n@oh3cC_V3owx`fbh~v1F%-)=k#k3-S zHk3RhG7Q5P&>0zs%7lq3BT0aeZfKhxcQ)jpyNHo=G?XkD8Fw;oem?NSLgvjNe@}7% zcZD`otV7@o+^=faj(`-ZotjCi6+##-l{dL0aUP7)hK=!?4WC4AN!WmThyjZQHhO+gfeg zwr$(CZLRid+qPfteeS#WMAW}8Dx&6>BXeYqs9Cd$f`?QhL8u{u(ROc&`}Jepg7x;` z-c}cR>HyeIUt7HjfNW4!b)R|4_e$KgqeplTmD}7 z_Z`26Br^s^)Nn|}_|G#=!`Po?=Esi5DbN{vF;x(cHxN%Ggr|aFjU`Y^1Q1gs#Cem- z;OjXuLUYT~lVYVCIrO9px|ZgFFR}@(q}ztvrUt+MJ_0SQnEwCfK=8;yj{SW>dOP67E%f!Ps=>|>DYqN9VCmKF)1AK{WLu#idc1YRDPGOXp=e(>L!~}eH=z#{Qb0gkl^+& z(qnI?Av_|8pJ&=r&2nH5M}pF!17(87kQ1!G#!Pu~Ip3%?n!d=ak25bfGrEBJTgqXg zT`OsS!X!C(QkH#9`>$bD06EGuND_DN!JxI23HOjrv9`%nX)y6(G8|zeiYV~=ot%#3 zt|1Hzy;5dNYD?5T&n9#&hgM@N>RbG)el_Clx0QQ(V7eF6GNOzqm{I+1MQh-&;h}>| znXnfVqJLTm;s}G?nw3kZjH;FDJSj!qDzbLtnl@{C3?rnlL=tf&@g9hgDg&j4$mD}L z=v^Yj8a#%aVSRdWlYfdQcIoP)*m#SPK@Wx~!$g~I^4^?jQpmgt-~Sd&I@gZm?X>cQ z54HFNXB#3JqLvtl#9oHsgDdB;650K`^tjV@l+J9OTm51OJPGm>%=sA4yDl zJeMwPYDGQvVj3bxGoY|E{Od2GsWI}6KOy>W^iI7t`B_DJ!Cf&VoiBxInxMc0jPUYx4h&vb{Fj)ZJ z%N&1k-r8ZJxtwNi*BhmD`LtJP2I3Pk0_Ce7X2+q}_b8sy2~r>|saSr!0{S-{iHvPT zsQ!OVTJCR#T+B%5Pl?X&KCojKk`-`Xqi$FlF$mCa&RZ*5HCCyQFyo}CkWm>^L(yi{ z+6v3C5um^*9rcD?*ZBiKnMY3*CW+W~RYmbudrb`gN zPa3#VWfy?}x}ySx^Q$eC4EWGJNF1j#65&sxlnd zqS8acQno=h=mG^!VG`-PIBR`Vmm@!j6XO(jw1$(C1yQHTs`uCxEAafxaF z%eFV%Xv%zNVLZqFw2W|f?k&yQgS&E7uF{0rUXmCkl~5%WZP}TUzdW+3X9FyyXG%+5 zdV)*9G2AwS*K($wXU0Cg*F+JEtAw_R{d0w;CknQ@NBr65SQjQ0QBWf1)j)UqJM9El zh{OVRh+}20Pyx`U0Mq-ouiQ4ha`HSg_%A#@xub{o`i#!*oc+7*fG7PCKK6dNpi z9Ct$h8{d%$?j@v)KfFNir?UhnI3={K zspX86N#eP=FTW2oyqTJHZB>$2aLN#|bxq-cw)m4*ln$$xyqRP_$T%H)FiMpi;J2d$ zKZf09du&TqAIbQWUw@-B$&WZMG5uSCMBe{ffpM?IC5m25|HRaUJ1?e|EHTko6_wZX z&jvPrZzjWKw*3M=?A@bF+Tw_p-*(fNzu2>1YnRa;r>C9(_XO{zk=^tk%J}FU|8YPI z(W^)BVFkvMYx%kgs3LGbYL2V$5P){}`K3R1T?q?C+e`Lq>B~YJdhcSd5LX_qjfXZC ztI|Fo5;}3BLFs`#U{Nn?v>JSfZU6RXL&?7q=wsNHW?Pa`!5{KdYsTr_7_a}-nhFK1 zx2U z_HW;~YbfsyLB!_N4r}f@ba-8xN3(qyM+(7#+~0z>a^E6smFXNuhzJF|`D1yUwNbN7m;n601igPwuuZr1o zq8dKD5ie#{6(m?X=*s*sxf^j_3>b11L~oTZzgeVTVKbDjGWaLZZ{9h6bOHZr2mCl2 z$jPVqj`8Dtkx{FXQDoOC+8`zm5jPJiZ~jsEk2*G_nlUn>M@A3Tkgr;~u&@mUvJU@- zh94_~TeT9%0@NJX6(`27h#c#&!v}NT<Nx7)i$ao6@KSqgo=iwdrfZ&3^PvVj?N`$bP$^wVQ8E~Eq+{%of!Bklm!jW8e6S7z)Q`qc=~ck7>6Kz!E*>Fhf7kLB~(7W3Vtt6wGb2*ItM{Sc#uIG5vt*e;YgsH9LxOj%~i+YdQ)QUnk^B|U2Mh0P>U3`g`Az%{1w5g(*M+%os zB25N=5MY>xFn#-ENQUFCwlE!75AJdenxBlYz?tK-{G;A5Mdt0mPO2&`&B`K&u#)t3 zWSEA|_u7`_R}i8V;mA`eA(t1)S(aF}=9aaild}biIalE!P&>FRAN*c8D^K6BaAndi zgY7_z8-^piS>a17;!oU}Rr>nNiwegssc_$3XMxWxf# z#jPT|8cC39T<8a47G`RV&LN!Wl`#R&=m@Z+b(=~^%lHg^X2bj7PndW!8RQj078x_G zL#;o+SnhAclFNi5Y;UFy_eF)hiXrM&Fh3CMB>bzQht&Vce4A?2peoMp4zm!86|^c# z5C?|EQMh9QQSquaG%<^aw!Gqtobu~J(*EHaI<>$==IYMNP}Sy$~~C+RRIjqEAnOqL(yuLW69AdR`5!s26#?y5C6<(A^< zUMF|yaP~R7fVA!Wp|e!x5sOUBrL#9XOCzN!$Q4W@s=1bl)*^69exswWCi@hb%EPNw ziQ)6&5mfgDx{zv*kp{0S8ahY%h0&s||AY$$CnGdB?jHS_)b_>wXSY3&y{#xuZYcwb ztoh~T`T3NStDD8vVKpIFEmtuuN3r#}1`|j{@X6uxefz2-yG5?$go!T?IqsGMT2=O< zJr8~#cWzud@hOFg%B%W+&_0)AQ-O2u)t(>u`1)6@7ym@I8 zeT|U3WuW;<9TIy>QYk~@XzqKr7C#=Ls<81qt7fj@s*UIdabqv+a1Bg^w(L8;S33@ItE4-)CxI|tB=hP~ZITz`>0zgx8Ixn`tcPgt<0#o@-)y{N+N#u?~0BDuDa9+;_mtX4|-ad!7yHeAQ$N zKd4Q>M^=md6uadeBRG?Lp5TA7iqXnEAOr{yg4t}9E69L9KbQZnuP6RIU{k+))!M6b ztlQ~$I0XC<}l4&5x5vCf$Pf_~xS-|fH|*#*Y*8wrshd_R`NRG zP{y0e^RH*eU#*V6Y|X8$2R|A|*EbOrYt&LId-VLyyGzf~GH{@W{`L^{jy6HQv*+R0NxHZgGBAadmO$vED_b-pcd`^-QzHV6DLfH1q5a@ZIFT&Tx)t=B3yu zwB&#O1?VMwj0O>`NMXr;W_huV2;n%r2{Ur`d8Ab8f|7^nbgcu z?8uD9$0Nw@#*y?VIY?{0dC%=joD`t_;un=02Y1)6@R7 z+n2BI>c>FIaqjz)wOs8CwtoTjH&e_-WE(hMACX0{*C1FS0^B9mgh9!;6(DWnZ#Cu6 zg~KN|Zva3Dm6f3J^Pl&3A7P|0_hqCqk!Y&tmV3NJ#7tKvu2guOY_0+yfdjEvZT@mQ zjihVM{O!2B*p0vBn!&(XcfYE+hiY{aAY~7NcDJ5MR*P?TmAjq>|GiD2#M*U!CH+!N zXws7k=>x(C_@Y5NGeeTiW>5Q=<2j9zs^@Z=ADD{W_EG>%x9a=V)7?3X#bY}96yMlV zb*|I-+j+L)Dp@C+Dy6lR#?o4Xna(zowk$;Jh}AqLM%4c#K#j5QfXx3s8VKW%q(5f;^+m#zYhuB>JHmj zl25-SpN^z3m8-!$GEyyo6=)vk-pX7S>m1j~NBHV^IZKLjN^hCWKZKZV2Hl7QP@4QJ zKF^zz479PtVS2oM9rV3;SlLLzKj*)?4eu4x5J{pW(WPDsLQ8)2uz+DQyn%I;M)j@N zDV6g(eezG>>BxD+F%E-~J{7gtVBx6aMG22&q?Y{pOq}1O2zx3{BGm+WJN>P={DmyW zR;a`O1ZFc=lCqWR^{s&763aI3S>Q?P5?vyVWMqsLL%MPGmUNvhr*c}k+Scg%&@r%) zN5LWQ>@TXCIDX!=NV6^q?MNg%I#LHyWf=t%Lk4cYa6KBx&Rn&-9JLY^UGi&Xhm@s( z%(#~Ey_JoVUvY$PQBkmou7l5gm;K8eXdF4qTjf9;f6kNI8yg5%)4`Y-Q=%G1bd+>C zv}7ZW`@N#`qdUXbL-zg;#Zo*+ostU)R=jm^eD^CiX5p}e)yc(2JWCv|2-_}X{2x-5 zi*YmL=kmz0En0C|7tqt`%``yE;-?+GgMg$tz8vLF3C{A|hM~o>6fek|Utzr88xKk0 zRuL>EJs`xAGl?JNA+POj73CBtv587S=cBz8Pxdf6dh=ZmmtxWLCj=^k0C0F#!$w>T z%bNkAe24_TJ6JJK12)?g@5@SxIL{xMN6tp?mF+>*VHGL_$;6> z8ySq|gdJ~-Hj?S2RYebzI6}UwABwgdllE_`iYUOW>5F4*r%uw)!;{oc&E7;5Bf&hH zt=N<{WfoS{WVCXZc{t1mU^CC7g^0KkCG0hEb1c$fY$m|mMh3^sgwN&rU9i&`K75(I z_0Tj%0?Ku{jX#S3a(vT^F3y?)`mMZv5ty3Z{}ISKNf_@hV@<=Blf{<7+rn8|G`mZ? ztsJQ(g@cJYmdz?W^|XN~0o&#a8MWxm?{qg$Iv`H;Ea^iYoPGc+{l)xe&391!tg58m z%)(WP84+hQ@||%B#=+RQ3(rXOBr^iDW}9`%vdzcs_=Ewa)^{Z~3YP&h>T}=QNXa>k z%|m)n3RH$AK{-KOmAL^(2#lLqEQ*^3k9!%~F6}7897rdZ+X5hC!+hiA5~wp6+; zqb#G{gvI|LNVkJe)-d+zSpKqv>8G%|x61HZv~#mivAsdJKE1FSA5>2$!kH;Gn3bpx z2(j}_$JwsA?tjWIbgc%o%B4&>A&N^!Y+4J@zC8wA#@b?vAmwJzGU3M3@3KXl#)T+#C+m4VNWIhlcWPxv)Ob9))2LCVk&fYa{%IkP|KD{ zT9{Ucfz&j=nNB25yC~ss%*^4xG^Q|PL*Xp3&_rr4OTU903=_ZkL#vADSo3}MQ1q7F zepm|%=#am>UEUG0aqdQzzkOTw4r2R-9njB#UK>G`uxCu)NuNZ=4>AakJ&#Tjc{A!= z>A5ok^cgXR9U(f=v4#d#y}Tzhd&5CqzU7si4C&e%*Trluo_^bK)O9|b#4QH^&yS&_ zGK`$m4*`b)TeHQF6Sv!P+jc?51`(Y~TTmsk@5~OiPiXVC8(|-_$Si@eyp`ra>|x>t z$rxMz!kR!vHY~zlF8w}N0?#O!**Eln`t+@%P)aMU{*xKDxU7v3^EEnFEJIOP3(Yh> zgEg}yQ49SNN(erSxE>VRiZ)w;Umjg(M(nvZwzw@^0p{piC(R;_F{uM^HJb=KCbhqvK!iKWf8RB zhAtB=mQgV{Dh*R|MpQY_EhaPHnU%w8qSGibNYNHt5#j-#%4Oe>36u-==$^@Yg)2|R9b&(88#@wR{-c8Q@Z;|TsJsQ~J`f2?- zMe~{UeNl$Gj=g0Su8&fbm3)*Hzd}{}_ndn6I-9DN0}xErG6vA-g!Lj=ViVwgWd6_r zJEK9Awi%m@Xf!|&)GcbTW=3PTzm6D1C_M>sVfq*fkEnfOKQ{SFJb8N<^_WNxiB3IP zQRSK$>;+|S`p+IXKz1np@nbu0QC=a-F%D8kav^|DfEb`Gpf(8nI7hqe;PYP`fzk&` z2jCEZ(x9uLcE~$~e&W2riln(^5~*^FynKKYa_|JX{1l0?2AX(6=7e~FPYACN>Rg-3 zim2>WguK4k_J>39Ne}El!@q$8TN%DXe^GaXVu3t3SH1dy^$LL$p8xgsK5|@-Egb#Wq|rreKvlg0CSAwCID<4fH!D< z&kBHkK=P1z1lP>{^ac(U<6Mg>Hbl0GYzk1~U5Ov5n%}`)`O9SExl3;}W!dt%__oX( zI%V2$vj|;8LNr2`p~u|r)g0@45hzJJo`?g(;4SHy{su37Vdm(tXjTkJiwtj!CtTusu7@Rg_ z;d#I0lyjR&WG)+ae=OLY5RZ+WVHl1!0xY&R`*1|koRUnaC5s?UmefWW@JAS-zPGe6 zaN;w->}Nk2cBn%NzcPUk>y z(Ym3sx}mVr@*w~vK-j=-5b&Vzew;|?+XX44U9f7T+PHfPjK-lCiMB;r*sBLaM%fBv6ycw8BhGeRfh(2n_aBF>iH4G-q(Iv_a4e9C}j zVkq6F7Y}~Uau^kTQq4Rk8+BhB9wkQ zh#6ob8ZF_(jKSkWj=Sk*1%~Mz+Ic(iQboVq-yb`R8PVTZFpm_%n(`(ZI(*VLg1CJm zT7TDa7KqNL30xg*42-QqsvK&c#8NF~N|7=MVRYXi_D5sWbd!jMWz43N%NR~0ByCa@ z_B+{7v+F_UeXVwoDTLJqi>Iff{G~XRF=Uw;Oqm-K)XQmqpBlvx-8Ysl8r=uoceEno zY|shf%V&svSvK@nZ8-+chzcc+!~V4&tnx8evMjJ}#ymmm2u9&LLgA$Uvp;R73V-QR z0d_L2Sf$D-`_u{SvS}>34?UMwv4nl0M{)`8@Mh+bFznpHK^b!kn3G^Jhk>O&bF`2$ zVkoe97Hl#|DM6^@UY|Lo#1adlZn^&8= z-Ed35Ggj-@F=`}b_WH1CS(hOAvA6aI5=G;sGQ zZdLxbno@Q<>CAx$NBpx4+wd5u>|J0J?hIfN@Jx+b7mb93wz_1fcm>8ae85hvU#1-WD^8Wz^HI)KE(<3GXSN4(VUJMgH4#K7+y3lsyA-8AMC<+gbNXmq!822 zS(MMDFZ?G62t6oIcuQg93xhS4qJ9!s-Up6mfXkdFtk|)zFBmMh8OKduKGb4(ECSvG zFSK{?r5gzjST{GCbrdc*C3uC1<2>wQOyn*3-fpQdRYCR`n9&Asw~d%g8B7hm2a0zP z$(Q28>j_Cx#9Kk8J}=FQwO5pA$BL*RJ_Bx1Qs~6aIN^iX1E~kN>F&xHq3#}V*FbGp zPh^!DKnBD{4}`5xxG#R?uBOoTj;LrTA<@_&oAlq4*%PL$kWV-28bWttgf)p&e3&S9 zfSPnO+_86xlh0q|Mp*G<6mQtAx$h!lVOf!w1|nT2<_}yCn5=!$n{Bw;vD>5H_=980 zcg(L@y#1H^U!=038rv~f!m)XuC*W57#V@K}SUHhudyg+{Zd_MG*E`TfSV+vBb0U399vvt(s&5#nBiVZe_{RXf(c8nYX+bFi1CKFZlEcz>Gp~6i+lGY`x^b(m2=(`4H=W7g3nzTBNqj%p3%(-t`l?1 z#UB@i6U}*XL@ZCKJCe4fTIWUI(B3FMvvl*-b|V}(XNFB2bZ17R_evZl+p;&*Hq<_l zzlgts^N_BPaS;awT;T~}5U7T=hBfUYS4n#+)4~3}a$1OldieewJU-Fn3}`73lORZi zDlKRg$So~MZwl}$N$7S1)(F-TXZ4MxPy02}nkSWoX8Z}ZCQ=jE-vkspvOn*I_@p-VMXEO(gEd(oQa31_@Ndh<-oYP4?}L2#)NVO=oUD;pqdj9AWnVet-yGCKzl)441i#F@XV26hg$tmljnT%z~_MO z0M7!vy8u5?XAh3@#1sg0!+QjKLv`Xuw@D75$6sg|V?EP|cTt7gyy-g`v!W?%Md0={ zJA~TAd4(tEC}cxt=J)`fOUEXg0y>9c2OSN-s|4ZlJ5Ds6==7#PVP*x8)$*~gu+>|W znfu)Hbb(b(pjMk$S2r*9!6(c?n^pxJNBnf9L7?k_YfAfM?eYZf^<(9LsGe9Y5J= zP(aQ*6|Cw6uH(n~k@t74Pk#`_&6yN${_5n_@3lR%NRFk zzse*Ejs%&Chl9uUlCx+$u8?)bo85$q_Rrwr$vC+TU|Sb{H)v-E;_}QK0T@Pot!AYw z4TTo+QKoNo5q9SV9{LO6&qBZ1He7x4sApb@Jxq($0Q zC_fiu*IyYSCU<%_3#imZtzF?GuUb)18PVqfynCHS1aT;Yx&g*$)I*MqDordx0$exA z)3kzdzI$`#HTtpcCrPCe>WxaaEVGHc+e-*?On~#LNCH{mO3p}<9YMXpVxQohrk|8Q ztiWc;nZBsa9p-p^djqd{Vt&NJCV>YPn!=t=X4$y9DCoI#oS)B7X4Fzlw@Q%MX!-by z#U>OZ&H*QB?@^Gm6C|sXlo#>eCD~B`5=iIRRvs{H2jg5GxF^ZNGMBc=z7Mpi&ub)F z!%$GD;vRx?b1W!po*CCpsZBt2hu3$Cx9BlS)9$P(C}>mH zbu=*{4i5X*W2sn^teW4vfWb~4IduRpg25hO$&J&*BT}yQdc}2#klJzhB0#h&(gZ)$ zePDWnk6#uW*x1S|<+bLW+iM~z61**Kl9Iy9CFOHRy;PmE9H2Mk*>V@L~=-y+8j2Yct8WG?zrQ^w_? zrzvrwdTx*ui?sXKm(kD7UIdQz5La$91Bio(dkneV3`eR*YapjzPwI7|Hp;i6t^{PX zNr97l@Pr7t>EcU&hN2!}xC!)e_Muz~T8YcLvMXxat#r_nkgS~nSD6!31@IhDQ9rx` zeF^%8CEJ~YKi-!*qk{2IzwCVxw+^KkN-=mkc5m$!B>0o$IaCQecsNeCAd^Y7Kp8Tk z1Q}P-keKiE?Gf72##C*)=GL&ZyG?zFNL5;}Z7g$tyDD9^v`#iwusvkc_g<{49nW^U z&UoJ+TW5V`F3=oF`2Nj$&D>phI0!ko3rI!9)zURDuV7T!sNZJjo%!>r^jmS}W0ch8 zqskiTZ4Aqzv})?K1tX`t*Qh=B5IM!q8GER?pSN1!aXt9zPeLy91FbG{lj|w_rW|(< z6$k+ULHVDe@muF!>L%VXE!OSH!0#eXg*eSmCvGAhFM+69D#U#FRG!x8D%w{^{t+v4YbSMRDeUA z*~6TI24D~+hXpRS>1lv$Td+j8s!c^<*gL&+!DjkM>kzB7T+x^y`}8Ww^`A_ZU|FZO zA*E3U1pQ7N!C|S*&#SVK$+5(_xXxMKsT51M!8Vfi>C@$|K&b2jDN`4RjTuN#+JMl< z1&O2eehHUv?1`lb&#X-75&DX(_yH+{zbytK{{j*>8YD*XOqi6wg>7vafWD-kf20?S zkX+Qg43eQh&m5x)TZdupN+=TAMI=7}0zv$+N#n!FR3uNBAe#q`L;Xsl=U zC>hrj?Rz7)v0SsIAaz3X4o37~8&G|MJExyJI{_7@-J#!Ffzs`A56-@foYY~A0(*Dl z+1^&`l;nj4YeJpQLn8>9-WXJ zkmZF`8nD0!ugapcN1$`X-!$SW#HtM~IkdHpRSE#=?Kn4lK61Yj6wcmj3{e49L3><)#FZ{VCnGEiHq>?@lE*-MI(|U>>dmngzi5;#EY_`bYlwhqLN_j60%qsytuengvYGj zf7MLQjNZn)1mI8s`0F(-V=~1*7%+1>ff|W`ifJX2cpVBDc)Ed&N(q^imc9G^s-#%x zICty*s=Jq?%l2@>`(3rRt34%a1iNP!PAQXUK9(?k>>NCYGsqY1^>SFs&MEWzvMZE- zbXHLO0s15j7Arl3<=o?U4!;wmc|J%%VM!;1l6Yls!WI?DzgdzA=~Tv^H} zVn3Nvg_E;YHvI2gxPH^tF-G#=>~GPAs!L1x6_pAqYH=wE6G;sD_7zXX5?w$D(6euh z4LxobA&!i@N{^T9VJrD*Q?BI6obD}n->fIrbQ|aq6IVu4BTr{o2OR^ zRagQBf+0Q|r-KSmgWao$`!d8_r>sX`cV7}8wBEG;`WsSaS_WD zn5QCQg93kR@yTx+5-1|YIzo@Y+zyWvWPOim#Z;5S85684?OOhHMs zN9S86zh1fGb1Bm3h9>p_TY@EK{St-+7XeYK$E6YXvy>iEh#BY2O{}Y~Nl!8`es$+a zgB;{WP+sa`MPFL5;$q3*NMo?1;ZZx?hy}ym%1mp)-jbG!X6S3U#}-+2`|hl zrN7cp%u*Ct;LqOA(n?L7urx>I1^GH; zhvV)u_yCv}t};)@fn`=ctNQ(CiicbGYz5~NL z2r(!GW)tL|@OtIMInyGaW1DTR^}B85EpFG~eB=S`7iYIIy#ry$Exi)RlUxTUy;J}O z{!~hl@yrb2oid}^Jdi7QooStRDO!rIhr#I~81r-Q>y}8nv`BZ@q$iTw0TS&F{;7fg*L;W1qB9+Yt-MfXS z7yq++OLT{!fSdG^$6{r;tI}$Ao+!%{_AY0MupRM1196~4DOf*gB2jE4_(Zu&Cy~Yy zd1!@#1-ccj(XAeaa_|&a(rOx;e6u9=sQ?nx2(z>?$;8BiYI9qTcHL33sTxX5z2?K? zZs^hMx|Q{<*Zmz28R}Gy`}gu#@Uvdz9{9!j3foq%L##7dyXjKYJD%6v=G#$LNxD+* z>9yD6yivTb@3`zAbA3P)_TaNPfA+K^90A3Ll8r1{RHgE1B~elHPQB{sJx6Pa1jv9VM>ZO#`63IX~ixR#S-8%ACr1G;1{)?NCG{N%pr47 z3qMDR9e8M+xFHg4imXi_20bWnWNkBA=@~{PCerl|JmOx@k7zbc!eO^F=%&lFX*%I2 zzeAq}PeAmb(>xW{FOk*a%tiDqw+%mz7a~kq=mJyT20wjSDvUD<5-Z?X6>B~cb5fb^ zr`~yWZWK8ZW{@SqE-=D8Wh1Z2hDH^gx;=*#nmZI!jJmX}SCCaP25`S~iv_JF#9)YE zR92dyEDs=<;aLozf`BxZIYWwcSuHlP4pBH}oRa5nOQPp{|7kf<>Ug~YJiNZ`9k$%? z(W`Q5PX1TpyXKdjxGj@W@=+@|vD&iTmh50iE9Xn-mf`iJL0MPM+Z_LNH`Y$7L-)sLQg}^@}t4USsR*4P27lK>37LJUo#kCGM zvRcO52V3Ya#s9Lk&~2)1NU*KC{DoaT$?Hl7I^D;%%(5UBEewPSkW*_AkDszO80?sE z^we-tql>(fRCfy5XDqrFDUH=V&0lyfSP+`iZ>b!?BQ{9A9O`MN!(NlrQm~XAAU!1h zB`3R=7N=w@3zBQoXh?cg-NS~I=3e@(?H9SGXtE3&q^$m7K<-Ckr+ql%QUp8_)*&H( z@wpGRrG455)}ktTu}I1#G{>J#vj+uE$FE6Kp^4a_Z0~Oi70wZBS2=Ko-;dd3jwUKu zku%58ZyDoVVWjiil_;nnMN!>FwPbN$EFGD;-A62drNB&?zew~TRV=B&U)BZDAX_$a^|!XWK*>A|D3JuF~2NeBRn`~_Gg~a3Vx}5 z=QLkn^-}ACsK-Uy-$6nw^LxZ9F>ILLou6SmSxCOcq?MwRU$=_X|2f~Op^-#6BNygD zGfBjSQqz@zR<=5)i6b8RD#YyG!Ft7nrF9+jxUojFZtz&ZEC27kzR4c%uX2i&hYzoB ze5IOgW9DeQ+Ld*%=n_ohMwo>*uzD{g1BeX<0CfcRED*u^CQ7bCdZq!za*G~<;-a{b z3$by2DSL$RnTZ4OhNS_Njz%dcQ2)t^shJs*a5d;VkTztk2I_`q$L>|kRw;e|sGxQA zp5x_=?)#i~pYft>lk{n=Y-uF{$nBaI2^f zcB_FYloyt&k1#fx^sm$wI8o^)Ov09TvZR`-PWw-%Vw;}3jg$2wpE?&b*vp>kr_-y` zOqtVmHf6)X6g2yzNj$M5ulwt<8Sm)IWACQl<7jd{Z?}hX^^l!%Jj z){yBY7x9hgy>c9-`AN^6f1~?8I~2r=hl_euE6kA;XloIY5Dg=E6Rs|wA|f~g&0`{2 z5o->qPv%ovF^^mLy?RSwzbZtFKuD1+*4+e(oDB%;(tJAjbBi&lamj4)w@%pJ+Cq#T zNHypVuIx}MQp_%~O?)SOnY^SbOiE<=Gbwh z6iC^)GNjPN6P`JLUti*Unui9mczvhQPSbkRaASY@^_r2`^*!CSOAP@k}niM#|{@A5Z=rqU_k)ZVuVK9qdv=*z&)Er z5tfAdmaO30-2QyXfxC5G7yHc#_4<@6wnr4dYs|Ri;`U0E*(YWbNd9IyXTmhW|N0_L z?F$1{a!`LkGa5ZrF_Dq2QtK^GH6^7rLbn`1cZfF!-OftWe0;=ZjiJddq<2z$jrQfL zsZy_I-YkJ?>f@t}`(8U_;IA!PieY|nV^egj<5_Dq4U3Ro)Kgj6;0YRz6AQwQOTj@6 zk3vlifdWzj5fEZeSyn-&o~{XnW z`@`6~t0?b?>(&(xtNUCK8JigF%_U2y>E_q_zy=YFBdjbI|7f~(BbAM2((|N^0;LYU z!$vptIWyNAiZ7clrip&<8;?0ydai&Sb#K|kQ2=AIfekYKlplnlxhSv)y%E*l{_9dY zbl3&d!ORfXxz{LPleFlRUyh<+(`avL_c%5yJLdn z1*Jo1I%>&#KZiQ4nmjJc7b~!cB%Wn4kUWuWsJ-(Qc|&?BFReZE9ACX>bG;{MB&3fs zLP8Q#1J}2Q`nC4>w0VE&bI5t!!?SPvH;S(Tcy*sBV6#jF8&Y zg|Apx<1zDbWv8o{`GNu}U(CNj{H3}row^3(*Y0~|19U%i>Zrw?Jydn}Yj(51G}y?)<;DIGuwWSx^oRJ$~22Z9PyL&LtB z+#g&N1X7S7Vu)BcTscGV0E&TfkAN_oau7#V$e|2nP_`gW0pq(x;d79sf=;_I!Z%WZ zLoSkt+T3X}iK@!pDG80;9|hficOYLJ!l5CEo?nnax)1FJ%#2nNT&Ztyj(~Vb5g*@O zQ5kjx7;|p6ncU{DB*wOlMNBd%aKGQ_vw*Qt`XYMhM72nYGv3SHyvVke+igZ-ZP(}P zxullB*OOjM4(B@=mE4x{8*t~O9?SXEpD*uT%4A$#qp1@6!cw1?InQsiu>I9HG;w=7 zxngM?()+{X)i(SaZV@K831S9XC7@X64bwF15A%npq9o;fWCaX_6z{IdjO2dl54b*Q zF>DB=JLf`b&1WO(ceUvndft>VT+N*Ru$u`8zBQ`u5NR4AKZ|Mj6n#m-;UhWYc*+{ zH!5!KtZ*! zL|)T=dhwpI!rlse7ZsqT(7O76PMMP#1L=i^2>|)|zFGk6`rAZH_p%`PTUZlu4Ngy? zq~ua*bZCkcazaMxS|aOWz{khp^5*jK^vE&<0|a5dQQJC7Q5RL)19c8zT~siXD;p#r z#ZBasA(Bag8%=3&0V^7#_l{@8F^$RX$AsWfW8pDnA2v#6@7Ws#Sbcz$kfKElchRRQ zG>Gb|*yXd;Tm!&3L58&s4s z#ced`QG<>T?uEzp?j7XVU4sw7MaQPW-oe@EZk|NIbS)Zl8g!D1Idt!zb_K{g13@EU zvg)L9UzP`)a%J>ZRjfC=Bzq03pyw#EW3K;7kE`Ik;IF1y-dt2M=b5o0buB*4t zH5vO{6}Qi!h+Q;qP>r@EyN=z=B6~;i%5BsJY750QQx?@py-gjVSTl((uA^wyE=J(F z2|082u{&pnTeXZ0kXpT5)0b>h{5M3WTc^By=k0KfMSX zq0<3_NB_yaIGaJ^JbvhX`V5@GfH1*7V;MY`yBJ==-Jss!;Y5OZ+hq)T{UEZPiR+>` zLdC@j6&Ht9T+B++zhMi#1tBYAejMLE5%68hwp$>A9p~aJRsbujTugdF(rbA;yT5vKAh_yjMxq|ilWXCUyAOLj8$%A z;cwhnG;lt`+)UccuR3e`in_fEpZfk&&w~x2jo+QJ=6m#K1L6MPuXqdlRFoOAr(n#0 zr;%}u)79hif;h2O8q1B7PL$@;Yw1^L{!-~R`ZW|fVbmufUmbf3a})ar^O3+x3>eEC zU~m`dJCZ35ge{m;zQ4xx{zf9yyD5s( z(H$7H?G1zm*#>logvT+a*fqDuF|^oDPS8{j38xT}B7w#IL3LPCO#CvdE3`-fD2TE~ z2_lqaj$n}C0MM~M0zd|Zi^|TOf8pNw!1fXSez-ZWW6vJrg%|cu1weIdM2YbY76Ma%%$q(+V!d+LsrPEN0ywXzqd= zk^30EjZF&uVDt_}lw8u*VP-9{ASEs38X3sD&~0l#M(>6F=%fQ`vQ$y9q=+w4a3Dn` z^;HHi`e9*blI>!9SmdGM#$FGOgTlBix7Z#UB)$Xlndn)h;_1O6*5CFKed7`1FyT3` zznajT=!AStna*7B-;{y^4`Jv41&0n08gu3r1-({R2~_IP7h5$6zvy%qywsPtb~J!8^x(MhAcev) zPy;-7gEUy&5(tk4O98vPRM=cv!0!6$v)fPVyoVk*HjR1itFg>GUnTJ#C@6P&lYNQO zs3@?#+{}m$e1^{#4Mw93V=z8BC`XxxgMHf58XXLVqA*!ydFFWM1g*#dc7ZtGnCDsQ zT@+jzDn#Z-Zw~$x8sRuin{iq6kBA=p714v=jUM_6{%jIuslTacM&(g7fX$V6LntI1 zA^61O_yDUt?=}PQI3gxy#z%UpK$Y%-pzea8Ue2}jEXKfcpQ@8|c?%R*VM*cGS;M)j z%V-tLZIZLU-n?2Yc1O3$CZV!qkq(o*ho&p~QE|NoGa)438E;UnV<=A>%+^#>XMr2Q zxaYvMN4J;yp4?yBwecBH^~#??^okE}|6}PD_qmv6jX+OXppu;@3Xf0Xuv zHW2Lv@{dc0Yz~VVM3|~lAu!60QI>hm_raOQOy6Q-v5%3JI5JHt7_u1vbHs#vYl~QK z!ORM~(e&87wN?-aH!K(q%pJ8%JWfI+83E{TB&50{uDT>-X0NddO2{2Iutw2dyfD7>{Z!YW4C7i9C{-gmP5dg&}CaRPvMTHmS~;{`9clsM3#Yc zppNG2vY`M=aVgpxVIh7(vFUhRr=gIJ^I~L#(nKnhCQ?zNh-AGXJiA`kXuWPw@5R=O z=hy2Rt+%X3-Wf2GZ0Ko#4JlWRQmz`M%7&ZDCXo{;+p8QR`2?|7Ib1(%ufyg#+X*&Z zYb8vy!;b{>l&95r)_At)P}9_E471&Z zQ=i2+aN*#48!vbing460cR}=x^Oh`Lc5g9veg3M&d%%*{Ujt|FdaCrx*LRfO{!w%B z=ODigNIx#UQbKPo{jqjZ80+KxC}-J(5FtcW!)u5>rc7A_=D66R#5uwR2}UF>;sQDH zZos6=YX1`-k4`H6v~4e5AL!w#|c|SJk!|&RKWP==E27tFrd%=>3Ls z#;;q`k&w}5#AYNmO+E>juK|q(}F8Ji13$L^BFg zk$}XRxObZkiDDoa3CDxK8QN39#P6}WmSB)dRTG>GAx+eT_z1m?SLkhgILVD?wV!kD z+7Qk~CPLtZ36;ZooMsE4vC^d#R*I<@UaZMM8_rs9Wk*ak}yEIqFq6Fufc9A|)T5|wBu(TRlf z9+V52=%HD$yn&J)qdI{e z6hsJHL(rD=-KOq`H|_hwmA`*+cHO*LLr3?{yKsI}YUcld`>(s}+!Ky2qMW4m2p)Y2bOzl`Y zADco?=Vw(-O`MRPR(mSFkY7?YzwSn_R)eWztUPH~$hbn*6>43fhUk_3W?RU(Le>>( zG50hLOLb~C4byaOW}Mzub3$fn^P*&-W?p8cyh1%+JIA*ybcKASdZm7~aY=ejW-Wb_ ze4~1k{v+eM^baz3sCVgi`QuI^)RfAa(QHJ_)`KiX)kjQb%;+q&3_*|DbVc;WD2!$T zYE!&612SxYEf>Goc#{~92WS#HVIsI_GuHT2Bu!1thwVR6t0|M#RGCf1s^U?BM|m{l zKqg&{u5oNU+7z*{4c&%fkHZ0~iBS3^9W+1^bb>Ch3akSh=m%RYr752DdXJxne=&5T6VH*dPPl&}wcY-KriUyiklB74ufjEhV0<>FWLgs2WNXB977^h5^CW}Pvo_MF~ z>h}c$Opw?!c5m4wJJqGnTz%0ar*I6%zbpOir{ERi!XM2)e$5F}&#eibksJTOvWuQNd-)%()o#A^+QoBPThFhXwByoC z_OH44L(CMkps02i?k)mB!W3{WvD8%4HQ7yIFw z-lW|uvy)2#*h~W&$vc3<)PG>f1m^_@JE85`@@a3QAc1qyLQdX2y5PTie;k1d9HLTuJ6?0Q5%Bq_-9s3&|yZcc-hwB_Z zFo}47DXTAF76{J@OrYPXc(gH-glWtS;Zpq}_5+<)DCogUo;cAr!eRO<48k`|_WH8W zrMO|a>;Vm@?)8opAtXpK834&ZX8?8uRt0(jbl{(634H~Xl)&85hm>^I0odMCa&1Q{ zdrygRI1$@>N@edU75zBPANHO$*EriKI<#>)c_V2;4(AD+2aRptN=~GpY;$xtIRLF5 zCto9cF`1Gx*P<3=hYF1j5F6BnyMsc08M>(R%Nu^VP43q`vwEc@fkqML7 z(LvhD(7%>MF)6S!viGq-Hu>WlCU~|{I#R;_yG=9!J_$a|Sds;+gbu1h?;baI5!rbH??q0C1C*qG%Q_JP z*nKP|2rgrcbBYvbwdtK!04EPV^Cxiis6=%WxaH}=z3i^9Ug=qN`Q=PKsRW@EfWH(+ z|L`C7DkI(1Ei`w?0v#36Dzr==8Z5tq9`O!W-}K?WN`@;l%N2@eE41qkX;(nM&yA`y z^bxL3>J|E_S2$p0=q2=PRHy0Fk*(H3J(cy;o7qsF8i#z36WqhVoVmnTq=o1Y%b+T4~t^K+`c64-3o{M!OdIkzJ2J>zR#5^4@k{* zq~@LqqcA1BbjLP<40^4hk`X1A;Lxbr@C&_)#aeicHy{N3>Z09qH1a2EsfvlP08JTy ze!=Mh#bl^$D_+}Hye2w%TR{!Ly`TWxSGwwVZ>J*@BoO@QPjhNwP4E4-bm8vObG3ZX zS9%sonB|MYa62>0l}*QeRUOVIydn3Z_>C09YAB!pGYkSUtT*eu6ToBUt>6CX6Ew5U4g%95kC64xA)ZdLL!aG4CVOg&#GH)vUN95YdvDC18& zNjQxu3QOcg+G*ywU>UPQIA30_Ei*4+t`u7Ogz()j_U-V+Zu~}K6{5~Tjc{rSde_&}?GB^sV z$i+ZNY8qHyky_a1Swxm8iU9wgI5djKyt<~Uz%W#g>GjHJ+Mp`aidT{WXF#tgdA&(W zL@rvSp{gbo+NUTqaxXLup;uKEg%Xh2~saOg`IJR_WQd%eNk!YzO^zT^ec#?ig z;X8;e{TwVlHAEhvHcZ8hr)-8hl@xcCRiL{gV(bo%#Ff#lh5lq zwy<_#U**ZRuzd@Od$9S>C~FhQ$X#D zgM%=4q;y*%HQHZV2M6G9N;h26(K#PnH#mFXODH#u?TnWI-nZ6?zZBR-;xCzX!W#t% z6-j_vkpws)QF(oU!j-)t7!j3~*X=SW5S{FG;268gOmP`^P#Yu|ZbQgnx zU`TL|bD_g{AsIfshjXEJyhoGA_Egu8%H;$UeX(S%0hX@ED+~;Dn7Jj0yhyBKZGoVO z3bPBrFFkbBUN>kj_QB+rNQ(XFfehoVtzpb-E&Nucb)3yMAaj`Rl2*znK^WFpvTB#4 zV#8YNfs+QG`xvA;ryhSgh`l?w6J9{iE=~LHch{@~n+JLae~fd3dX(L6!MX`fwPUo3 zc>e24xwjQe4O^?OdfH9`CkiKtv?R!)6DwPqLTM_H;|dB+;v7Q9!S;^9eGW3_9%az{ z0l`h5OBkt6j z_Y7jt)J7@3MX*qSJwxe`fgI5Q#d340u!{3q6ne})iogx`dA83!+TCs(GzQA8ukD^Z z8DFxoPd7$A&2XZJ)eFgrV$zKv!s=8Wgi;u;-r5n)!)h`~If8#^Iw*-W9HJPRV@Y1j zIeBqz4B3?kj2n-WW5B2U_3+cqlLr3CL{~h*Vg|ma8Kl6)nDf}M%9uX ziLmrg_>sE4@b0>O;r(@g^1oRpoDcwUOgVXQqHCJND~!fs_dN$oiC`j>YiwxCGx^5p z%t?&}VPWnZVR`OS<$C2=Mbxcv&jOsKlq-87-u zO@x|lW41hn=Jb=?ehwzM4i0iYmlN=n_g%0*XH_r#9L#kbMo$mgd)So!aktIN=F7`W z2`b{ACaOESlcIAuMbYZ}=_XuSjnzu@7$VbhC>V_S?7cVma?fuES$0E;W90>tm{lB4 z{)}y_wYT2*4kR>Vz>jyHtI5(FuR(h$HhL4?e)i)lHa~IVnv=$!|N6P0b?Ob*Tv4?p zbm0p(-tb7LAqK0Thy~BwchQnD7c4*T7ul*G%$xS;bthkYvQJYZ>5Oz?({T&CL)|ye zw9c3@>hdFBU3c6B@Mc}isGHqle zLD+EFB2A!aV@20~^2= za0D<3&;jNE8ekF>8!ZwBtSW3?fM_=$%powbb_1f_I3?JQ&5FD=fWI;bk(Pb3v<-yg zCypOM@?phYZTH2KYX_0?4~{ely9C@pmX6t>K=*2-(A$AzXnuPW0h!^VWD^07w>Rj_ zjHGTG|&J-Z%y{{c8K_t!HlTwo0G<_Y>#Cwt2T-`q(cox%4r1 z*Wll8n{(Um*OWdj9k>_V_2j&ppMUO!r=Lf@q;u#4`Y`ev5qO3j0R)GRxG|;VE`=3c zL3ahi74Q^QvT$wMH9F8Se0EZ+kUwM0n9PS_j0`kCFW|A}$yoDb#|qxSW6cw*fBvPX zNkPWgR~&;MWIqZ~0g2cY@08%F-cy5J-mc(1@E-bS>Vw9E5k*kL(h9hoUcp|XtWtZ_ zhm;*+pR_|!0?JzDFOb%%m+BYk*XXnkkQ=bFEu>?*3w^D1)CTGu>Ih1tbzP>0zhex2 zb+Q%RFd^ltxn9uInn3(bb(A7KUq>r^!zbmpQE54sKrtr(z|wMd>CJNV8CcG!fpInp zC($LMXBJVilZa|Xh-yub`Cah#yQ=MXz&lm&r}y(9!FTYG*GLbNgg<~MUKtOtU1d-l z^WjHF+xC^Iep?MI+VEF9|3%&7C=%H-VIg{T^-c=@j3ov2)?s>@x8zUsr5T;wAQF@0;O6-b21mgMSSlB8V7BBytf9 zqcbBIQ~6Oat&R#zgk#m2aH=}ZH$66ADyZkGhq(6x$G}m|0DfAN4ILq+%zG#VmB{Bz zmPSBjc|Cck6;Qi}qiQPS(MO=F{;lekF6bG>mh{@tP>s$>x9Sc*Yvo3nV#M5w?n{svFU1=>1vs2Ygu2xO!ID48h2-4 z&6`wslHbq2%@6Sm*1kDB&BuuelfZzF+onx4k_2abglJ?q-qu-xlQ{n-^^Y<%l8bf| zJ;KZOgHCA#KZb!4_aH{M(ikLB3PdAF(I`o_ky7S$8!0|_4Mn1 z*oS@dOyry62rKjdgTAT31@F1XsIY9CG{-T-QY@f z*E|qjMyzdU+oA$BlE7;KGTAnK-igD`1V{vSy8&@uA<$a(2g8d>1=mj-Y2HdVw7L4? zs+j{*R<3~Cnae5^BPwKrT8t58+5Py1kZ zyR&bNvq+nC$49LyinypAp&_?!b|$}U5%eS{$c4;;Ctg`pn-u8q;1!ob<5!E zaIP|;aN~C$28G}Q+d%@wC<>@6y;b_sNN(PB9=LPul=B|K`MMXWVGsKv6$Gc-9hN>3 z=;7vYOV|pp3g4srTzyy-B5IwwCA=rhgbBG8Nwif7Dy`@-3HV{o=VfS)lGgixZ^&y; z*3N?0Vulx4yMPdMRs+i@m0&0u-T}y>u-?%V+Q{OtTrAPHjsjr|Lr~aK5d=9*OC4cZ zsxc^0jSkoHnbU6MbJ~qQB5@UIhbMc6_75G~NwTpALg6RCE-FQR4kXGYWXf}%BYS1H z6QDSpJ6yE68N5Mc-eWH|^cfyb#0v$97YdfWP>^_` zV1T@a8Fu1@@Vhwt-1b62d$j`+ki$GyflDRW7waHHRVQ49Ot=b}a1=6FNTi?C z_v>%#LpqbtJM=jy#&cmscRbaof=*yXk6^XatMRweWB42C#53vt%h;E|M^)YXpL6cM z%w1+CvnQEMGTA1QkW2^(kz5r8r4SH|28c^VECGceA_5}R1#4X>UC`I|iOX~A!jb?H zwWe;hRVub>|Jow-Q?yv6&3on1Do*mwIrrX~n_xfx26FFjCil*rd+zW2&Tswx=*px= zGj*%W$l{clU63q&PR5JjU7zRzMJ3KDf~0-S!3jHN2k`r_VuZCJJV`?g0D%NYHF-SZ zYKkI4;!)>|0@YM@1Z=C+R_n2h!V(0tT$og;Q#-TD#snklR=C+M5es-0uO&N`#`9L+ za#uuyYj*v9`1-f*eQw?3*Zh9R&;Ih@03qNXf`aGsu^TB2=oLe1Ql5wqtB=wu2Nmy#;WR4(~{LRDLX2`Aqj@4G83{WKtVO# z1_|>>#EoK7r~+!-NilMqL_N0@)0+ByB$8!8jYR@(KwqEQN2^r) zID|KY3;{xp?^9$TGaQy&4Fk(Lg3eRZJoTw8n_`>5b zE6|*WW?g!q3n{Lh?h?F92$;x!XwG9@6==>wvz}}L)_J;&OYklsV8ZiF3sIH=&3R}x z@8)aik|vSo+$n99c1XLVA?b)TED1m=l~zidq=%fhj!L7FTq}FH>?d!&dAf+LJpDdEqmPWtg>95y{P0ejU-GqnE}`ZVtXx9#W@L=b(NJB&mp{gx zw2VurF5z?3%XAmZrMW3=6L%-ag+-1NSQfEd06?FDn4rpbat;i4qM2e^NGm z{5nEBLG7~*5_0VW9kYnzCqrQo@=wHUYT9CmHWZ2`8hWK@$Z;rXLLAsLeq7>oe77m! zS#L?pO$CL_Y8P%}7oFbm z@~p*J+~Il8{F77`Gt}SMPad8VNtC`U(~C}$ygi#&=kqYZ4sfuQ=;Cb?kniFbNR00L zJ9mm_Bo{l%&gGX~LUIX)L?CD_z$MI0GV=4u01YV)_xr0zh;euT@BJKogQgG+TestP zc$Vc@zD1gj*?~VxzD&M}xlw+f`4cZZ&ckxPQb>!f{A8)a*XiqKyZOt6Zs`{GX6`}h zRsJ{ZyZkZ!W8okCXJV0GmN|xD5h-hyMEpV$#k5__%&=_QE^wCdG-pX(7|W4l97O># zI|y}4;#e9MNr~iDQIh&+47(s~D>kGGmCP<1E2;zPrldiB`sCRj8bYjVcYsbT zsY&trM7kVN{seYGKa~{3O^TNv>IVYUT?L}5?~i5Emv}joGNz+KlO*51QzXgvWadOZ zEdZO{;Z_nHW8Ly+QU@(yP8Hi3x^=>SzL^p%m2PK{6!Do^ygc=F+rY(^EY%gaN@8(w zJE>dVQ%uU2-`;q2n06#jkr>vDBsR1Ff`(Teji=Oe0zEbIKx8hbM z5-$|Fl>aab#b5|uEf{R48&W;7CqhpCba&i79QJhEA%sF=GOcCQWh}K>z>0WDWqErk zwbQQLx@ejLAYcgypZ<8H7ryYp$iugC2fla??iyK>TZ~HAjga0bx8e1(g(6IBK6CZV zht|JjtsJ)|<`4an6>!{2=lRq#*0udz99_OBmPE^B8&e|NZ0{Q;+Ize8)R2|NI-ky! zau0DwIJOgShB>B`Tgh$WMmZJ_iHsOqNg|&_m8BwV9X$l#5Ev#sqzW3-KMNXDu}5RF znbWrYM91)RGm%F}-P~knF$1&Nv5Og5%}B_|!J(k9&RDzpfowlK=ds;3Kp`n?Etjvv z_E_gv4r`X;%cj|5>@n$&;SZDCJKU)x z3X92dDH2ag3{zf`;ERZbB|yGB7B%EUX}C4LBaPB{k=4>$O=z;zZ%J$OOd2tze#;;Q zucj?F2%DIQdN1i3YtmS$=@w%ae3*lOu1@ul_w)Ku^?{tUg4Bet*Dyew5c7bJM^G3X=*S~8C12Y#T}Cl{*iMXyHbfw#=Xg33aA;O_PTkAMahWy>#QR{`2Yn@u4Zjf_Uvq!`qKAwRZWAs_O|K26oen6R2> z=4*KqHqoV3M5x6Yq1LNH?N)`_txDc*Rj9mEQuGKK)T9a{wOjG)&zvBq>_k6L*`=on zHH{UB|0}a2M83v|4I3Gbpp}swkzJ9Y2peHgQ&Gs}y^za|Ay@ATQ3-u&z%(5YjW0D_ z<#DE~=`medM;;GZ{_&>p>@WpM&;QuQ>`7|Qj`>5z#lxXEP8}x-_H2kZC0UdOnc>GqKH!fe4NS@ok*Z- z2o1gf5O;$6Y5a zHm>tu7g`*-2^L8_=Ud3k=jO``)#c1J+%@uYRSqXu!Nd|WIL7xD^hAJydEcAS6|9I; zKUXdLm2!^Rg)d4D?#E_*`q_YhI1cD(X1xCoHlaS!x5iBWb z%>r@lV_I{WEN`r7PT=tzJO_ZP5$`U=d<8U$3lfy6sL$RJUQ~Dkim(JMd}$&T5pV;O zg+^Vf6KVnzW5m7h^yl(&lF^sx!Rl$xSpITR4@gLeCTh*&=1E`WzACXq&7*>9w_@6n zA%zXwjkyF55JC&)BVd=00k3Oq+GF2%<@YeO{*!MW89DLHo-KFo>Az#k9u$C8_pKTE zWA5N5Uxy{o_r~jQy!FcKzrwe)Wn?K^hPlcQO5i(G3awU+vy8KinFiaD+?7P7$r`o1 zxUs0Q_}t=^$*oDTE!-BrD11@8TU@9v3NMQHip$ic#&zLk@uB2zgNGxBW4|pq7CcsR zG&!0Km9rTmQ`F4185gh@84HXLl~0OC48_!#P=cgs@S%jJ04+L(p`sp!isl(A(G{&Y zBtt{CMY8YrjO@#oWE0UZ@ zq807(rvdo#3=B8%!tf+s7-JGIPK{5zpvh)Kk^CEajfRd+ywOMjv=|lSHHttGh<{a za};xp0TS?MlxvnND1&MvQ_xIwv&wfAbwp=Ix0dWE;j)2jyrX1VU|M`$U|#&{z}4|9 zOE#6f&A;RSi2qpqOT?%_DK%5nikj66(FN)Pv=qIk{yy@j(8tk_;$I*gvc6y}p$Hlu zOt6?$!dep;!!2M;B16IT4@dx7hlXzHSL&N|wuHL=ODMnS)b+3DUH>|D{p-~AuTw>e zI^9F$3F0PC zi%Z74^&PLi$EEK&^iQ^*$saa*KsHF(gH<%%r^G0GC}Y_Jnod%~B*$GpCdyn_yZw^q zNB*|rw;NySdn8x(D43cP@I6*{5u|*y0l~A(-IYK`Z^n|WIyO8i_clrqV;FJ#>YK zF89zW4_)S=lX)d_Ll>J0rrM;7q-hmhscTXjr2C}XD;^L0sP09^Cxv5?aKp^Hcf(v9 zU4oF&2<6Bkagnr0UZgBi7x{X{Ua42^ReIH4-$3O+l}?JID{3ZHERegE#g&VzSC_A@ z*i`Xt`3LH@>g{#kZFo$6N`18IvFiTHS1Lo*t}&N#iE@{yaEWT$4d)y~h;o;xaEW44 zkKr$AT_9GaRhf+?D~niVLUD|Q9#hdenx+!%h;~M=i0+KO8Rhk8X>>*ONR%y&-XBHL z=P?@<}M78NfqM#YIDfwdEAsjK`W z*B$m7; zWUriPVWHHu9}ApX{CRs5t%qu1Ex9!Lm|7RDqt+F2wKnJ^CZ2U4dVg1KjDDB0s@m+8 zjYEy7qj6IsY9#3z6(C|;hjjWR?Z<#uWkQf|NQnL9OC}xh80tz^=yajf>5b?~N9KM` zOh`;o{3$2IX_t>!W|y8i;yMqb6P-K?EDyc-_E^uzoLDv6P1Vh0`bai~$D}+#(!nyM zyJR2D(S5$ZitJ=qbDbZQ~R`Sgcf57EiDn z@l8;ou~<iU+=CztucscW=K5ALjq4h(HwNNlXM;k1bcvHdD@;Dhj8%HKBqiQ3=^VklF)!- zpV$VNZ~*m!2%NNg$vEd9?O$z&Pmhts`UENAAd9ux)I@taxz<5^Hxr@=NsL0Upc_e> za;$Nfnk><^TjptNxW>kM#}G(|?Ibah?qRmjUU#&@9vQK(w10JZ-R-yc@7){7RF^#b zkTLa|N6^*xKwA9YK$g#Hpfi79|5A0yQ*jMg75S zCIBnMKuCpwkb;+K6OTV=3XSnPggiP~$m4Ygr6XbD9*9xjLzsFU!hV`+kuN$3(=|Gr z_cw%tPSS-FCl6DXR+#u3d}PQ+!*D1J!?R-)hk>{nV#6`CGPWbOD>fQqWBD*!K7i*0 z=lV$;Kd(5D_RUG@kaSdHC0B8f@`{5K!k1~_p4N2HU_JFUNHk0?&5n+7^g6NdGo1>y z5ySj@y&L-XlAQV~r$2r#_Cs&U{GO*?p2Tf5mVPsFMmW`2{ps~9E3Q#R;u zQ>yJe!Kz9cGYc1>d6|w4?_B<9r=bie=Jj*u-Zy372Lm&%>ukOOZOirFJ8}BldH3Ii zT2H@^xgbXJC@>eu=;|}-s6228;LG6Y#$m zKCV9FMLeK@2m6~j2vTONOjd25*(!zniL6LA2rpIrcn_VuOnkgjNm&+D;|;a*q*OW! zLU@B;y>D%-o{$AeywTMfP%Tx;t)N++0jA4cunTpImq|=$;+zXY$y?}K;bPr;w$)8M3Bhi^xYfRJ1b zNL#p0V963^`9oO_vvJn#)l6_6c%tkQcGoG`2B7O584HT$MqSrYW#4i2;zSSD~5`Ez6QNNk|%m z@x2zei9;NwEGdaBm{R`o8^X>fV$obrt|t~bajeH_nU{~OnXO|HJV`mAQ`S=W@d7ds z3QRG#j~TT8(p2)a3o7g zgvH{u{+s!A!fNpu{(!#E|G)fcsai3sLA9?+tJbUh^})%Y#eb7{r}zM~U3~&RiJnv* zSNDQ_`~mGX_Feux={S2_|Fi!j|GAVj$PNh-pDj zYs7V>35*Y_Y2V=JyH*QX#(Y>h)KdSH4+aCgteBN@#+=VyEH5&bn;Xo#P1%%LEGx+4 zupi8L6p#AM$$A?)%Q!~<*{U=CAGd-GMfVUmNtQ)LRb|68u?8`-p96ku2wZ3_k##Nk zk|~Hu!SwqxoDk$VLBr2E?bCujpC+2Ro{_~MKAk{*IFbw?DEL`XH&x9?zn&lK0Hjw9 z5p8~*V6w`=Q-%+cCJmc>4Cdx1EIHXJ!xi$aq^=rWVo9AQTw&g75_qOdEXCm9l{7re zVBz<~UU({SY6&$eqO(r+^hB^xfd3OA*c173xDQ7vnsobbpnV9M(N2E1IAyvsca_e| zmstCfY7#v+dK4R!NAdhWGyod(q~C7V?Lgnm+?AbIK>QF#5A7BjAbr1V-ppN1UN{hO z^yqFOY5&nbwox1bCOotcn_T#Uc%?bCM`$3I*#jn{1NPpx}wuh8|m2VOsjmYjYcZP@$8n?$SCu|D(Pc;zrq z#@1(i1xajZ1u&2?;7?u!rAUVg&mxIOybn(Wof_bJeTL2k+K4N@U-v^j6}3_A=R{i< z=-*?%CqAhChd#s&@k7Gvx};m7))*6zihMDn8MY~#;eCo&@4uAo7P^(owC(T#`2l4= z8dP6XexXq-H824=^EOph~7dTudn z&<OZWe7c@&ntYu^6N>(Qj-pQ zN9!}O!?DQ0Skxdp>h7dVY`kAjK%I>H4T;w3V3)pAW-OnDc_>-kkTu9gP$hrJ7x7mq zRce)Qk~+!PtUYKd)&A1SRVbh&;;cSRzg=haX#OT_r>sAZG1a2$ zs)1J*tP4kjfk4_X2k{GC#mh%pk%NjN2T1Y1!jlgG2_u2(6E7rCVi0xg)$xc}!9g_N zQab#WA6?;p!H@id@Z5bmOo8*`GWio7Gb^b!sGTY^M;)cmHs|)&>v)7v$3Q%}0WT$Z z2y>*_C+21a|N-HtI<+1dOp6adQ6*Re`~t<775Q|j7hgw0A$8M*Go!L`2@`N?3C*N@(Ygo|HKiHNVz0Cwt`^rz--LIF-;h3oCs8~qR>B%FBejbECH@WyL~86ein0hVUJ?QHF88-W z)F#PDl;t!;SpPtfw30O_}5*tmT>QqLP(IC_Zur|W+&!U9@0D%M+Xhb{Z z+o3_AS=yD_CT&>bDDXoC`IEL9$QvQt31BB!0Y(7>C<-@->c;9aB0fpf$4+uIa)daR zp;bdhj<_(}jSoB8b05+Gfc#zJ z6vOoy_9g&sW^s3qRS$i2Syj za+j}{zCSu@qk(WQqDn9gGmQZ51^7z;hgn%=d7b;!)2&Ure~Gq&+4IPJ&zU43G}RY@L4>#_Xq%u`=MYtX$eF9;b_** zK}e;u^#T;&f*BbIg~I3HQE0}WMDuyLr|~DvrPu!*ezX8I_d^IP-GgmmwikrUp>j?p z{tT$b44A6Oc2>h`0t~);21y|3rr(Tae9&)pv2#Bs-TNsXE=I*Hy`SQ7_d`8;^sLLA zv;K_FDzgGGfvv7=X`&NLJF}hKLZUE$nPxIOKVY9mo!pCs zJe=#HHAg)(DLZNS}RQw3i@3pEXXAK5&Er9X;*2_7eu}%jC41CsP&>xO{B3 zuIlUSgMH2qX`ZekMbW~+02D0&+F9`j>kl^7(fOZMH0_YLpkpS8zYzv^T3ttbQmBPvZx<|vs{jFB?4{#L5RXU>L^~bK zV+N(M><^%pknQk};p4 z7zd;5ub+WG29ZqE211H-w9h)x>Hwh<5)=Y%20Vw`V1;7Olk;T#pkTUD=q`p(~ilAxE?uD z*lkds>!UO`8YF3A{xLUr{^@|vhGHHrv?6mO=oSq)f?~R6J<8fXL&pP-S^gv1M1uK~A4qDRa6*O8Lj+^J(Ha}HSNtdBm;e38jz zjupatb-|FNL8d5;DuYa@5fp_G3^L(HAZbb?EJA@s7=m~s`@}}tx3kc;bMxlSl)3bP z$lAq{n-n6v-nioO9)dbZn5&W`XW6xoO+;NHwbKG07GPUz_ta%m%9APK>&$iYJFY#i zG*uLW>`PypI(1S>d3M#R$rX`EJszJAvHW|PyBj~Vv*`F}2r_sE;i>XE``-Uj7cHnK zoeJD#{a(%G(?3_uyUlhM_7yf<;@Cf~WafVeR=*9@? z*760z${dVEBaGmSME$V?=qiwarTa`@Rfh((185M)=qf8{!g!)hs0qFRd^K7Xh!#Kf zH3vJ5$OsZ_%bo1O@*`(DKupd895EA&83VQq>2@;l;(L9*m>eVHvPU-Q{Tyo~u6HuD zSP`yhaq?n_upkM+L~am)9OY{|U^1S*VA{Fo6m2iQ|IY3APC0AGymI(;bhx#(>#dTS zOvBXr^NbZs*IY7x=HwgBuDF?4jOcZAC%*p-*h%l-EEkPHxiL%ELmaGXz(+iXZ)$AK=47xl^eRE7zW4H;CtU+9E(Onq2l}lHI6mXM&eB*_u9s{4;65G z1iri_G=5<0rtl;(Rkkgd%uJcyHRDpXNE1VIXSPq7+!4ON=9aZvZ<~Hz_x%6dcF%X1 zhxPVQ$?TR!ytZBs+cW8GU0b+!{<1kOU4hUw(|Yb+K~Uxnz%+ak5{Vmm9w78L0MRE{ zc^lr%!Fq#4*YIP+8YX;l#1H=p(?502;o|@QbGZ2D4{=u&&Vk@xo%3PgI$-1gyr6K7 z_-~vef`1$kJ?9wz#yJM~+X2Hq#{f&f0(K!g8wfzh(z6s)fqKvaI>2<$2`&X!fNQZq zaTB-|yk=efwdHf>&tG)e+6|N2SFWzEyK-^GS7xZZiy{+CErwAWQs)U`90C9(}c z!-yniU$kb`s;@4&;M|StCN*B)>knPrh4{9qUHD(>@&zTa1?zejEa+XwEJ?{)?Su)H zsU@KPgM+R02M-;jO(*K>jY9{GgLtN4>L4M#zw|g*Z|{v?+sBVP_>AN62n5Sh&Do~L zDrX;X_F-r5{#_XNdi;L;-^agBkNbT0dd%Am*=)mi$mSnS6PqSh5Nf2Q5&!(8Y2w5t zbTQfHV&n~UTmIPGPaCq0jr3sn8u{DEBC`DlIruw-V!qc%?4pTHBfo2Ens@}ifZH+A zMLujj-oWP@>zi{kF!kMrhAc`t2aO1rI8IJ`FWZovfC<7$w3ZdG@j6&)>+NXtxHUmk zvl=fYSRL@t$MC*1uz;1FoCQ`tj33v5-bKe)kF$^;>7mQ$l5e%1LBq4Fhx(o;q z=mZ4lKoUX{LcVliBwIq3Ez7bJ%h}kD{X2>yV_U|t*9Yq(wtU2K9N+OewzJ9N9P8xw z#$vS9Jp)3vH(&n!clXPF3k6NR?tb0X)z#Hi{rdIW7FxNoU>gr{JVyS3?1mDoTS+uz zcGxbHD$@6Bpk1?FLp9VR=8IGWm0BWQCV-$iM^`@x3JD>B^Y4w0=eCUEj2RdWwwy0) zX&E0yfez(4^MGv#OtT0Ep*(UO+_I~qW9XCJC;Q>;h;_qBkb*4ouV`U@hV`0+MjWg- z%TgjC>7rapv4S6>=@EE$3=4i~>?Nkey+#vrt*LNp{8;2#>i#@+H_V2#zQvJWMvh<$ z-bL>Dum$mG=2eHaIG=zfJvqUYF2fld3k+)&GQ}N=A1Ej&koY9VSOcGVES#}?l(rax z`Z4V1z*z9zv0#8PIyw#HaT_O(^V^_zA`UatQZ43SZsgrNq{*(}tyz8B=hrM*cr|23 zp6gy1hC|oxy>1V9WQlRfKbv1Vw{LqzdE{7RL+MPoX<%S4JA;IMjmRp_A|@2m%J7W! zMrbm^dNnkup;Zob_)FU;mGlf*!D@9T_c(N*GuxG#L_0YrM7P&NpoO2HgM_w3e}J7k zXV%iRRJK#96z#m&v}G~J(ZZb%?kq0rd$4E6gF8yf`p)(oyJ_gwqc)Uj zMr#Wkj3LmJj!wdLz^;ROYvMevq}Vf|Xc_Ui3d<+kND&aC?;- zcEufxqX#X}XMr{Y)Ei(>3p=$?C5K88QoTN3a?e326ifT1G+m0)qf%wO=!KKs`@ADw zVT<=VFJ0_i<)w4H;PV!EsTYhrCetExw@lJhuhHn$+v7)&XI}c)4~d$y&QKUI78YVx zw;<*E^HJ^@StR}+%MCD@Ynl9UI+2&5QXy|9`|iBVTPg%&jFxEynN#?u3oBFVPwwj8 zGtZn<*i`yQ%Q@M+-qUN_PIZNRb$grYd#gP%dN#kWe^)5Cvb5Cenw_2exvA;U%IvJ# zomG`x_0{Q~lH3dvKgGlSO8fQlK=nckO9 z8(h$3fgU5Y8llbz^Nld5fk8F23(!iop^!NWdpu5uBg^BF^u)*OO0#-!F6y~j2a9y< z=siIfD9eJZEI%o6+8xO{eYPHw^~rjZ-#!zC>_L-Vsg1EKIy?-)G4@OlxrUr;VPk|T zRs7GaCmcJ4EmPSx@dI{YLMXj_GhZoYIAxHnud*wdyg+$ep~mf)>b&K39r~WzwMq~bBi{d zSdnn-aK_@z6|*`Q_?3!pClt2K%daa=xqgpx<>8gtd8-DN_S}-mMq*B+Un~}bDBoIA z5l+&`R3Z??k9)QIwX_{gajDp)hDtT4A62{A}caB;tK@C5Kro<>3NvFgDl91x z(u{;DOX2f3BTpwjDutvE#)HB`!pYCZD5KJ#5hpI!8S9ro1xJF%k_u!bdMJ1Yhk7qs+G_shvoPyt{16I-9v`rAwFK} zG4&XYsXbDoDZx$zA;n_XX;bWq36;h6bdJ58%T#Psc3OgC!EclqY4nU8eoPlTNz=n8 zVxvJaMWqR=^3H7>jsSh}Jfuf{d*QD4{%vx5^YfP#bzE; zLWn5iIV}9T{^BQM9KVj^*XTuyKFJ7PTjTjkEnXAJJw!?pe?3t{0+uL6Uy$*>>*9No zjgr^#z6#PGzT(h4*fkG2%b_g{^aTD*I69X56<#~jJRYxBn3yj@sI>WL zM9nra91Ui(T>#W`S{%jft6w-`B^%$@#mjxoJ8x_2dwfrM;l7{W@#vcw_9ZuVue@PR zvF=H8IGWdCifkwO3c#JWH-_SpI+ZFG+1F@GLCz7H_|4a$$U!@L2zP`x9`Hb`8)R;)n|7r_eFDf5pgtZd;=yCsZa82N4r-uZ4V`l6l0lvT zUIFqc9I?aIc35wRW;;~b!A^+9LmYYsbvV*f;@GFAbjlPZRT8@cnVghn*9l2>iDE*O zIe*!F!Dr#zK(Hk`3cn`IjKdxeKQfB%T{c=QPP@R?Pr%7`F>9%$+p*=;Gh6Q*|3S;j zGhf_x^pn$dUp_9Y?!UL=^!vUG*9pC*pFP%k=Z-3PZO0?K!(A^x+N0kE?NeQyPe*=p zf5o-W4$Obz5vcynpNe-r#AcDZ36V4-cWk5}?A)$6prHHZXh1`fgME*T*mWw0#vrxF z30g|jC^4g`O_<@6d&!<~8e)>b-sB8gf)nB(o(!xUTD|AqwcaNmmZz-RHMDT&^G6p8 z)dP?ArHj@6`aR2fPc)@rlWdJ!_E%mpxV14^?rrNkbj7A~`>LPB^oHIO zjcMP|%#?ZEi|1}w;EOhQY6fiiDU{Nsk`e5O{BX)41?*Blo(MXPgMFh`Whag#)+&Wo zu11lb>;>KlQMCw$i7{tjN8Y8y#;O5UWUV~HdcpV9!wSc$T}QANh89akEu;%Q9(2I@J5X;sdD<8eNd+0)-1I)1WT}x>BGp1rFJv%MKk$&=3#v;=pRDu+VlL zbmHVF!T|#IIBT*s*^@-#Z8n?V8Sk-LO&;RZI~`8J>CEx7ubJy)DKaYa*wsR^&7PEi zA{rk@DC(GC@cmK!cy8|dqukVw+4{LrZGP3j=qSXG>Dm9-qo!~Ear5sla@FHP!51xN zDuXo04GBT(C2h|%ySU|+$M1}cpIh580`&IwM{d8WA+T*7SbshKyIpNx{Q9=pm2|;@ zhq^XAI-?`A@tjHhV$H)uPwv_ak>r%6c` zH<-=Q_l>~sc0~_=TB#CM7OBH#)XU;*f>gz9CN|yS?}R(VOrl_5QWrRJ)G%WrI>QBX zt--t?Oq!k1rVAf@Pt3WgqwTI8vuF3-)%JL+I2@T%wC;)-o~n)WE4nJu0*gBb7B60M z?4|x|ULIO_wC_TF_UdD6SAMH|R>_9rP3^a}1=*}V80mmn(G%K8TG%X7x0EeuIrxiv zf>tJB8=Brf&nO)oXCn(`l)cz6I6OQY>5x4B=eg1YFU8JH_=1n8hHy@F5b^!bN`;IP zrP9qlx&lh-X2+9Jk)32MqaasE(fA{vj4H>c*ungP797TWaInFmj~~Uc!-fenP-8_)|p9M)u&vKcKfaf_70xI6)ydxx)q^28ZDnhTj=P zgNeu`HicS+vO1Q_TD4{TAp-@GLhH@%$XhCLWCT&!8s%Se!#~6}qX16ON z!{~Aq&2**6%j8s!BgdAaGf4w>y+-D?gTSd`zl^w;Y>c98jK4HFPq@>j$VD6zjHtGq zq}=^gISGoL_pZ5jcV%hsJssqN5RYGV<7Sr=TSbt~>kGQ)i!eLO6K{6_Jv1ce7va|L1>l{$$0FMJ4 zJ%o6A9D30E?d&ixr`;mq?2P&&u|{IsxSfoGGR1~-hDs%&srn=4_{&T&nV4{AA!VSv zV_{)NiYEKk*43xFOXl`Ju(9`{-Qhsj{kxmTl<`@eC7$5us4 zxSzCu`$704ZV|VjzO;}t;T1ZqNolqSqDd@}o{&;0B5sM)ERj}8pg;mL2}mTSb`y9_ z%S_ZnZGnPPhDcNQzCG{#np-e#Yg9UW$1(sOT?Il9L2F@ z;A`}#iXkDu`WlUif!J;%2~MwQ&KtOW(ZXY)MURuMcGO@5c2J`;O>hcn5Htx{f*0*F znILXCe^o@k?HPFH<%OHIX1!V}N>mz?b`#8xjEGytx8XFF=g&yA`7`r8k#|tZlM~o} zKepdYoFt1Z4`-7sy(>xL@;Q=#`1C%S@5BcUh~Dz#H&yMTx4gsq9zqWDG*A4Y7JD%p-~3a zGN=<^8O~}hi-ov`T&G<+0)6~to>_`qLpH3E&b!u7UN3NGkw|skL$DNxB+eRihC^qo^ z%MKe=ZUvkrnWQ6lO{o-fzBgBlv7giTY z!RXfO%?g*?h&MeXSE%?P#A%@{>bWvG25uvG@GMT1FBn9bh`@H zsi0m3^N=+fO>|z=NDfM%4<|=mrH=L@`>3ebNkkdj`a`W!nVY@;OBI5d9omtBvmeM~ zvtMwO3wSQK?AXgs_@ke66y50xLjtI zqsyam>lL6-Xy`=m-auhJ?WdH=*n_9AdaoQ><=arBMu$UgOA8MsnuSAmKp&mBC&=fd z2idB;So_5I!{P%!qSfMAq3Oci*c*2XP5imsXW|>ET};GFR)xzBc;J8o4%%Qa4vLJ` zMp~nWA~npBL%tkBGAO5zM?vBu3Hk&_f{>7a?m!BARA*DF?6$w~s4hAyeeHQ&DV^$) z)05Zy+jwc`PInC zg@XsZl^wIc5VvHaMPIY8wJ1_gt6SC=R{IT{)87@pKu#y2UH@_TCR;yHPI#`A*7t#2axYoJA)xef= z`Pcdck0(Fdm0|_!0T=ARB%9M;X>YJoyTfKPs{Cs8^*ZR(_33Df4r+8zq=R%UDnkw` zIm)pdvrKj(nuE~=UjEE*{Qbff_Q0!Ua@hf4EVl&(FgFm4F1WLUbH3i)Z08U=yuy3Q zt1#t;*z*nc4#L-Zf7znkw%oj`10`jLmrO{(m6bIMy_NmGHsNccaQ$10909{#Yk9WA zc}XOavvm871*w}}`3AXo0p-Gq-c>_5(;UanDst)hh6xvYdBkB8Y&Kf+z z^PLfDYdyWWx3B^?f2-WyXaHW$;U5+QMnnr{Lyk$E@V4T$J*9= zcFq@tl(icy>BVkmuFqvMXD{q+sNUU}ThMm6UR~BwYER6bo9->jPPbZ07OkCC-h)1B z!?jCeU!WB};>j+zC3=On{Digr&IVe(tj>;jqrr<+J%7d z+G$qCQS7CKSVjtI3grsn(&LS-cFO9z771Mk)$aN<}x@ z2u%fnYIFoNfT|PB1QxS_1A76s0<;1E)rmylHHuNfI@yA5mvAnd9%`K9tmxX){ zf}Lv}M9(cc(~7GiInPFBy#RS~wNfsjaV;8lZKHDU#y6%wtWvcfG2U~BZ$nxIfw zRSI{4)tq2eB;3wTk4hC}s30BW~YIhH=clKgOeioM6e}_)P_7tw3!oa zV&W;zm353C&rmo=;bsc!C^S+CQSecq>k@Y)4kQZsiS>yz(VeK(kOXF}s3@o>eD%>N z>n2q&GBC=+sLe9@K!7>xXwFUHE6X{>nwgq2TFlov1K5Lf_EB+1r_me=F5Txb6qgn0>F49Ce2q)z7_+y}rhHE`le$)J58fJHYB9@++MqBIwNbAy zDRc}|DoiSnnWbjA3M4Er$<1=N!emw`Oja}-%^EFH6Do)*HK@>hR-5sXSXC;8*`(%H zpd5(e5?|RK0{&1Xy6`bNs%Ia|2F?<0KCu^US-_%oIPioVD2c!F!p7 zIz>k0o!8-w$eN%3#%x!~GeG%VqyYjYwPt-;WH+s)$&qumETg6j8pc1K+FmUw3EQP^ ziKrAo>voU_P~$>ug&Wx@2wJXm1ilK&-cVfd8Kwb*iYj2!G7u{GiyiG<$y zJUQE-@q7M^Jl`Bife-0W@UVZ)b11J<`zSc?E!J-0h)9Cl`t)pIfV}| zl+uPokKZ`HS?C=+42o z1gUH`g}6tB8L^#%n4kOmJpYZcw^SqtW-l9*E@@Wjwd| zwbE-PA7bv~(RaQeOhU2JozoXaF--Aq30Cg7+5XFO-5hsy6{wCRa zEa6@HTR}#COUQT{k)0*1UwIl^dcK~g{ca-7Hj(DUQV-DIW7_XA&CSx%Rk1WH-glV( z7Hcelr5E?{8hN2SwF*-=(f2U543=Z+)Ea~6XJ5nboDIujcUmTC4bqqBHInnuRJw+z z8ia||R7|~|r(!!}smjSzzT1TDMb-4icsw$(7qzm+DnahmE_Cv^QYpx{JzV}$NUbP=4<)+vqSdApXRFA zi1--}5>8J>re2TqWK6#3$MRc|8;2#2Mf-p*j`lj8>;w8f-NaL|50F>b2Rt#lc{e`> zC&-uNOSPDQ8kEtOGqwdz&Xt7@0prJ1X}SNFF5 zF2mJEweg_ol)2ubv^*Sl!P=7GOYkMi5}&u}lLu0^I`od$Q*~)Sav$@2=)G$ap7lPP zeqY8v&M3>=ne}MkhU^b>KFz%t{3vfAzqTM;xU6VT@wZCupS7^;uJE4O`{%qmZ>+*w zIZ}20-+^CEg=!%Nz8Ea7UOx$ge-VE2p9eKN7o=PUwSOh_Oo7K2Jbp#=XY*eTPc95E z{P{FY!!-Oag+KgPz#{cDOvB$Gcou~hHBG}bOv5xx!!%68G)%)ZOv5xx!(Ri7+or(7 z)9^P1PfWu!{Evj6MPZ3K28%iLBE0c;EK>z`UCUp8~uP{aI&a}Dn{IvX1r-)g+rv=-r$<;LYz%a<&Ft+~AU z;pQ(}idxpUyt6{NB5lR86=zobWM$3DldB}F7Ogg{-m)fjP5GKT){L)xyLD;n(bjjq z2LCb@+Eg(}^62)1v8ncn~lCZY8| z33mTK!Xbp)rePYUVH&34ZyyLh`Ht3NxEih{Qt~Vji0k4J3_};+!LS5FGcjN6ATA@-NsAK)bfuml#C@UR(E zgP7+X40Vw&Ff{Pcg{gU*o;o{J|@dl1J@iLn+EW}#MG1PP1!0}|vQ;4;&kkwL%<+HGo=UIR? z7GlW^uj6?dc*t5>gryz9P>*?vur!7zbKK5D7td49!%7~*-ncEo(imRH!v-EUU;K=e za6Xi9zLj8^Y*@|{@%mo_E868PK0T6!vm3#6Q0 z9mB;bc_bvBJ{`lQnE&kAOq>=eBRP|Ka4x@w+%K=lDU6E09n-{Z$N)@-T`=c^Ji`JdEPvlsr)$ zM)4>QqqvN$v7LHQzip(CZ00d@@oFpLEL@H8ojgYtrpzWA z5FBJF#;wEqw~-!x)rSAuF!y#0TX{|mLM2|U!Pqvk17jBP(l=qf6ZI^>()+ONUM$Cf z<#uD4on$TIYZ2d!XB{dNEfk=bQuMC;FobX=2>zYEBcAfL2~3qj^1VUHgAXdcK;o=(1Xw z46Q?cY~b}ch!693@)mSY@-3azb6)jKwkL$;G8wp3(iKSAf3KV?`QNmx|4)(ie`D`k z0HdhR{l7VzEP?FIZjb^Z$biT*1O!9`R02szAS5&iFKd-evLS(xO*bzPY85p_ z&CA*)r7zp$;r12tb(L!TliAKIxSmRGwUxI>mEuvno6D}`9<0Pw)qGCoD&%$q#xr_s zs#Ok4Q+$n5N`iez4)P)0Xe^yd=8KW12z;{A6KRiDy~)9PqI+PCSRKo$h%G0U%<5E6 z%h;yM*?Iz&9xZ#Br<`LWas8+WU5#D3)rQu}Hrx^d`sric59nJ!_ha=SP4+Fb4&-c{$RoaSCXShv&?4HD83Z`&4sTKr5S`&*aF>4_Z!D*vh~f zZ%Ye2s;*_M%N1(eley16HP2YsBay+)^0&r0pvRV8RVoCxYLN4QHLp|zHN{P#`8*oW zPQzFPCFJJ5d)1s1z>i{1sex=P8wss(OrF)smClR|w6W>2B{`2p%;@GIrGb`=ig}hP zkHDG6eLO{ZjJ{=@FK~5ibW4sxw}9-Ub4#gNcpBdCK)XV#t&r7(W}?6tCNti9xt5Y3 z?+McoiCfkPRiU)d3~RNzklW%>GgVD+EW@$H8pCmF#H-j!%7bkP*ma~XHD9XXGrZNy z@R=r3r$dscV>zyDEGBU_clH3nKX4_qF~&s1kqQFa!WC)+RU&)|4Y zu$>vIrKv0QySsAd_1YlHV+Z^U-oy{%o8r;29zpIn%hO`7FJ3B{SLEZ016}vPNna z_eM%p${-E#d2q9Xvdd%NYD->NX_2y9#OFg-S^Y~@{w$VUE_2ps%wn#9$4Z_}R%4mR z{fMr05o=;PUzN%|&JSux25Ya?`ha#?b>xP%#Hvq@ZFpM(T5X=fMyyf-=NG7vZY&om z^;DLLY*&7;=B7$cdC;6N{*uegf>Mt;&s*WGUR~)iXL)^nTn#bv@Hl==0Q>xs{%Z0+}bkbx3t2{tSPRNH5HVWRhi}C<&=1R=FGCf^0Fd#xv6Tz zHC|L|R(WfDMIHnt)pc&4$E>L+_V~$GTre|fLr?}WtY?fQ8 zX0fNL$X8Y=JIHkud#c@KGrKKy(LXcCy+SR%9-a`R#Wcw znIq?w75TifX`>c;d{wfV%TmUV=ZoeQ1WRJUrTN@-WfjZJ+>#Qs&Kzszc?-)b%$%~K zQg6AtD%qUxuJ)A`mATD)H}|p1yyWsJ6M{9ERW+5BFZX zwUnq#Hmkj6k| z3bfu^QNG$7SvJZVyRgeq!l_zo4Yib~&r>DkCWk3hfy^E(YZ^;nWEpCy_NMKL7 z#ooG#a<98MQhIJnR8TQ=$BU}q*Hl+RRf|2coAR1cPkCjeL}5M^tJURlKu{p$Q(9J7 zhBl|@x>T$ZZ+W?wRX~Y4*(`Kdp{?GEpgIQzVPt7_b>-A?<2)59b!98cDm}$z?i8@BKUi4k#IMqgGA$&8dGM)cOqS8#G*6t}3@Bk{l*hnUxy zb!FA1GC54$l9js2)(1|PmqAahx@B2D3s6x58xF&-|U z*bCU@wk-D)RR zF3Kv%%w14m;)=Y~oPs50Zibnfv&5X6m6MiirZ1kKm!6+*=H{7M^X6w~r6VmXXIA!t zw5*)j=1keEncPF7Av9%@OSm!4CQf?APgrY{6z=4Ym6XLD7l z3()#JZr`lj`AhP$W@i?dnYr0%=}4TJj+Uj)%ucteLZ@bBr)JGdHq%n)rOr<0T)8ME zk1tcLTa=m3NvJOsf3pg*a&u%iX65D-8aT$D_>>~zc>Z!8ZYmWbwtHH*mkU?Xf)^@g(SUJ$>rF*WP`vz58B!$KPwW zo|kstZ||D-+pW>-zUSV3&%OJed-px}Xf*G>?;d&IJs_R#d+*)%-n;L;cd~o$VLMni z&k+Is9p2G;B6hf*h&?RtV&g81yCiOI-0Zk3;9rib-9SFMPPg!?RC`SOk&PHX<^I;k zzXFqGsNath`A5)pibWc(NC0vqQM}(zPWh|rdEz%i#pQ9siDtYOzX!Z&-SiHSA4FIA zzevr?&Ko}-S6Stde9N-9QLHBc1S7GLG_gtCLpE`*xEJy7iSHr4L+n8O`{F*te;__W z{O{r<;{UWIk!I^{>rFP>dA1D1XWQl?o^87U@o(9_MZ$KY?Kt9}+Wv+3zinS2?zj2L z7DsVaq{UUoRU=*#w;J*5y6S0i3yuR*-l zUWfQ9`>iDG_4aQgzTSQt;v0JGB(2Afd;FMeJsNua67k&$sU#9+Cafh}!Z#DpyM%8g z>_Ghc3C9rs--P3cf7%nZ^jy-jj%+1aNlU6v!k8v)OG0|mT}j)a zadAoq1r1?Muynv0eKqcoc^)KOkbrSaSeyU}CtRI?UL?2^ir|+dRKl-KSPlPrjE)?a zo8YfYScjCG6K+QQmV|o5znyR!;u{ifNBjzVX*a@v!XyDsCqi zU7+GUVEF@8Jb`-CAQkUP=h1~MRmsP3OZw2@uoR6F=_^3HK#E3vQLe}?$TaD~g1osV zaN4?302%tx5XITBQt3}a6&J@}WVwij6;)PM(rfI$$Nn+)PfA}CD?Gjm&B6XK_NTL7 zz&f0g~i>>riBAogdnzmWaqD_5*sA#Py5 zp8d`2Z)g8L_8ZuLg#F#@Kf(Tf#^BzNW}gazmK#a?UXCPf8I)xvP zP@t7@h@F~?<9Q|484a2x|Jx@4VJ~Qq1KMCfHwn5m7}_)hngMN~i)lF4qa(2k9Zh4P zNn)Z7PeYd_}Kd2wpPZ)Ni zuQA-1Y-AVl*Hw?8 za7FT$M)8?V57RHyq8kQeN#feD1^2SL18#|b{ zLrw!=F{5D>Q?0Xg*Ql^og?Fg%Ar-24RdQ7yXlN);BU z@P{fq##i?TQeTPvP!9IK*HQ^~Cbe_})zfC|NbaKsdW3e<6SSXRpo8=#9j0Se?t0bE zdNpqKIVx1+T(8FY+kI51+WzhJDpY#BevS(7Q{izdyiKLwrpmkRGb`Mnda>aF6)L^F zU8UdtuoZ4p_ObC=6)OAMc#?ZPl;&XXcQxPp^3nCQjyBMpbT8dc57Fbahn}S8=w$$2 zK%u{SjSkTV^f7&=3CtM1F=q_LtT6%e#!PLFmZwToE!gCDktgtnkj|DpWoD&M*}!iEYbNp_1HPN@Cm9b=#GszMG;#mG5qs z3YCT4t@?4#^(s7Rh4)sfP-*n{lx2VKO)K1?>|@6(k=nT9P^3mTT+h6NH8UlK)>&6I zs8HGHPZVDMM#KMZS{ zN%DWmu|hAPYp|CuSJ!M*;qzAbQ#Fb|RnmA^;q1ezoj+6k`q^G9d_?K>Bd=NEqh>6d zeN?sjQDv)-DJy&INxpg-t)*LNBW(ev~Qy+QBMQ94fl(&99S)<+wt z4bzgfN!oNRP0Pk==Nhbc%CX{Ei#5+ita^4}-SaS3K6|nDc^<2uH?aOWsvXzGfWv8ULwd^Mpf%3Tb|$%Kz;I6)L3qowA!Jl^s2$kmxBj1MV|a zs5I$m)sLqivBLcet?(H&zdxgp{!67luiE_w)z3dD`MjX) z>xK8M@Q(^7UQ~Ad;=io$rN^xBWrZIvZ??h%%B~N*V1=)!^8VCYg}bfr;8H96Z&m+) ztMpe3BklHo5+d#Pjiph%FN)s~w)TPS-uPkU+V0Q&Bl$Ng8e8I9YOLQk$K+w zsBxaRmBqcI@b#T)z9z<+>m8+m?c>mpa6hc`s=o1^$`QT)A8{12n} zhA95wDE^Ts{;??j@hE;*6u&!)-xJ0EHj3XL#Xld#zZ}KC62-q3#lIcJACBUWM)Aj@ z_~TLhXOaB-6vf-4_+C-GD~j(M#Se_)heq+kqWIxa{KzPNbQGT)#ivB^WqQT(JR zesUB)C5oRK#m|W1GotwHNPBrdFOvT-axbg>?e0ka*xE?`BN4?{M)IG`iR6zTi{w9z zLeYOv6kid^pBx{_|MRs-{_`6m`G1d$L>GTT6ki<0|287Opn;LRC?)Y!f4QrFdeU>N zu+qPex~Uz>zXk4fj=kQ-Qnv8%x-6$HWpz{MCI6ImD5JFPWt>|it*cR5DUMySWhrei z(gM4x%)@)>f2|JUKFgIud^*1s!8TB&t3FHcvMc6cvaXFHbteQ`2W zV*9kLGn4G2zahvCYuB=0Z;WbZAGN)gYArX2S7d{5l!i)Ueo(+hfvfVZnY?amYr8vw z{D*M7F8d(+=-(4e-*c*5%_ujGWw$GGc4gfTt(A9$q}aCFI+6l&tN+zt%AIX2af`M3 z#}OtMmR3j$gZl&jv9{ILkp#&di<;|RXmwd?uJEU^1lKguyELw^REAyGUM2bW`1h&) zl=^ps%@xc2J5F1jUxua^pRSs_2DM3>vfHg0U6Rg)Ro&^Lu8U&b)DhHP_X4`fBL7Q` zW8D-^{^j9!PyF^k+Lz?o)b8!*g1g@Kl3h#oSFz>P6{XirEu)UuSDb0`FKs%_zt_L_ zOtz()Vw1XWyp-dQb!=O@DoIQ3rj}9LpI4l_bZ$IZXdgOl_uL1!wPlTHr$0>|P1g88 zjKsz5-il@u+8VrnjM&v3*Ai}lvIzeZmh0T){}cPcc6Mxw{ZEHl(FJ7pbQIqqE%v|L z%a*VltBzxDUt`7ZHbt0XREZ`j)S^mS18w+E?t2y|0k*CifMq z&)t26|8f80Rv7DC1ouC&uZWfN%#eS5EAq6{ioSb4+s69qSRxPk>tdd>ko6(P#`{8C z=nBhq)0a~$yFGWQb$hZvyrcJI9ZUXq{O@oW14FGdG4s6S|6||^aDO~~?d#0s|Go8` zHP+MCP+H{KK%Q9V&OK_)v+ZtbjoyWL8J_EUcQ%v%K#Vkd3(KgpR${TrI(sPe9~FVM zXQ;p3zZpLj`QHnZ)B*o7$@!1K{RZ))9oe$3N-Vu2?N-{-_A04!k$)m<8tYzTZ1V4H zmpabUJ?NQ`-C0ZhB5ZT4^!!KEFV4nxM1#5#h2~Njv*y`ATKlXp+W-GbL1~Q0W4X0Q z;FkIuxcy62tNVRvtB^13s#fR;>O2sf7t*ZXJGS2}ak@xh%#nZ(>FxBt#4_CJ-;1z` z9z>?MRWndmSb5g(Q@Vic_CiVrq?DAk?8RDqFOCNEXH$eNMfD}btK3I|HrC=^`|pa7 zU9cRq;y^@AooZiUl@94`g0^jHJf}e}o7CO$Ks(g^az5%57o7jCD_hZyvt?h=k4HQ9 z@2VsJdnkZ%?K>B$Qcux}PDE|d>C=TvU1k5S<_Zg2`USPf3WGCf0v41C&aZ{}Rl87X{?LQ)IPG|F^oy^Ex%k^a)vaWk%HWh*+j&c&jLR)^%$ zSVH~6Tp&lg$+5G`j#tJ}n8N(d=(`$`^IqdVwWXK-KZmVKqkQv|B^Lwa8K4|&1gIpomJanQxmN{^XvL9bsy!F)SR_$7q|y?=ASX1 znfs1shoDh?)}iShG43)m8d)4{laoJ zxn^p`^NMEf$vPMDQysM~R`>6$74XhR(%c!zwdZ=XYs#*r6iZ_Ke3s6hKDHkP{+nNF zT42vh!TT&qTMzJ#*xCsn>6T%D0?)Tua=~Za^7(hr$`4qY7qIiwch9Y*&u2TDA~h{? zClMQsI`jR?&P&bv{mQvS;ZGogS{OD9tKU?#;-2R@K+SyCWBr<{o5Crecj3=oBA-gC zC%SvPXV@qj8`P%Y6R}`urSyx?%x=7E9!1EhTk9HA#Pi44>yK_-J0+=kHpZRe01|fV zT~ieKOV;pvlF_p3UK_`xXxog$yLSFfMPq8|^VyE3pr*+caPU{3pGz!pOxcW zBmWkEY1_WR(mCF$+;Z~QhkfV0z76HH;vQ62yKfbu$TtzU<_)td=dQNC4ZpqKrhlfX zy}qIP#mO_1r*n{hZ3K5itIM(8l{={A+9UIHO`QYMy&n2LdFyRf`DV` z3Fg}PwK7Pd#qZaac{;;)c3MvS2J4XQTK$WE^)CFAO@C##DUx|wo~tuZ`{`YqznR=c z|I5Yyg4_@Jt2y4vZ@r(ZYm~N=+*h=*gf6lE@0)iZbxq{% z9MrkKRo>O8<==L*s5Rf%IvwBT>NsjWYIoyZ)OVs4_1A&^?C|%a@Vi<<@Ag`*{*%6Yo{dTVnGxKp9o3F5N&O;L5$Zpg z8^5FXi;vWQh__(PA@iKwzeL5{s(#hvKS(j(9oW{lo}SLPrgkJ*-~Le4WxoBtb~Fym#>okpD*!|9xT2&d?s#h6 z`;D!8pDnY&v;N-abQNxF;=HCg$VNK#ptHcbEDrSmVB2A== z3^7||iYzfl%oW*Up2!ioV!rsQ$P@XZKr9do#Uim-ED=|WuZe5K*TuEsIYCaixr|=tP~Z(D=I~ms1IEH|N{P^;>EwVeWuc4(I1K325^_SXt|k|B z>l(zRekDP}en7oh%aWjHzo7G=YrjODyK#I4I=6@VLhtrrwYVQg67=s`_;2Ir4?R4B zvmfF(ANnXL2|5`EU)OXR0Nr%LPtua8KXmkbx&V550ZCmQOaq~>L*S3m#?T<>Z8BX5 z-5pDVp}*tEgbq)jA<*NAh;P@nqs(7xzeZ_KX-}bqXS8Q%D0KTJx(NDxfciqm58|3X zYkx+{TiRRj-_hQI|E~5f&i+OF3k`$r|D7&|{(nltVFM><1nl4+G!nM(Pa36tu6<6U zVG~4S&=rl6VH@!@7WUDDQeYzqG!Ayslg7hVdeJ4Y7Y9v%&FC}|cH^Xpu$_K13HEb7 zT?!kzfF{F^2GV7)rNJ}>_GFT@sUdVZ>}nWIg>4N-$|x}k{unU^ezHiWX|S~vnhtv# zM_0h+E}<)7ca!KU*xscy1NL_rrNRcM&`j9j|82<2 zA1MQj0dy?^l7$ax{@NFd0M;oIN zA7hN6X~4QvGIK)_3BD^PGU-3cVTjJ^XjyqvZH z5vS5!K*eda9mqHxC0t=#LEi;JUWt;gGOoh)GmIHHJIk1b_-tb~-3`>tqI-axb5Pe@ zV=mnb1kFa7^Ne})Js@cg?EsqQqMSS<4}QLpk2WkY7QhF(qJ$;J68b(c_8U|KOkGR0 zFyg-|42{PjfQr4~OFXp!_nbgd7mj$~SQ6qAVeK>sM-RFXM*^d5Pnv+E7h`K8W2=L) zRcCB9C=G{`GH|#k6GsxGZEwoPaUSL2NTPfkeW(D(R~Uu+(n1{lXfcldjL7FRA`f6h zzJMOYF_0d@F^GPO<3jp5j=}Ue4wH7_5RA@47@dbQI$y*nd=aDSFhyR&;>C=E zmoN@m2sn`uaFTEd7qBl$B+)3*Tl5A3o+r)&0`?JofPj5PUtpg^$*H2h=ntfmSUFt` z5Ced8A;i2=3=)HYcNdBafp-!;QyD!+h@oOAQ12pf5%5l8XqvcKTnxOENSYx=h!McM zkzyq3lBk*~MvKuvJ&COuVyqYo?3*km!*1k#Qa)V-BNXE~DXm#=);L4(2fe z<}(5oFaj=M1YF1nxCq$yRbZS%y(Nrv7RG&zG42}1xUVzDUCS7E9b?>5#yB@)Tp?pz zkth^}K(``M1ay;lSHgI=jPb5iEECIsZW8sDi!xEBux|xpUpZsnO2)nl#y&4&UnOJT zb>bW18$ddr@F6a7utZdgYM@>X(6EZpu$s}ZSgaPSsfKZIG~-|`<6xb>R$mJQ{HFd* z;MYz1P4I8lZw3xZd|ad7uHOy>+@f!Rf2V#YaPYhOcM-owzX!fV$r~6Yzr`qdBctR^ z`hV#ELF@FL`c7Qapf}LXjF@Zm$MnaLvPXXczC_QP7(LhM&*;w~L;_0o7q_;AX)-#6Q${1SD==p6% z&-IL+w=sHdVD!A5(eqa0V&h`qn#9n0#?VcSp|=~Oj8RCJNVvecNhi0)~&$Sg{Wl_5O%Av*jNmNl{mYVakiFmw$AvO@iSU&{My({*8^)Ev>sau zmv~&RTE*YRNg`WsTW?CR&9=>@p79goCy^09C4L&Y?CJKo)W@D<&!-FQ3+;<&h<%Cu zYjjcK1Bs8)@Wjs@L@D|r{aTvj9O@iS)16m2ucB1vi_SmMOy?WU4=B?W=Zd36t~IVT zwAgi*>n>W7RG;)6V5y+K;(x_QsC%$&C<)sL+hnraZn7PxzVRdDlW9Zzbo(^gV!zTp zOWR_<#=cCu%U)(L(|%-MVK3M2xBKi>+RntEC;m!nz!J}^Jz~7&>@Nm7M>w&XaW**r zC@P$Or(fLdDs`<8_qbNNt{2~TZE|fBKTYx^trNdU+Lp9UyhNo$j-zlNljeXV9A6OW zair z*Rs=8XvGhy_+Jq}hVXb3*G2MyJfwd{n1o}TQ~3;g%=9oPUUn>ZR61%MYaQzx>)CB~ zY-4w?I)U3cic_5S*W z2!|mYt&e9nS)Z=Y)HC%Q$8o&?*IlhIWj7hu&D8rl*6AheHtXfm={|jxeuI9CzCpi( z-F93n-44X1yB~45PW3i2nwp8)?a#Nn`uPLM9h8{nnugZ1dCoCyR?1`2?|qv3m^Xq}y%mW%s1JHWVcSg1LLvOITUWBQSD4IZgfu4 z9nPtGf9DK@85rZq&TM_AGcPcf&c!HGx@(myb{uyu*U4F_-@&dHWl6Udap~3}4(C|s zT+eQ^bF*~%2In?*|3}`}hgEf6`R={XJ{yqp#oqgTf1g7Mp~O1YT5B1@IMfj9wboi| z97C-&4)s!MEVW!~4KdUjLM@?&dbyTM3AJ3VA&g@w_2F?Sv6f35ODrJ{A;d6_C4>@c z2xExCUF)|GN=z~{cb?}y^T#|szjfAL?|Q%1yWX|lcb`L2W3Of0(yu4|`g!#e&s6s~ zaM*r=VLxf92imPIz!~BhXNf1=_7!^%p?BVMKf^vqx`Q96Kg_U?*vA>xPWxm6(+vBF zLtr=*>p6zC(_vvaRC;E393ddxkp(QWoB@^^uwHcJB(O4p`~>jqSW9}04F=|X)UnyI zm2umL9Xo)z@*>9$#%&*V>}Je8J4$WIj5%L*?6+k&%594s6_!Cq)jZ!M*kg_wd#0mi z?%8q7QNy_POncMOK>m1Jzlro)Zk3;+@>8}F$7x#`(3!wF$9dqQ;}T;o?#%hSW5{+C zxI#Q*lz7Gj@dR77V+yEq++c8wN|SEKskCHzwh?sVb&g|cK037fEF)rT5spM6##ZNMG?E>k(nV

          O$K_b&0J_U9RS;tJF2>dUcbfM=c<1x1M9n?FDtG?Yg?lF3){h4yb#8!|FZ; z<$@hR1LX|D?R=&lU|1_GhkzR53F;yBFvB*W9$`>hwZLJuo}nJMRx#2jRx;ERmU`f% zwS{pz2BZ};>?3MB!`i8y0p{|_EnARZ7Fj3Mv$hPi$F^AQwG671Kh;5c9=^S|c(3uZ zI`ZDVW{;`k_RO@5dHbk^_ED2MNw%7{^vvypIs0jXWsqSxt0|UVO|jK!7J{mIY#l(z z*3GcBY3V?hmIYkU76A#nXiIHDMd-RgYLE^$gx?G**J1P0x$zd{m<~ zF!W{gyn>z^=$UZ)oTTS5Zu_Ucn(@B##;tfv@tI)TtFHqN5?@KUV;%L4whmy6t(#%r zu5YvNw7aaE^*qMhvu!}nV^}Zhg^anFqZjKX3_d5&KH9;Ut84Al_X0QcGKNjk4>ImN zTk4g1HE`5&hH?AMq}SP2=#92&y_sR@*IOBSn{@}!q2~c@mP0^?yqGOK%<`m6mM|6j<=44|nKz)% z@`+g)`k9!E%%$d!aLaN7OUy4o=N-)Mr{Eug{3!S#qJL0+LZx439m!{2NqmFw3Fusa z*9^6R0(-e2y(6Z)M7*QjL6{Aj->Un|MYt_tnUn zWS{S%^fBTKWx6Yy@@F3f|0~#vTfU6Gd@}pt(9M3V0{iDE_-y%?Sg(B6Q69voo@EA6W-2kD9+tbob1gD1|*03+Y?Uf5{X&+2&V?KFbpE+1bs| z`2q2tGd)i_rrEu0bNN$PQ`Udoyo2e?B>Fncqm{oxk_>_O*B{L6S1~i$M=TH=OyQHY zvkR!TwK7(dd7*UX9M)(n+W9_cn8z$X04qSbKymXZ%24kre}#hGegly`ik^@=5IcY@o!^^iTp=) z%%)Qzkfxic(e+JL5$NG{7ioe7v{C4I~7~2<7`g!=+FEIDdvv(<@Bw5QI zMKP_A$A)#>XZ{h!_9J-Ln^@W3V0I5;c1$(-7l`MdM4VZH2*W=48Do8uvf(G2u(A)r zubzhIqc3wecA|oQ*RniG!hSr1-8zVVABQI+>lwL5c>p=LP@g;Qd&g7eU{^zMvf>-OrRp4$3)^TKhTpOhks?zyhB^ z?|*`K4KXj9AU_WNdFY2RU)o>dQjX`Mra(t|1Q9iiD8X6&GNS0^Sw}bLVdq&x*>>4sq#G`CG~vj-wSTbTb4<| zYwNOg34XiR9uNZdH|%3V#9?-rg;?5CX*J|`v_nl*1X>-_G5TyE(Amn=LZ7DyrxTxy z&UrlTRue@Y6Ga}=B?3it6Ga#kMIO^c0#k|48wO;GI&yLX%+v0c^?A>f-^jC#Pl`Y? zMIxCZkh~baE6B9|GDRM`5eV|S1U3Sqyd@#uh`I21?gWnyW2AG5Ak(~MilQ>Dr%X2h znW7T<_9ezJ#~)1av^QmnK=RQK(R=UnTpdBCXeBp(K-pZq<`0z5$47)Uw9eZp=9g0L zsib{WFErC`JtK4r7llFLDn*NFQ5J2YM~sQt;!-hR+$?Svi^YB7L9t4#6&uACv0dyD z2L+SVC3Q;|q&{gtx=d-{k~Ab;kw%HTDvgos8gXZ(9%)?aC+;GZUy+80Yn9rh%hFZi z&QN*3G)&wvsX;m~wGh`#3BlOD-uO6^L7;cCnCFql6@A3pVT#w}{(FQY+Qd^9ho)i>t+T|H(7Mzu_H_ z?Blb$ykFou+qlw?tj>3&X;UBCak1kvIO!r?onJV@I9>_x5uk| z%M~YQ(}`|iO7aYx&NKLah`YpUrqn_%D79(YkyJ!KgoU395|vpWXytT%0knKASM;@X*DSz(|O%o%BO#MSUJe;;3iOD7I2f?N%A!^ z-S(xo`2CA%7v|NMm@l8KRP@-!a#`W|nhrx}1pF>uP1CM~zQNbvZcjEbN!+GV#cx}b zNsRNjd4k5X0Je3p%}thsJd-7~)|_{J^Kv!c5+&)Mt#m#YOtvnEIjsgclW#9OC4M*Y zCCZuCq)F**>7S+RlsWG+<(uv|tu}p@GbiQEPnkbWd2^L=pOUZKudG%+OZoG2$~xuq z$`?3?Dw`>L{;$;L)c>7&BDE#;+0=JaZ=~K#owW#*NjF&^ux_^gm30f{)3`m|{t?Qh zFW7%?@3Z&YU$S4KocfCWRr_W8YxaM%U$OteK4O2}K1w_H z_W^qI!8!wk%m0er2V;YHNIXn9Lbs;)pmdPKwi#ASsfC zf5j#8uN+(H{w21yKm2!w*DdkIRr43>X+-AyrJNQ?Kl>bVl{ZhG9L3y$U*|b4w zGO`Rkbte9uqYTVhy2;4n(u6d1>)$Eq#vR#YejfRM%^?5g-0`nviudJ+56cdT>@z!d zJ1^Xs5h%260IdS;2j$2!sO;v*mb8s$m(%pG{U5i?|h~#`5+bQtK-O^jqlzF+bo^Lg&&!o;+AG8+O zGw2p`(f*?SAM6A6m+eFLVf#PXuR5Me<2O|LzgT0wF8_5k|9=4v6OIsS3H1d2FD0BH zoJ`0W?SwOl^0SH0IrQA|%;*(#I#cf#%7qG{it^tvp+RU8TIjrUTIdwc3Fqk_|FzCV z0lNfeG2{I8T;j~~zEcw9IQ4wc=_YZmd4@|l&kNI>$%*Hai!ieSbP4D#Pz!4Lpu=7; zebaac%WtKA#qab;$EceRdV(o*gc~hbrCowaJZ{=V_e6(WLbn}3-i!NAwfrMNlAn^F zqU+bn(?@>hju@{Z(PLVEI^Xl$(yzzXxdbTIpW%E3);M$;K}VUlA?~|0Fyt{6QEKzAa1%v%+^pNz4+yFII?^ zLaSIKz9{^y_=23oKh>fQ+|?iLh`3Po6;kFH0Adx1JZpducS;#pG$dnfi8V5H6=AgdMwqJ zYM07W)l|21F!j~c5vkI$%Tg!RSl+fu(r>JOt6%!PHE4}Xeby{%mh`gq9_u~Qp#2;6 zZ%D5QMS`G?5XK3UglR$2$b_0gun_1(rFjz1AwoJKEAhN2fu#wZ9Ky<55Vd@2Yb{{| zVKY7jZ7Y4!-AXH(2fB%ArG)(nu&kU=k*Lq8N}wj8e~du)JFSV(a!ddAm`)K+6Y>e2 zXoJUW)G_)Mv~z^>(37-_3E8E82k3^cU73eb!UXIgX;Xw7w?LsMA)6vT8DlfX$IrG8 zg;B2ar!=G%s>N!Fx>qez52}@FwR%*oQybN0wN-6XJBaV1(r%JmQ2U4usF&5N>X>>> zy{^tc(xJ)P0?nab*IZga?bBkUL;6}K)os%jYDVH;YJ6(nCvnpJv@eoSwmx=qBdCB8~;(NF28^-leqeqO(*Z6bO}+r)O$hx9A@ zsM?`V=u_%|e#0qgnfin?Ssl>ooi?7uJUZ^w!4q}*AfeegBP7qDdA*N1vz?3e3g6IfoLw~28_sT8(=z7;XPsG;g zz$b~S2a$j+saF43h?g{sl z`-VsIB-1J!bWeF~9^K>PHa!s!`IW)zswbO#jOuz8dzN`txK1SaJm%F(&uX>Vv(B^8 zv&FN`Q>ZOue{f&&6!VNcCDg)E8dVeVdp%{h_=BEGiVW=MJ+AG{lkXAlsb=1D6nq`c zDBx*y7JHgKGz(*0Jk4sir_Iyh>GEWdyc?sv;OW!aJp-OL+D+r0%fw&xjJXziu6eGj zW3F7!j5_AI=FDT>D}$%q;a%XWbvA30UWeD^4R~YTOz%SP67O@h#!QhMh^j-CJ+)yax^YW1qHrk8{7?6Z%?Dv-hO8 z-Fek}#(P#B@b-{SiF?Sq%iHVB_V(-PR63~b^bUJR^d{oR!B2v}E${J8(@Kr$HQrve z+b2*g%J(T+t=i|a(2VkF9eaGLTI}=qLfR2ux=ZFP;LGwY@-5Z+eL23B9Aka?E{88i z?eMMjZJ>1o@7&0-*SFcX)wjb}Hj7}afX zo%A(nYkVyvZ}FY-)@p0CT#}#Gdc1o)ZN5(5Ip29_#M`5-r!idgou1=q{4LIiOZHtN zuU4G8Z;1N6Lj8{VCfw&-1->aQldQLeJ=u4I=A|O0Rr)2jz7gTK#^1wkzOY>|drH^{?>fk(KKF+3rhfw|})3@UQc4q-?m? z&(WB&hJTA%=-&oOp=U8^7W+&5d;MjkY4acSSNf~{NBwmisr-%pW`C~_xd}? zEB5$u{4FjbNT~8SedU2ofdcY@;lTF5&cLp~ zp1{7qfxw}_;lPnVt+qW-A2=R35jYuW51di22hIk10=&wk}PN$t0|0*3#1dzd%!qi?fom2z34(7GqV5cs4s)Og}{L@=|o7d!E zOYow5%D*CbiOx2~-u141!J*)l;Hal8I1!u*-q70p>(oZ~){sQGw=R^d7Hd7cb|D+D zT}bEMVa&oer1g{B$2*s;m)IS&(?gL^hPII6lJ1Q7`#goDc|4RIS{z!Y4Tl!1d+7w# z6Iwy7y)v{ndMaXIP`OrGhjij?Bv@KK^T0yiJ`o*CVqI+F?LS>L9Mm zKM?8;T?qAo8vJG6FW&V$e(!q2)AW35xi)k)G^Pc-2SV34KC@@~%0t&fGhT;U7n<>v z`^UnvzBRlc>|h$|V5$pYS2*C!q*EV9j5D4>?_s?v91CaCNLs@S!%Nh@@bWONB=4#4 zs_+`$Xn09@y}qC58nR@i)*cRoH<3Nb8s5X9lHd@v&=4-rn?kGo)!xIDWrj&Y>*X3} z8s4rQ_Y{VAavTot3@;%a@+Dqb8fUjRQ_rE^cNwR$P)T@CVm$l82f~MFgmgL$A0|(z z46k9iw>PvUd?Z}!+~}RADB;iwytM9=C3}J^!}a0gYGe3B_++>}d?tL>UmZT=uM78t zd%f$`;&6X>kmzuDMC}fb(|)N8PinaoojP16!qfhah`>1_qC_m(k%$`1qOnU4+;+JZ=kGF@3DoloGAEEi|J5}Hd{MBwv$WD)qK;B%bYnCFZcS?S!UmW6k* z+`Uy-iRbfwTO^;>@oYq8p5)-&`Fsb7tmV_btH3)Q*+6Ie;qXq6kM0Y(?ou8P?~%yn zP%@2SYjBk1ksY_>MUd|XU&?%Vmv@1B)q9BV3t@-LLHY|L`?UqZ9NIyRzD}Nt?-cWq za`5TovD5;2Y{*v;sUW^8Qll0|jzM0<@<;>tCg#JANQ?hM>L!bu_P0J%@5`4fxIA^O+C%m=EuAwnips7gy;k{R8uP zFP-Aumm*W_$=+NV^Npw!UJy+NUj*LfY>nz_hrd-j5%sBsQ9Y6qjS!!~@@RH+vA;U% zdmq0H`YVE2(L8OHYl&NluGZveUUZ#$Ibw-!oX2kgzm54&2W8CcXd!uNO{kgqNGbE4 zd3>~(&nI+-%nQc?YrK2B)4tAVNjMhW>pjUgLGN(1jLtA?wC&M@dPB47w9)@YmF6zzz1 zIU~NTXt!@DdLi1U3(=MuSoE5n9=#sD7M-D59psG^k-Ufa7U>${h^<$|d#uhr;VoN+@vE{Mc*s9o?*m~oR9NVOi#tQhR8Qadc$k@)M<8F&v?fe_7aaT2Nsj+>r1Mj`78n@Bdq1fTrkyvf4K6X5IB6c#?9y=2|8|#Vn z#`S9xXL4mdoYrb+armG zj9C~Fl5fiKbiN}K#k~0DPA%hp&2fqAlAoXD3=+@c3=&_&lK4{IgYi&2M>`Q;X|#sh z_eeZHzBaxgzB#@%T$^}1fj0*69cppBNNuHaPDgxqyfnVwco$*Z`s3yCig;DLCVnj5 zV7zlM>}I@GFz)a1rg%&Il(8bl`+>w847{)4T9Kmo>3F9vKYlKLK5C2S#4pA##fRco z;-m2i@4kRT5NBR8&j{kpm-!dkGjH;@i!*;@dUGv)u_?&SpwHu7cnJL8flh%wB8aoU zNaz$3{aS+m1>RD>1^PPPmp%&0ZQ2tpp9T-j1lLBhWm;)RY8?#Tc{E0#mbq z(cXi0nxNUqd{Pnge+SJbls*mqzbEVvq+Wgud6ZYd)WB3)gwiPF8IYGlt{M`Q=0W~D z$n!AYD#J3ET?)qULutlM{#|+=%Y`>kT43<-tJlDnLMH?KAawSDe+_fl!R?r*(c=#E zz8w6JFz{>N?8J(ccBwup1dm;YsZoXGrW|k zbU%NiB_-b+U<>0L#X@84z{}w8h2}UUcVP@2kSvFnrh{LE)gNMBPK6|sHIoeg|2RCS zlzF8Qy>CG~MVMC+R@s1{*c}+j1?Wt|Zr_5%9!8IohS$Mj_ZYKAX&%qWv;w`9vRw8- zZiSyrVqO(&J@Oo0%`9lHV!0^^ZQhT*+F*Y>#_TrM7qfT=E!0Bi9m5B(7N0c6555Am za?NiNJ%Lqt!PtphDofBj!{3O?&!DwUSjQgN>J8Kl7;}wV>rbNKA-(_3$pt+Oz}w%Z6p}E2lNEz(-Lkp|6i&E?>kx?SLl_!vg2f z?^lr=|`CUdV z0{sm7vY@rcP}&7Ay@c$#X__HnJ^$hb!qu?f`#3|78|MNd6m~Phbx&FgzTki$L?B^E=iNgBX9A z@&)E$y{lYG)Q5ae277i{$!^ClPC`6&3v?30L`cVX?m%9iABlO+>MMSj-Jdu`0#qcOdz%Rnyf5oscXti+;fj@i-?I50*4;Z~eUXFG7pXjR`c6-T)!>Icv zG_RvIANXX%s2`!$Qe$6Z)i!Z!=1Rz0jHrcieiL*%Bqw3d3WfiwB^T{$h?DzZx9jkw zUqkcP=w&ZjdjMnGWkeY0ltJGFx)!r|1YX^5tUF7R5uX=qW}7E3K?a1UrBuT+k!zII zEJS!0|x_W)%; zn!g~b@8KPURp^4Pda)k|utph)ILTw%X85_WJMdSNCeU8P!icwv(eFn1)mmef(eioY zJO+u?IM3h&IBdwVD}Mt1W&D-X3rrtVfI@cFP|KKu~b+4NsgYQtI&qP4$9JFAT|Gy1xTk-ULkCX5p-TI&RF zg}es4<7MR82}1%u`H69&M(Lm7%+`vLPyJu^z6Q*ys_K95^L@YX9SNstB*FoL`OGF4n zgh)t4L^$(b>$lIjbMBoxdl$za^kZhAD}EK{!Zq|b zuC{M8t=EH74cqQV?M4{;$+k%bzi~N2-Q}U&a`bbI0=na4doT;>>PmsxK%Wf{&xZF# zs#M%H%v1LZ+~3UmuzqfjzTKJMV>LG7jrBrs9){#3^vpxZ8wM`1dQh(4n>547??Uqg zv`$ZxBg7x!H)FJ(Shs)OByD=gsAbx{-#o&1L&hwOBa$&j<1PUA)CTTJ#Xgpiuds~R z2hLl}q5IP#Sc7ri0njsB(a>Co5(A9Io4A`84f-v0rwRN!;MdfBbW<0?cxIvraJoWg z8FY4q$an;+m;PwqzgmxB4bX#Wj(^j7V$8;P=LD@MbL8J( zKk6d?<~|uK#VE-GgRghU=I>f=1MO&cmxY6!myp1+QaD=A85p>Q?4#!~T zXa!mit(SHq_HQrNZqaT}?$3UYHd4D!8>2m_J&HZpAJ-;pGt4~eHDL%LiU|f2loIg% zwS$QoE=GvaqC!j{Dm^-}IxRjCk%`S$aHMI|?-6eraG#m2!BvRo2Hdl%CrR$AbVTqV{r()=A5kleMlyb)z2FR~w)W(n{#pFs)o0rH$ohiP}57hB4Pt zAD&~ZpfOUw&p(Z~nKoVk|1rkqUHk;qXkuDUW~>iJ>i598#ry@$V_A@tzz;&hOVBwC zI0DXO==mXJg1}cWwg*DnK47K4Mz7%>2K)n^M!o)qxtjYQbF>n36Vdy5KMnm^=Ewqr z-@o}JW4$}*&Ma?bxf*^#_+{p6PZ(DbeYd^>qyE!GKaX5bGp5yhXFQ8zya@Qep>2kd zkGVacpDHl6%Axr*V`~rS6_6Rn@`eS@A!sN8oedj0f}YOUn5xs5ls6z(0b}zW=x=0f zfTKOkn8rf~p~SjLYWguNinss~hsK{6Vr}LT1@zOjPADM)7FCWuv z3!goxqVlR#eNgr^N}owK@;O~!CY$`W`Jt`6>A-d6FMzOL7DkpN>+adbws1Q6C+XL! z46uyK^aJPffa~IcXB+#B^Ko5PP??@@yt4gm$U3|_u8yot@#8f2OzEC{G9Ra{k8DW# z*3-@BO|A`0Z;fonc~@j_((m5cE1Q3FdwOTjcJ>$B#dSCsInpY>S2yo`JaQ^3qE<8< z%}TM;SC>|{R;BsDJLmdrKe~v^<$mwY*U_42ZFFU{&huH)F1L?H*G21-b!7R5=;ml6>DUq7 z?TvFUPjr9uQ1oc@1bpxHNjgVQ$28Uvb7IkCfA!ApTo-E>%ZYW2bp~A!D~k1q^@;V5 z4U7$m4dr<~Ru&rx-k8|9*u>am$W5g=k>|_wHYOj&W|01LK8^p_?ATncTWmo~8D4s9 zacn8qAvtc&*7ugBjqUV4l|Emk&r7b4*rwR>*eY)hiLHq}7keqTF}5YPE$OSOw0YH6 z*NoR9|D57NY-el_{LFA5b~tt{cG7>HiZ#WJcrYH1w~yzh=<=?!1o2Ms{CL-RH_*M} zeR0k8z?F{=h!4WKBt9%&9v>AS8y}DQw*m1<@hS$d-^HiJXW~33KF@zGjW3KZi7$(< z@Lzl4tK+y9#n;EH;74v>|FylF>Id-+@l9M`)NyNkdwf@XFY+CXAMyJuems6EAre+1 zoXARKCpskZ5?vC7iSCKsiGGRV#Nb3}Vt8UiVsxS+F(G{}%y{kdt||U`xUF;5S@e17 zd>vcn>u;In{Y@G4dvl_k-IR?jx(+LXTR zKYQcGNE=6K*FXPUigE8dC$IZyb5hE=EqkY>`7^D&CmN(uK)rt8$4ibwJHHq59%0yja9iTqZz>r*rd-^=x1c}Xw#^f00a{TLKZ~S>{ zV>ds~-+Y}&>`3fRj(Z+^H12r(`Sm6CCk|y?d%JoQM-wMf#$nnV<;_Kj(^*=|I-b*L z9A`OM(eTNvb`c{hC#z#tXV87K3L@RIiXx-3dSvy<>W|-)9vPoC5b2bbH6&{&_$0$; zPX~DUS!IwJnKg#X;(Jx|MZ#75K6LY4&3lQym+xxjkF6MSZf~a4=0O}CWDdoX$)7ac zLi8)3_c3kk1N|`5R!=6~ipW9+@_jMCLV^^Yn`I90nH`nw?43eZED){#q2 zMY(Sx*HQ3cr-Ypb;v%%Mkogtp{i-goa2M^B`ZR{%M6hke84*@vpA75Pa;!Ah$M^VOA`|d|1X$BO$W_oSwjf zu~4Z8kos4qX-+HSe*~cCZ{XxYrVug<>qW6dc;;=X-PKqXJ$e@giZL+=0m7Q?p6Lgi`2=}6+uN)u;$rAcCOqR=0 za;zLLC(%(Qr(u7Rc{sYsg;WY1q>VMwFFB7vE+N^V>_*p`qXzHY_#@uCLhr)Z$T7zu zR%9H{axRDQDsXW~%aEMh^7K`o&Z*k{#`PR?f@jEAnD+>dpUmNZ|DmBL z@Mz#-MI&zwc4XUvJv>w&7_N5QbVd>GM17#M$QNBif#@neDLy5N#HXnTd`9%3)*V1C zJ5US~gT<}lHc=vO7emDz)Q2XDNn(naivJc~m)H@6q&g9lpofhTW5sxqDHl~@nwTl( zh1B|nd5T3&_J zA91QS4D=hIR|C(2e1*$r`QzXe0`~{b!g$!lGL*_u&W(`o3=N%;>k#l`kZA(`Jg|ZI z=9ht$H&1a$G07~NcIGSJ(2X( z+ArA~$sealc8k4@v}(}cK^3?svT$Lt9SBIJAc^(PFJTJ zwO2LQmaJsT1Fk>kWJ$K`d|o};0$s~k{0?P6Q6m`uolZxYC(Lb zoLkuiwt>n>+FwcK9;Nl;K*D3Kqjct!DORO3-k!+2#5mKOnO3zk$C>9Wq`om9{j|VY zV%0gzNNR<%+F5I_a@MmC$*&unP3%c$tFxW-x1$oN4V_)iUedbRIcOI-N1Wr%selMr zfp8!zkR9j{$P09#epwwTL~BwBf$o9c49>1VA+;THa9W^Wpcs88=}qN1dud=WT0GgN z)Q9T>rDVZGt06F)`&M8?U^H}B1SUAstOQtPIoz)={2%Dj_e>5ZD}O4D6s|x4p`4vU39a1Ba{= zfun&Ffzv@P=mev|b||6JIvpf`20I2j+e5jGU_r1b*u&WXtEl8)pJ0FT-ezZ6V1IC6 zpi6K_aHx|TEVJr@Be|7=W9)YD#RThUa9nU=aB^^}T}HK{5g437FgrLkIG5&{HNgc* zf2|2F4lbn?KG%L0%^9xWt@&gn&UU-ts^FU7bHSH*6nQ)+7@SIFZ)6B=32qDS4DPX3 z+MSbtvF&UR9w50nE%QPW*4ae>jQikWf@8sx!EM}kf=wX< zXta)oriEsP<`92gXklncXqjCUD0X&*R)kiE*4kyE^`Q-+O`)x!?V(+PywKjz!O)S= zdYXUMQfoEvoJ;LNvs37J=oEZHc87(UDY*v|)hBF)!*s35Z$81RDzyRtUW2RkNyfZ0 zF2~=2wtyG4T&J~OkY9nP4$F}`6Y>YZ!MjR&86?$8VjlS8Ah`^jS)g-3Hvrcn*L2WZ zq3smt=Qz$w9}N!H6XKbs$)pXmK3?%5GaeCP<*;)PQcFM&L~0*!x*^gHU#O6!NR5Ke zJBCTyft{7$uT*<$f&)LuPQVf1Y}mHiEuHTnwnB4%#%6EEh6TI|{FB(Dt4^)J5N%Y2 zD5S4*UG(3my2Gk5zQJvEuw*zmNVT$+=W!>rk+Crd_AFKX1d*+? z6o-9CK4&{?kSh#3!_Yj5IRVtmIR^iupIB?*^V#eft%9+=AN+E(y8s_6SL?XyIncQY ze%{I0TC94b`fdhjtV;FCkaw^<>LKixI$hZVzFOUGR6WzZ+p9sFmZ5c+(-$pLin5+l z9)PuV@KPmODh~QTp=SehX2FupYV3eU9rXp!R*iM@Mtpf78+Zcvj$A{rCMPF_jku#fMZqQ;X>Dw?33+~8Oi#M!^&6SOhT_HbbH7);eFR-9yqn2r$WB7 ziV_7r0?%OoS;M`r;63Na<{I?C8jK6h+kidiPPx5;N5N57!#0e~ZSdzd^lDWWb2hv3 z+wg>M8}8J{Lq^5x)u3;49UXXS56c*zRre>59|in<@UMes>S0@7y8DvGQ)s){z@tphKaJa(tRL*J7qk) z#2U~#=BpS-Q_<6|h9zni&2{gH+6#^D$O#Kc*Ds!f{%^(n&~+!gN67F2#QwB2B>RSRc54HOWl)pHK}y=Pl~;1kX}CO z(B$*?F<<+*{zJZ?TV}AO&Pl%8hOoh{BOiW0CjA-r$$Mu`>*Z@>Us|#a`P|n%5AfM= zEVXR>&i9@Dwj1twP=@>`Q|lNhAs9wbo@S@NPU-bX^Fyn1TA8i-f**W+)~iFZKXvly z7#!RHle z<8U>>T7va0eoyAvK(Hy?G8Vn_R#(UNaOzxhvSqG|>>}9f(gz8S5F95s6~??C6^a+N z2*R!$&xzeKw4vwAbUu|8&2sDJE5l2VW~(}+%zNAn1} z5ES}+)z&=Z`99P2DUBcP?)sS^+MA$XIORGOEhZRDP@1NzQwv0g6O3@_(W-5d;OVJw z&l3nL38tv}w*}GZ3cP+7o#mdZ!ztI&=zM}j;goqgTH~H;T|Z{|>h4|N$yd>ps=laW z9l<&`Uwx{-q74L_2^tA@5bP${PjHCfD8UJW)8WH0?HuML|2RCuynL?xEqV6FRvXuz zHs^o;+~^zY>F1Q|a;9_p%y3pa&NlaE@?ZM+$#nfc+u1)CWjdcv`}qCT#x*lz`5De$ zoA}pH?BAHvGTvfQH4b9!2yzHIy3kpHw_Z)IzdYRpu>#*1Hd4oEa{PH~W3POkzv(&= zD{8R;V{effe|~+j9^uSuZ&z=uPuf^apQGHlDAqrmx{i;laU2`iQoq;`-@NO}#fGN! z6W8CdveZ7C^pWQWmKmwi`L5es!Vx}|<>8WUK)jNHrb- ze>r3ODaI1=8aNJQ?5iO87WlUVuVAbz{cnOsUgHgLeg&PoK;H;j@$Uj{0w=)f3wkp0 zP6Td3iDBT5NIeG0J3t2@1CAa7|DWJ@1?MNge`Fkl{Q=a)83p_VQWrt<9OSwV+RBhR z0I5@;a~b&CfoFj8XW$4pG2lvI4frqc$ztGf;5-dnfl|H%3_lp7ft3&20sk7D*}x-! z^MOl&;UD7x*rw`u1MGhm7^#l(!_ScV5a@c8mQAPN$JR&ra)%v>tPCuta7|t+fnD~%0 z*{KrksePUlA9lXxd`;v!-*CPuuEG}qI^v4}p9ozWx=ws5R2V80-9m>$hsCGE8^XU7 z-NUbhUlBbbiAa0VGm;(27B{}{<@FUpPA8Zp`0E%#&L>zzP(x5lu+sfqN3c$)uWIt| z1{XHFGU^MPEwI}s<9%`Ss8Cb{yJ1UaY1X(Gk$mwo+CBZCNE$7p*2$;``s&RjfCaFp{ zZ!P6rNyj2t=R4N5z4P0}*z*m0yQS>LrgnjAy(in5c4KR62eziY_I$E@zuk*1=NO@; zy(+R1yQ8>Ycft3d-S53v&x@9?yG#IHDw1D)VLi#O$FvjPS6>9au_LSpfvbRT0)7&s zbrj*}B!6i#if?uZr_{NFW*7cuhly`?1o6#|h%?D~Tx2`boM|*}raLoe+{|+RQ*;a! zggz-cg${+@5}m^h;RcZ(xiWI4xHj_P$cIIjOQ!caexy$jPJ=8LvfXnBf;@sQJ}4yU zPSD$h4leX_&&57nEIU~6w`~-JUELmV+VHc&b%?l0J=VA4oSC2Lkneu6d5ZA%Boz2c zyTCVGynP7q^(1#^LhiSw%by5*8zO1n292JnwDEJ~cfW{#8pOLNAyXzaSt(3WCh|n_ zzu|oZO_*8%|2v}<(Y$MF-LyM}rOni4ih}5M(L2Q_sAb~RGW{;Qr5_Z~gdwk!pP)|s zj{LjO5f__Y_5dS5v z7VGG^Ml^_RB46yG<1=C}9X-T;I(mvf(a}r%nT{L8TXggmC+PUBI4S-i`iOth(O0}n z$LFLbHPMf^G!r*Ti&iWBr6U94^D-nu;tMh&BcfQwWK7&F6EYzN$}8j*;*0V_@f zyi#5%Zjm3B9~Oh zUx=~tdHK9}K)xVf5Eb%8`J#AGzARrBpFU3Rh75R!7FMlO}B_5W)mcJGgUz4wiN9F7Cbume9m)pf-atGZFRmz=mr+8fcUjAN8mVc0c5dR_Hly8bE zxlisBUyXbr@&z#^^37;KJdyl9J0ea9KF1Nk)*${DJi0N;5e+PnD_XuJ+s~IqvWa=E zbnr@9hJKi)!!OYv5;bR#_&g+*p23a*sdmJQA;D|-92bQ6LdM#p$`og`HdW^4jP|C= z49sY82UiaF7UGK;Y}P2h(xmD&D1*)EGPh)~IbCLO2Ak7mZp~n`MiRdp+-x0V{7!FnA&SN5wGx+{bAIy|7XDXFpy*0+|rJA?JD zrOGo{-&*RP4A%2|8$8N&f^6*HCB%q~y`r_;y&3yOYq^mbdq!)y`!e>8Y*$iC%8km{ z?ycp%oU!Fw%Z<+1_O0da&)E9eNlEF-jmg-ut>wOwv29z+jm_A)t>qrbV4vaoS4paV zP?5pDOmYuqurHI`xD57Xl6$C?ecqcd-2^}Pks7}l8`FNQ{Z#ueZMF74T0 zNBfQlgkB155W&#N&`A-YG+SGuJ) z`T8QgMz7UZ>UH`$ykXi#`5%Y(mwC(+UK2< z@}9mn&gbekW0kSSc+Pmq*l28_`fT(3}!lP2bhDrb}~!MVP?5G%Hx}3&GF_W zv&x)i&NSzk^V;-_YgclV9Rj`|*v6=t2paLf@@8=U42&py6<02P0DL3kW<=Jj_-Of8 z;7=kIQT8fQRelQ`MCA*_&Wn#D?=OKnKqdhG3}D0vH$M#xh;x@;2SzS27xWdNtAS0( zC)B(F4kDTbVriT4u7HX@mf#4~w|N`%qb&I&;G2-T3aQZC^nJ$f{+{t^I#Q#a?+s`V0EfWmcPU^u zu59@jBjf3spr>3f_(~DvD~k5rz@35ezK=fd>QQ0uP6dhfcUU+WFS>4-?i% z%eT)lU#ATD_|23H$vyXsxxMQ-BF;&A{&`*txx8AslBe$C%3qjoaCaVUpsRQTb|0;6 z*?*MNWDZI5v4akN#&Lpp9RW#gyho{Ml$~4cVw%(;i-_(a`%r4V>`$p|1IvJ*oA=yNjQ4v4-XaoD`uaJ>wfGq@W=Js`7(J&MbArITL;|yldY4FG&J=h@MBu#~ zfwzbRW(Kt;X~x?#5;K6rn;dE`5{RQ0KL=KC4!xDq8`U~-g4;HXm-t#d2luEg>6&n~ z?`q!_0{?wU>rv}bp*aJb0YaztpCk-w^W&mZ=mfR=)v;r-zlyvRo$cLwqahbnYc{RG zI^Za|sCx5ALl^hCz#~L+pQl*`BQ?~f$2z+5{&dFsd_EXLJ{X!J_ug&w>prsujhE1Z z##VjGU;e9ZYG*nZ(A{MFGy3#G+l^P`UFjH^wB*v1(}mUtg*ZmJPna%MNow2-xg>o? zjh+&MVV6vM2khN&@wMkr3v{HTlwkNJ)ZY=ij9+~Hxx%8WDj!1$$}T|(m!ju1Uecb^ zcu9Ls<0bAn>H05r&uP5mJ*P3l_5VUOznby-f3dWtU;i(bUiQFncV?fM)EU%%m|VSH zMXT5CqO-O`+basS{j`$3!J24I6gOf$+ZXHE&tW~=59?X}2O?%Y8n`P^7PvcbPhdn~ zRA6-AD}jds69SI}Ccy^3r>b2~O}u~_ymlv#wOP%m(La+OC8h3k{WC0HzI~!gb{Im<$C>k*hT2q=U?M| zs&l7SUh}T;=U0dFu|p1dso8|$*bY}ZNb@m*?5_KdG6(3Dqo(v1?A% zVV+lQHaEFK_*bymYv*}bL;kB+%~!uMzI*S>ef1mbyF0&pwiM86y@-wqg3<0%)XQfL zkKdseW&FOEE9tO{G78VHWN$1DzbIqr{L3EU-Up`NOI*l&{meOApzak%;$E>V+56sK z8#)M^a^}%k%)>689WIL%+yl#f&lE1tI>_q{m%{?@xq;UkE{6@5rWMY21$FUT;oL2_ zbggi1HmGOxUYw?XHT*rn|Je1R(KM_Op3}i{&xU)}2{d22KcAVF_cmjaQDsacm}$&0<{1l( zCB`y>6~<~~t+C$NU~D4TYHT-l8GDU`#u0+!#wk;nmKip)2(pb`W(PCR>|z!YbT@mO z{mf!xt2vl*9W+bL;pPZeaDNm7RcEdvsHa~I z=4P|e++psfocql~r1L20JnHJ4Z=N8XC(P59W;v-kt*F(`JYlu7a;%P4XRE+GY84Um zu=<$QR)1@tHH2WO)y|k>m66;Kf|1r3Yn(OFIA~2Km}MyH`qb4Zi~~;+~E|Pb<`?*&B4xKvS5hv zyi@87Cm4aTIp1t_MiW%HJ{#;zFn3#%QGzE~Ns<^x4tda-j{2Q+W;xXa^SMUk!A0cf zMdY16&Z4wB)Ht=yN`g9Pompx{oqDIisW-Eo%}yi#vYMQF+i*79agh=U;OT2k5oic=$n9*B?G}nRECClZncZ2+9Ok-Ep!#< zQwXef2}J~myOZmm!0!#L_Hc!ayBFqoaE=1Q9(O-i#C}M%Cp=n2?PRI;>69w2NkxyS z*b>mjVPNb5DVBilhg>Swt2=Npu-ZZM7toAorRE&c#Gb5!Cy7=uY-*2N4N+|pv1e9- zBbBuOX4+IyTZr}2{^EL@HOz7)*^+0$zZEhc0u6bI7&C!ZRxy5>+Iv;?C3sKm5-Ld)evPTR9g&mTbB8-$3S$v zUetU{xG^&(`i6nAY#>TdMR}>cX^pAC*dbWQI5H4dW;_mz_(mNqsB6fj_5gkz_Dq8f zYGybN%he9Vsz0M2(wMFD_6e4VnnT>9dJlx}DAAq-k0w`;=NDn6)B0|F;8AyN+E=J3 z4k0F;wxq2qSzT%{&_wvl@y_a6;zU?sZGL@h0^CGv(qO|nE7wnx(T8CVOT4&Om zCA@d2CM8oyF7#VBy%@C_azUlG);iFwP02;p+g5FMT$0-CxJ0#4@7A=#)x@jMW62rd zLZ9|}t_}wi(+rb-WJ!R9lE_od(;~+<@id{><@%R9N)m6 zp80{WMzvS_4_td?e}LLcy&YPdv_{R=@7>=cF+Qpz(k`sD^3=%`sKc|b)bd2IlT;^Z0ApB{6^_{aa#a;2+|6q&cbgZus92M;?Nq+>iHn#L>V%YwC2%3L;Of zjrbd4$?=?zl-*WCeksV?OX8G&2V4!nFNiJuTjOeyRCwe*MJfNT!I{V37h59?S9#j* z?~JWU(%?yivUMTyT(n#n8TU8FSMnt(xk_y>>3Tn4ZmDZP<&|&C!Y5Nn4blk0N*yN| zdY$a}rBL;Mx=JG{T2M(@t5epN>(MB*1)Wdb>+2GTNWP@CO zuHhk9Yh>z~xLVUTLIOLHJj=TK^>pN1wjG~pzL>71u@t@MG*a$7z1W}LGL)?z3-4=FFl{n%%Fi48nSk*NQW zaXe8m_AD>++0*aJ$}i8Bepj~go=yF(tTlZ0^t-aw@!8bx%38~EeNFzyoq}s2oymj} zN8PiJWBAtwRoU79O8%FWT&+*azw1+p($zKT94R})eF1Ve97nx1{(r}R#i_Rc^|HUd za)0c}>?V!&cx1+^3+jc zprn8O{*1DhGjx}Ql&Syf9SG&A(O@~x#9oQ=)M;?X!x(ZVc081)R{ekS$CER;Z=pQ3 zn-WsyGq?Mo>?IE0Lm)`agdXIg|hM%UWuAk}eHLQYmi; zt+%^dxaRJt9Ms)i?prJ5sm&93+l1Y<+mZGQ+^Q?@(#^(Ob7!J^4$T9<0=k4QL;rqs zC0zqP>**%Cg>I*XbT2(XkI*HIF)tIWB8z89tQt#WwO9sg#G0{|tPN}Le=$Az%JlGM zoiJR;TTMi}4^#4$H+dWz&^xC>zPfvI!7= z3O&H4vsr8|%V&$&o6r)g*xInNKw3nfIo79*)k$JJtIE{rVRhzp8~WhMV0F?_od8y+ ze)V}@JWovV-UD@_m)(VSb%GX8Ept4xs88kMDN=^#S=CwFVmwbw(@5ZSBfAm5CZQeA z+A=)T$?)VT{~hgkMpoTmpihXtg?4r37|)NYldtLwr8<2pZ$=^1@S%M=epTmO@g%g? z!LRN~P$!So8C*Ows!u|zv%>Q+9d%Mxoz=!OzQ$0rzeK(BsMAcVZb*n~Ep$R@F;V-7}yOALg27@)z%u_xJh z_Dmp@?AKDaT`K-tD*0vs6;hs6mJ}jSmp9h0bT`*;EB&@bQ*vU69j>}&pcRBujIS!Fp|EYd?h+S&NmnK7df&RV(!wVRj$CJrq znl@)@bB;FiLcSM(xkS7D=CTk|ewQ~56p-~~6PR1T+#WFf;dH$e;~f{psG+|Y@4+a> zll?{eLh5C5u-~!z!QNVo^{CJEk4Jx`$>P2k7wJ%)BQK5*_HL+Uc@I?!oDs=-d za`ZT`E82L%JTLj*<=tI0a1d?4d=7`%%1?<0$s=BIE-{@r>9} ztiz&tq@?@)h6G08(r&k)qy`DS0dPpE;VE*I6N&XMQMW}g(hT@pOzZFYrsLg^eEy0}w{<-)L#rY$)RMCcDyXaQHQ}0Jn??TbCU`r_~ElNU& z^jU=5^62J}7H>;J?>9tE1n@qBb@RlZ)CU6&lB3T#$sH{eD9RuIc-)SHyjA`a+$x`v zOZik8OBoq^D8~M?ds0e|J@KSsPdcgCPoGrmXUZJAB2cRASHakS9uIPW_C7Z6VVL*0 z6D+xk{p3l-9$yZ;Q$z3`Rw_jY;}I~h2@TR17* z^(XRlJ3&1w!?k^sHl=JhN!zDtGt@o<-q{$g0&=J<;7q-NE9HPoa;CBP^u{L(_qC;j zjKBE^Q3FcgZd3_T3N2oNa0x=ZG3+Qxk430grl^0&$fCxY8X^2GDP(-As&s)?EFDuml#k?N`2;?NPggi9pAv9X*oER1iczV! zsCv_7z%+HNS$rb z80jUn9p>mCS=724!+Sre(rJcLg}yyg-7kr2XB6-2q!&r3*T`_)isDL^zD-i;m%}+2 z*@N&2^ub#@l@>Ls*2T6X?23@0KWgVAn4`MSRNu|&!7xgXoVukH?^o69YmcCug#Mv- zl`3s)v@WLh4u)KZ5Z4MRmQAh1F~o=}{c=sv-T-4EzDkQA!!i&oZRpLU$KE2Uv>Ng@ z_;ob;p^r2#zO5H9Pbb1S0Gfn2XDZT zJ2b~q+K_ODiff4FJ?lrvJbWYX(Oe&LkLEJ42k*bcTQq4rO_Dcc0))qZk0$!z6LODc zE%>q?ph|1KOb1g5qyhQlkuBhp0q#b$8Er}1Ku+yx8`=pdSf!HY?>|cCARiZ`X|=k{ z)!n*ko%q9GeJLtew5WQKqFqG+N~fOI#)!12bu22{!nF#sT9D54n(odZHFKmej<;+o zO?;}o4P2$;-v!&!$k%OlYHmF}yC46WUe!~I^Z#yomGIQu^y+Vw^neZ-xhgS}{fEtF zFR}$JpM4CY>Zj~8w%Pp&aZ7?2Nu(M{gSQ%~1$Mc9m;ttC0o<1%yfFkv)t{aVDb*!9 z_c&bflsi-WdM3+97aWplgRj)r8vd^^{7<3!PbmMzjljQZ>XrZGq<;ZjiT-OM{}zV- zE2IVTFCATp|Ndln|Etr(e~9w`9i)Nb)w6{U~4`^SGVKUKv2;o@#Is^UdNuN+nx5Zu2U+JuU4eebq z)@HPiK)a18EJFKw^dFD*AJ9HnhY1;_QIp}R8l{(^xjw+TBoCB4t`I^Tkvxp#>G2vK z9MiWTKl7?5ga^V%ETK-T5Yxd_0%@cH7tFx%xgw6y0{Yw*goQ9xXUMUdb_+JZD*RsCghoDTj3kqyEsj&9mj+ zbyU{5O;FxrFoOx7-M|x=+vvFt4V4^$zC-3Vg(@8g8%RUVZNR4y#K)NpP(B07Zx6KJ z+b@3xYUgc)_|KH002Im_}!#Y)SP@E%DoPAO?vsZH%wPWW(^jEuCl%{Z{8U1s# z<9`i~yL328sa)-E!PyJT#klLxuI92|AjFvr$N7)(Fxs&^{3Y~3xsv0blrzwBURCEH zho4N#$y5Sql+beVkW+hr!C7gbaz?FviE+OrNa}WdnjhUCB zy~&wvvp|d0l24$`YL&2(AZK9fq1}#Yv+$J!@M#9|RbT4_Ibn+hdRuTMVOo%i*{30G zhE%L}uIaj764GYNLh5u=NSlod=}$S4ZKnE`@mR3sj6}2_2(}YbD;qw9YTXCtga+RE zVf==$V@S)*&@Gn&usw4A?ZID;jxfY61ILfol3B$CLvU7nQEt>y7gik`k)lXkwa2k z8&YzKUM<2NtoAYLTSV0TB>4hOYwkRx~1vPf-&I2Ni^L*5u6 zrf(n(akUnRf3Xe!T1u#7s&+b**6!hw>9J3sKj@vAYFA|EQ<_(rHj@G)9m-y6m!^`a zPGeq5VpFSxBXnL$``A2E*8L0R>pzkSZ=xrOvV4?TI$NsUIlV@yj znHOp~T=LH#H*F?INZKrH%?nZqNyE=UyFtjkv^UM7IW(6Jr6cKBI)P51)9EZaH_)$e zj|)>WN4JoAS9b|183m3Y8&)^_Fh%Q+2ir;YCDk)I{)<;P>8N#Y%_&t+R_m|o zpNNuCdgh7bn`@TiEH4M)&v>uOWO<(p-xktKab1opywoj4DrGE{x(R6W?P0X&@UAvK_?hj`7BkOu)-+d1`(EILg z*)*|V*PJYxP7;XGyh&S_7u?+HjwI6lw${y(NY3qT0Zt&KxR}HclSBg_s7$KEe5N+J zj&vZMym0St^_Zpa0WRkncz51&MR}`y|%Ylc~g?Y#I8MTtqGd~)HFC!UYD#BU_>mzK6uw{>|`|dT`AZ(AY6T)r?d-v><)z!#Cn1e7E;ZTGl zduDg-Zj41Z8Q~0sa}gHw$?B71EJe5i;cA5I5N_-<;J$vwR|vmFxD(+|2=_zLx*CTh zG`$Gp5LQK4t6$c@d(FlOnq=M zIE0fBPK9K$%^3)1Bbn1V1JVI73^5jGwGRADto*a~4=gqa9C54g8`f2#+=EQEs)4o5h4 zzB}9zb|RLJvde z%>mp!0%07&M1<84rVq^O)7?`KVMByX5w<`mSDZNTnly4nIc$_%Pzp5QF@YCFpMYKM z`jk>p9Pq!Iz{hF>kE{#4?keC~R|7X`0DRyY;EUG+e`^99;X2@-*N4R{$;N==#+AX8 zD_;^OlnU)qAP1fpPcABljUrz@K8z^^n!sf%0Dr8Ar9V*@C6|>7adncYy$tH6L|pOJ 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

          05&ln@^G}5PG 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 D4XsKX literal 0 HcmV?d00001