mirror of
https://github.com/Alvin-Zilverstand/femcode.git
synced 2026-03-06 02:56:56 +01:00
Initial commit: Basic interpreter structure
This commit is contained in:
3
docs/README.md
Normal file
3
docs/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Femcode
|
||||
|
||||
A femboy-themed programming language.
|
||||
1
examples/hello_world.fem
Normal file
1
examples/hello_world.fem
Normal file
@@ -0,0 +1 @@
|
||||
UwU Boy "Hello, Femboy World!"
|
||||
BIN
src/__pycache__/interpreter.cpython-313.pyc
Normal file
BIN
src/__pycache__/interpreter.cpython-313.pyc
Normal file
Binary file not shown.
BIN
src/__pycache__/lexer.cpython-313.pyc
Normal file
BIN
src/__pycache__/lexer.cpython-313.pyc
Normal file
Binary file not shown.
BIN
src/__pycache__/parser.cpython-313.pyc
Normal file
BIN
src/__pycache__/parser.cpython-313.pyc
Normal file
Binary file not shown.
18
src/interpreter.py
Normal file
18
src/interpreter.py
Normal file
@@ -0,0 +1,18 @@
|
||||
class Interpreter:
|
||||
def __init__(self, ast):
|
||||
self.ast = ast
|
||||
|
||||
def interpret(self):
|
||||
for node in self.ast:
|
||||
self.visit(node)
|
||||
|
||||
def visit(self, node):
|
||||
method_name = f'visit_{type(node).__name__}'
|
||||
method = getattr(self, method_name, self.no_visit_method)
|
||||
return method(node)
|
||||
|
||||
def no_visit_method(self, node):
|
||||
raise Exception(f'No visit_{type(node).__name__} method defined')
|
||||
|
||||
def visit_Print(self, node):
|
||||
print(node.value)
|
||||
51
src/lexer.py
Normal file
51
src/lexer.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import re
|
||||
|
||||
class Token:
|
||||
def __init__(self, type, value):
|
||||
self.type = type
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return f'Token({self.type}, {self.value!r})'
|
||||
|
||||
class Lexer:
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
self.pos = 0
|
||||
|
||||
def error(self):
|
||||
raise Exception('Invalid character')
|
||||
|
||||
def get_next_token(self):
|
||||
if self.pos > len(self.text) - 1:
|
||||
return Token('EOF', None)
|
||||
|
||||
current_char = self.text[self.pos]
|
||||
|
||||
if current_char.isspace():
|
||||
self.pos += 1
|
||||
return self.get_next_token()
|
||||
|
||||
if current_char == '"':
|
||||
self.pos += 1
|
||||
string_end = self.text.find('"', self.pos)
|
||||
if string_end == -1:
|
||||
self.error()
|
||||
string = self.text[self.pos:string_end]
|
||||
self.pos = string_end + 1
|
||||
return Token('STRING', string)
|
||||
|
||||
if re.match(r'\bUwU Boy\b', self.text[self.pos:]):
|
||||
self.pos += 7
|
||||
return Token('PRINT', 'UwU Boy')
|
||||
|
||||
self.error()
|
||||
|
||||
def tokenize(self):
|
||||
tokens = []
|
||||
while True:
|
||||
token = self.get_next_token()
|
||||
tokens.append(token)
|
||||
if token.type == 'EOF':
|
||||
break
|
||||
return tokens
|
||||
19
src/main.py
Normal file
19
src/main.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from lexer import Lexer
|
||||
from parser import Parser
|
||||
from interpreter import Interpreter
|
||||
|
||||
def main():
|
||||
with open('../examples/hello_world.fem', 'r') as f:
|
||||
text = f.read()
|
||||
|
||||
lexer = Lexer(text)
|
||||
tokens = lexer.tokenize()
|
||||
|
||||
parser = Parser(tokens)
|
||||
ast = parser.parse()
|
||||
|
||||
interpreter = Interpreter(ast)
|
||||
interpreter.interpret()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
36
src/parser.py
Normal file
36
src/parser.py
Normal file
@@ -0,0 +1,36 @@
|
||||
class AST:
|
||||
pass
|
||||
|
||||
class Print(AST):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
class Parser:
|
||||
def __init__(self, tokens):
|
||||
self.tokens = tokens
|
||||
self.pos = 0
|
||||
|
||||
def get_next_token(self):
|
||||
if self.pos < len(self.tokens):
|
||||
token = self.tokens[self.pos]
|
||||
self.pos += 1
|
||||
return token
|
||||
return None
|
||||
|
||||
def parse(self):
|
||||
statements = []
|
||||
while True:
|
||||
token = self.get_next_token()
|
||||
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
|
||||
Reference in New Issue
Block a user