From 39789bd96ad190e8e5f0da238f7db417ec75f47d Mon Sep 17 00:00:00 2001 From: Alvin <524715@vistacollege.nl> Date: Tue, 22 Jul 2025 15:56:40 +0200 Subject: [PATCH] Initial commit: Basic interpreter structure --- docs/README.md | 3 ++ examples/hello_world.fem | 1 + src/__pycache__/interpreter.cpython-313.pyc | Bin 0 -> 1582 bytes src/__pycache__/lexer.cpython-313.pyc | Bin 0 -> 2913 bytes src/__pycache__/parser.cpython-313.pyc | Bin 0 -> 2171 bytes src/interpreter.py | 18 +++++++ src/lexer.py | 51 ++++++++++++++++++++ src/main.py | 19 ++++++++ src/parser.py | 36 ++++++++++++++ 9 files changed, 128 insertions(+) create mode 100644 docs/README.md create mode 100644 examples/hello_world.fem create mode 100644 src/__pycache__/interpreter.cpython-313.pyc create mode 100644 src/__pycache__/lexer.cpython-313.pyc create mode 100644 src/__pycache__/parser.cpython-313.pyc create mode 100644 src/interpreter.py create mode 100644 src/lexer.py create mode 100644 src/main.py create mode 100644 src/parser.py diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..81b41a2 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,3 @@ +# Femcode + +A femboy-themed programming language. \ No newline at end of file diff --git a/examples/hello_world.fem b/examples/hello_world.fem new file mode 100644 index 0000000..410b0aa --- /dev/null +++ b/examples/hello_world.fem @@ -0,0 +1 @@ +UwU Boy "Hello, Femboy World!" \ No newline at end of file diff --git a/src/__pycache__/interpreter.cpython-313.pyc b/src/__pycache__/interpreter.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0470a69185d6d44f1f88d36682aa6e411523d82e GIT binary patch literal 1582 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 literal 0 HcmV?d00001 diff --git a/src/__pycache__/parser.cpython-313.pyc b/src/__pycache__/parser.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6bd80ea00362d6f458087566ecda4c939235f726 GIT binary patch literal 2171 zcmaJ?-A@}w5a0VU#(;70L5TV2k?I>7%S%N?j0#0 zRqYdks)$A^f=ZQ2q)JKpls@%u=$nyMVcl!Bt&#!P;@=awTWPp9*{v;kHQ2VDT7rx zi4;?wa8=R`aJ5kSI96e@MIOL9oiI@sn52tLPDx?ek#6c!2N?LA#KMZ>H4HPcKn=t3 z8OB0(b}@tVTEqBiF_9^G>J4Kq%`7{UHmR8fccWogcEV04jf8Ep^vt47EyG|~+%X=( z8IR0o7ii?+N4C8jnWc{+DY}q0(|yTIIx_)&O1$muVWSg#i(TQf+|A&y)0* zzwz`|6{zn>u`#sabBp)@46(3>d0=GdWnNU(sPGyYl8Hm>#$yiVFDop7@3~6eh=S7M z#-O`0Fx}v(3=F`d=s+;$(G^yO)N(u%{2mVQK$THy=i8k{Nf+WIQ|2K7%*5CM1i|Qd z?Ce8oT8@;zQP z{SK2Y5+{=|o|kEi-~xVJaZUzHI}X9sCI$%ZQX#7H-gw6*KyY2Clvx-0>agBZQpJT% z7bJ!$!V+tR!I3i5Ocpz3x+>g;Vm2+E*45L1kcGw`nB;^f&USMut@&^^E#_Jn-^mG?x6 zJZgg9%Kzn(;!?#d5?|j1>xD_I;haq43*-Xpk@x4M%#HG>k-L|tu^DmE<+7a$XRJ!) zTKwdycp86a7w+E^bEL7mpFw+?{5&@0c=Rb4$5%SWmU1*{(^)N{S~haaLmaqJ3gUzq(x9nyz_A?JUd~a+lgQ<$IqS9#Y+6qB*iw?_>~z))%ltJu zKJ4mrftt3(Gz{^b63jw^Y9MZxQ+SVdYD=u+U)Zj!UqE4lyRhaf`Wt{>`)bdg+Ed`% zs#n*)*;StUp7@^8f_AkSXgq8pfl%Ii@i0gNjhid$D?48n>N|^V9s6wqdu;=SwvT`G z6@zWtHy+>Eoi7CYi)#D6+O?;4{YIaCvEMtq*E?M3zW%p5@-lQe-#K0gMe}O(Wz&cG zOP{=m|9St9`!8e(R^U^)kRXGGQ2B%X#9=E!ru2cUj&f#qN>z}FQ5YzGR4A9 zzDkZnQE5E#DvJ8XA5cPWL&lgGyl#9k?hWvzNWjys?s$jYAMgn42M4m-0-};bNf3m$ eq99biBA{M-M4@Hv)7J!sx87DEbVNY$ZT 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 diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..404c4ed --- /dev/null +++ b/src/main.py @@ -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() diff --git a/src/parser.py b/src/parser.py new file mode 100644 index 0000000..8c8a731 --- /dev/null +++ b/src/parser.py @@ -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