Bienvenue sur CFTPfr.fr › Forums › modules › MIRA_LANG — moteur (lexer, parser, interpreter, main)
- Ce sujet est vide.
Affichage de 1 message (sur 1 au total)
-
AuteurMessages
-
25.07.2026 à 21h58 #218
Mario Da Conceicao
Maître des clésSauvegarde de travail — version du 25/07/2026. Le moteur du langage MIRA_LANG : lexer → parser → interpréteur.
lexer.py
import re TOKEN_SPEC = [ ("NUMBER", r"\d+(\.\d+)?"), ("STRING", r'"[^"]*"'), ("LET", r"\blet\b"), ("PRINT", r"\bprint\b"), ("IF", r"\bif\b"), ("THEN", r"\bthen\b"), ("ELSE", r"\belse\b"), ("WHILE", r"\bwhile\b"), ("DO", r"\bdo\b"), ("FUNC", r"\bfunc\b"), ("RETURN", r"\breturn\b"), ("IMPORT", r"\bimport\b"), ("API", r"\bapi\b"), ("IDENT", r"[A-Za-z_][A-Za-z0-9_]*"), ("OP", r"==|!=|<=|>=|[+\-*/=<>(){},]"), ("NEWLINE", r"\n"), ("SKIP", r"[ \t]+"), ("MISMATCH", r"."), ] TOKEN_RE = re.compile("|".join(f"(?P<{name}>{pattern})" for name, pattern in TOKEN_SPEC)) class Token: def __init__(self, type_, value): self.type = type_ self.value = value def __repr__(self): return f"Token({self.type}, {repr(self.value)})" def tokenize(text): tokens = [] for match in TOKEN_RE.finditer(text): kind = match.lastgroup value = match.group() if kind == "NUMBER": value = float(value) if "." in value else int(value) tokens.append(Token("NUMBER", value)) elif kind == "STRING": tokens.append(Token("STRING", value[1:-1])) elif kind in ("LET", "PRINT", "IF", "THEN", "ELSE", "WHILE", "DO", "FUNC", "RETURN", "IMPORT", "API", "IDENT", "OP"): tokens.append(Token(kind, value)) elif kind == "NEWLINE": tokens.append(Token("NEWLINE", value)) elif kind == "SKIP": continue elif kind == "MISMATCH": raise SyntaxError(f"Caractère invalide: {value}") tokens.append(Token("EOF", None)) return tokensast_nodes.py
class Node: pass class Program(Node): def __init__(self, statements): self.statements = statements class PrintNode(Node): def __init__(self, value): self.value = value class LetNode(Node): def __init__(self, name, value): self.name = name self.value = value class NumberNode(Node): def __init__(self, value): self.value = value class StringNode(Node): def __init__(self, value): self.value = value class VarNode(Node): def __init__(self, name): self.name = name class BinOpNode(Node): def __init__(self, left, op, right): self.left = left self.op = op self.right = right class IfNode(Node): def __init__(self, condition, body, else_body=None): self.condition = condition self.body = body self.else_body = else_body or [] class WhileNode(Node): def __init__(self, condition, body): self.condition = condition self.body = body class FuncDefNode(Node): def __init__(self, name, params, body): self.name = name self.params = params self.body = body class FuncCallNode(Node): def __init__(self, name, args): self.name = name self.args = args class ReturnNode(Node): def __init__(self, value): self.value = value class ImportNode(Node): def __init__(self, module_name): self.module_name = module_name class ApiCallNode(Node): def __init__(self, endpoint, args): self.endpoint = endpoint self.args = argsparser.py
from ast_nodes import * class Parser: def __init__(self, tokens): self.tokens = tokens self.pos = 0 def current(self): return self.tokens[self.pos] def eat(self, type_=None, value=None): tok = self.current() if type_ and tok.type != type_: raise SyntaxError(f"Attendu {type_}, reçu {tok.type} à la position {self.pos}") if value and tok.value != value: raise SyntaxError(f"Attendu {value}, reçu {tok.value} à la position {self.pos}") self.pos += 1 return tok def parse(self): statements = [] while self.current().type != "EOF": if self.current().type == "NEWLINE": self.eat("NEWLINE") continue statements.append(self.statement()) if self.current().type == "NEWLINE": self.eat("NEWLINE") return Program(statements) def statement(self): tok = self.current() if tok.type == "PRINT": self.eat("PRINT") value = self.expression() return PrintNode(value) if tok.type == "LET": self.eat("LET") name = self.eat("IDENT").value self.eat("OP", "=") value = self.expression() return LetNode(name, value) if tok.type == "IF": self.eat("IF") condition = self.expression() self.eat("THEN") body = [self.statement()] if self.current().type == "ELSE": self.eat("ELSE") else_body = [self.statement()] return IfNode(condition, body, else_body) return IfNode(condition, body) if tok.type == "WHILE": self.eat("WHILE") condition = self.expression() self.eat("DO") body = [self.statement()] return WhileNode(condition, body) if tok.type == "FUNC": self.eat("FUNC") name = self.eat("IDENT").value self.eat("OP", "(") params = [] if not (self.current().type == "OP" and self.current().value == ")"): params.append(self.eat("IDENT").value) while self.current().type == "OP" and self.current().value == ",": self.eat("OP", ",") params.append(self.eat("IDENT").value) self.eat("OP", ")") self.eat("OP", "{") body = [] while not (self.current().type == "OP" and self.current().value == "}"): body.append(self.statement()) self.eat("OP", "}") return FuncDefNode(name, params, body) if tok.type == "RETURN": self.eat("RETURN") value = self.expression() return ReturnNode(value) if tok.type == "IMPORT": self.eat("IMPORT") module_name = self.eat("IDENT").value return ImportNode(module_name) if tok.type == "API": self.eat("API") endpoint = self.eat("IDENT").value self.eat("OP", "(") args = [] if not (self.current().type == "OP" and self.current().value == ")"): args.append(self.expression()) while self.current().type == "OP" and self.current().value == ",": self.eat("OP", ",") args.append(self.expression()) self.eat("OP", ")") return ApiCallNode(endpoint, args) if tok.type == "IDENT": name = self.eat("IDENT").value if self.current().type == "OP" and self.current().value == "(": self.eat("OP", "(") args = [] if not (self.current().type == "OP" and self.current().value == ")"): args.append(self.expression()) while self.current().type == "OP" and self.current().value == ",": self.eat("OP", ",") args.append(self.expression()) self.eat("OP", ")") return FuncCallNode(name, args) raise SyntaxError(f"Instruction inconnue près de {tok}") def expression(self): return self.comparison() def comparison(self): node = self.term() while self.current().type == "OP" and self.current().value in ["==", "!=", "<", ">", "<=", ">="]: op = self.eat("OP").value right = self.term() node = BinOpNode(node, op, right) return node def term(self): node = self.factor() while self.current().type == "OP" and self.current().value in ["*", "/"]: op = self.eat("OP").value right = self.factor() node = BinOpNode(node, op, right) return node def factor(self): tok = self.current() if tok.type == "NUMBER": return NumberNode(self.eat("NUMBER").value) if tok.type == "STRING": return StringNode(self.eat("STRING").value) if tok.type == "IDENT": return VarNode(self.eat("IDENT").value) if tok.type == "OP" and tok.value == "(": self.eat("OP", "(") node = self.expression() self.eat("OP", ")") return node if tok.type == "OP" and tok.value == "-": self.eat("OP", "-") return BinOpNode(NumberNode(0), "-", self.factor()) raise SyntaxError(f"Expression invalide près de {tok}")interpreter.py
import operator as op import requests from ast_nodes import * from pathlib import Path import importlib.util BASE_DIR = Path(__file__).parent class Interpreter: def __init__(self): self.variables = {} self.functions = { "len": len, "str": str, "int": int, "float": float, "print": print, "__read_file__": self._read_file, "__write_file__": self._write_file } self.user_functions = {} self.api_url = "http://127.0.0.1:5000" def _read_file(self, path): with open(path, "r", encoding="utf-8") as f: return f.read() def _write_file(self, path, content): with open(path, "w", encoding="utf-8") as f: f.write(content) return True def visit(self, node): method = getattr(self, f"visit_{type(node).__name__}", None) if not method: raise Exception(f"Pas de visiteur pour {type(node).__name__}") return method(node) def visit_Program(self, node): result = None for stmt in node.statements: result = self.visit(stmt) return result def visit_PrintNode(self, node): value = self.visit(node.value) print(value) return value def visit_LetNode(self, node): value = self.visit(node.value) self.variables[node.name] = value return value def visit_NumberNode(self, node): return node.value def visit_StringNode(self, node): return node.value def visit_VarNode(self, node): if node.name not in self.variables: raise NameError(f"Variable inconnue: {node.name}") return self.variables[node.name] def visit_BinOpNode(self, node): left = self.visit(node.left) right = self.visit(node.right) ops = { "+": op.add, "-": op.sub, "*": op.mul, "/": op.truediv, "==": op.eq, "!=": op.ne, "<": op.lt, ">": op.gt, "<=": op.le, ">=": op.ge, } if node.op not in ops: raise SyntaxError(f"Opérateur non supporté: {node.op}") return ops[node.op](left, right) def visit_IfNode(self, node): if self.visit(node.condition): for stmt in node.body: self.visit(stmt) else: for stmt in node.else_body: self.visit(stmt) def visit_WhileNode(self, node): count = 0 while self.visit(node.condition): for stmt in node.body: self.visit(stmt) count += 1 if count > 1000: raise RuntimeError("Boucle trop longue") def visit_FuncDefNode(self, node): self.user_functions[node.name] = (node.params, node.body) return None def visit_ReturnNode(self, node): return self.visit(node.value) def visit_FuncCallNode(self, node): if node.name in self.functions: args = [self.visit(arg) for arg in node.args] return self.functions[node.name](*args) elif node.name in self.user_functions: params, body = self.user_functions[node.name] if len(node.args) != len(params): raise RuntimeError(f"Nombre d'arguments incorrect pour {node.name}") old_vars = self.variables.copy() self.variables.update(zip(params, [self.visit(arg) for arg in node.args])) result = None for stmt in body: result = self.visit(stmt) if isinstance(stmt, ReturnNode): break self.variables = old_vars return result else: raise NameError(f"Fonction inconnue: {node.name}") def visit_ImportNode(self, node): module_path = BASE_DIR / "stdlib" / f"{node.module_name}.mira" if not module_path.exists(): raise ImportError(f"Module {node.module_name} introuvable") with open(module_path, "r", encoding="utf-8") as f: module_code = f.read() old_vars = self.variables.copy() old_funcs = self.functions.copy() old_user_funcs = self.user_functions.copy() from main import run_code run_code(module_code) self.variables = old_vars self.functions = old_funcs self.user_functions = old_user_funcs return None def visit_ApiCallNode(self, node): endpoint = node.endpoint args = [self.visit(arg) for arg in node.args] try: if endpoint == "execute": response = requests.post( f"{self.api_url}/execute", json={"code": args[0]} ) elif endpoint == "plugins": response = requests.get(f"{self.api_url}/plugins") else: response = requests.post( f"{self.api_url}/plugins/{endpoint}", json={"args": args} ) if response.status_code != 200: return f"Erreur API: {response.json().get('error', 'Inconnu')}" return response.json().get("output") or response.json().get("result") except Exception as e: return f"Erreur API: {e}"main.py
from lexer import tokenize from parser import Parser from interpreter import Interpreter import sys def run_code(code): try: tokens = tokenize(code) parser = Parser(tokens) ast = parser.parse() interpreter = Interpreter() return interpreter.visit(ast) except Exception as e: return f"Erreur: {e}" def main(): print("MIRA_LANG v2.0 - Tapez votre code (ligne vide pour exécuter)") lines = [] while True: try: line = input("> ") except EOFError: break if line.strip() == "": break lines.append(line) code = "\n".join(lines) try: result = run_code(code) if result is not None: print(result) except Exception as e: print(f"Erreur: {e}") if __name__ == "__main__": main() -
AuteurMessages
Affichage de 1 message (sur 1 au total)
- Vous devez être connecté pour répondre à ce sujet.