Python compiler for simple language to java vm code algorithm - python

I have a simple language that I am trying to write a compiler for (yes it is homework) to compile a simple language I shall describe if necessary to java vm code.
It currently works pretty well I've just hit a bump with logical AND's and OR's.
Each work fine in a single if/while condition, but if I try and chain them things go wrong, correct me if I am wrong but I believe that AND has precedence, but I was wondering if there are logical ways of arranging them? I think is what I'm trying to ask, the java vm code output just has the compare and jump statements one after the other (which seems wrong). I realise it's quite abstract so maybe what I'm after is a pseudo code/algorithm for how to structure chained AND's and OR's.
EDIT: Currently just treats any combination of AND and OR as AND's. Comparing the factor/term/expression connection (compared to booleanfactor etc) I believe that AND has precedence? Just a thought.
Apologies if this is poorly understood :/
So i figure ill include relevant info just incase.
compiler
import re
import sys
# Restrictions:
# Integer constants must be short.
# Stack size must not exceed 1024.
# Integer is the only type.
# Logical operators cannot be nested.
class Scanner:
'''The interface comprises the methods lookahead and consume.
Other methods should not be called from outside of this class.'''
def __init__(self, input_file):
'''Reads the whole input_file to input_string.'''
# source code of the program to be compiled
self.input_string = input_file.read()
# index where the unprocessed part of input_string starts
self.current_char_index = 0
# a pair (most recently read token, matched substring of input_string)
self.current_token = self.get_token()
def skip_white_space(self):
'''Consumes all characters in input_string up to the next
non-white-space character.'''
if (self.current_char_index >= len(self.input_string) - 1):
# bad fix for it over-running the end of the file
return
while self.input_string[self.current_char_index].isspace():
self.current_char_index += 1
return
def get_token(self):
'''Returns the next token and the part of input_string it matched.
Returns None if there is no next token.
The characters up to the end of the token are consumed.'''
self.skip_white_space()
# find the longest prefix of input_string that matches a token
token, longest = None, ''
for (t, r) in Token.token_regexp:
match = re.match(r, self.input_string[self.current_char_index:])
if match and match.end() > len(longest):
token, longest = t, match.group()
# consume the token by moving the index to the end of the matched part
self.current_char_index += len(longest)
return (token, longest)
def lookahead(self):
'''Returns the next token without consuming it.
Returns None if there is no next token.'''
return self.current_token[0]
def consume(self, *tokens):
'''Returns the next token and consumes it, if it is in tokens.
Raises an exception otherwise.
If the token is a number or an identifier, its value is returned.'''
if self.current_token[0] not in tokens:
print('Token ' + self.current_token[0] + ' isn\'t in the tokens: ')
for token in tokens:
print(token)
raise Exception('Token is not in tokens this shouldn\'t happen much')
if self.current_token[0] == 'ID':
symbol_table.location(self.current_token[1])
value = self.current_token[1]
elif (self.current_token[0] == 'NUM'):
value = self.current_token[1]
else:
value = self.current_token[0]
self.current_token = self.get_token()
return value
class Token:
DO = 'DO';
ELSE = 'ELSE';
END = 'END';
IF = 'IF';
THEN = 'THEN';
WHILE = 'WHILE';
SEM = 'SEM';
BEC = 'BEC';
LESS = 'LESS';
EQ = 'EQ';
GRTR = 'GRTR';
LEQ = 'LEQ';
NEQ = 'NEQ';
GEQ = 'GEQ';
ADD = 'ADD';
SUB = 'SUB';
MUL = 'MUL';
DIV = 'DIV';
LPAR = 'LPAR';
RPAR = 'RPAR';
NUM = 'NUM';
ID = 'ID';
READ = 'READ';
WRITE = 'WRITE';
OR = 'OR';
AND = 'AND';
NOT = 'NOT';
# The following list gives the regular expression to match a token.
# The order in the list matters for mimicking Flex behaviour.
# Longer matches are preferred over shorter ones.
# For same-length matches, the first in the list is preferred.
token_regexp = [
(DO, 'do'),
(ELSE, 'else'),
(END, 'end'),
(IF, 'if'),
(THEN, 'then'),
(WHILE, 'while'),
(READ, 'read'),
(WRITE, 'write'),
(OR, 'or'),
(AND, 'and'),
(NOT, 'not'),
(SEM, ';'),
(BEC, ':='),
(LESS, '<'),
(EQ, '='),
(NEQ, '!='),
(GRTR, '>'),
(LEQ, '<='),
(GEQ, '>='),
(ADD, '[+]'), # + is special in regular expressions
(SUB, '-'),
(MUL, '[*]'),
(DIV, '/'),
(LPAR, '[(]'), # ( is special in regular expressions
(RPAR, '[)]'), # ) is special in regular expressions
(ID, '[a-z]+'),
(NUM, '[0-9]+'),
]
class Symbol_Table:
'''A symbol table maps identifiers to locations.'''
def __init__(self):
self.symbol_table = {}
def size(self):
'''Returns the number of entries in the symbol table.'''
return len(self.symbol_table)
def location(self, identifier):
'''Returns the location of an identifier. If the identifier is not in
the symbol table, it is entered with a new location. Locations are
numbered sequentially starting with 0.'''
if identifier in self.symbol_table:
return self.symbol_table[identifier]
index = len(self.symbol_table)
self.symbol_table[identifier] = index
return index
class Label:
def __init__(self):
self.current_label = 0
def next(self):
'''Returns a new, unique label.'''
self.current_label += 1
return 'l' + str(self.current_label)
def indent(s, level):
return ' '*level + s + '\n'
# Each of the following classes is a kind of node in the abstract syntax tree.
# indented(level) returns a string that shows the tree levels by indentation.
# code() returns a string with JVM bytecode implementing the tree fragment.
# true_code/false_code(label) jumps to label if the condition is/is not true.
# Execution of the generated code leaves the value of expressions on the stack.
class Program_AST:
def __init__(self, program):
self.program = program
def __repr__(self):
return repr(self.program)
def indented(self, level):
return self.program.indented(level)
def code(self):
program = self.program.code()
local = symbol_table.size()
java_scanner = symbol_table.location('Java Scanner')
return '.class public Program\n' + \
'.super java/lang/Object\n' + \
'.method public <init>()V\n' + \
'aload_0\n' + \
'invokenonvirtual java/lang/Object/<init>()V\n' + \
'return\n' + \
'.end method\n' + \
'.method public static main([Ljava/lang/String;)V\n' + \
'.limit locals ' + str(local) + '\n' + \
'.limit stack 1024\n' + \
'new java/util/Scanner\n' + \
'dup\n' + \
'getstatic java/lang/System.in Ljava/io/InputStream;\n' + \
'invokespecial java/util/Scanner.<init>(Ljava/io/InputStream;)V\n' + \
'astore ' + str(java_scanner) + '\n' + \
program + \
'return\n' + \
'.end method\n'
class Statements_AST:
def __init__(self, statements):
self.statements = statements
def __repr__(self):
result = repr(self.statements[0])
for st in self.statements[1:]:
result += '; ' + repr(st)
return result
def indented(self, level):
result = indent('Statement(s)', level)
for st in self.statements:
result += st.indented(level+1)
return result
def code(self):
result = ''
for st in self.statements:
result += st.code()
return result
class If_AST:
def __init__(self, boolean_expression, then):
self.boolean_expression = boolean_expression
self.then = then
def __repr__(self):
return 'if ' + repr(self.boolean_expression) + ' then ' + \
repr(self.then) + ' end'
def indented(self, level):
return indent('If-Then', level) + \
self.boolean_expression.indented(level+1) + \
self.then.indented(level+1)
def code(self):
l1 = label_generator.next()
return self.boolean_expression.code(l1) + \
self.then.code() + \
l1 + ':\n'
class If_Else_AST:
def __init__(self, boolean_expression, then, _else):
self.boolean_expression = boolean_expression;
self.then = then;
self._else = _else;
def __repr__(self):
return 'if ' + repr(self.boolean_expression) + ' then ' + \
repr(self.then) + ' else ' + \
repr(self._else) + ' end'
def indented(self, level):
return indent('If-Then-Else', level) + \
self.boolean_expression.indented(level+1) + \
self.then.indented(level+1) + \
indent('Else', level+1) + \
self._else.indented(level+1)
def code(self):
l1 = label_generator.next()
l2 = label_generator.next()
return self.boolean_expression.code(l1) + \
self.then.code() + \
'goto ' + l2 + '\n' + \
l1 + ':\n' + \
self._else.code() + \
l2 + ':\n'
class While_AST:
def __init__(self, boolean_term, body):
self.boolean_term = boolean_term
self.body = body
def __repr__(self):
return 'while ' + repr(self.boolean_term) + ' do ' + \
repr(self.body) + ' end'
def indented(self, level):
return indent('While-Do', level) + \
self.boolean_term.indented(level+1) + \
self.body.indented(level+2)
def code(self):
l1 = label_generator.next()
l2 = label_generator.next()
return l1 + ':\n' + \
self.boolean_term.code(l2) + \
self.body.code() + \
'goto ' + l1 + '\n' + \
l2 + ':\n'
class Assign_AST:
def __init__(self, identifier, expression):
self.identifier = identifier
self.expression = expression
def __repr__(self):
return repr(self.identifier) + ':=' + repr(self.expression)
def indented(self, level):
return indent('Assign', level) + \
self.identifier.indented(level+1) + \
self.expression.indented(level+1)
def code(self):
loc = symbol_table.location(self.identifier.identifier)
return self.expression.code() + \
'istore ' + str(loc) + '\n'
class Write_AST:
def __init__(self, expression):
self.expression = expression
def __repr__(self):
return 'write ' + repr(self.expression)
def indented(self, level):
return indent('Write', level) + self.expression.indented(level+1)
def code(self):
return 'getstatic java/lang/System/out Ljava/io/PrintStream;\n' + \
self.expression.code() + \
'invokestatic java/lang/String/valueOf(I)Ljava/lang/String;\n' + \
'invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V\n'
class Read_AST:
def __init__(self, identifier):
self.identifier = identifier
def __repr__(self):
return 'read ' + repr(self.identifier)
def indented(self, level):
return indent('Read', level) + self.identifier.indented(level+1)
def code(self):
java_scanner = symbol_table.location('Java Scanner')
loc = symbol_table.location(self.identifier.identifier)
return 'aload ' + str(java_scanner) + '\n' + \
'invokevirtual java/util/Scanner.nextInt()I\n' + \
'istore ' + str(loc) + '\n'
class Comparison_AST:
def __init__(self, left, op, right):
self.left = left
self.op = op
self.right = right
def __repr__(self):
op = { Token.LESS:'<', Token.EQ:'=', Token.GRTR:'>',
Token.LEQ:'<=', Token.NEQ:'!=', Token.GEQ:'>=' }
return repr(self.left) + op[self.op] + repr(self.right)
def indented(self, level):
return indent(self.op, level) + \
self.left.indented(level+1) + \
self.right.indented(level+1)
def true_code(self, label):
op = { Token.LESS:'if_icmplt', Token.EQ:'if_icmpeq',
Token.GRTR:'if_icmpgt', Token.LEQ:'if_icmple',
Token.NEQ:'if_icmpne', Token.GEQ:'if_icmpge' }
return self.left.code() + \
self.right.code() + \
op[self.op] + ' ' + label + '\n'
def false_code(self, label):
# Negate each comparison because of jump to "false" label.
op = { Token.LESS:'if_icmpge', Token.EQ:'if_icmpne',
Token.GRTR:'if_icmple', Token.LEQ:'if_icmpgt',
Token.NEQ:'if_icmpeq', Token.GEQ:'if_icmplt' }
return self.left.code() + \
self.right.code() + \
op[self.op] + ' ' + label + '\n'
class Expression_AST:
def __init__(self, left, op, right):
self.left = left
self.op = op
self.right = right
def __repr__(self):
op = { Token.ADD:'+', Token.SUB:'-', Token.MUL:'*', Token.DIV:'/' }
return '(' + repr(self.left) + op[self.op] + repr(self.right) + ')'
def indented(self, level):
return indent(self.op, level) + \
self.left.indented(level+1) + \
self.right.indented(level+1)
def code(self):
op = { Token.ADD:'iadd', Token.SUB:'isub',
Token.MUL:'imul', Token.DIV:'idiv' }
return self.left.code() + \
self.right.code() + \
op[self.op] + '\n'
class Number_AST:
def __init__(self, number):
self.number = number
def __repr__(self):
return self.number
def indented(self, level):
return indent(self.number, level)
def code(self): # works only for short numbers
return 'sipush ' + self.number + '\n'
class Identifier_AST:
def __init__(self, identifier):
self.identifier = identifier
def __repr__(self):
return self.identifier
def indented(self, level):
return indent(self.identifier, level)
def code(self):
loc = symbol_table.location(self.identifier)
return 'iload ' + str(loc) + '\n'
class BooleanFactor_AST:
def __init__(self, condition, logic):
self.condition = condition
self.logic = logic
def __repr__(self):
if self.logic == False:
return 'NOT ' + repr(self.condition)
else:
return repr(self.condition)
def indented(self, level):
if self.logic == False:
return indent('NOT ', level) + self.condition.indented(level + 1)
else:
return self.condition.indented(level)
def false_code(self, label):
if self.logic == True:
return self.condition.false_code(label)
else:
return self.condition.true_code(label)
return
def true_code(self, label):
if self.logic == True:
return self.condition.true_code(label)
else:
return self.condition.false_code(label)
class BooleanTerm_AST:
def __init__(self, terms):
self.terms = terms
def __repr__(self):
result = repr(self.terms[0])
for term in self.terms[1:]:
result = result + ' AND ' + repr(term)
return result
def indented(self, level):
result = self.terms[0].indented(level)
for term in self.terms[1:]:
result = result + indent('AND', level)
result = result + term.indented(level)
return result
def code(self, label):
result = ''
for term in self.terms:
result = result + term.false_code(label)
return result
class BooleanExpression_AST:
def __init__(self, expressions):
self.expressions = expressions
def __repr__(self):
result = repr(self.expressions[0])
for expression in self.expressions[1:]:
result = result + ' OR ' + repr(expression)
return result
def indented(self, level):
result = self.expressions[0].indented(level)
indentation = 0
for expression in self.expressions[1:]:
indentation += 1
result = result + indent('OR', level + indentation)
result = result + expression.indented(level + indentation)
return result
def code(self, label):
result = ''
for expression in self.expressions:
result = result + expression.code(label)
return result
# The following methods comprise the recursive-descent parser.
def program():
sts = statements()
return Program_AST(sts)
def statements():
result = [statement()]
while scanner.lookahead() == Token.SEM:
scanner.consume(Token.SEM)
st = statement()
result.append(st)
return Statements_AST(result)
def statement():
if scanner.lookahead() == Token.IF:
return if_statement()
elif scanner.lookahead() == Token.WHILE:
return while_statement()
elif scanner.lookahead() == Token.ID:
return assignment()
elif scanner.lookahead() == Token.READ:
return read();
elif scanner.lookahead() == Token.WRITE:
return write();
else: # error
return scanner.consume(Token.IF, Token.WHILE, Token.ID)
def if_statement():
scanner.consume(Token.IF)
condition = boolean_expression()
scanner.consume(Token.THEN)
then = statements()
if scanner.lookahead() == Token.END:
scanner.consume(Token.END)
return If_AST(condition, then)
else:
scanner.consume(Token.ELSE)
_else = statements()
scanner.consume(Token.END)
return If_Else_AST(condition, then, _else)
def while_statement():
scanner.consume(Token.WHILE)
condition = boolean_expression()
scanner.consume(Token.DO)
body = statements()
scanner.consume(Token.END)
return While_AST(condition, body)
def assignment():
ident = identifier()
scanner.consume(Token.BEC)
expr = expression()
return Assign_AST(ident, expr)
def read():
scanner.consume(Token.READ)
variable = identifier()
return Read_AST(variable)
def write():
scanner.consume(Token.WRITE)
expr = expression()
return Write_AST(expr)
def comparison():
left = expression()
op = scanner.consume(Token.LESS, Token.EQ, Token.GRTR,
Token.LEQ, Token.NEQ, Token.GEQ)
right = expression()
return Comparison_AST(left, op, right)
def expression():
result = term()
while scanner.lookahead() in [Token.ADD, Token.SUB]:
op = scanner.consume(Token.ADD, Token.SUB)
tree = term()
result = Expression_AST(result, op, tree)
return result
def term():
result = factor()
while scanner.lookahead() in [Token.MUL, Token.DIV]:
op = scanner.consume(Token.MUL, Token.DIV)
tree = factor()
result = Expression_AST(result, op, tree)
return result
def factor():
if scanner.lookahead() == Token.LPAR:
scanner.consume(Token.LPAR)
result = expression()
scanner.consume(Token.RPAR)
return result
elif scanner.lookahead() == Token.NUM:
value = scanner.consume(Token.NUM)
return Number_AST(value)
elif scanner.lookahead() == Token.ID:
return identifier()
else: # error
return scanner.consume(Token.LPAR, Token.NUM, Token.ID)
def identifier():
value = scanner.consume(Token.ID)
return Identifier_AST(value)
def boolean_factor():
if scanner.lookahead() == Token.NOT:
scanner.consume(Token.NOT)
logic = False
else:
logic = True
result = comparison()
return BooleanFactor_AST(result, logic)
def boolean_term():
result = [boolean_factor()]
while scanner.lookahead() in [Token.AND]:
scanner.consume(scanner.lookahead())
temp = boolean_factor()
result.append(temp)
return BooleanTerm_AST(result)
def boolean_expression():
result = [boolean_term()]
while scanner.lookahead() in [Token.OR]:
scanner.consume(scanner.lookahead())
temp = boolean_term()
result.append(temp)
return BooleanExpression_AST(result)
# Initialise scanner, symbol table and label generator.
#scanner = Scanner(open('test.txt'))
scanner = Scanner(sys.stdin)
symbol_table = Symbol_Table()
symbol_table.location('Java Scanner') # fix a location for the Java Scanner
label_generator = Label()
# Uncomment the following to test the scanner without the parser.
# This shows a list of all tokens in the input.
#
#token = scanner.lookahead()
#while token != None:
# print(token)
# scanner.consume(token)
# token = scanner.lookahead()
#exit()
# Call the parser.
ast = program()
assert scanner.lookahead() == None
# Uncomment the following to test the parser without the code generator.
# The first line gives back the program by calling __repr__ of the AST classes.
# The second line shows the syntax tree with levels indicated by indentation.
#
#print(ast)
#print(ast.indented(0))
#exit()
# Call the code generator.
# This translates the abstract syntax tree to JVM bytecode.
# It can be assembled to a class file by Jasmin: http://jasmin.sourceforge.net/
print(ast.code())
testing bat file
python compiler.py <test.txt> Program.j
java -Xmx100m -jar jasmin.jar Program.j
java -Xmx100m Program < testInput.txt > test_output.txt
and language (BNF)
Program = Statements
Statements = Statement (; Statement)
Statement = If | While | Assignment
If = if Comparison then Statements end
While = while Comparison do Statements end
Assignment = identifier := Expression
Comparison = Expression Relation Expression
Relation = = | != | < | <= | > | >=
Expression = Term ((+ | -) Term)
Term = Factor ((* | /) Factor)
Factor = (Expression) | number | identifier
BooleanExpression = BooleanTerm (or BooleanTerm)*
BooleanTerm = BooleanFactor (and BooleanFactor)*
BooleanFactor = not BooleanFactor | Comparison
I think thats all that is relevant, cheers if you take a go at helping me on this

