diff --git a/examples/simple.spf b/examples/simple.spf index 06138d2..61f4245 100644 --- a/examples/simple.spf +++ b/examples/simple.spf @@ -8,6 +8,6 @@ afficher nom, age, majeur; #TODO: Ces lignes devraient donner une erreur -majeur = 42; +# majeur = 42; -afficher majeur; +# afficher majeur; diff --git a/modules/Variables.py b/modules/Variables.py new file mode 100644 index 0000000..08a073c --- /dev/null +++ b/modules/Variables.py @@ -0,0 +1,68 @@ +import sys + +trace_format = '\033[1m -> ' +reset_format = '\033[0m' + +class Variables: + + class Variable: + types = { "entier": int, + "texte": str, + "booléen": bool, + "liste": list } + + def __init__(self, typ, value = None): + assert typ in self.types.keys(), "Ce type de variable est inconnu" + self.type = typ + assert self.checkType(value, typ), "Le type n'est pas équivalent" + self.value = value if (value is not None) else self.default(typ) + + def set(self, value): + assert self.checkType(value, self.type), "Le type n'est pas équivalent" + self.value = value + + def __str__(self): + if self.type == "booléen": + return "Vrai" if self.value else "Faux" + return f"{self.value}" + + def __repr__(self): + if self.type == "texte": + return f"\"{self.value}\"" + return f"{self.value}" + + + def checkType(self, value, typ) -> bool: + return type(value) == self.types[typ] + + def default(self, typ): + if typ == "entier": + return 0 + if typ == "texte": + return "" + if typ == "booléen": + return False + if typ == "liste": + return [] + + def __init__(self, trace=False): + self.variables = {} + self.trace = trace + + def get(self, name): + assert name in self.variables, "la variable {name} n'éxiste pas" + if self.trace: + print(f"{trace_format}accède {name}{reset_format}", file=sys.stdout) + return self.variables[name] + + def declare(self, typ, name, value=None): + assert name not in self.variables, "la variable {name} existe déjà" + self.variables[name] = self.Variable(typ, value) + if self.trace: + print(f"{trace_format}déclare {name} = {value}{reset_format}", file=sys.stdout) + + def assign(self, name, value): + assert name in self.variables, "la variable n'éxiste pas" + self.variables[name].set(value) + if self.trace: + print(f"{trace_format}modifie {name} = {value}{reset_format}", file=sys.stdout) diff --git a/modules/__pycache__/Variables.cpython-313.pyc b/modules/__pycache__/Variables.cpython-313.pyc new file mode 100644 index 0000000..b7acd23 Binary files /dev/null and b/modules/__pycache__/Variables.cpython-313.pyc differ diff --git a/spf.py b/spf.py index 0b1da1b..d076365 100755 --- a/spf.py +++ b/spf.py @@ -7,32 +7,13 @@ import argparse import lark import sys from enum import Enum - -variables = {} - -class VariableType(Enum): - boolean = 1 - integer = 2 - string = 3 - list = 4 - - -class Variable(): - def __init__(self, type, value): - self.type = type - self.value = value - - def __str__(self): - if self.type == "booléen": - return "Vrai" if self.value else "Faux" - return f"{self.value}" - - def __repr__(self): - if self.type == "texte": - return f"\"{self.value}\"" - return f"{self.value}" +from modules.Variables import Variables class SPFInterpreter(lark.visitors.Interpreter): + def __init__(self, trace=False): + super().__init__() + self.variables = Variables(trace) + def afficher(self, el): for toprint in el.children[1:]: print(self.visit_children(toprint)[0]) @@ -41,26 +22,20 @@ class SPFInterpreter(lark.visitors.Interpreter): def declaration(self, el): type = el.children[0].value name = el.children[1].value - assert el.children[2].value == "=", "Unexpected" - assert el.children[3].data == "expression", "Unexpected" - value = self.visit_children(el.children[3])[0] - variables[name] = Variable(type, value) + value = self.visit_children(el.children[3])[0] if el.children[2].value == "=" else None + self.variables.declare(type, name, value) def assignation(self, el): name = el.children[0].value - assert name in variables, f"Unknown variable : {el.children[0].value} not in {variables}" - assert el.children[1].value == "=", "Unexpected" - assert el.children[2].data == "expression", "Unexpected" + assert el.children[1].value == "=" and el.children[2].data == "expression", "Unexpected" value = self.visit_children(el.children[2])[0] - variables[name] = value #TODO: vérifier type + self.variables.assign(name, value) def expressionleft(self, el): return self.visit_children(el)[0] - def variable(self, el): - assert el.children[0].value in variables, f"Unknown variable : {el.children[0].value} not in {variables}" - return variables[el.children[0].value] + return self.variables.get(el.children[0].value) # Literals string = lambda self, el: el.children[0][1:-1] @@ -68,6 +43,9 @@ class SPFInterpreter(lark.visitors.Interpreter): true = lambda self, _: True false = lambda self, _: False + def dump(self): + self.variables.dump() + def main(): @@ -81,9 +59,6 @@ def main(): action="store_true") args = arg_parser.parse_args() - if args.trace: - print("Trace activated (TODO)", file=sys.stderr) - with open("spf.lark") as grammar: spf_parser = lark.Lark(grammar, parser="lalr", strict=True, debug=True) @@ -91,11 +66,11 @@ def main(): program = spf_input.read() parsed = spf_parser.parse(program) - interpreter = SPFInterpreter() + interpreter = SPFInterpreter(args.trace) interpreted = interpreter.visit(parsed) if args.dump: - print(variables, file=sys.stderr) + interpreted.dump() if __name__ == "__main__":