compilation/spf.py

224 lines
6.9 KiB
Python
Raw Normal View History

2025-03-15 19:37:31 +01:00
#!/usr/bin/env python
2025-03-15 17:16:09 +01:00
# Projet de compilation Umons 2025
2025-03-15 19:37:31 +01:00
# Par Debucquoy Anthony (231687)
import argparse
import lark
import sys
2025-03-19 16:29:54 +01:00
from enum import Enum
from modules.Variables import Variables
2025-04-28 15:38:42 +02:00
from modules.errors import *
2025-03-19 16:29:54 +01:00
class SPFInterpreter(lark.visitors.Interpreter):
def __init__(self, trace=False):
super().__init__()
self.variables = Variables(trace)
2025-03-20 13:27:57 +01:00
def while_loop(self, el):
2025-03-23 09:52:05 +01:00
old = self.variables.variables.copy()
2025-03-20 17:34:27 +01:00
while self.visit_children(el.children[0])[0]:
2025-03-20 21:11:17 +01:00
self.visit_children(el.children[1])
2025-03-23 09:52:05 +01:00
self.variables.variables = old.copy()
2025-03-20 13:27:57 +01:00
def for_loop(self, el):
2025-03-20 21:11:17 +01:00
type = el.children[0].value
name = el.children[1].value
2025-03-23 09:52:05 +01:00
old = self.variables.variables.copy()
2025-04-28 15:38:42 +02:00
try:
self.variables.declare(type, name)
except SPFException as e:
e.errorline = el.meta.line
raise e
2025-03-20 21:11:17 +01:00
target = self.visit_children(el.children[2])[0]
for i in target:
2025-04-28 15:38:42 +02:00
try:
self.variables.assign(name, i)
except SPFException as e:
e.errorline = el.meta.line
raise e
2025-03-20 21:11:17 +01:00
self.visit_children(el.children[3])
2025-03-23 09:52:05 +01:00
self.variables.variables = old.copy()
2025-03-20 13:27:57 +01:00
2025-03-19 16:29:54 +01:00
def afficher(self, el):
2025-03-20 13:27:57 +01:00
ligne = ""
2025-03-19 16:29:54 +01:00
for toprint in el.children[1:]:
2025-03-20 13:27:57 +01:00
ligne += str(self.visit_children(toprint)[0]) + " "
print(ligne)
2025-03-20 13:33:23 +01:00
def append(self, el):
(_, toadd, var) = self.visit_children(el);
2025-04-28 15:38:42 +02:00
try:
var_val = self.variables.get(var.value)
except SPFException as e:
e.errorline = el.meta.line
raise e
2025-03-20 13:33:23 +01:00
var_val.append(toadd)
2025-03-19 16:29:54 +01:00
def declaration(self, el):
type = el.children[0].value
name = el.children[1].value
2025-03-20 00:52:05 +01:00
value = self.visit_children(el.children[3])[0] if len(el.children) >= 3 else None
2025-04-28 15:38:42 +02:00
try:
self.variables.declare(type, name, value)
except SPFException as e:
e.errorline = el.meta.line
raise e
2025-03-19 16:29:54 +01:00
def assignation(self, el):
name = el.children[0].value
assert el.children[1].value == "=" and el.children[2].data == "expression", "Unexpected"
2025-03-19 16:29:54 +01:00
value = self.visit_children(el.children[2])[0]
2025-04-28 15:38:42 +02:00
try:
self.variables.assign(name, value)
except SPFException as e:
e.errorline = el.meta.line
raise e
2025-03-19 16:29:54 +01:00
def expression(self, el):
return self.visit_children(el)[0]
2025-03-20 13:27:57 +01:00
def logical(self, el):
result = self.visit_children(el)
if len(result) < 2:
return result[0]
if result[1][0].type == "AND_OP":
return result[0] and result[1][1]
elif result[1][0].type == "OR_OP":
return result[0] or result[1][1]
assert "Unreachable"
def comparison(self, el):
result = self.visit_children(el)
if len(result) < 2:
return result[0]
if result[1][0].type == "SAME_OP":
return result[0] == result[1][1]
elif result[1][0].type == "DIFF_OP":
return result[0] != result[1][1]
elif result[1][0].type == "LT_OP":
return result[0] < result[1][1]
elif result[1][0].type == "LE_OP":
return result[0] <= result[1][1]
elif result[1][0].type == "GT_OP":
return result[0] > result[1][1]
elif result[1][0].type == "GE_OP":
return result[0] >= result[1][1]
assert "Unreachable"
def sumterm(self, el):
result = self.visit_children(el)
if len(result) < 2:
return result[0]
if result[1][0].type == "PLUS_OP":
return result[0] + result[1][1]
elif result[1][0].type == "MINUS_OP":
return result[0] - result[1][1]
assert "Unreachable"
def multterm(self, el):
result = self.visit_children(el)
if len(result) < 2:
return result[0]
if result[1][0].type == "TIMES_OP":
return result[0] * result[1][1]
2025-03-23 00:08:42 +01:00
elif result[1][0].type == "DIVIDE_OP": # Division entière car nous ne gérons pas les flotants
return result[0] // result[1][1]
assert "Unreachable"
def priority(self, el):
result = self.visit_children(el)
if len(result) < 2:
return result[0]
elif result[0].type == "SIZE_OP":
return len(result[1])
elif result[0].type == "NEG_OP":
return -result[1]
elif result[0].type == "NOT_OP":
return not result[1]
2025-03-20 13:27:57 +01:00
2025-03-20 21:11:17 +01:00
def list_get(self, el):
result = self.visit_children(el)
2025-04-28 15:38:42 +02:00
try:
return result[0][result[1] - 1] # Index start at 1 (like lua)
except IndexError:
e = SPFIndexError(result[0], result[1])
e.errorline = el.meta.line
raise e
2025-03-20 13:27:57 +01:00
def finalterm(self, el):
2025-03-19 16:29:54 +01:00
return self.visit_children(el)[0]
def variable(self, el):
2025-04-28 15:38:42 +02:00
try:
return self.variables.get(el.children[0].value)
except SPFException as e:
e.errorline = el.meta.line
raise e
2025-03-19 16:29:54 +01:00
2025-03-20 21:11:17 +01:00
def test(self,el):
2025-03-23 09:52:05 +01:00
old = self.variables.variables.copy()
2025-03-20 21:11:17 +01:00
if self.visit_children(el.children[0])[0]:
self.visit_children(el.children[1])
elif len(el.children) >= 3:
self.visit_children(el.children[2])
2025-03-23 09:52:05 +01:00
self.variables.variables = old.copy()
2025-03-20 21:11:17 +01:00
2025-03-19 16:29:54 +01:00
# Literals
string = lambda self, el: el.children[0][1:-1]
entier = lambda self, el: int(el.children[0])
true = lambda self, _: True
false = lambda self, _: False
2025-03-15 17:16:09 +01:00
2025-03-20 21:37:08 +01:00
def range(self, el):
(left, right) = self.visit_children(el)
return list(range(left, right+1))
def dump(self):
self.variables.dump()
2025-03-16 11:34:15 +01:00
2025-03-15 17:16:09 +01:00
def main():
2025-03-16 11:34:15 +01:00
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("spf_file", help="Fichier source à interpréter")
arg_parser.add_argument("-d", "--dump",
2025-03-15 19:37:31 +01:00
help="affichage de la mémoire du programme",
action="store_true")
2025-03-16 11:34:15 +01:00
arg_parser.add_argument("-t", "--trace",
2025-03-15 19:37:31 +01:00
help="affichage de la mémoire au cours du programme",
action="store_true")
2025-03-20 13:27:57 +01:00
arg_parser.add_argument("-p", "--pretty",
help="affichage de l'arbre et quite",
action="store_true")
2025-03-16 11:34:15 +01:00
args = arg_parser.parse_args()
2025-03-15 19:37:31 +01:00
2025-03-16 11:34:15 +01:00
with open("spf.lark") as grammar:
2025-04-28 15:38:42 +02:00
spf_parser = lark.Lark(grammar, parser="lalr", strict=True, debug=True, propagate_positions=True)
2025-03-16 11:34:15 +01:00
with open(args.spf_file) as spf_input:
2025-03-16 11:50:54 +01:00
program = spf_input.read()
2025-04-28 15:38:42 +02:00
try:
parsed = spf_parser.parse(program)
except lark.UnexpectedInput as u:
e = SPFSyntaxError()
e.errorline = u.line
raise e
2025-03-20 13:27:57 +01:00
if args.pretty:
print(parsed.pretty())
return
interpreter = SPFInterpreter(args.trace)
2025-03-19 16:29:54 +01:00
interpreted = interpreter.visit(parsed)
if args.dump:
2025-03-20 00:52:05 +01:00
interpreter.dump()
2025-03-16 11:34:15 +01:00
2025-03-15 17:16:09 +01:00
if __name__ == "__main__":
main()