added structure & interpreter & lexer & first ast stucture
This commit is contained in:
28
src/Interpreter/Interpreter.py
Normal file
28
src/Interpreter/Interpreter.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from Interpreter.Validator import Validator
|
||||
from Interpreter.Lexer import Lexer
|
||||
from Interpreter.Parser import Parser
|
||||
from Interpreter.Repo import Repo
|
||||
from Interpreter.Utils import Utils
|
||||
|
||||
|
||||
class Interpreter:
|
||||
|
||||
def __init__(self, repo: Repo, utils: Utils) -> None:
|
||||
self.__repo = repo
|
||||
self.__utils = utils
|
||||
self.__lexer = Lexer(repo, utils)
|
||||
self.__parser = Parser(repo, utils)
|
||||
self.__validator = Validator(repo, utils)
|
||||
|
||||
def interpret(self, line: str) -> bool:
|
||||
toks = []
|
||||
if self.__repo.error is None:
|
||||
toks = self.__lexer.tokenize(line)
|
||||
|
||||
if self.__repo.error is None:
|
||||
self.__parser.parse(toks)
|
||||
|
||||
if self.__repo.error is None:
|
||||
self.__validator.validate()
|
||||
|
||||
return self.__repo.error is None
|
139
src/Interpreter/Lexer.py
Normal file
139
src/Interpreter/Lexer.py
Normal file
@@ -0,0 +1,139 @@
|
||||
from Interpreter.Repo import Repo
|
||||
from Interpreter.Utils import Utils
|
||||
from Models.Token import Token
|
||||
|
||||
|
||||
class Lexer:
|
||||
|
||||
def __init__(self, repo: Repo, utils: Utils) -> None:
|
||||
self.__repo = repo
|
||||
self.__utils = utils
|
||||
|
||||
self.__ml_comment = False
|
||||
self.__toks = []
|
||||
|
||||
def __add_tok(self, value: str, type: str) -> None:
|
||||
if value != '':
|
||||
if type == 'word':
|
||||
if value in self.__repo.keywords:
|
||||
type = 'keyword'
|
||||
|
||||
elif value in self.__repo.types:
|
||||
type = 'type'
|
||||
|
||||
elif value in self.__repo.bool_values:
|
||||
type = 'bool'
|
||||
|
||||
elif value == 'empty':
|
||||
type = 'emptyType'
|
||||
|
||||
else:
|
||||
type = 'name'
|
||||
|
||||
self.__toks.append(Token(type, value))
|
||||
|
||||
def tokenize(self, line: str) -> list:
|
||||
self.__toks = []
|
||||
word = ''
|
||||
ol_comment = False
|
||||
is_string1 = False # 'hello'
|
||||
is_string2 = False # "hello"
|
||||
is_number = False
|
||||
is_expr_char = False
|
||||
|
||||
for i in range(0, len(line)):
|
||||
c = line[i]
|
||||
# ignore comments and spaces
|
||||
if not ol_comment and not self.__ml_comment:
|
||||
|
||||
# end of number
|
||||
if not c.isdigit() and is_number:
|
||||
self.__add_tok(word, 'number')
|
||||
word = ''
|
||||
is_number = False
|
||||
|
||||
# end of expression char
|
||||
if c not in self.__repo.expr_chars and is_expr_char:
|
||||
self.__add_tok(word, 'expr_char')
|
||||
word = ''
|
||||
is_expr_char = False
|
||||
|
||||
# comment filtering
|
||||
if c == '#' and not is_string1 and not is_string2:
|
||||
ol_comment = True
|
||||
|
||||
elif c == '/' and line[+1] == '/':
|
||||
ol_comment = True
|
||||
|
||||
elif c == '/' and line[+1] == '*':
|
||||
self.__ml_comment = True
|
||||
i += 2
|
||||
|
||||
# begin of is_string1
|
||||
elif c == '\'' and not is_string1:
|
||||
is_string1 = True
|
||||
word = ''
|
||||
|
||||
# end of is_string1
|
||||
elif c == '\'' and is_string1:
|
||||
is_string1 = False
|
||||
self.__add_tok(word, 'string')
|
||||
word = ''
|
||||
|
||||
# begin of is_string2
|
||||
elif c == '\"' and not is_string2:
|
||||
is_string2 = True
|
||||
word = ''
|
||||
|
||||
# end of is_string2
|
||||
elif c == '\"' and is_string2:
|
||||
is_string2 = False
|
||||
self.__add_tok(word, 'string')
|
||||
word = ''
|
||||
|
||||
# format char
|
||||
elif c in self.__repo.format_chars:
|
||||
self.__add_tok(word, 'word')
|
||||
self.__add_tok(c, 'format_char')
|
||||
word = ''
|
||||
|
||||
# begin of number
|
||||
elif c.isdigit() and not is_number and word == '':
|
||||
word += c
|
||||
is_number = True
|
||||
|
||||
# continue number
|
||||
elif c.isdigit() and is_number:
|
||||
word += c
|
||||
|
||||
# begin expression char
|
||||
elif c in self.__repo.expr_chars and not is_expr_char:
|
||||
word += c
|
||||
is_expr_char = True
|
||||
|
||||
# continue expression char
|
||||
elif c in self.__repo.expr_chars and is_expr_char:
|
||||
word += c
|
||||
|
||||
# bool expression char
|
||||
elif c in self.__repo.expr_chars:
|
||||
self.__add_tok(word, 'word')
|
||||
self.__add_tok(c, 'bool_expr_char')
|
||||
word = ''
|
||||
|
||||
# end of word
|
||||
elif c == ' ' and not is_string1 and not is_string2 or c == '\n':
|
||||
self.__add_tok(word, 'word')
|
||||
word = ''
|
||||
|
||||
else:
|
||||
word += c
|
||||
|
||||
if c == '\n' and ol_comment:
|
||||
ol_comment = False
|
||||
|
||||
if c == '*' and line[i + 1] == '/':
|
||||
self.__ml_comment = False
|
||||
|
||||
# self.__repo.output_tokens(self.__toks)
|
||||
return self.__toks
|
12
src/Interpreter/Parser.py
Normal file
12
src/Interpreter/Parser.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from Interpreter.Repo import Repo
|
||||
from Interpreter.Utils import Utils
|
||||
|
||||
|
||||
class Parser:
|
||||
|
||||
def __init__(self, repo: Repo, utils: Utils) -> None:
|
||||
self.__repo = repo
|
||||
self.__utils = utils
|
||||
|
||||
def parse(self, toks: list) -> None:
|
||||
self.__repo.output_tokens(toks)
|
54
src/Interpreter/Repo.py
Normal file
54
src/Interpreter/Repo.py
Normal file
@@ -0,0 +1,54 @@
|
||||
class Repo:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.debug = True
|
||||
|
||||
# interpreter
|
||||
self.keywords = [
|
||||
# define keys
|
||||
'lib',
|
||||
'class',
|
||||
'func',
|
||||
# builtin functions
|
||||
'output',
|
||||
'input',
|
||||
'length',
|
||||
'range',
|
||||
# normal keywords
|
||||
'if',
|
||||
'elseif',
|
||||
'else',
|
||||
'pass',
|
||||
'in',
|
||||
# loops
|
||||
'while',
|
||||
'for',
|
||||
# access
|
||||
'public'
|
||||
]
|
||||
self.types = [
|
||||
'number',
|
||||
'string',
|
||||
'bool',
|
||||
'list',
|
||||
'dict',
|
||||
'emptyType',
|
||||
'void'
|
||||
]
|
||||
self.expr_chars = ['+', '-', '*', '/', '=']
|
||||
self.bool_expr_chars = ['<', '>', '!', '!=', '==', '>=', '<=']
|
||||
self.bool_values = ['true', 'false']
|
||||
self.format_chars = ['{', '}', '(', ')', ';', ':', ',']
|
||||
|
||||
# runtime
|
||||
self.error = None
|
||||
|
||||
def output_tokens(self, toks: list) -> None:
|
||||
if self.debug and len(toks) > 0:
|
||||
# outp_toks = []
|
||||
for tok in toks:
|
||||
# outp_toks.append({tok.value: tok.type})
|
||||
print({tok.value: tok.type})
|
||||
|
||||
# print(outp_toks)
|
||||
print('\n')
|
19
src/Interpreter/Utils.py
Normal file
19
src/Interpreter/Utils.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from termcolor import colored
|
||||
|
||||
from Interpreter.Repo import Repo
|
||||
|
||||
|
||||
class Utils:
|
||||
|
||||
def __init__(self, repo: Repo) -> None:
|
||||
self.__repo = repo
|
||||
|
||||
def input(self, prefix: str) -> str:
|
||||
return input(prefix)
|
||||
|
||||
def output(self, text: str) -> None:
|
||||
print(f'-> {text}')
|
||||
|
||||
def error(self) -> None:
|
||||
if self.__repo is not None:
|
||||
print(colored(f'{self.__repo.error.code}: {self.__repo.error.msg}', 'red'))
|
12
src/Interpreter/Validator.py
Normal file
12
src/Interpreter/Validator.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from Interpreter.Repo import Repo
|
||||
from Interpreter.Utils import Utils
|
||||
|
||||
|
||||
class Validator:
|
||||
|
||||
def __init__(self, repo: Repo, utils: Utils) -> None:
|
||||
self.__repo = repo
|
||||
self.__utils = utils
|
||||
|
||||
def validate(self) -> None:
|
||||
pass
|
0
src/Interpreter/__init__.py
Normal file
0
src/Interpreter/__init__.py
Normal file
38
src/Main.py
Normal file
38
src/Main.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
from Models.Error import Error
|
||||
from ServiceInitializer import ServiceInitializer
|
||||
|
||||
|
||||
class Main:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.__services = ServiceInitializer()
|
||||
self.__utils = self.__services.utils
|
||||
self.__repo = self.__services.repo
|
||||
self.__interpreter = self.__services.interpreter
|
||||
|
||||
def console(self) -> None:
|
||||
print('sh-edraft.de basic language interpreter:')
|
||||
cont = True
|
||||
while cont:
|
||||
cont = self.__interpreter.interpret(input('> '))
|
||||
|
||||
def files(self, file: str) -> None:
|
||||
if os.path.isfile(file):
|
||||
f = open(file, 'r', encoding='utf-8').readlines()
|
||||
for line in f:
|
||||
self.__interpreter.interpret(line)
|
||||
else:
|
||||
self.__repo.error = Error(1.1, 'File not found')
|
||||
self.__utils.error()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main = Main()
|
||||
print(sys.argv)
|
||||
if len(sys.argv) == 2:
|
||||
main.files(sys.argv[1])
|
||||
else:
|
||||
main.console()
|
6
src/Models/Class.py
Normal file
6
src/Models/Class.py
Normal file
@@ -0,0 +1,6 @@
|
||||
class Class:
|
||||
|
||||
def __init__(self, name: str, ast: list, access: ''):
|
||||
self.name = name
|
||||
self.ast = ast
|
||||
self.access = access
|
5
src/Models/Error.py
Normal file
5
src/Models/Error.py
Normal file
@@ -0,0 +1,5 @@
|
||||
class Error:
|
||||
|
||||
def __init__(self, code: float, msg: str):
|
||||
self.code = code
|
||||
self.msg = msg
|
6
src/Models/Func.py
Normal file
6
src/Models/Func.py
Normal file
@@ -0,0 +1,6 @@
|
||||
class Func:
|
||||
|
||||
def __init__(self, name: str, ast: list, access='') -> None:
|
||||
self.name = name
|
||||
self.ast = ast
|
||||
self.access = access
|
5
src/Models/Lib.py
Normal file
5
src/Models/Lib.py
Normal file
@@ -0,0 +1,5 @@
|
||||
class Lib:
|
||||
|
||||
def __init__(self, name: str, ast: list):
|
||||
self.name = name
|
||||
self.ast = ast
|
5
src/Models/Token.py
Normal file
5
src/Models/Token.py
Normal file
@@ -0,0 +1,5 @@
|
||||
class Token:
|
||||
|
||||
def __init__(self, type: str, value: str) -> None:
|
||||
self.type = type
|
||||
self.value = value
|
6
src/Models/Var.py
Normal file
6
src/Models/Var.py
Normal file
@@ -0,0 +1,6 @@
|
||||
class Var:
|
||||
|
||||
def __init__(self, name: str, value: str, type: str) -> None:
|
||||
self.name = name
|
||||
self.value = value
|
||||
self.type = type
|
0
src/Models/__init__.py
Normal file
0
src/Models/__init__.py
Normal file
12
src/ServiceInitializer.py
Normal file
12
src/ServiceInitializer.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from Interpreter.Validator import Validator
|
||||
from Interpreter.Interpreter import Interpreter
|
||||
from Interpreter.Utils import Utils
|
||||
from Interpreter.Repo import Repo
|
||||
|
||||
|
||||
class ServiceInitializer:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.repo = Repo()
|
||||
self.utils = Utils(self.repo)
|
||||
self.interpreter = Interpreter(self.repo, self.utils)
|
Reference in New Issue
Block a user