automated commit TP3
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
/AritListener.py
|
||||
/AritVisitor.py
|
||||
@@ -0,0 +1,33 @@
|
||||
grammar Arit;
|
||||
|
||||
prog: statement+ EOF #statementList
|
||||
;
|
||||
|
||||
statement
|
||||
: expr SCOL #exprInstr
|
||||
| 'set' ID '=' expr SCOL #assignInstr
|
||||
;
|
||||
|
||||
expr: expr multop=(MULT | DIV) expr #multiplicationExpr
|
||||
| expr addop=(PLUS | MINUS) expr #additiveExpr
|
||||
| atom #atomExpr
|
||||
;
|
||||
|
||||
atom: INT #numberAtom
|
||||
| ID #idAtom
|
||||
| '(' expr ')' #parens
|
||||
;
|
||||
|
||||
|
||||
SCOL : ';';
|
||||
PLUS : '+';
|
||||
MINUS : '-';
|
||||
MULT : '*';
|
||||
DIV : '/';
|
||||
ID: [a-zA-Z_] [a-zA-Z_0-9]*;
|
||||
|
||||
INT: [0-9]+;
|
||||
|
||||
COMMENT: '#' ~[\r\n]* -> skip;
|
||||
NEWLINE: '\r'? '\n' -> skip;
|
||||
WS : (' '|'\t')+ -> skip;
|
||||
@@ -0,0 +1,23 @@
|
||||
PACKAGE = Arit
|
||||
MAINFILE = arit
|
||||
|
||||
ifndef ANTLR4
|
||||
abort:
|
||||
$(error variable ANTLR4 is not set)
|
||||
endif
|
||||
|
||||
all: $(PACKAGE).g4
|
||||
$(ANTLR4) $^ -Dlanguage=Python3 -visitor
|
||||
|
||||
run: $(MAINFILE).py
|
||||
python3 $^
|
||||
|
||||
ex: $(MAINFILE).py
|
||||
python3 $^ < myexample
|
||||
|
||||
test: all
|
||||
python3 ./test_arith_visitor.py
|
||||
|
||||
clean:
|
||||
find . \( -iname "~" -or -iname "*.cache*" -or -iname "*.diff" -or -iname "log.txt" -or -iname "*.pyc" -or -iname "*.tokens" -or -iname "*.interp" \) -exec rm -rf '{}' \;
|
||||
rm -rf $(PACKAGE)*.py
|
||||
@@ -0,0 +1,58 @@
|
||||
from AritVisitor import AritVisitor
|
||||
from AritParser import AritParser
|
||||
|
||||
|
||||
class UnknownIdentifier(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MyAritVisitor(AritVisitor):
|
||||
"""Visitor that evaluates an expression. Derives and overrides methods
|
||||
from ArithVisitor (generated by ANTLR4)."""
|
||||
def __init__(self):
|
||||
self._memory = dict() # store id -> values
|
||||
|
||||
def visitNumberAtom(self, ctx):
|
||||
try:
|
||||
value = int(ctx.getText())
|
||||
return value
|
||||
except ValueError:
|
||||
return float(ctx.getText())
|
||||
|
||||
def visitIdAtom(self, ctx):
|
||||
try:
|
||||
return self._memory[ctx.getText()]
|
||||
except KeyError:
|
||||
raise UnknownIdentifier(ctx.getText())
|
||||
|
||||
def visitMultiplicationExpr(self, ctx):
|
||||
# Recursive calls to children. The visitor will choose the
|
||||
# appropriate method (visitSomething) automatically.
|
||||
leftval = self.visit(ctx.expr(0))
|
||||
rightval = self.visit(ctx.expr(1))
|
||||
# an elegant way to match the token:
|
||||
if ctx.multop.type == AritParser.MULT:
|
||||
return leftval * rightval
|
||||
else:
|
||||
return leftval / rightval
|
||||
|
||||
def visitAdditiveExpr(self, ctx):
|
||||
leftval = self.visit(ctx.expr(0))
|
||||
rightval = self.visit(ctx.expr(1))
|
||||
if ctx.addop.type == AritParser.PLUS:
|
||||
return leftval + rightval
|
||||
else:
|
||||
return leftval - rightval
|
||||
|
||||
def visitExprInstr(self, ctx):
|
||||
val = self.visit(ctx.expr())
|
||||
print('The value is ' + str(val))
|
||||
|
||||
def visitParens(self, ctx):
|
||||
return self.visit(ctx.expr())
|
||||
|
||||
def visitAssignInstr(self, ctx):
|
||||
val = self.visit(ctx.expr())
|
||||
name = ctx.ID().getText()
|
||||
print('now ' + name + ' has value ' + str(val))
|
||||
self._memory[name] = val
|
||||
@@ -0,0 +1,28 @@
|
||||
from AritLexer import AritLexer
|
||||
from AritParser import AritParser
|
||||
# from AritVisitor import AritVisitor
|
||||
from MyAritVisitor import MyAritVisitor, UnknownIdentifier
|
||||
|
||||
from antlr4 import InputStream, CommonTokenStream
|
||||
import sys
|
||||
|
||||
# example of use of visitors to parse arithmetic expressions.
|
||||
# stops when the first SyntaxError is launched.
|
||||
|
||||
|
||||
def main():
|
||||
lexer = AritLexer(InputStream(sys.stdin.read()))
|
||||
stream = CommonTokenStream(lexer)
|
||||
parser = AritParser(stream)
|
||||
tree = parser.prog()
|
||||
print("Parsing : done.")
|
||||
visitor = MyAritVisitor()
|
||||
try:
|
||||
visitor.visit(tree)
|
||||
except UnknownIdentifier as exc:
|
||||
print('Unknown identifier: {}'.format(exc.args[0]))
|
||||
exit(-1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,5 @@
|
||||
1 ;
|
||||
12 ;
|
||||
1+2 ;
|
||||
1+2*3+4;
|
||||
(1+2)*(3+4);
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python
|
||||
from AritLexer import AritLexer
|
||||
from AritParser import AritParser
|
||||
import pytest
|
||||
from MyAritVisitor import MyAritVisitor
|
||||
|
||||
from antlr4 import InputStream, CommonTokenStream
|
||||
import sys
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input, expected", [
|
||||
pytest.param('1+1;', 2),
|
||||
pytest.param('2-1;', 1),
|
||||
pytest.param('2*3;', 6),
|
||||
pytest.param('6/2;', 3),
|
||||
pytest.param('set x=42; x+1;', 43),
|
||||
pytest.param('set x=42; set x=12; x+1;', 13)
|
||||
])
|
||||
def test_expr(input, expected):
|
||||
lexer = AritLexer(InputStream(input))
|
||||
stream = CommonTokenStream(lexer)
|
||||
parser = AritParser(stream)
|
||||
tree = parser.prog()
|
||||
print("Parsing : done.")
|
||||
visitor = MyAritVisitor()
|
||||
|
||||
def patched_visit(self, ctx):
|
||||
self.last_expr = self.visit(ctx.expr())
|
||||
|
||||
visitor.visitExprInstr = patched_visit.__get__(visitor)
|
||||
visitor.visit(tree)
|
||||
assert visitor.last_expr == expected
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(sys.argv)
|
||||
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
grammar Tree;
|
||||
|
||||
|
||||
int_tree_top : int_tree EOF #top
|
||||
;
|
||||
|
||||
int_tree: INT #leaf
|
||||
| '(' INT int_tree+ ')' #node
|
||||
;
|
||||
|
||||
|
||||
INT: [0-9]+;
|
||||
WS : (' '|'\t'|'\n')+ -> skip;
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user