mirror of
https://github.com/Alvin-Zilverstand/femcode.git
synced 2026-03-06 11:06:47 +01:00
feat: Implement variables
This commit is contained in:
2
examples/variables.fem
Normal file
2
examples/variables.fem
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
my_variable is "Hello, again!"
|
||||||
|
UwU Boy my_variable
|
||||||
22
src/lexer.py
22
src/lexer.py
@@ -20,11 +20,14 @@ class Lexer:
|
|||||||
if self.pos > len(self.text) - 1:
|
if self.pos > len(self.text) - 1:
|
||||||
return Token('EOF', None)
|
return Token('EOF', None)
|
||||||
|
|
||||||
current_char = self.text[self.pos]
|
# Skip whitespace
|
||||||
|
while self.pos < len(self.text) and self.text[self.pos].isspace():
|
||||||
if current_char.isspace():
|
|
||||||
self.pos += 1
|
self.pos += 1
|
||||||
return self.get_next_token()
|
|
||||||
|
if self.pos > len(self.text) - 1:
|
||||||
|
return Token('EOF', None)
|
||||||
|
|
||||||
|
current_char = self.text[self.pos]
|
||||||
|
|
||||||
if current_char == '"':
|
if current_char == '"':
|
||||||
self.pos += 1
|
self.pos += 1
|
||||||
@@ -35,9 +38,20 @@ class Lexer:
|
|||||||
self.pos = string_end + 1
|
self.pos = string_end + 1
|
||||||
return Token('STRING', string)
|
return Token('STRING', string)
|
||||||
|
|
||||||
|
# Match keywords
|
||||||
if re.match(r'\bUwU Boy\b', self.text[self.pos:]):
|
if re.match(r'\bUwU Boy\b', self.text[self.pos:]):
|
||||||
self.pos += 7
|
self.pos += 7
|
||||||
return Token('PRINT', 'UwU Boy')
|
return Token('PRINT', 'UwU Boy')
|
||||||
|
if re.match(r'\bis\b', self.text[self.pos:]):
|
||||||
|
self.pos += 2
|
||||||
|
return Token('ASSIGN', 'is')
|
||||||
|
|
||||||
|
# Match identifiers
|
||||||
|
match = re.match(r'\b[a-zA-Z_][a-zA-Z0-9_]*\b', self.text[self.pos:])
|
||||||
|
if match:
|
||||||
|
value = match.group(0)
|
||||||
|
self.pos += len(value)
|
||||||
|
return Token('ID', value)
|
||||||
|
|
||||||
self.error()
|
self.error()
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from parser import Parser
|
|||||||
from interpreter import Interpreter
|
from interpreter import Interpreter
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
with open('../examples/hello_world.fem', 'r') as f:
|
with open('../examples/variables.fem', 'r') as f:
|
||||||
text = f.read()
|
text = f.read()
|
||||||
|
|
||||||
lexer = Lexer(text)
|
lexer = Lexer(text)
|
||||||
|
|||||||
@@ -5,6 +5,17 @@ class Print(AST):
|
|||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
class Assign(AST):
|
||||||
|
def __init__(self, left, op, right):
|
||||||
|
self.left = left
|
||||||
|
self.op = op
|
||||||
|
self.right = right
|
||||||
|
|
||||||
|
class Variable(AST):
|
||||||
|
def __init__(self, token):
|
||||||
|
self.token = token
|
||||||
|
self.value = token.value
|
||||||
|
|
||||||
class Parser:
|
class Parser:
|
||||||
def __init__(self, tokens):
|
def __init__(self, tokens):
|
||||||
self.tokens = tokens
|
self.tokens = tokens
|
||||||
@@ -15,22 +26,50 @@ class Parser:
|
|||||||
token = self.tokens[self.pos]
|
token = self.tokens[self.pos]
|
||||||
self.pos += 1
|
self.pos += 1
|
||||||
return token
|
return token
|
||||||
return None
|
return Token('EOF', None)
|
||||||
|
|
||||||
|
def peek_next_token(self):
|
||||||
|
if self.pos < len(self.tokens):
|
||||||
|
return self.tokens[self.pos]
|
||||||
|
return Token('EOF', None)
|
||||||
|
|
||||||
def parse(self):
|
def parse(self):
|
||||||
statements = []
|
statements = []
|
||||||
while True:
|
while self.peek_next_token().type != 'EOF':
|
||||||
token = self.get_next_token()
|
statements.append(self.parse_statement())
|
||||||
if token is None or token.type == 'EOF':
|
|
||||||
break
|
|
||||||
|
|
||||||
if token.type == 'PRINT':
|
|
||||||
next_token = self.get_next_token()
|
|
||||||
if next_token.type == 'STRING':
|
|
||||||
statements.append(Print(next_token.value))
|
|
||||||
else:
|
|
||||||
raise Exception("Expected a string after 'UwU Boy'")
|
|
||||||
else:
|
|
||||||
raise Exception(f"Unexpected token: {token.type}")
|
|
||||||
|
|
||||||
return statements
|
return statements
|
||||||
|
|
||||||
|
def parse_statement(self):
|
||||||
|
token = self.peek_next_token()
|
||||||
|
|
||||||
|
if token.type == 'PRINT':
|
||||||
|
return self.parse_print_statement()
|
||||||
|
|
||||||
|
if token.type == 'ID' and self.pos + 1 < len(self.tokens) and self.tokens[self.pos + 1].type == 'ASSIGN':
|
||||||
|
return self.parse_assignment_statement()
|
||||||
|
elif token.type == 'ID':
|
||||||
|
raise Exception(f"Unexpected identifier '{token.value}' without assignment.")
|
||||||
|
|
||||||
|
raise Exception(f"Invalid statement starting with token {token.type}")
|
||||||
|
|
||||||
|
def parse_print_statement(self):
|
||||||
|
self.get_next_token() # Consume PRINT token
|
||||||
|
token = self.get_next_token()
|
||||||
|
if token.type == 'STRING':
|
||||||
|
return Print(token.value)
|
||||||
|
elif token.type == 'ID':
|
||||||
|
return Print(Variable(token))
|
||||||
|
else:
|
||||||
|
raise Exception("Expected a string or variable after 'UwU Boy'")
|
||||||
|
|
||||||
|
def parse_assignment_statement(self):
|
||||||
|
var_token = self.get_next_token()
|
||||||
|
var_node = Variable(var_token)
|
||||||
|
|
||||||
|
assign_token = self.get_next_token()
|
||||||
|
|
||||||
|
value_token = self.get_next_token()
|
||||||
|
if value_token.type == 'STRING':
|
||||||
|
return Assign(left=var_node, op=assign_token, right=value_token.value)
|
||||||
|
else:
|
||||||
|
raise Exception("Expected a string value for assignment")
|
||||||
|
|||||||
Reference in New Issue
Block a user