All but examples
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
## Calculator Language to Jcoco Assembler
|
||||
### Nicholas Pease
|
||||
|
||||
## Contents
|
||||
/hacky-solution - Alternate Solution which Requires Python 3.2.6 and makes use of the Jcoco disassembler (Included as I thought it was interesting)
|
||||
/hacky-solution/calc1.py - Calc.py file for hacky solution (DO NOT GRADE, INCLUDED AS IT WAS INTERESTING TO ME)
|
||||
/hacky-solution/disassembler.py - Python to Jcoco disassembler
|
||||
|
||||
calc.py - Python compiler for calculator language to Jcoco. For use see below
|
||||
|
||||
## Usage
|
||||
Feed lines of the calculator language in via the standard input. The compiler will listen for the EOF signal (CTRL+D) and then generate jcoco code to the standard output.
|
||||
|
||||
Valid operations are (+,-,/,//,*,**,%), unary minus (-num), assignments (=)
|
||||
|
||||
To feed in a file in linux and execute output in Jcoco:
|
||||
cat filename | python3 calc.py > tester.casm && ./coco tester.casm
|
||||
|
||||
Jcoco also requires Java runtime to be installed, and the jcoco binaries downloaded
|
||||
@@ -3,5 +3,25 @@
|
||||
[](https://gitea-actions.nicholaspease.com/latest-log?branch=main)
|
||||
[](https://drone.nicholaspease.com/umaine-npease/COS301-HW4)
|
||||
[](https://wakaapi.nicholaspease.com/summary?interval=any&project=COS301-HW4)
|
||||

|
||||

|
||||
<hr>
|
||||
|
||||
## Calculator Language to Jcoco Assembler
|
||||
### Nicholas Pease
|
||||
|
||||
## Contents
|
||||
/hacky-solution - Alternate Solution which Requires Python 3.2.6 and makes use of the Jcoco disassembler (Included as I thought it was interesting)
|
||||
/hacky-solution/calc1.py - Calc.py file for hacky solution (DO NOT GRADE, INCLUDED AS IT WAS INTERESTING TO ME)
|
||||
/hacky-solution/disassembler.py - Python to Jcoco disassembler
|
||||
|
||||
calc.py - Python compiler for calculator language to Jcoco. For use see below
|
||||
|
||||
## Usage
|
||||
Feed lines of the calculator language in via the standard input. The compiler will listen for the EOF signal (CTRL+D) and then generate jcoco code to the standard output.
|
||||
|
||||
Valid operations are (+,-,/,//,*,**,%), unary minus (-num), assignments (=)
|
||||
|
||||
To feed in a file in linux and execute output in Jcoco:
|
||||
cat filename | python3 calc.py > tester.casm && ./coco tester.casm
|
||||
|
||||
Jcoco also requires Java runtime to be installed, and the jcoco binaries downloaded
|
||||
Binary file not shown.
@@ -8,8 +8,7 @@
|
||||
# Originally located on PLY Github at https://github.com/dabeaz/ply
|
||||
# -----------------------------------------------------------------------------
|
||||
# Modified by Nicholas Pease
|
||||
# 6 FEB 2024
|
||||
# Modifications denoted by comments (- NPEASE)
|
||||
# 4 APR 2024
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import ply.lex as lex
|
||||
@@ -30,17 +29,14 @@ class Parser:
|
||||
self.debug = kw.get('debug', 0)
|
||||
self.names = {}
|
||||
try:
|
||||
modname = os.path.split(os.path.splitext(__file__)[0])[
|
||||
1] + "_" + self.__class__.__name__
|
||||
modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" + self.__class__.__name__
|
||||
except:
|
||||
modname = "parser" + "_" + self.__class__.__name__
|
||||
self.debugfile = modname + ".dbg"
|
||||
# print self.debugfile
|
||||
# Build the lexer and parser
|
||||
lex.lex(module=self, debug=self.debug)
|
||||
yacc.yacc(module=self,
|
||||
debug=self.debug,
|
||||
debugfile=self.debugfile)
|
||||
yacc.yacc(module=self,debug=self.debug,debugfile=self.debugfile)
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
@@ -48,10 +44,8 @@ class Parser:
|
||||
s = input() # per homework guidelines - NPEASE
|
||||
except EOFError:
|
||||
constant_string = ""
|
||||
for i in code_constants:
|
||||
constant_string += "{},".format(i)
|
||||
totalCode = "Function: main/0\nConstants: {}\nGlobals: print\nBEGIN{}\n\tLOAD_GLOBAL 0\n\tROT_TWO\n\tCALL_FUNCTION 1\n\tRETURN_VALUE\nEND""".format(constant_string[:-1], code)
|
||||
print(totalCode)
|
||||
for i in code_constants: constant_string += "{},".format(i)
|
||||
print("Function: main/0\nConstants: {}\nGlobals: print\nBEGIN{}\n\tRETURN_VALUE\nEND""".format(constant_string[:-1], code))
|
||||
break
|
||||
if not s:
|
||||
continue
|
||||
@@ -108,7 +102,7 @@ class Calc(Parser):
|
||||
def p_statement_expr(self, p):
|
||||
'statement : expression'
|
||||
global code
|
||||
code += p[1]
|
||||
code += p[1] + "\n\tLOAD_GLOBAL 0\n\tROT_TWO\n\tCALL_FUNCTION 1"
|
||||
|
||||
def p_expression_binop(self, p):
|
||||
"""
|
||||
@@ -120,26 +114,26 @@ class Calc(Parser):
|
||||
| expression FDIVIDE expression
|
||||
| expression EXP expression
|
||||
""" # Added both modulus and floor divide -NPEASE
|
||||
if p[2] == '+':
|
||||
operation = "BINARY_ADD"
|
||||
elif p[2] == '-':
|
||||
operation = "BINARY_SUBTRACT"
|
||||
elif p[2] == '*':
|
||||
operation = "BINARY_MULTIPLY"
|
||||
elif p[2] == '/':
|
||||
operation = "BINARY_DIVIDE"
|
||||
elif p[2] == '//': # add floor divide to computational part of program -NPEASE
|
||||
operation = "BINARY_FLOOR_DIVIDE"
|
||||
elif p[2] == '%': # add modulus to computational part of program -NPEASE
|
||||
operation = "BINARY_MODULO"
|
||||
elif p[2] == '**':
|
||||
operation = "BINARY_POWER"
|
||||
match p[2]:
|
||||
case '+':
|
||||
operation = "BINARY_ADD"
|
||||
case '-':
|
||||
operation = "BINARY_SUBTRACT"
|
||||
case '*':
|
||||
operation = "BINARY_MULTIPLY"
|
||||
case '/':
|
||||
operation = "BINARY_DIVIDE"
|
||||
case '//':
|
||||
operation = "BINARY_FLOOR_DIVIDE"
|
||||
case '%':
|
||||
operation = "BINARY_MODULO"
|
||||
case '**':
|
||||
operation = "BINARY_POWER"
|
||||
p[0] = '{1}{2}\n\t{0}'.format(operation, p[1],p[3])
|
||||
|
||||
def p_expression_uminus(self, p):
|
||||
'expression : MINUS expression %prec UMINUS'
|
||||
if 0 not in code_constants:
|
||||
code_constants.append(0)
|
||||
if 0 not in code_constants: code_constants.append(0)
|
||||
p[0] = "{}\n\tLOAD_CONST {}\n\tROT_TWO\n\tBINARY_SUBTRACT".format(p[2],code_constants.index(0))
|
||||
|
||||
def p_expression_group(self, p):
|
||||
@@ -148,8 +142,7 @@ class Calc(Parser):
|
||||
|
||||
def p_expression_number(self, p):
|
||||
'expression : NUMBER'
|
||||
if p[1] not in code_constants:
|
||||
code_constants.append(p[1])
|
||||
if p[1] not in code_constants: code_constants.append(p[1])
|
||||
p[0] = "\n\tLOAD_CONST {}".format(code_constants.index(p[1]))
|
||||
|
||||
def p_expression_name(self, p):
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
## Calculator Language to Jcoco Assembler
|
||||
### Nicholas Pease
|
||||
|
||||
## Contents
|
||||
/hacky-solution - Alternate Solution which Requires Python 3.2.6 and makes use of the Jcoco disassembler (Included as I thought it was interesting)
|
||||
/hacky-solution/calc1.py - Calc.py file for hacky solution (DO NOT GRADE, INCLUDED AS IT WAS INTERESTING TO ME)
|
||||
/hacky-solution/disassembler.py - Python to Jcoco disassembler
|
||||
|
||||
calc.py - Python compiler for calculator language to Jcoco. For use see below
|
||||
|
||||
## Usage
|
||||
Feed lines of the calculator language in via the standard input. The compiler will listen for the EOF signal (CTRL+D) and then generate jcoco code to the standard output.
|
||||
|
||||
Valid operations are (+,-,/,//,*,**,%), unary minus (-num), assignments (=)
|
||||
|
||||
To feed in a file in linux and execute output in Jcoco:
|
||||
cat filename | python3 calc.py > tester.casm && ./coco tester.casm
|
||||
|
||||
Jcoco also requires Java runtime to be installed, and the jcoco binaries downloaded
|
||||
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# calc.py
|
||||
#
|
||||
# A simple calculator with variables. This is from O'Reilly's "Lex and Yacc", p. 63.
|
||||
# Class-based example contributed to PLY by David McNab
|
||||
# Originally located on PLY Github at https://github.com/dabeaz/ply
|
||||
# -----------------------------------------------------------------------------
|
||||
# Modified by Nicholas Pease
|
||||
# 4 APR 2024
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import ply.lex as lex
|
||||
import ply.yacc as yacc
|
||||
import os
|
||||
|
||||
code_constants = []
|
||||
code = ""
|
||||
|
||||
class Parser:
|
||||
"""
|
||||
Base class for a lexer/parser that has the rules defined as methods
|
||||
"""
|
||||
tokens = ()
|
||||
precedence = ()
|
||||
|
||||
def __init__(self, **kw):
|
||||
self.debug = kw.get('debug', 0)
|
||||
self.names = {}
|
||||
try:
|
||||
modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" + self.__class__.__name__
|
||||
except:
|
||||
modname = "parser" + "_" + self.__class__.__name__
|
||||
self.debugfile = modname + ".dbg"
|
||||
# print self.debugfile
|
||||
# Build the lexer and parser
|
||||
lex.lex(module=self, debug=self.debug)
|
||||
yacc.yacc(module=self,debug=self.debug,debugfile=self.debugfile)
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
try:
|
||||
s = input() # per homework guidelines - NPEASE
|
||||
except EOFError:
|
||||
constant_string = ""
|
||||
for i in code_constants: constant_string += "{},".format(i)
|
||||
print("Function: main/0\nConstants: {}\nGlobals: print\nBEGIN{}\n\tRETURN_VALUE\nEND""".format(constant_string[:-1], code))
|
||||
break
|
||||
if not s:
|
||||
continue
|
||||
yacc.parse(s)
|
||||
|
||||
|
||||
class Calc(Parser):
|
||||
tokens = (
|
||||
'NAME', 'NUMBER',
|
||||
'PLUS', 'MINUS', 'EXP', 'TIMES', 'DIVIDE', 'MOD', 'FDIVIDE', 'EQUALS',
|
||||
'LPAREN', 'RPAREN',
|
||||
) # Add Additional Tokens -NPEASE
|
||||
# Tokens
|
||||
t_PLUS = r'\+'
|
||||
t_MINUS = r'-'
|
||||
t_EXP = r'\*\*'
|
||||
t_TIMES = r'\*'
|
||||
t_DIVIDE = r'/'
|
||||
t_MOD = r'%' # Added modulus token -NPEASE
|
||||
t_FDIVIDE = r'\/\/' # Added floor division token -NPEASE
|
||||
t_EQUALS = r'='
|
||||
t_LPAREN = r'\('
|
||||
t_RPAREN = r'\)'
|
||||
t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'
|
||||
|
||||
def t_NUMBER(self, t):
|
||||
r'(\d|\.)+' # Changed to reflect decimals -NPEASE
|
||||
if "." in t.value: # Look for decimal and convert to float, otherwise keep as an int
|
||||
t.value = float(t.value)
|
||||
else:
|
||||
t.value = int(t.value)
|
||||
return t
|
||||
t_ignore = " \t"
|
||||
|
||||
def t_newline(self, t):
|
||||
r'\n+'
|
||||
t.lexer.lineno += t.value.count("\n")
|
||||
|
||||
def t_error(self, t):
|
||||
print("Illegal character '%s'" % t.value[0])
|
||||
t.lexer.skip(1)
|
||||
# Parsing rules
|
||||
precedence = (
|
||||
('left', 'PLUS', 'MINUS'),
|
||||
('left', 'TIMES', 'FDIVIDE', 'MOD', 'DIVIDE'), # Added modulus and floor divide to precedence -NPEASE
|
||||
('left', 'EXP'),
|
||||
('right', 'UMINUS'),
|
||||
)
|
||||
|
||||
def p_statement_assign(self, p):
|
||||
'statement : NAME EQUALS expression'
|
||||
self.names[p[1]] = p[3]
|
||||
|
||||
def p_statement_expr(self, p):
|
||||
'statement : expression'
|
||||
global code
|
||||
code += p[1] + "\n\tLOAD_GLOBAL 0\n\tROT_TWO\n\tCALL_FUNCTION 1"
|
||||
|
||||
def p_expression_binop(self, p):
|
||||
"""
|
||||
expression : expression PLUS expression
|
||||
| expression MINUS expression
|
||||
| expression TIMES expression
|
||||
| expression DIVIDE expression
|
||||
| expression MOD expression
|
||||
| expression FDIVIDE expression
|
||||
| expression EXP expression
|
||||
""" # Added both modulus and floor divide -NPEASE
|
||||
match p[2]:
|
||||
case '+':
|
||||
operation = "BINARY_ADD"
|
||||
case '-':
|
||||
operation = "BINARY_SUBTRACT"
|
||||
case '*':
|
||||
operation = "BINARY_MULTIPLY"
|
||||
case '/':
|
||||
operation = "BINARY_DIVIDE"
|
||||
case '//':
|
||||
operation = "BINARY_FLOOR_DIVIDE"
|
||||
case '%':
|
||||
operation = "BINARY_MODULO"
|
||||
case '**':
|
||||
operation = "BINARY_POWER"
|
||||
p[0] = '{1}{2}\n\t{0}'.format(operation, p[1],p[3])
|
||||
|
||||
def p_expression_uminus(self, p):
|
||||
'expression : MINUS expression %prec UMINUS'
|
||||
if 0 not in code_constants: code_constants.append(0)
|
||||
p[0] = "{}\n\tLOAD_CONST {}\n\tROT_TWO\n\tBINARY_SUBTRACT".format(p[2],code_constants.index(0))
|
||||
|
||||
def p_expression_group(self, p):
|
||||
'expression : LPAREN expression RPAREN'
|
||||
p[0] = p[2]
|
||||
|
||||
def p_expression_number(self, p):
|
||||
'expression : NUMBER'
|
||||
if p[1] not in code_constants: code_constants.append(p[1])
|
||||
p[0] = "\n\tLOAD_CONST {}".format(code_constants.index(p[1]))
|
||||
|
||||
def p_expression_name(self, p):
|
||||
'expression : NAME'
|
||||
try:
|
||||
p[0] = self.names[p[1]]
|
||||
except LookupError:
|
||||
print("Undefined name '%s'" % p[1])
|
||||
p[0] = 0
|
||||
|
||||
def p_error(self, p):
|
||||
if p:
|
||||
print("Syntax error at '%s'" % p.value)
|
||||
else:
|
||||
print("Syntax error at EOF")
|
||||
|
||||
if __name__ == '__main__':
|
||||
calc = Calc()
|
||||
calc.run()
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
|
||||
# parsetab.py
|
||||
# This file is automatically generated. Do not edit.
|
||||
# pylint: disable=W,C,R
|
||||
_tabversion = '3.10'
|
||||
|
||||
_lr_method = 'LALR'
|
||||
|
||||
_lr_signature = 'leftPLUSMINUSleftTIMESFDIVIDEMODDIVIDEleftEXPrightUMINUSDIVIDE EQUALS EXP FDIVIDE LPAREN MINUS MOD NAME NUMBER PLUS RPAREN TIMESstatement : NAME EQUALS expressionstatement : expression\n expression : expression PLUS expression\n | expression MINUS expression\n | expression TIMES expression\n | expression DIVIDE expression\n | expression MOD expression\n | expression FDIVIDE expression\n | expression EXP expression\n expression : MINUS expression %prec UMINUSexpression : LPAREN expression RPARENexpression : NUMBERexpression : NAME'
|
||||
|
||||
_lr_action_items = {'$end':([1,2,3,5,8,17,18,19,20,21,22,23,24,25,26,],[-13,-12,0,-2,-13,-10,-1,-11,-8,-6,-5,-3,-9,-4,-7,]),'FDIVIDE':([1,2,5,8,9,17,18,19,20,21,22,23,24,25,26,],[-13,-12,10,-13,10,-10,10,-11,-8,-6,-5,10,-9,10,-7,]),'RPAREN':([2,8,9,17,19,20,21,22,23,24,25,26,],[-12,-13,19,-10,-11,-8,-6,-5,-3,-9,-4,-7,]),'DIVIDE':([1,2,5,8,9,17,18,19,20,21,22,23,24,25,26,],[-13,-12,11,-13,11,-10,11,-11,-8,-6,-5,11,-9,11,-7,]),'NUMBER':([0,4,6,7,10,11,12,13,14,15,16,],[2,2,2,2,2,2,2,2,2,2,2,]),'EQUALS':([1,],[7,]),'PLUS':([1,2,5,8,9,17,18,19,20,21,22,23,24,25,26,],[-13,-12,13,-13,13,-10,13,-11,-8,-6,-5,-3,-9,-4,-7,]),'MOD':([1,2,5,8,9,17,18,19,20,21,22,23,24,25,26,],[-13,-12,16,-13,16,-10,16,-11,-8,-6,-5,16,-9,16,-7,]),'LPAREN':([0,4,6,7,10,11,12,13,14,15,16,],[4,4,4,4,4,4,4,4,4,4,4,]),'EXP':([1,2,5,8,9,17,18,19,20,21,22,23,24,25,26,],[-13,-12,14,-13,14,-10,14,-11,14,14,14,14,-9,14,14,]),'TIMES':([1,2,5,8,9,17,18,19,20,21,22,23,24,25,26,],[-13,-12,12,-13,12,-10,12,-11,-8,-6,-5,12,-9,12,-7,]),'MINUS':([0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,],[6,-13,-12,6,15,6,6,-13,15,6,6,6,6,6,6,6,-10,15,-11,-8,-6,-5,-3,-9,-4,-7,]),'NAME':([0,4,6,7,10,11,12,13,14,15,16,],[1,8,8,8,8,8,8,8,8,8,8,]),}
|
||||
|
||||
_lr_action = {}
|
||||
for _k, _v in _lr_action_items.items():
|
||||
for _x,_y in zip(_v[0],_v[1]):
|
||||
if not _x in _lr_action: _lr_action[_x] = {}
|
||||
_lr_action[_x][_k] = _y
|
||||
del _lr_action_items
|
||||
|
||||
_lr_goto_items = {'expression':([0,4,6,7,10,11,12,13,14,15,16,],[5,9,17,18,20,21,22,23,24,25,26,]),'statement':([0,],[3,]),}
|
||||
|
||||
_lr_goto = {}
|
||||
for _k, _v in _lr_goto_items.items():
|
||||
for _x, _y in zip(_v[0], _v[1]):
|
||||
if not _x in _lr_goto: _lr_goto[_x] = {}
|
||||
_lr_goto[_x][_k] = _y
|
||||
del _lr_goto_items
|
||||
_lr_productions = [
|
||||
("S' -> statement","S'",1,None,None,None),
|
||||
('statement -> NAME EQUALS expression','statement',3,'p_statement_assign','calc.py',107),
|
||||
('statement -> expression','statement',1,'p_statement_expr','calc.py',111),
|
||||
('expression -> expression PLUS expression','expression',3,'p_expression_binop','calc.py',122),
|
||||
('expression -> expression MINUS expression','expression',3,'p_expression_binop','calc.py',123),
|
||||
('expression -> expression TIMES expression','expression',3,'p_expression_binop','calc.py',124),
|
||||
('expression -> expression DIVIDE expression','expression',3,'p_expression_binop','calc.py',125),
|
||||
('expression -> expression MOD expression','expression',3,'p_expression_binop','calc.py',126),
|
||||
('expression -> expression FDIVIDE expression','expression',3,'p_expression_binop','calc.py',127),
|
||||
('expression -> expression EXP expression','expression',3,'p_expression_binop','calc.py',128),
|
||||
('expression -> MINUS expression','expression',2,'p_expression_uminus','calc.py',166),
|
||||
('expression -> LPAREN expression RPAREN','expression',3,'p_expression_group','calc.py',170),
|
||||
('expression -> NUMBER','expression',1,'p_expression_number','calc.py',174),
|
||||
('expression -> NAME','expression',1,'p_expression_name','calc.py',178),
|
||||
]
|
||||
@@ -1,21 +0,0 @@
|
||||
Function: main/0
|
||||
Constants: None, "Hello, ", "!"
|
||||
Locals: myname, greeting
|
||||
Globals: input, print
|
||||
BEGIN
|
||||
LOAD_GLOBAL 0
|
||||
CALL_FUNCTION 0
|
||||
STORE_FAST 0
|
||||
LOAD_CONST 1
|
||||
LOAD_FAST 0
|
||||
BINARY_ADD
|
||||
LOAD_CONST 2
|
||||
BINARY_ADD
|
||||
STORE_FAST 1
|
||||
LOAD_GLOBAL 1
|
||||
LOAD_FAST 1
|
||||
CALL_FUNCTION 1
|
||||
POP_TOP
|
||||
LOAD_CONST 0
|
||||
RETURN_VALUE
|
||||
END
|
||||
@@ -1,8 +0,0 @@
|
||||
import disassembler
|
||||
|
||||
def main():
|
||||
x = 5
|
||||
y = x + 5
|
||||
print(y+5)
|
||||
|
||||
disassembler.disassemble(main)
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
Function: main/0
|
||||
Constants: 5,0
|
||||
Globals: print
|
||||
BEGIN
|
||||
LOAD_CONST 0
|
||||
LOAD_CONST 0
|
||||
BINARY_ADD
|
||||
LOAD_CONST 1
|
||||
ROT_TWO
|
||||
BINARY_SUBTRACT
|
||||
LOAD_GLOBAL 0
|
||||
ROT_TWO
|
||||
CALL_FUNCTION 1
|
||||
RETURN_VALUE
|
||||
END
|
||||
Reference in New Issue
Block a user