All but examples

This commit is contained in:
2024-04-02 18:19:05 +00:00
parent 60dc6b8222
commit 395ba37c83
16 changed files with 246 additions and 118 deletions
+19
View File
@@ -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
+21 -1
View File
@@ -3,5 +3,25 @@
[![](https://gitea-actions.nicholaspease.com/actions/umaine-npease/COS301-HW4/badge?label=build&style=flat&branch=main)](https://gitea-actions.nicholaspease.com/latest-log?branch=main)
[![](https://drone.nicholaspease.com/api/badges/umaine-npease/COS301-HW4/status.svg)](https://drone.nicholaspease.com/umaine-npease/COS301-HW4)
[![](https://wakaapi.nicholaspease.com/api/badge/LAX18/interval:any/project:COS301-HW4)](https://wakaapi.nicholaspease.com/summary?interval=any&project=COS301-HW4)
![](https://server1.nicholaspease.com/badges/cloc/npease/COS301-HW4.svg)
![](https://server1.nicholaspease.com/badges/cloc/umaine-npease/COS301-HW4.svg)
<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.
View File
View File
View File
+23 -30
View File
@@ -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):
+19
View File
@@ -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
+164
View File
@@ -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
View File
@@ -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),
]
-21
View File
@@ -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
-8
View File
@@ -1,8 +0,0 @@
import disassembler
def main():
x = 5
y = x + 5
print(y+5)
disassembler.disassemble(main)
-15
View File
@@ -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