if you want a method to chain OR's and AND'syou can use this property:
p v q === ¬p ^ ¬q
Is equivalent, you can process all in the AND form. for example.
p v q ^ r v s === ¬p ^ ¬q ^ ¬r ^ ¬s
So evaluate the expression in AND form is simple with an algorithm.
I guess the expression doesn't have any parenthesis, in other way you need prioritize the grouping symbols (), [], {}.

Related

Can't print __str__ from the class

I wondered how can I print the class contents of a particular index. I made a class that has all the values of a certain seismic movement and stores each in its own data type.
Here is the class:
import re
class Txt_data:
def __init__(self, result):
self.date = result[0]
self.time = result[1]
self.latit = result[2]
self.long = result[3]
self.depth = result[4]
self.md = result[5]
self.ml = result[6]
self.mw = result[7]
self.region = result[8]
self.method = result[9]
def date(self):
return self._date
def time(self):
return self._time
def latit(self):
return self._latit
def long(self):
return self._long
def depth(self):
return self._depth
def md(self):
return self._md
def ml(self):
return self._ml
def mw(self):
return self._mw
def region(self):
return self._region
def method(self):
return self._method
# This does not work
def __str__(self):
return ('MAG: ' + float(self.ml()) + ' DEPTH: ' + int(self.region()) + ' DATE/TIME: ' + str(self.date()) + ' ' + str(self.time()) + ' LAT: ' + float(self.latit()) + ' LON: ' + float(self.long()))
result = [('2021.12.02', '22:29:24', '36.9605', '28.1775', '13.0', '-.-', '1.5', '-.-', 'KARACA-MARMARIS (MUGLA)', ' Quick')]
print(Txt_data(result))
I was trying to print the data using str method but it doesn't work.
Here is the error:
Traceback (most recent call last):
File "/Users/seyfalsultanov/Documents/uni comp 100/comp100-2021f-ps5-seyfalku/main.py", line 73, in <module>
print(Txt_data(result))
File "/Users/seyfalsultanov/Documents/uni comp 100/comp100-2021f-ps5-seyfalku/main.py", line 60, in __str__
print('MAG: ' + float(self.ml()) + ' DEPTH: ' + int(self.region()) + ' DATE/TIME: ' + str(self.date()) + ' ' + str(self.time()) + ' LAT: ' + float(self.latit()) + ' LON: ' + float(self.long()))
AttributeError: Txt_data instance has no __call__ method
My question is how to print the string i tried to print using str method in the class.
Thanks very much beforehand.
Your immediate problem is that you shadowed all your methods with instance attributes, instead of using _-prefixed names for the attributes that the method expect.
def __init__(self, result):
self._date = result[0]
self._time = result[1]
self._latit = result[2]
self._long = result[3]
self._depth = result[4]
self._md = result[5]
self._ml = result[6]
self._mw = result[7]
self._region = result[8]
self._method = result[9]
However, none of those getters are necessary; just use the instance attributes directly. In __str__, use an f-string to perform any necessary type conversions (which you are currently doing wrong; non-str values need to be converted to str values, not the other way around).
class Txt_data:
def __init__(self, result):
self.date = result[0]
self.time = result[1]
self.latit = result[2]
self.long = result[3]
self.depth = result[4]
self.md = result[5]
self.ml = result[6]
self.mw = result[7]
self.region = result[8]
self.method = result[9]
def __str__(self):
return f'MAG: {self.ml} DEPTH: {self.region} DATE/TIME: {self.date} {self.time} LAT: {self.latit} LON: {self.long}'
result = ('2021.12.02', '22:29:24', '36.9605', '28.1775', '13.0', '-.-', '1.5', '-.-', 'KARACA-MARMARIS (MUGLA)', ' Quick')
print(Txt_data(result))
Finally, I would recommend making __init__ not be responsible for splitting up a list. Have it simply take 10 different arguments, and use a dedicated class method to parse a list in a fixed format.
class Txt_data:
def __init__(self, date, time, latitude, long, depth, md, ml, mw, region, method):
self.date = date
self.time = time
self.latit = latit
self.long = long
self.depth = depth
self.md = md
self.ml = ml
self.mw = mw
self.region = region
self.method = method
#classmethod
def from_list(cls, x):
if len(x) != 10:
raise ValueError("Wrong number of elements in list")
return cls(*x)
def __str__(self):
return f'MAG: {self.ml} DEPTH: {self.region} DATE/TIME: {self.date} {self.time} LAT: {self.latit} LON: {self.long}'

