Improve code maintainability
This commit is contained in:
26
Project-02-03/lib/console.py
Normal file
26
Project-02-03/lib/console.py
Normal file
@@ -0,0 +1,26 @@
|
||||
def prompt_choice(prompt: str, options: list) -> int:
|
||||
print(prompt)
|
||||
for i, opt in enumerate(options, 1):
|
||||
print(f" {i}. {opt}")
|
||||
|
||||
while True:
|
||||
try:
|
||||
s = input(f"Enter choice (1-{len(options)}): ").strip()
|
||||
idx = int(s) - 1
|
||||
if 0 <= idx < len(options):
|
||||
return idx
|
||||
except Exception:
|
||||
pass
|
||||
print(f"Invalid. Enter a number between 1-{len(options)}.")
|
||||
|
||||
def prompt_confirmation(question: str, default="y"):
|
||||
s = input(f"{question} (y/n) [{default}]: ").strip().lower()
|
||||
if not s:
|
||||
s = default
|
||||
return s.startswith("y")
|
||||
|
||||
def search_programs():
|
||||
base = Path(__file__).parent / "triplaprograms"
|
||||
if not base.exists():
|
||||
return []
|
||||
return sorted([f for f in base.glob("*.tripla")])
|
||||
100
Project-02-03/main.py
Normal file
100
Project-02-03/main.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import triplayacc as yacc
|
||||
import triplalex as lex
|
||||
import syntax
|
||||
|
||||
from pathlib import Path
|
||||
from graphviz import Source
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.image as mpimg
|
||||
import lib.console as cnsl
|
||||
import os
|
||||
|
||||
import matplotlib
|
||||
matplotlib.use("TkAgg")
|
||||
|
||||
# Renders a diagram of the AST
|
||||
def render_diagram(dot_string: str):
|
||||
# Set DPI for PNG
|
||||
os.environ["GV_FILE_DPI"] = "300"
|
||||
|
||||
src = Source(dot_string, format="png", engine="dot")
|
||||
png_path = src.render(cleanup=True)
|
||||
|
||||
img = mpimg.imread(png_path)
|
||||
|
||||
fig = plt.figure(figsize=(12, 12))
|
||||
fig.canvas.manager.window.wm_title("TRIPLA AST Viewer")
|
||||
|
||||
plt.imshow(img)
|
||||
plt.axis("off")
|
||||
plt.show()
|
||||
|
||||
# Pretty prints the AST
|
||||
def pretty_print(node, indent=0):
|
||||
prefix = " " * indent
|
||||
print(f"{prefix}{type(node).__name__}:")
|
||||
|
||||
for key, value in node.__dict__.items():
|
||||
if isinstance(value, syntax.EXPRESSION):
|
||||
pretty_print(value, indent + 4)
|
||||
|
||||
elif isinstance(value, list):
|
||||
print(f"{prefix} {key}: [")
|
||||
for element in value:
|
||||
if isinstance(element, syntax.EXPRESSION):
|
||||
pretty_print(element, indent + 4)
|
||||
else:
|
||||
print(" " * (indent + 4) + str(element))
|
||||
print(f"{prefix} ]")
|
||||
|
||||
else:
|
||||
print(f"{prefix} {key}: {value}")
|
||||
|
||||
# Exports the AST as a DOT file
|
||||
def export_dot_file(dot_string: str, filename: str):
|
||||
try:
|
||||
Path(filename).write_text(dot_string, encoding="utf-8")
|
||||
print(f"Saved DOT file as: {filename}")
|
||||
except Exception as e:
|
||||
print(f"Could not save DOT file: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("\nTRIPLA Parser Tool")
|
||||
|
||||
while True:
|
||||
choice = cnsl.prompt_choice("\nSelect action:", ["Parse .tripla", "Exit"])
|
||||
|
||||
if choice == 1:
|
||||
print("\nBye Bye.")
|
||||
break
|
||||
|
||||
programs = cnsl.search_programs()
|
||||
if not programs:
|
||||
print("\nNo .tripla files found.")
|
||||
continue
|
||||
|
||||
idx = cnsl.prompt_choice("\nSelect program to parse:", [p.name for p in programs])
|
||||
path = programs[idx]
|
||||
|
||||
source = path.read_text()
|
||||
ast = yacc.parser.parse(source)
|
||||
|
||||
# Pretty print
|
||||
if cnsl.prompt_confirmation("\nPretty-print AST?"):
|
||||
print("")
|
||||
pretty_print(ast)
|
||||
|
||||
# Export DOT
|
||||
dot_str = ast.to_dot()
|
||||
if cnsl.prompt_confirmation("Export AST as .dot file?"):
|
||||
default = f"{path.stem}.dot"
|
||||
cnsl = input(f"Filename [{default}]: ").strip()
|
||||
if not cnsl:
|
||||
cnsl = default
|
||||
export_dot_file(dot_str, cnsl)
|
||||
|
||||
# Display AST diagram
|
||||
if cnsl.prompt_confirmation("Display AST diagram?"):
|
||||
render_diagram(dot_str)
|
||||
print("Rendered AST diagram.")
|
||||
1139
Project-02-03/parser.out
Normal file
1139
Project-02-03/parser.out
Normal file
File diff suppressed because it is too large
Load Diff
53
Project-02-03/parsetab.py
Normal file
53
Project-02-03/parsetab.py
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
# parsetab.py
|
||||
# This file is automatically generated. Do not edit.
|
||||
# pylint: disable=W,C,R
|
||||
_tabversion = '3.10'
|
||||
|
||||
_lr_method = 'LALR'
|
||||
|
||||
_lr_signature = 'EleftSEMICOLONrightINleftCOMPleftEQOPleftAOPAOP ASSIGN COMMA COMP CONST DO ELSE EQOP FALSE ID IF IN LBRACE LET LOP LPAREN RBRACE RPAREN SEMICOLON THEN TRUE WHILEE : LET D IN EE : IDE : ID LPAREN A RPARENE : E AOP EE : LPAREN E RPARENE : CONSTE : ID ASSIGN EE : E SEMICOLON EE : IF B THEN E ELSE EE : WHILE B DO LBRACE E RBRACEA : EA : A COMMA ED : ID LPAREN V RPAREN LBRACE E RBRACED : D DV : IDV : V COMMA VB : E EQOP EB : E COMP EB : B EQOP BB : B LOP BB : TRUEB : FALSEB : LPAREN B RPAREN'
|
||||
|
||||
_lr_action_items = {'LET':([0,4,6,7,8,9,12,13,19,24,30,31,32,33,34,42,49,53,55,],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,]),'ID':([0,2,4,6,7,8,9,10,12,13,19,23,24,25,30,31,32,33,34,42,49,51,53,55,60,],[3,11,3,3,3,3,3,11,3,3,3,11,3,39,3,3,3,3,3,3,3,39,3,3,-13,]),'LPAREN':([0,3,4,6,7,8,9,11,12,13,19,24,30,31,32,33,34,42,49,53,55,],[4,12,4,19,19,4,4,25,4,4,19,4,4,19,19,4,4,4,4,4,4,]),'CONST':([0,4,6,7,8,9,12,13,19,24,30,31,32,33,34,42,49,53,55,],[5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,]),'IF':([0,4,6,7,8,9,12,13,19,24,30,31,32,33,34,42,49,53,55,],[6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,]),'WHILE':([0,4,6,7,8,9,12,13,19,24,30,31,32,33,34,42,49,53,55,],[7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,]),'$end':([1,3,5,21,22,28,29,38,41,57,58,],[0,-2,-6,-4,-8,-7,-5,-1,-3,-9,-10,]),'AOP':([1,3,5,14,16,21,22,27,28,29,36,38,41,43,46,47,52,54,57,58,59,],[8,-2,-6,8,8,-4,8,8,8,-5,8,8,-3,8,8,8,8,8,8,-10,8,]),'SEMICOLON':([1,3,5,14,16,21,22,27,28,29,36,38,41,43,46,47,52,54,57,58,59,],[9,-2,-6,9,9,-4,-8,9,9,-5,9,-1,-3,9,9,9,9,9,9,-10,9,]),'RPAREN':([3,5,14,17,18,21,22,26,27,28,29,35,36,38,39,40,41,44,45,46,47,48,52,56,57,58,],[-2,-6,29,-21,-22,-4,-8,41,-11,-7,-5,48,29,-1,-15,50,-3,-19,-20,-17,-18,-23,-12,-16,-9,-10,]),'EQOP':([3,5,15,16,17,18,20,21,22,28,29,35,36,38,41,44,45,46,47,48,57,58,],[-2,-6,31,33,-21,-22,31,-4,-8,-7,-5,31,33,-1,-3,-19,31,-17,-18,-23,-9,-10,]),'COMP':([3,5,16,21,22,28,29,36,38,41,57,58,],[-2,-6,34,-4,-8,-7,-5,34,-1,-3,-9,-10,]),'COMMA':([3,5,21,22,26,27,28,29,38,39,40,41,52,56,57,58,],[-2,-6,-4,-8,42,-11,-7,-5,-1,-15,51,-3,-12,51,-9,-10,]),'ELSE':([3,5,21,22,28,29,38,41,43,57,58,],[-2,-6,-4,-8,-7,-5,-1,-3,53,-9,-10,]),'THEN':([3,5,15,17,18,21,22,28,29,38,41,44,45,46,47,48,57,58,],[-2,-6,30,-21,-22,-4,-8,-7,-5,-1,-3,-19,-20,-17,-18,-23,-9,-10,]),'LOP':([3,5,15,17,18,20,21,22,28,29,35,38,41,44,45,46,47,48,57,58,],[-2,-6,32,-21,-22,32,-4,-8,-7,-5,32,-1,-3,-19,32,-17,-18,-23,-9,-10,]),'DO':([3,5,17,18,20,21,22,28,29,38,41,44,45,46,47,48,57,58,],[-2,-6,-21,-22,37,-4,-8,-7,-5,-1,-3,-19,-20,-17,-18,-23,-9,-10,]),'RBRACE':([3,5,21,22,28,29,38,41,54,57,58,59,],[-2,-6,-4,-8,-7,-5,-1,-3,58,-9,-10,60,]),'ASSIGN':([3,],[13,]),'TRUE':([6,7,19,31,32,],[17,17,17,17,17,]),'FALSE':([6,7,19,31,32,],[18,18,18,18,18,]),'IN':([10,23,60,],[24,-14,-13,]),'LBRACE':([37,50,],[49,55,]),}
|
||||
|
||||
_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 = {'E':([0,4,6,7,8,9,12,13,19,24,30,31,32,33,34,42,49,53,55,],[1,14,16,16,21,22,27,28,36,38,43,16,16,46,47,52,54,57,59,]),'D':([2,10,23,],[10,23,23,]),'B':([6,7,19,31,32,],[15,20,35,44,45,]),'A':([12,],[26,]),'V':([25,51,],[40,56,]),}
|
||||
|
||||
_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' -> E","S'",1,None,None,None),
|
||||
('E -> LET D IN E','E',4,'p_E_let','triplayacc.py',25),
|
||||
('E -> ID','E',1,'p_E_id','triplayacc.py',29),
|
||||
('E -> ID LPAREN A RPAREN','E',4,'p_E_call','triplayacc.py',33),
|
||||
('E -> E AOP E','E',3,'p_E_aop','triplayacc.py',38),
|
||||
('E -> LPAREN E RPAREN','E',3,'p_E_paren','triplayacc.py',42),
|
||||
('E -> CONST','E',1,'p_E_const','triplayacc.py',47),
|
||||
('E -> ID ASSIGN E','E',3,'p_E_assign','triplayacc.py',51),
|
||||
('E -> E SEMICOLON E','E',3,'p_E_seq','triplayacc.py',55),
|
||||
('E -> IF B THEN E ELSE E','E',6,'p_E_if','triplayacc.py',59),
|
||||
('E -> WHILE B DO LBRACE E RBRACE','E',6,'p_E_while','triplayacc.py',63),
|
||||
('A -> E','A',1,'p_A_single','triplayacc.py',72),
|
||||
('A -> A COMMA E','A',3,'p_A_multiple','triplayacc.py',76),
|
||||
('D -> ID LPAREN V RPAREN LBRACE E RBRACE','D',7,'p_D_single','triplayacc.py',84),
|
||||
('D -> D D','D',2,'p_D_concat','triplayacc.py',88),
|
||||
('V -> ID','V',1,'p_V_single','triplayacc.py',96),
|
||||
('V -> V COMMA V','V',3,'p_V_multiple','triplayacc.py',100),
|
||||
('B -> E EQOP E','B',3,'p_B_eqop_E','triplayacc.py',108),
|
||||
('B -> E COMP E','B',3,'p_B_comp','triplayacc.py',112),
|
||||
('B -> B EQOP B','B',3,'p_B_eqop_B','triplayacc.py',116),
|
||||
('B -> B LOP B','B',3,'p_B_lop','triplayacc.py',120),
|
||||
('B -> TRUE','B',1,'p_B_true','triplayacc.py',124),
|
||||
('B -> FALSE','B',1,'p_B_false','triplayacc.py',128),
|
||||
('B -> LPAREN B RPAREN','B',3,'p_B_paren','triplayacc.py',132),
|
||||
]
|
||||
184
Project-02-03/syntax.py
Normal file
184
Project-02-03/syntax.py
Normal file
@@ -0,0 +1,184 @@
|
||||
class EXPRESSION:
|
||||
pp_count = 0
|
||||
|
||||
def __init__(self):
|
||||
self.pp = EXPRESSION.pp_count
|
||||
EXPRESSION.pp_count += 1
|
||||
|
||||
@staticmethod
|
||||
def copy():
|
||||
return EXPRESSION()
|
||||
|
||||
# Returns a list of tuples (edge_name, child_expression)
|
||||
def children(self):
|
||||
out = []
|
||||
for key, value in self.__dict__.items():
|
||||
if key == "pp":
|
||||
continue
|
||||
if isinstance(value, EXPRESSION):
|
||||
out.append((key, value))
|
||||
elif isinstance(value, list):
|
||||
for i, elem in enumerate(value):
|
||||
if isinstance(elem, EXPRESSION):
|
||||
out.append((f"{key}{i}", elem))
|
||||
return out
|
||||
|
||||
# Export AST to dot format
|
||||
def to_dot(self, visited=None, root=True):
|
||||
if visited is None:
|
||||
visited = set()
|
||||
|
||||
# Prevent infinite recursion
|
||||
if id(self) in visited:
|
||||
return ""
|
||||
visited.add(id(self))
|
||||
|
||||
parts = []
|
||||
|
||||
# Add a header at the root node
|
||||
if root:
|
||||
parts.append("digraph AST {\n")
|
||||
|
||||
# Append to label
|
||||
label = type(self).__name__
|
||||
if hasattr(self, "operator"):
|
||||
label += f"({self.operator})"
|
||||
if hasattr(self, "name"):
|
||||
label += f"({self.name})"
|
||||
if hasattr(self, "value"):
|
||||
label += f"({self.value})"
|
||||
|
||||
parts.append(f' node{self.pp} [label="{label}"];\n')
|
||||
|
||||
# Draw edges
|
||||
for edge_name, child in self.children():
|
||||
parts.append(f' node{self.pp} -> node{child.pp} [label="{edge_name}"];\n')
|
||||
parts.append(child.to_dot(visited, root=False))
|
||||
|
||||
# Add footer at the root node
|
||||
if root:
|
||||
parts.append("}\n")
|
||||
|
||||
return "".join(parts)
|
||||
|
||||
|
||||
class LET(EXPRESSION):
|
||||
def __init__(self, decls, body):
|
||||
super().__init__()
|
||||
self.decl = decls
|
||||
self.body = body
|
||||
|
||||
def __str__(self):
|
||||
return "let " + ", ".join(str(d) for d in self.decl) + " in " + str(self.body)
|
||||
|
||||
class DECL(EXPRESSION):
|
||||
def __init__(self, f_name, params, body):
|
||||
super().__init__()
|
||||
self.f_name = f_name
|
||||
self.params = params
|
||||
self.body = body
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.f_name}({self.params}) {{ {self.body} }}"
|
||||
|
||||
class CALL(EXPRESSION):
|
||||
def __init__(self, f_name, args):
|
||||
super().__init__()
|
||||
self.f_name = f_name
|
||||
self.arg = args
|
||||
|
||||
def __str__(self):
|
||||
return self.f_name + "(" + ",".join(str(a) for a in self.arg) + ")"
|
||||
|
||||
class ID(EXPRESSION):
|
||||
def __init__(self, name):
|
||||
super().__init__()
|
||||
self.name = name
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class CONST(EXPRESSION):
|
||||
def __init__(self, value):
|
||||
super().__init__()
|
||||
self.value = value
|
||||
|
||||
def __str__(self):
|
||||
return str(self.value)
|
||||
|
||||
class AOP(EXPRESSION):
|
||||
def __init__(self, operator, arg1, arg2):
|
||||
super().__init__()
|
||||
self.operator = operator
|
||||
self.arg1 = arg1
|
||||
self.arg2 = arg2
|
||||
|
||||
def __str__(self):
|
||||
return "(" + str(self.arg1) + " " + str(self.operator) + " " + str(self.arg2) + ")"
|
||||
|
||||
class EQOP(EXPRESSION):
|
||||
def __init__(self, operator, arg1, arg2):
|
||||
super().__init__()
|
||||
self.operator = operator
|
||||
self.arg1 = arg1
|
||||
self.arg2 = arg2
|
||||
|
||||
def __str__(self):
|
||||
return "(" + str(self.arg1) + " " + str(self.operator) + " " + str(self.arg2) + ")"
|
||||
|
||||
class COMP(EXPRESSION):
|
||||
def __init__(self, operator, arg1, arg2):
|
||||
super().__init__()
|
||||
self.operator = operator
|
||||
self.arg1 = arg1
|
||||
self.arg2 = arg2
|
||||
|
||||
def __str__(self):
|
||||
return "(" + str(self.arg1) + " " + str(self.operator) + " " + str(self.arg2) + ")"
|
||||
|
||||
class LOP(EXPRESSION):
|
||||
def __init__(self, operator, arg1, arg2):
|
||||
super().__init__()
|
||||
self.operator = operator
|
||||
self.arg1 = arg1
|
||||
self.arg2 = arg2
|
||||
|
||||
def __str__(self):
|
||||
return "(" + str(self.arg1) + " " + str(self.operator) + " " + str(self.arg2) + ")"
|
||||
|
||||
class ASSIGN(EXPRESSION):
|
||||
def __init__(self, var, expr):
|
||||
super().__init__()
|
||||
self.var = var
|
||||
self.expr = expr
|
||||
|
||||
def __str__(self):
|
||||
return self.var.name + " = " + str(self.expr)
|
||||
|
||||
class SEQ(EXPRESSION):
|
||||
def __init__(self, exp1, exp2):
|
||||
super().__init__()
|
||||
self.exp1 = exp1
|
||||
self.exp2 = exp2
|
||||
|
||||
def __str__(self):
|
||||
return str(self.exp1) + "; " + str(self.exp2)
|
||||
|
||||
class IF(EXPRESSION):
|
||||
def __init__(self, cond, exp1, exp2):
|
||||
super().__init__()
|
||||
self.cond = cond
|
||||
self.exp1 = exp1
|
||||
self.exp2 = exp2
|
||||
|
||||
def __str__(self):
|
||||
return "if (" + str(self.cond) + ") then { " + str(self.exp1) + " } else { " + str(self.exp2) + " }"
|
||||
|
||||
class WHILE(EXPRESSION):
|
||||
def __init__(self, cond, body):
|
||||
super().__init__()
|
||||
self.cond = cond
|
||||
self.body = body
|
||||
|
||||
def __str__(self):
|
||||
return "while (" + str(self.cond) + ") do { " + str(self.body) + " }"
|
||||
92
Project-02-03/triplalex.py
Normal file
92
Project-02-03/triplalex.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# ------------------------------------------------------------
|
||||
# Tokenizer for the TRIPLA parser
|
||||
# ------------------------------------------------------------
|
||||
|
||||
import ply.lex as lex
|
||||
|
||||
reserved = {
|
||||
'let': 'LET',
|
||||
'in': 'IN',
|
||||
'if': 'IF',
|
||||
'then': 'THEN',
|
||||
'else': 'ELSE',
|
||||
'while': 'WHILE',
|
||||
'do': 'DO',
|
||||
'true': 'TRUE',
|
||||
'false': 'FALSE'
|
||||
}
|
||||
|
||||
# List of token names.
|
||||
tokens = [
|
||||
'ID',
|
||||
'CONST',
|
||||
'AOP',
|
||||
'COMP',
|
||||
'EQOP',
|
||||
'LOP',
|
||||
'ASSIGN',
|
||||
'LPAREN', 'RPAREN',
|
||||
'LBRACE', 'RBRACE',
|
||||
'COMMA',
|
||||
'SEMICOLON',
|
||||
] + list(reserved.values())
|
||||
|
||||
# Simple tokens
|
||||
t_LPAREN = r'\('
|
||||
t_RPAREN = r'\)'
|
||||
t_LBRACE = r'\{'
|
||||
t_RBRACE = r'\}'
|
||||
t_COMMA = r','
|
||||
t_SEMICOLON = r';'
|
||||
t_ASSIGN = r'='
|
||||
|
||||
# Arithmetic operators
|
||||
t_AOP = r'\+|\-|\*|/'
|
||||
|
||||
# Comparison operators
|
||||
t_COMP = r'<=|>=|<|>'
|
||||
|
||||
# Equality operators
|
||||
t_EQOP = r'\|\||&&|==|!='
|
||||
|
||||
# Logical operators
|
||||
t_LOP = r'\|\||&&'
|
||||
|
||||
# IDs
|
||||
def t_ID(t):
|
||||
r'[A-Za-z_][A-Za-z0-9_]*'
|
||||
t.type = reserved.get(t.value, 'ID')
|
||||
return t
|
||||
|
||||
# Constants
|
||||
def t_CONST(t):
|
||||
r'0|[1-9][0-9]*'
|
||||
t.value = int(t.value)
|
||||
return t
|
||||
|
||||
# Linebreaks
|
||||
def t_newline(t):
|
||||
r'\n+'
|
||||
t.lexer.lineno += len(t.value)
|
||||
|
||||
# Ignore whitespace
|
||||
t_ignore = ' \t'
|
||||
|
||||
# Single-line comment
|
||||
def t_comment_single(t):
|
||||
r'//.*'
|
||||
pass
|
||||
|
||||
# Multi-line comment
|
||||
def t_comment_multi(t):
|
||||
r'/\*([^*]|\*+[^*/])*\*/'
|
||||
t.lexer.lineno += t.value.count('\n')
|
||||
pass
|
||||
|
||||
# Error handling
|
||||
def t_error(t):
|
||||
print("Illegal character '%s'" % t.value[0])
|
||||
t.lexer.skip(1)
|
||||
|
||||
# Build the lexer
|
||||
lexer = lex.lex()
|
||||
2
Project-02-03/triplaprograms/argsParamsExample.tripla
Normal file
2
Project-02-03/triplaprograms/argsParamsExample.tripla
Normal file
@@ -0,0 +1,2 @@
|
||||
let a(x,y,z) {x}
|
||||
in a(1,2,3)
|
||||
15
Project-02-03/triplaprograms/complex.tripla
Normal file
15
Project-02-03/triplaprograms/complex.tripla
Normal file
@@ -0,0 +1,15 @@
|
||||
let
|
||||
f1(b) {
|
||||
if(b==0) then 0 else f1(b-1)
|
||||
}
|
||||
f2(a, b) {
|
||||
if(a > b) then f1(a) else f1(b);
|
||||
let g(c) {
|
||||
a*b*c
|
||||
} in g(a*b)
|
||||
}
|
||||
in
|
||||
f1(10); f2(10, let max(a, b) {
|
||||
if(a > b) then a else b
|
||||
}
|
||||
in max(20, 30))
|
||||
1
Project-02-03/triplaprograms/condition.tripla
Normal file
1
Project-02-03/triplaprograms/condition.tripla
Normal file
@@ -0,0 +1 @@
|
||||
if 2 < x && x > 9 then 1 else 0
|
||||
4
Project-02-03/triplaprograms/defSemiExample.tripla
Normal file
4
Project-02-03/triplaprograms/defSemiExample.tripla
Normal file
@@ -0,0 +1,4 @@
|
||||
let a(x) {x}
|
||||
b(y) {y}
|
||||
c(z) {z}
|
||||
in a(1); b(2); c(3)
|
||||
38
Project-02-03/triplaprograms/factorial.tripla
Normal file
38
Project-02-03/triplaprograms/factorial.tripla
Normal file
@@ -0,0 +1,38 @@
|
||||
let
|
||||
fac(x) {
|
||||
if (x == 1) then 1
|
||||
else fac(x-1)*x
|
||||
}
|
||||
fac(x) {
|
||||
if (x == 1) then 1
|
||||
else fac(x-1)*x
|
||||
}
|
||||
fac(x) {
|
||||
if (x == 1) then 1
|
||||
else fac(x-1)*x
|
||||
}
|
||||
fac(x) {
|
||||
if (x == 1) then 1
|
||||
else fac(x-1)*x
|
||||
}
|
||||
fac(x) {
|
||||
if (x == 1) then 1
|
||||
else fac(x-1)*x
|
||||
}
|
||||
fac(x) {
|
||||
if (x == 1) then 1
|
||||
else fac(x-1)*x
|
||||
}
|
||||
fac(x) {
|
||||
if (x == 1) then 1
|
||||
else fac(x-1)*x
|
||||
}
|
||||
fac(x) {
|
||||
if (x == 1) then 1
|
||||
else fac(x-1)*x
|
||||
}
|
||||
fac(x) {
|
||||
if (x == 1) then 1
|
||||
else fac(x-1)*x
|
||||
}
|
||||
in fac(3)
|
||||
1
Project-02-03/triplaprograms/faulty-multiple-let.tripla
Normal file
1
Project-02-03/triplaprograms/faulty-multiple-let.tripla
Normal file
@@ -0,0 +1 @@
|
||||
let n(a) {a} in n(5) + m(5) ; let m(a) {a+1} in m(5)
|
||||
1
Project-02-03/triplaprograms/faulty_if.tripla
Normal file
1
Project-02-03/triplaprograms/faulty_if.tripla
Normal file
@@ -0,0 +1 @@
|
||||
if (2 && 7 > 2) then 1 else 0
|
||||
7
Project-02-03/triplaprograms/func.tripla
Normal file
7
Project-02-03/triplaprograms/func.tripla
Normal file
@@ -0,0 +1,7 @@
|
||||
let func(a,b) {
|
||||
while ( a > 0 && b != a ) do {
|
||||
b = b + 1;
|
||||
a = a - 1
|
||||
}
|
||||
}
|
||||
in func(10, 8)
|
||||
12
Project-02-03/triplaprograms/ggT_euclid_iter.tripla
Normal file
12
Project-02-03/triplaprograms/ggT_euclid_iter.tripla
Normal file
@@ -0,0 +1,12 @@
|
||||
let ggT(a, b) {
|
||||
if (a == b) then
|
||||
a
|
||||
else
|
||||
do {
|
||||
if (a > b) then
|
||||
a = a - b
|
||||
else
|
||||
b = b - a
|
||||
} while (a != b);
|
||||
a
|
||||
} in ggT(3528, 3780) // result should be 252
|
||||
8
Project-02-03/triplaprograms/ggT_euclid_rec.tripla
Normal file
8
Project-02-03/triplaprograms/ggT_euclid_rec.tripla
Normal file
@@ -0,0 +1,8 @@
|
||||
let ggT(a, b) {
|
||||
if (a == b) then
|
||||
a
|
||||
else if (a > b) then
|
||||
ggT(a-b, b)
|
||||
else
|
||||
ggT(b-a, a)
|
||||
} in ggT(3528, 3780) // result should be 252
|
||||
3
Project-02-03/triplaprograms/invalidProgram.tripla
Normal file
3
Project-02-03/triplaprograms/invalidProgram.tripla
Normal file
@@ -0,0 +1,3 @@
|
||||
let f1(b) { if (b == 0) then 0 else f1(b-1) }
|
||||
f2(a,b) { if (a > b) then f1(a) else f1(b) }
|
||||
in f1(10); f2(10,-20)
|
||||
@@ -0,0 +1 @@
|
||||
let m(a){a} in m(5);let m(b){b+1} in m(5)
|
||||
1
Project-02-03/triplaprograms/multiple-let.tripla
Normal file
1
Project-02-03/triplaprograms/multiple-let.tripla
Normal file
@@ -0,0 +1 @@
|
||||
let n(a) {a} in n(5) ; let m(a) {a+1} in n(5) + m(5)
|
||||
1
Project-02-03/triplaprograms/or.tripla
Normal file
1
Project-02-03/triplaprograms/or.tripla
Normal file
@@ -0,0 +1 @@
|
||||
if(true||true==true) then 1 else 0
|
||||
3
Project-02-03/triplaprograms/p1.tripla
Normal file
3
Project-02-03/triplaprograms/p1.tripla
Normal file
@@ -0,0 +1,3 @@
|
||||
let g(a) {
|
||||
a*a
|
||||
} in g(5)
|
||||
9
Project-02-03/triplaprograms/p2.tripla
Normal file
9
Project-02-03/triplaprograms/p2.tripla
Normal file
@@ -0,0 +1,9 @@
|
||||
let f1(b) {
|
||||
if (b==0) then 0 else f1(b-1)
|
||||
} in f1(10)
|
||||
/*
|
||||
f2(a,b) {
|
||||
if (a>b) then f1(a) else f1(b)
|
||||
}
|
||||
in f1(10); f2(10,20)
|
||||
*/
|
||||
14
Project-02-03/triplaprograms/p3.tripla
Normal file
14
Project-02-03/triplaprograms/p3.tripla
Normal file
@@ -0,0 +1,14 @@
|
||||
let f1(b) {
|
||||
if (b==0) then 0 else f1(b-1)
|
||||
}
|
||||
f2(a,b) {
|
||||
if (a>b) then f1(a) else f1(b);
|
||||
let g(c) {
|
||||
a*b*c
|
||||
}
|
||||
in g(a*b)
|
||||
}
|
||||
in f1(10); f2(10, let max(a,b) {
|
||||
if (a>b) then a else b
|
||||
}
|
||||
in max(20,30) )
|
||||
4
Project-02-03/triplaprograms/p4.tripla
Normal file
4
Project-02-03/triplaprograms/p4.tripla
Normal file
@@ -0,0 +1,4 @@
|
||||
let func(a,b) {
|
||||
a = b + 1
|
||||
}
|
||||
in func(10, 8)
|
||||
9
Project-02-03/triplaprograms/p5.tripla
Normal file
9
Project-02-03/triplaprograms/p5.tripla
Normal file
@@ -0,0 +1,9 @@
|
||||
let func(a, b) {
|
||||
let func(a, b) {
|
||||
a * b
|
||||
} in
|
||||
do {
|
||||
b = b + 1 * func(3, 1);
|
||||
a = a - 1
|
||||
} while ( a > 0 && b != a )
|
||||
} in func(10, 8)
|
||||
13
Project-02-03/triplaprograms/p6.tripla
Normal file
13
Project-02-03/triplaprograms/p6.tripla
Normal file
@@ -0,0 +1,13 @@
|
||||
let f(a, b) {
|
||||
if (a == 0) then
|
||||
2 + b
|
||||
else
|
||||
let g(a, c) {
|
||||
a + c + b
|
||||
} in 2 + g(a, b)
|
||||
} g(c, d) {
|
||||
if (c == 0) then
|
||||
1 + d
|
||||
else
|
||||
c * f(c - 1, d)
|
||||
} in f (2, 3); g (3, 2)
|
||||
5
Project-02-03/triplaprograms/side_effect.tripla
Normal file
5
Project-02-03/triplaprograms/side_effect.tripla
Normal file
@@ -0,0 +1,5 @@
|
||||
let f(x, y) {
|
||||
let g(x) {
|
||||
y = x + 7
|
||||
} in x = g(5); y
|
||||
} in f(1, 2)
|
||||
4
Project-02-03/triplaprograms/simple_dfa.tripla
Normal file
4
Project-02-03/triplaprograms/simple_dfa.tripla
Normal file
@@ -0,0 +1,4 @@
|
||||
let g(x, y) {
|
||||
y = 3;
|
||||
x
|
||||
} in g(2)
|
||||
1
Project-02-03/triplaprograms/simple_if.tripla
Normal file
1
Project-02-03/triplaprograms/simple_if.tripla
Normal file
@@ -0,0 +1 @@
|
||||
if (true) then 1 else 0
|
||||
1
Project-02-03/triplaprograms/simple_if_2.tripla
Normal file
1
Project-02-03/triplaprograms/simple_if_2.tripla
Normal file
@@ -0,0 +1 @@
|
||||
if (true && false) then 1 else 0
|
||||
1
Project-02-03/triplaprograms/simple_if_3.tripla
Normal file
1
Project-02-03/triplaprograms/simple_if_3.tripla
Normal file
@@ -0,0 +1 @@
|
||||
if (true || false) then 1 else 0
|
||||
1
Project-02-03/triplaprograms/simple_if_4.tripla
Normal file
1
Project-02-03/triplaprograms/simple_if_4.tripla
Normal file
@@ -0,0 +1 @@
|
||||
if (1 > 2) then 1 else 0
|
||||
1
Project-02-03/triplaprograms/simple_if_5.tripla
Normal file
1
Project-02-03/triplaprograms/simple_if_5.tripla
Normal file
@@ -0,0 +1 @@
|
||||
if (2 > 3 + 5) then 1 else 0
|
||||
1
Project-02-03/triplaprograms/simple_if_6.tripla
Normal file
1
Project-02-03/triplaprograms/simple_if_6.tripla
Normal file
@@ -0,0 +1 @@
|
||||
if (1 > 2 || 3 < 5) then 1 else 0
|
||||
1
Project-02-03/triplaprograms/simple_if_7.tripla
Normal file
1
Project-02-03/triplaprograms/simple_if_7.tripla
Normal file
@@ -0,0 +1 @@
|
||||
if (2 == 0 == false) then 1 else 0
|
||||
2
Project-02-03/triplaprograms/square.tripla
Normal file
2
Project-02-03/triplaprograms/square.tripla
Normal file
@@ -0,0 +1,2 @@
|
||||
let square(x) { x*x }
|
||||
in square(10)
|
||||
4
Project-02-03/triplaprograms/validProgram.tripla
Normal file
4
Project-02-03/triplaprograms/validProgram.tripla
Normal file
@@ -0,0 +1,4 @@
|
||||
let mult(a,b) { a*b }
|
||||
add(a,b) { let inc(a) { if (b!=0) then b=b-1;inc(a+1) else mult(a,1) }
|
||||
in inc(a) }
|
||||
in add(mult(2,3),add(4,5))
|
||||
7
Project-02-03/triplaprograms/while.tripla
Normal file
7
Project-02-03/triplaprograms/while.tripla
Normal file
@@ -0,0 +1,7 @@
|
||||
let func(a,b) {
|
||||
while ( a > 0 && b != a ) do {
|
||||
b = b + 1;
|
||||
a = a - 1
|
||||
}
|
||||
}
|
||||
in func(10, 8)
|
||||
3
Project-02-03/triplaprograms/while_2.tripla
Normal file
3
Project-02-03/triplaprograms/while_2.tripla
Normal file
@@ -0,0 +1,3 @@
|
||||
while (true) do {
|
||||
3
|
||||
}
|
||||
8
Project-02-03/triplaprograms/wrapped-ggT.tripla
Normal file
8
Project-02-03/triplaprograms/wrapped-ggT.tripla
Normal file
@@ -0,0 +1,8 @@
|
||||
let wrapper(a, b) {
|
||||
let ggt(noneSense) {
|
||||
if a == b then a
|
||||
else
|
||||
if a > b then wrapper(a-b, b)
|
||||
else wrapper(b-a, a)
|
||||
} in ggt(0)
|
||||
} in wrapper(21, 49)
|
||||
9
Project-02-03/triplaprograms/wrapper.tripla
Normal file
9
Project-02-03/triplaprograms/wrapper.tripla
Normal file
@@ -0,0 +1,9 @@
|
||||
let wrapper(number, threshold) {
|
||||
let square(x) {
|
||||
if x*x > threshold
|
||||
then x
|
||||
else x*x
|
||||
}
|
||||
in square(number)
|
||||
}
|
||||
in wrapper(4, 10)
|
||||
143
Project-02-03/triplayacc.py
Normal file
143
Project-02-03/triplayacc.py
Normal file
@@ -0,0 +1,143 @@
|
||||
# ------------------------------------------------------------
|
||||
# Grammar of the TRIPLA language
|
||||
# ------------------------------------------------------------
|
||||
|
||||
import ply.yacc as yacc
|
||||
import syntax as ast
|
||||
from triplalex import tokens
|
||||
|
||||
# Operator precedence
|
||||
precedence = (
|
||||
('left', 'SEMICOLON'),
|
||||
('right', 'IN'),
|
||||
('left', 'COMP'),
|
||||
('left', 'EQOP'),
|
||||
('left', 'AOP'),
|
||||
)
|
||||
|
||||
start = 'E'
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Rules for E
|
||||
# ------------------------------------------------------------
|
||||
|
||||
def p_E_let(p):
|
||||
'E : LET D IN E'
|
||||
p[0] = ast.LET(p[2], p[4])
|
||||
|
||||
def p_E_id(p):
|
||||
'E : ID'
|
||||
p[0] = ast.ID(p[1])
|
||||
|
||||
def p_E_call(p):
|
||||
'E : ID LPAREN A RPAREN'
|
||||
# E : ID(A)
|
||||
p[0] = ast.CALL(p[1], p[3])
|
||||
|
||||
def p_E_aop(p):
|
||||
'E : E AOP E'
|
||||
p[0] = ast.AOP(p[2], p[1], p[3])
|
||||
|
||||
def p_E_paren(p):
|
||||
'E : LPAREN E RPAREN'
|
||||
# E : (E)
|
||||
p[0] = p[2]
|
||||
|
||||
def p_E_const(p):
|
||||
'E : CONST'
|
||||
p[0] = ast.CONST(p[1])
|
||||
|
||||
def p_E_assign(p):
|
||||
'E : ID ASSIGN E'
|
||||
p[0] = ast.ASSIGN(ast.ID(p[1]), p[3])
|
||||
|
||||
def p_E_seq(p):
|
||||
'E : E SEMICOLON E'
|
||||
p[0] = ast.SEQ(p[1], p[3])
|
||||
|
||||
def p_E_if(p):
|
||||
'E : IF B THEN E ELSE E'
|
||||
p[0] = ast.IF(p[2], p[4], p[6])
|
||||
|
||||
def p_E_while(p):
|
||||
'E : WHILE B DO LBRACE E RBRACE'
|
||||
p[0] = ast.WHILE(p[2], p[5])
|
||||
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Rules for A
|
||||
# ------------------------------------------------------------
|
||||
|
||||
def p_A_single(p):
|
||||
'A : E'
|
||||
p[0] = [p[1]]
|
||||
|
||||
def p_A_multiple(p):
|
||||
'A : A COMMA E'
|
||||
p[0] = p[1] + [p[3]]
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Rules for D
|
||||
# ------------------------------------------------------------
|
||||
|
||||
def p_D_single(p):
|
||||
'D : ID LPAREN V RPAREN LBRACE E RBRACE'
|
||||
p[0] = [ast.DECL(p[1], p[3], p[6])]
|
||||
|
||||
def p_D_concat(p):
|
||||
'D : D D'
|
||||
p[0] = p[1] + p[2]
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Rules for V
|
||||
# ------------------------------------------------------------
|
||||
|
||||
def p_V_single(p):
|
||||
'V : ID'
|
||||
p[0] = [p[1]]
|
||||
|
||||
def p_V_multiple(p):
|
||||
'V : V COMMA V'
|
||||
p[0] = p[1] + p[3]
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Rules for B
|
||||
# ------------------------------------------------------------
|
||||
|
||||
def p_B_eqop_E(p):
|
||||
'B : E EQOP E'
|
||||
p[0] = ast.EQOP(p[2], p[1], p[3])
|
||||
|
||||
def p_B_comp(p):
|
||||
'B : E COMP E'
|
||||
p[0] = ast.COMP(p[2], p[1], p[3])
|
||||
|
||||
def p_B_eqop_B(p):
|
||||
'B : B EQOP B'
|
||||
p[0] = ast.EQOP(p[2], p[1], p[3])
|
||||
|
||||
def p_B_lop(p):
|
||||
'B : B LOP B'
|
||||
p[0] = ast.LOP(p[2], p[1], p[3])
|
||||
|
||||
def p_B_true(p):
|
||||
'B : TRUE'
|
||||
p[0] = ast.CONST(True)
|
||||
|
||||
def p_B_false(p):
|
||||
'B : FALSE'
|
||||
p[0] = ast.CONST(False)
|
||||
|
||||
def p_B_paren(p):
|
||||
'B : LPAREN B RPAREN'
|
||||
# B : (B)
|
||||
p[0] = p[2]
|
||||
|
||||
# Error handling
|
||||
def p_error(p):
|
||||
if p:
|
||||
print("Syntax error at token:", p.type, "value:", p.value)
|
||||
else:
|
||||
print("Syntax error at EOF")
|
||||
|
||||
parser = yacc.yacc()
|
||||
Reference in New Issue
Block a user