diff --git a/Pystan/config/__pycache__/cfg.cpython-313.pyc b/Pystan/config/__pycache__/cfg.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c3ffffab7a0737bfb74d5be43837053ddb87acb1 Binary files /dev/null and b/Pystan/config/__pycache__/cfg.cpython-313.pyc differ diff --git a/Pystan/config/__pycache__/constant_propagation.cpython-313.pyc b/Pystan/config/__pycache__/constant_propagation.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a01b56edf7eafb1c391af416e2e46c43bb51549 Binary files /dev/null and b/Pystan/config/__pycache__/constant_propagation.cpython-313.pyc differ diff --git a/Pystan/config/__pycache__/iteration.cpython-313.pyc b/Pystan/config/__pycache__/iteration.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..048fa971e9575d16379fd23b74dae85249c0effd Binary files /dev/null and b/Pystan/config/__pycache__/iteration.cpython-313.pyc differ diff --git a/Pystan/config/__pycache__/opsem.cpython-313.pyc b/Pystan/config/__pycache__/opsem.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06b6a357707d7d0870ab2b7b33ade29facc3a329 Binary files /dev/null and b/Pystan/config/__pycache__/opsem.cpython-313.pyc differ diff --git a/Pystan/config/__pycache__/syntax.cpython-313.pyc b/Pystan/config/__pycache__/syntax.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f2696bbaf18113c95f76aef9b1c34a4d5329266 Binary files /dev/null and b/Pystan/config/__pycache__/syntax.cpython-313.pyc differ diff --git a/Pystan/config/constant_propagation.py b/Pystan/config/constant_propagation.py index a530c34071106acc53ced1ee96915ab2cb9deb93..f7f78dd23bf9b669a115bc0ab9c07bf014bf80f2 100644 --- a/Pystan/config/constant_propagation.py +++ b/Pystan/config/constant_propagation.py @@ -82,26 +82,77 @@ def eval_bexp(env: abstract_env, e: BoolExpr) -> abstract_value[bool] | None: class Constant_propagation(Transfer[state]): variables: frozenset[str] - def __init__(self,instr): + + def __init__(self, instr): self.variables = variables_of_instr(instr) + def bottom(self) -> state: - ... + return None + def init_state(self) -> state: - ... - def join(self,s1:state,s2:state) -> state: - ... + return {v: abstract_value(None) for v in self.variables} + + def join(self, s1: state, s2: state) -> state: + if s1 is None: + return s2 + if s2 is None: + return s1 + result = {} + for var in self.variables: + v1 = s1.get(var, abstract_value(None)) + v2 = s2.get(var, abstract_value(None)) + if v1.value == v2.value: + result[var] = v1 + else: + result[var] = abstract_value(None) + return result - def included(self,s1: state,s2: state) -> bool: - ... + def included(self, s1: state, s2: state) -> bool: + if s1 is None: + return True + if s2 is None: + return False + for var in self.variables: + v1 = s1.get(var, abstract_value(None)) + v2 = s2.get(var, abstract_value(None)) + if v1.value != v2.value and v2.value is not None: + return False + return True - def tr_skip(self,s: state) -> state: - ... + def tr_skip(self, s: state) -> state: + return s - def tr_set(self,s: state,v: str,e: ArithExpr) -> state: - ... + def tr_set(self, s: state, v: str, e: ArithExpr) -> state: + if s is None: + return None + new_env = s.copy() + result = eval_aexp(s, e) + if result is None: + return None + new_env[v] = result + return new_env - def tr_test(self,s: state,c: BoolExpr) -> state: - ... + def tr_test(self, s: state, c: BoolExpr) -> state: + if s is None: + return None + result = eval_bexp(s, c) + if result is None: + return None + if result.value is False: + return None + elif result.value is True: + return s + else: + match c: + case BEEq(AEVar(x), AECst(cst)) if x in s: + env = s.copy() + env[x] = abstract_value(cst) + return env + case BEEq(AECst(cst), AEVar(x)) if x in s: + env = s.copy() + env[x] = abstract_value(cst) + return env + return s - def tr_err(self,s: state,e: Expr) -> state: - ... + def tr_err(self, s: state, e: Expr) -> state: + return None \ No newline at end of file diff --git a/Pystan/config/iteration.py b/Pystan/config/iteration.py index f91169661c566371dc324842b44f562fe95b4d76..50dbbb477e0fc2d1c0e90f331081cb71a808741e 100644 --- a/Pystan/config/iteration.py +++ b/Pystan/config/iteration.py @@ -43,4 +43,35 @@ def fixpoint_iteration[T](transfer: Transfer[T], cfg: Cfg) -> dict[Node,T]: output maps each node to the computed state """ - raise NotImplementedError + states: dict[Node, T] = {node: transfer.bottom() for node in cfg.g.nodes} + states[cfg.init_node] = transfer.init_state() + worklist: list[tuple[Node, Node, Label]] = [] + + for dest, label in cfg.init_node.succs: + worklist.append((cfg.init_node, dest, label)) + + while worklist: + src, dst, label = worklist.pop(0) + s_src = states[src] + if isinstance(label, LSkip): + s_new = transfer.tr_skip(s_src) + elif isinstance(label, LSet): + s_new = transfer.tr_set(s_src, label.var, label.expr) + elif isinstance(label, LTest): + s_new = transfer.tr_test(s_src, label.cond) + elif isinstance(label, LErr): + s_new = transfer.tr_err(s_src, label.err) + else: + raise ValueError(f"Étiquette inconnue: {label}") + + s_dst_old = states[dst] + + if not transfer.included(s_new, s_dst_old): + states[dst] = transfer.join(s_dst_old, s_new) + + for dest2, label2 in dst.succs: + worklist.append((dst, dest2, label2)) + + return states + +"""Les noeuds non atteignables sont les noeuds que le code ne peut jamais visité ici ils sont les cas ou les tests ne sont pas vérifés ce qui est impossible à visiter parce que les tests ont la condition 1""" \ No newline at end of file diff --git a/Pystan/config/opsem.py b/Pystan/config/opsem.py index 1313e985e2c11ca43cc8fcaa926eec02eba135f1..e46b9fd5a91e47680339a062503c876613f8977b 100644 --- a/Pystan/config/opsem.py +++ b/Pystan/config/opsem.py @@ -9,42 +9,66 @@ These functions return None when an error occur somewhere (Big step semantics) from syntax import * def eval_aexp(env: dict[str,int], exp: ArithExpr) -> int | None: - """evaluates an arithmetic expression""" + """evaluates an arithmetic expression safely""" match exp: case AECst(value): - raise NotImplementedError + return value case AEVar(var): - raise NotImplementedError - case AEUop(uop,expr): - raise NotImplementedError - case AEBop(bop,left_expr,right_expr): - raise NotImplementedError - case _: assert False + return env.get(var, None) + case AEUop(uop, expr): + val = eval_aexp(env, expr) + if val is None: + return None + if uop == Uop.OPP: + return -val + return None + case AEBop(bop, left_expr, right_expr): + v1 = eval_aexp(env, left_expr) + v2 = eval_aexp(env, right_expr) + if v1 is None or v2 is None: + return None + if bop == Bop.ADD: + return v1 + v2 + elif bop == Bop.MUL: + return v1 * v2 + elif bop == Bop.DIV: + if v2 == 0: + return None + return v1 // v2 + case _: + return None def eval_bexp(env: dict[str,int], exp:BoolExpr) -> bool | None: """evaluates a boolean expression""" match exp: case BEPlain(aexpr): - raise NotImplementedError + return eval_aexp(env,aexpr) != 0 case BEEq(left_expr,right_expr): - raise NotImplementedError + return eval_aexp(env,left_expr) == eval_aexp(env,right_expr) case BELeq(left_expr,right_expr): - raise NotImplementedError + return eval_aexp(env,left_expr) <= eval_aexp(env,right_expr) case BENeg(expr): - raise NotImplementedError + return not eval_bexp(env,expr) case _: assert False def eval_instr(env: dict[str,int], instr: Instr) -> dict[str,int] | None: """evaluates an instruction""" match instr: case ISkip(): - raise NotImplementedError + return env case ISet(var,expr): - raise NotImplementedError + new_env = env.copy() + new_env[var] = eval_aexp(new_env,expr) + return new_env case ISeq(first,second): - raise NotImplementedError + return eval_instr(eval_instr(env,first),second) case ICond(cond,true_branch,false_branch): - raise NotImplementedError + if eval_bexp(env,cond): + return eval_instr(env,true_branch) + else: + return eval_instr(env,false_branch) case ILoop(cond,body): - raise NotImplementedError + while eval_bexp(env,cond): + env = eval_instr(env,body) + return env case _: assert False diff --git a/Pystan/config/syntax.py b/Pystan/config/syntax.py index c0938bda1f9a7554cc4db3a13763d0d68732c5bc..bc1c53f78766f91360887b37538862d4331b48b3 100644 --- a/Pystan/config/syntax.py +++ b/Pystan/config/syntax.py @@ -67,7 +67,14 @@ class AEBop(ArithExpr): right_expr: ArithExpr def __str__(self): #TODO: only put parentheses if necessary - return f"({self.left_expr}) {self.bop} ({self.right_expr})" + if isinstance(self.left_expr, AEBop) and isinstance(self.right_expr, AEBop): + return f"({self.left_expr}) {self.bop} ({self.right_expr})" + if isinstance(self.left_expr, AEBop): + return f"({self.left_expr}) {self.bop} {self.right_expr}" + if isinstance(self.right_expr, AEBop): + return f"{self.left_expr} {self.bop} ({self.right})" + else: + return f"{self.left_expr} {self.bop} {self.right_expr}" @dataclass class BoolExpr(Expr):