ANTLR4 Arith Expression visitor order operation

I am trying to understand how visitor context work in python version of ANTLR4
I am using the Python3 grammar and I trying to visit "arith_expr"
with this input example x = 10 + 50 - 50 I have this context in the visitor
len(ctx.term()) = 3 is the value of atom [10,50,50]
len(ctx.ADD()) = 1
len(ctx.MINUS()) = 1
What is the order of the operator?
arith_expr
: term (('+'|'-') term)*
;
class Arith_exprContext(ParserRuleContext):
def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1):
super().__init__(parent, invokingState)
self.parser = parser
def term(self, i:int=None):
if i is None:
return self.getTypedRuleContexts(MBIParser.TermContext)
else:
return self.getTypedRuleContext(MBIParser.TermContext,i)
def ADD(self, i:int=None):
if i is None:
return self.getTokens(MBIParser.ADD)
else:
return self.getToken(MBIParser.ADD, i)
def MINUS(self, i:int=None):
if i is None:
return self.getTokens(MBIParser.MINUS)
else:
return self.getToken(MBIParser.MINUS, i)
def getRuleIndex(self):
return MBIParser.RULE_arith_expr
def enterRule(self, listener:ParseTreeListener):
if hasattr( listener, "enterArith_expr" ):
listener.enterArith_expr(self)
def exitRule(self, listener:ParseTreeListener):
if hasattr( listener, "exitArith_expr" ):
listener.exitArith_expr(self)
def accept(self, visitor:ParseTreeVisitor):
if hasattr( visitor, "visitArith_expr" ):
return visitor.visitArith_expr(self)
else:
return visitor.visitChildren(self)
this is the override visitor def
def visitArith_expr(self, ctx:MBIParser.Arith_exprContext):
print(len(ctx.term())) #3
self.visit(ctx.term(0)) #10
self.visit(ctx.term(1)) #50
self.visit(ctx.term(2)) #50
print(len(ctx.ADD())) #1
print(len(ctx.MINUS())) #1
return self.visitChildren(ctx)
Thank you for your explanation
You could collect all operators inside a list like this:
arith_expr
: term (operators+=('+'|'-') term)*
;
The operators is a list and contains all operators. You can then do something like this in your visitor:
def visitArith_expr(self, ctx):
result = self.visit(ctx.term(0))
for i in range(len(ctx.operators)):
if ctx.operators[i].type == MBILexer.ADD:
result += self.visit(ctx.term(i + 1))
else:
result -= self.visit(ctx.term(i + 1))
return result
def visitTerm(self, ctx):
return int(ctx.getText())
Or better, do something like this:
expr
: expr ('+' | '-') expr #add_expr
| term #term_expr
;
in which case the visitor will get a lot easier:
# expr ('+' | '-') expr #add_expr
def visitAdd_expr(self, ctx):
if ctx.ADD() is not None:
return self.visit(ctx.expr(0)) + self.visit(ctx.expr(1))
return self.visit(ctx.expr(0)) - self.visit(ctx.expr(1))
# term #term_expr
def visitTerm_expr(self, ctx):
return self.visit(ctx.term())
def visitTerm(self, ctx):
return int(ctx.getText())

