1. Définition du langage
Nous allons implémenter un interpréteur pour un langage simple qui supporte :
✔ Opérations arithmétiques (+, -, *, /)
✔ Parenthèses pour gérer la priorité (( ))
✔ Variables simples (x = 10)
📌 Exemple de code interprété :
txtCopierModifierx = 5 + 3
y = x * 2
print(y) # Affichera 16
2. Étape 1 : Analyse lexicale (Lexer)
L’analyse lexicale découpe le texte en tokens (éléments du langage).
📌 Exemple d’entrée :
txtCopierModifierx = 10 + 5
⬇ Lexeur produit les tokens suivants :
scssCopierModifierTOKEN(ID, "x"), TOKEN(ASSIGN, "="), TOKEN(NUM, "10"), TOKEN(PLUS, "+"), TOKEN(NUM, "5")
📌 Code du Lexer :
pythonCopierModifierimport re
class Token:
def __init__(self, type_, value):
self.type = type_
self.value = value
def __repr__(self):
return f"TOKEN({self.type}, {self.value})"
class Lexer:
def __init__(self, text):
self.text = text
self.pos = 0
self.token_exprs = [
(r'[ \t]+', None), # Espaces ignorés
(r'\d+', 'NUM'), # Nombres entiers
(r'[a-zA-Z_][a-zA-Z0-9_]*', 'ID'), # Identifiants (variables)
(r'=', 'ASSIGN'), # Signe égal
(r'\+', 'PLUS'), # Opérateur addition
(r'-', 'MINUS'), # Opérateur soustraction
(r'\*', 'MULT'), # Opérateur multiplication
(r'/', 'DIV'), # Opérateur division
(r'\(', 'LPAREN'), # Parenthèse ouvrante
(r'\)', 'RPAREN') # Parenthèse fermante
]
def tokenize(self):
tokens = []
while self.pos < len(self.text):
match = None
for pattern, tag in self.token_exprs:
regex = re.compile(pattern)
match = regex.match(self.text, self.pos)
if match:
if tag: # Ignore les espaces
tokens.append(Token(tag, match.group(0)))
self.pos = match.end()
break
if not match:
raise ValueError(f"Caractère invalide : {self.text[self.pos]}")
return tokens
3. Étape 2 : Analyse syntaxique (Parser)
Le parser construit un arbre syntaxique abstrait (AST – Abstract Syntax Tree) à partir des tokens.
📌 Exemple d’arbre syntaxique pour x = 10 + 5
markdownCopierModifier =
/ \
x +
/ \
10 5
📌 Code du Parser :
pythonCopierModifierclass ASTNode:
pass
class BinOp(ASTNode): # Noeud binaire (opérations)
def __init__(self, left, op, right):
self.left = left
self.op = op
self.right = right
class Num(ASTNode): # Noeud nombre
def __init__(self, value):
self.value = value
class Var(ASTNode): # Noeud variable
def __init__(self, name):
self.name = name
class Assign(ASTNode): # Noeud assignation
def __init__(self, var, expr):
self.var = var
self.expr = expr
class Parser:
def __init__(self, tokens):
self.tokens = tokens
self.pos = 0
def consume(self, type_):
if self.pos < len(self.tokens) and self.tokens[self.pos].type == type_:
token = self.tokens[self.pos]
self.pos += 1
return token
raise ValueError(f"Attendu {type_}, trouvé {self.tokens[self.pos].type}")
def factor(self): # Gestion des nombres et parenthèses
token = self.tokens[self.pos]
if token.type == 'NUM':
self.pos += 1
return Num(int(token.value))
elif token.type == 'ID':
self.pos += 1
return Var(token.value)
elif token.type == 'LPAREN':
self.consume('LPAREN')
node = self.expr()
self.consume('RPAREN')
return node
raise ValueError("Expression invalide")
def term(self): # Multiplication et division
node = self.factor()
while self.pos < len(self.tokens) and self.tokens[self.pos].type in ('MULT', 'DIV'):
op = self.tokens[self.pos]
self.pos += 1
node = BinOp(node, op.type, self.factor())
return node
def expr(self): # Addition et soustraction
node = self.term()
while self.pos < len(self.tokens) and self.tokens[self.pos].type in ('PLUS', 'MINUS'):
op = self.tokens[self.pos]
self.pos += 1
node = BinOp(node, op.type, self.term())
return node
def assignment(self): # Assignation de variables
if self.pos < len(self.tokens) and self.tokens[self.pos].type == 'ID':
var = Var(self.tokens[self.pos].value)
self.pos += 1
self.consume('ASSIGN')
expr = self.expr()
return Assign(var, expr)
return self.expr()
4. Étape 3 : Évaluation et exécution
L’interpréteur exécute l’AST en évaluant chaque nœud.
📌 Code de l’Interpréteur :
pythonCopierModifierclass Interpreter:
def __init__(self):
self.variables = {} # Stocke les variables
def visit(self, node):
if isinstance(node, Num):
return node.value
elif isinstance(node, Var):
return self.variables.get(node.name, 0)
elif isinstance(node, BinOp):
left = self.visit(node.left)
right = self.visit(node.right)
if node.op == 'PLUS':
return left + right
elif node.op == 'MINUS':
return left - right
elif node.op == 'MULT':
return left * right
elif node.op == 'DIV':
return left / right
elif isinstance(node, Assign):
value = self.visit(node.expr)
self.variables[node.var.name] = value
return value
else:
raise ValueError("Noeud inconnu")
def execute(self, tree):
return self.visit(tree)
5. Exécution complète
📌 Utilisation du lexer, parser et interpréteur :
pythonCopierModifiercode = "x = 10 + 5"
tokens = Lexer(code).tokenize()
ast = Parser(tokens).assignment()
interpreter = Interpreter()
result = interpreter.execute(ast)
print(interpreter.variables) # {'x': 15}
✅ Notre interpréteur fonctionne ! 🎉 Il est capable de lire, analyser et exécuter du code simple.
Conclusion
Nous avons construit un interpréteur de langage simple en Python, comprenant :
✔ Un Lexer pour découper le code en tokens.
✔ Un Parser pour analyser la syntaxe et générer un AST.
✔ Un Interpréteur pour exécuter les expressions et gérer les variables.
🚀 Prochaine étape : ajouter des boucles et des fonctions !
