Can someone help me passing a function as argument in python?

I have the following class in python. I want to pass the function get_priority as argument to access the object Task. I obtain the following error when adding the second task to taskManager:
if value == array[int(middle)].acessMethod(): AttributeError: Task
instance has no attribute 'acessMethod'
Task Class
class Task:
def __init__(self,id,name,category="",priority=1):
self.id = id
self.name = name
self.category = category
self.priority = priority
self.concluded = False
self.active_days = 0
print("Beggining Class")
def get_name(self):
return self.name
def get_category(self):
return self.category
def get_priority(self):
return self.priority
def set_name(self,name):
self.name = name
def set_category(self,category):
self.category = category
def set_priority(self,priority):
self.priority = priority
def __str__(self):
return str(self.id) + " | " + self.name + " | " + self.category + " | " + str(self.priority) + " | "
TaskManager Class
from task import Task
class TaskManager(object):
"""docstring forTaskManager."""
def __init__(self):
print("Initing TaskManager")
self.taskArray = []
"""Adding task ordered by priority"""
"""Maibe adding a check for autheticity of the object """
def addTask(self,task):
if len(self.taskArray) == 0 or self.taskArray[0].get_priority() <= task.get_priority():
self.taskArray.insert(0,task)
else:
index = self.__binarySearchIndex(task.get_priority,self.taskArray,'get_priority')
self.taskArray.insert(index,task)
def __binarySearchIndex(self,value,array,acessMethod):
middle = (len(self.taskArray) / 2) if ((len(self.taskArray) % 2) == 0) else (len(self.taskArray) / 2) + 1
if middle == 1:
middle = 0
if value == array[middle].acessMethod():
return middle
elif value < array[middle].acessMethod():
self.__binarySearchIndex(value,array[:middle])
else:
self.__binarySearchIndex(value,array[middle:])
def __str__(self):
taskString = ""
for task in self.taskArray:
taskString = taskString + str(task) + " \n"
return taskString
I've actually went another way instead of calling the method by its name, I simply make a lambda function to extract whatever attribute I want from the Task object.
class Task:
def __init__(self,id,name,category="",priority=1):
self.id = id
self.name = name
self.category = category
self.priority = priority
self.concluded = False
self.active_days = 0
print("Beggining Class")
def get_name(self):
return self.name
def get_category(self):
return self.category
def get_priority(self):
return self.priority
def set_name(self,name):
self.name = name
def set_category(self,category):
self.category = category
def set_priority(self,priority):
self.priority = priority
def __str__(self):
return str(self.id) + " | " + self.name + " | " + self.category + " | " + str(self.priority) + " | "
class TaskManager(object):
"""docstring forTaskManager."""
def __init__(self):
print("Initing TaskManager")
self.taskArray = []
"""Adding task ordered by priority"""
"""Maibe adding a check for autheticity of the object """
def addTask(self,task):
if len(self.taskArray) == 0 or self.taskArray[0].get_priority() <= task.get_priority():
self.taskArray.insert(0,task)
else:
index = self.__binarySearchIndex(task.get_priority(),self.taskArray, lambda task: task.get_priority())
self.taskArray.insert(index,task)
def __binarySearchIndex(self,value,array,accessMethod):
if len(array) == 0:
return 0
middle = (len(self.taskArray) / 2) if ((len(self.taskArray) % 2) == 0) else (len(self.taskArray) // 2) + 1
if middle == 1:
middle = 0
if value == accessMethod(array[middle]):
return middle
elif value < accessMethod(array[middle]):
return middle + self.__binarySearchIndex(value,array[:middle],accessMethod)
else:
return middle - self.__binarySearchIndex(value,array[middle:],accessMethod)
def __str__(self):
taskString = ""
for task in self.taskArray:
taskString = taskString + str(task) + " \n"
return taskString
if __name__ == "__main__":
taskA = Task(1, "taskA", priority=2)
taskB = Task(2, "taskB", priority=1)
taskC = Task(3, "taskC", priority=1)
taskD = Task(4, "taskD", priority=3)
manager = TaskManager()
manager.addTask(taskA)
manager.addTask(taskB)
manager.addTask(taskC)
manager.addTask(taskD)
for task in manager.taskArray:
print(task)
I've also helped debug your program a little. For starters, your recursive calls to the binary search doesn't return values, which is a behavior that you want.
Use getattr to get the function from the string you pass
method_to_call = getattr(Task, accessMethod)
if value == array[middle].method_to_call():
Don't pass a string containing the name at all. Use the methodcaller function.
For example:
from operator import methodcaller
class TaskManager(object):
def __init__(self):
self.taskArray = []
def addTask(self, task):
if (len(self.taskArray) == 0
or self.taskArray[0].get_priority() <= task.get_priority():
self.taskArray.insert(0,task)
else:
index = self.__binarySearchIndex(
task.get_priority(),
self.taskArray,
methodcaller('get_priority')
)
self.taskArray.insert(index, task)
def __binarySearchIndex(self, value, array, accessMethod):
middle = (len(self.taskArray) / 2) if ((len(self.taskArray) % 2) == 0) else (len(self.taskArray) / 2) + 1
if middle == 1:
middle = 0
if value == accessMethod(array[middle]):
return middle
elif value < accessMethod(array[middle]):
self.__binarySearchIndex(value,array[:middle])
else:
self.__binarySearchIndex(value,array[middle:])
...
If you simplify your Task class to get rid of the unnecessary getters and setters:
class Task:
def __init__(self,id,name,category="",priority=1):
self.id = id
self.name = name
self.category = category
self.priority = priority
self.concluded = False
self.active_days = 0
print("Beggining Class")
def __str__(self):
return str(self.id) + " | " + self.name + " | " + self.category + " | " + str(self.priority) + " | "
then you can use attrgetter instead of methodcaller.
from operator import attrgetter
class TaskManager(object):
def __init__(self):
self.taskArray = []
def addTask(self, task):
if (len(self.taskArray) == 0
or self.taskArray[0].get_priority() <= task.get_priority:
self.taskArray.insert(0,task)
else:
index = self.__binarySearchIndex(
task.get_priority,
self.taskArray,
attrgetter('get_priority')
)
self.taskArray.insert(index, task)
def __binarySearchIndex(self, value, array, accessMethod):
middle = (len(self.taskArray) / 2) if ((len(self.taskArray) % 2) == 0) else (len(self.taskArray) / 2) + 1
if middle == 1:
middle = 0
if value == accessMethod(array[middle]):
return middle
elif value < accessMethod(array[middle]):
self.__binarySearchIndex(value,array[:middle])
else:
self.__binarySearchIndex(value,array[middle:])
...

TypeError: unbound method getInterfaceName() must be called with Interface instance as first argument (got nothing instead)

class Unit:
def init(self, _chassisId, _unitNo, _interface):
self.chassisId = _chassisId
self.unitNo = _unitNo
self.interface = _interface
def getInterface(self):
return self.interface
#staticmethod
def parse(elem):
unitList = elem.find(UNIT+LIST)
chassisList = []
for unit in unitList.findall(UNIT):
try:
unitNumber = unit.find(UNIT_NUMBER).text
interface = unit.find(INTERFACE)
interface = ""
chassisIdElem = unit.find(CHASSIS_ID)
chassisId = ""
if chassisIdElem is not None:
chassisId = unit.find(CHASSIS_ID).text
elif unit.find(BURNED_IN_MAC) is not None:
chassisId = unit.find(BURNED_IN_MAC).text
chassisId = chassisId.replace(".", "").replace(":", "").upper()
chassis = Unit(chassisId, interface, unitNumber)
chassisList.append(chassis)
except Exception as e:
print "Unit details not found", e
return chassisList
def getChassisId(self):
return self.chassisId
def __str__(self):
str = "\n"
str += "\nUnit Details:- "
len = str.__len__();
str += "\n"
for i in range(1,len-1):
str += "-"
str += "\nUnit: " + self.unitNo
str += "\nChassis Id: " + self.chassisId
str += "\nInterfaces: " + self.interfaces
return str
def __add__(self, other):
return str(self) + other
def __radd__(self, other):
return other + str(self)
class Interface:
def init(self, _linkState, _interfaceName):
self.linkState = _linkState
self.interfaceName = _interfaceName
#staticmethod
def parse(elem):
prefix = Device.getPrefix(elem.tag)
interfaceList = elem.find(INTERFACE + LIST)
interfaceNameTag = eval(prefix + "_INTERFACE_NAME")
linkStateTag = eval(prefix + "_LINK_STATE")
interfaces = []
for interface in interfaceList.findall(INTERFACE):
try:
interfaceName = interface.find(interfaceNameTag).text
linkStateElem = interface.find(LINK_STATE)
linkState = ""
if linkStateElem is not None:
linkState = interface.find(LINK_STATE).text
elif interface.find(LINE_PROTOCOL) is not None:
linkState = interface.find(LINE_PROTOCOL).text
interface = Interface(linkState, Name)
interfaces.append(interface)
except Exception as e:
print "Interface details not found", e
return interfaces
def getLinkState(self):
return self.linkState
def getInterfaceName(self):
return self.interfaceName
def __str__(self):
str = "\n"
str += "\nInterface Details:- "
len = str.__len__();
str += "\n"
for i in range(1,len-1):
str += "-"
str += "\nLink State: " + self.linkState
str += "\nInterface Name: " + self.interfaceName
return str
def __add__(self, other):
return str(self) + other
def __radd__(self, other):
return other + str(self)
You haven't shown us the call to getInterfaceName() that causes the error, which makes it harder to help you.
However, I'll guess that the call looks something like this:
something = Interface.getInterfaceName()
You can't do it that way. You must create an instance of Interface, and then call its .getInterfaceName() method:
myInterface = Interface()
something = myInterface.getInterfaceName()

Printing a tree with branches recursively

I'm trying to print a tree recursively in Python. For some reason, the indentation isn't working (perhaps I'm too tired at this point to see an obvious flaw). Here's the structure / class definitions that I'm working with:
class Tree(object):
def __init__(self, data):
self.data = data
self.branches = []
class Branch(object):
def __init__(self, value):
self.label = value
self.node = None
As you see, each tree has Branches, which have a label and point to another Tree (that's the node value you see there). Here's how I'm trying to print out the tree:
def __str__(self):
return self.tree_string(0)
def tree_string(self, indent):
indentation = indent * " "
result = indentation + str(self.data) + "\n";
for branch in self.branches:
result += indentation + branch.label + ": \n" + branch.node.tree_string(indent + 2)
return result
This is giving me:
4
Somewhat:
Yes
Fuller:
3
Correct:
8
Caribbean:
2
Wrong:
Wrong
Correct:
Correct
Italian:
Wrong
Burger:
Correct
Wrong:
Wrong
Nothing:
Wrong
When it should be giving me something like
4
Somewhat:
Correct
Fuller:
3
Correct:
8
Caribbean:
2
Wrong:
Wrong
Correct:
Correct
Italian:
Wrong
Burger:
Correct
Wrong:
Wrong
Nothing:
Wrong
What's causing my code to have those extra newlines and not have the proper indents?
Update
Pretty sure the data is ok. Here's a modified version that shows it's ok:
def tree_string(self, indent):
indentation = indent * " "
result = str(self.data);
if len(self.branches) > 0:
result += "["
for branch in self.branches:
result += branch.label + ":" + branch.node.tree_string(indent + 2) + " "
result += "]"
return result
..which gives the output
4[Somewhat:Correct Fuller:3[Correct:8[Caribbean:2[No:No Correct:Correct ] Italian:Wrong Burger:Correct ] Wrong:Wrong ] Nothing:Wrong ]
However, the indent values are for some reason always 0 or 2.
Looks like it should work to me:
class Tree(object):
def __init__(self, data):
self.data = data
self.branches = []
def __str__(self):
return self.tree_string(0)
def tree_string(self, indent):
indentation = indent * " "
result = indentation + str(self.data) + "\n";
for branch in self.branches:
result += indentation + branch.label + ": \n" + branch.node.tree_string(indent + 2)
return result
class Branch(object):
def __init__(self, value):
self.label = value
self.node = None
tree = Tree(4)
b1 = Branch('Somewhat')
b1.node = Tree('Yes')
b2 = Branch('Fuller')
b2.node = Tree(3)
tree.branches = [b1, b2]
b3 = Branch('Correct')
b3.node = Tree(8)
b2.node.branches = [b3]
print(tree)
yields
4
Somewhat:
Yes
Fuller:
3
Correct:
8

Categories