From 93e54c984d82330c1c3189fae6f47ca64e95ab0f Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 27 Sep 2020 18:20:12 +0200 Subject: [PATCH] [DevState] testing with rply --- doc/target/main.bl | 16 - doc/target/test.bl | 35 -- doc/target/test2.bl | 12 - src/CCLang_sly/Interpreter.py | 31 -- src/CCLang_sly/Lexer.py | 108 ------ src/CCLang_sly/Parser.py | 61 ---- src/CCLang_sly/__init__.py | 0 src/First.cc | 22 -- src/Interpreter/AbstractSyntaxTree.py | 59 ++++ src/Interpreter/Interpreter.py | 42 +-- src/Interpreter/Lexer.py | 176 +-------- src/Interpreter/Parser.py | 491 +++++--------------------- src/ServiceInitializer.py | 2 - src/cclang.py | 7 +- src/test.cc | 6 + 15 files changed, 179 insertions(+), 889 deletions(-) delete mode 100644 doc/target/main.bl delete mode 100644 doc/target/test.bl delete mode 100644 doc/target/test2.bl delete mode 100644 src/CCLang_sly/Interpreter.py delete mode 100644 src/CCLang_sly/Lexer.py delete mode 100644 src/CCLang_sly/Parser.py delete mode 100644 src/CCLang_sly/__init__.py delete mode 100644 src/First.cc create mode 100644 src/Interpreter/AbstractSyntaxTree.py create mode 100644 src/test.cc diff --git a/doc/target/main.bl b/doc/target/main.bl deleted file mode 100644 index ff8fe93..0000000 --- a/doc/target/main.bl +++ /dev/null @@ -1,16 +0,0 @@ -use test1 from Tests; -use test2 as test3 from Tests; - -lib Main { - class Program { - func Main(args: list): void { - var test_a: test1 = test1(); - test_a.dec_vars(); - test_a.is_error(); - if (!error) { - var test_b: test3 = test3(); - test3.continue(); - } - } - } -} \ No newline at end of file diff --git a/doc/target/test.bl b/doc/target/test.bl deleted file mode 100644 index 9157407..0000000 --- a/doc/target/test.bl +++ /dev/null @@ -1,35 +0,0 @@ -lib Tests -{ - /* - declaration of some tests - */ - public class test1 - { - public var test_string: string = 'Hello'; - public var test_string_2: string = "Hello World"; - public var test_num: num = 1; - public var test_num_2: num = 1.0; - public var test_num_3: num = this.test_num + this.test_num_2; - - public func dec_vars(): void - { - var test_bool: bool = true; - var test_bool_2: bool = false; - var test_bool_3: bool = test_bool != test_bool_2; # true - } - - public is_error(): bool - { - if (error != empty) - { - output(error.code + ' ' + error.message); - return true; - } - else - { - output('continue'); - return false; - } - } - } -} \ No newline at end of file diff --git a/doc/target/test2.bl b/doc/target/test2.bl deleted file mode 100644 index 4f6a612..0000000 --- a/doc/target/test2.bl +++ /dev/null @@ -1,12 +0,0 @@ -lib Tests { - public class test2 { - var string_a = strings(); - public func continue(): void { - input(string_a.string1 + ': '); - } - } - - class strings { - public var string1 = "hello world"; - } -} \ No newline at end of file diff --git a/src/CCLang_sly/Interpreter.py b/src/CCLang_sly/Interpreter.py deleted file mode 100644 index 18fde1a..0000000 --- a/src/CCLang_sly/Interpreter.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Optional - -from CCLang_sly.Parser import Parser -from Interpreter.Validator import Validator -from CCLang_sly.Lexer import Lexer -from Interpreter.Repo import Repo -from Interpreter.Utils import Utils -from Models.AbstractSyntaxTree.AbstractSyntaxTree import AbstractSyntaxTree - - -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: str) -> None: - """ - Interprets code line - :param line_str: - :return: - """ - lexer = Lexer() - parser = Parser() - env = {} - ast = parser.parse(lexer.tokenize(line_str)) - if ast is not None: - print(ast) diff --git a/src/CCLang_sly/Lexer.py b/src/CCLang_sly/Lexer.py deleted file mode 100644 index 4f7bdfc..0000000 --- a/src/CCLang_sly/Lexer.py +++ /dev/null @@ -1,108 +0,0 @@ -from sly import Lexer as SlyLexer - -from Models.CCLang.TokenDefinition import TokenDefinition - - -class Lexer(SlyLexer): - # Ignored pattern - ignore = '\t ' - # ignore_comment = r'(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|(//.*)|([#].*)' - ignore_comment = r'([#].*|(//.*))' - ignore_newline = r'\n+' - - tokens = { - LIBRARY, - CLASS, - FUNCTION, - VARIABLE, - USE, - FROM, - OUTPUT, - INPUT, - LENGTH, - RANGE, - EXIT, - IF, - ELSEIF, - ELSE, - CONTINUE, - IN, - RETURN, - WHILE, - FOR, - PUBLIC, - THIS, - LBRACE, - RBRACE, - LPARAN, - RPARAN, - LBRACKET, - RBRACKET, - SEMICOLON, - COLON, - COMMA, - POINT, - PLUS, - MINUS, - ASTERIK, - SLASH, - EQUAL, - CARET, - TRUE, - FALSE, - STRING, - NUMBER, - EMPTY, - - NAME - } - - # token definition - LIBRARY = TokenDefinition.Library.value - CLASS = TokenDefinition.Class.value - FUNCTION = TokenDefinition.Function.value - VARIABLE = TokenDefinition.Variable.value - USE = TokenDefinition.Use.value - FROM = TokenDefinition.From.value - OUTPUT = TokenDefinition.Output.value - INPUT = TokenDefinition.Input.value - LENGTH = TokenDefinition.Length.value - RANGE = TokenDefinition.Range.value - EXIT = TokenDefinition.Exit.value - IF = TokenDefinition.If.value - ELSEIF = TokenDefinition.ElseIf.value - ELSE = TokenDefinition.Else.value - CONTINUE = TokenDefinition.Continue.value - IN = TokenDefinition.In.value - RETURN = TokenDefinition.Return.value - WHILE = TokenDefinition.While.value - FOR = TokenDefinition.For.value - PUBLIC = TokenDefinition.Public.value - THIS = TokenDefinition.This.value - LBRACE = TokenDefinition.LeftBrace.value - RBRACE = TokenDefinition.RightBrace.value - LPARAN = TokenDefinition.LeftParenthesis.value - RPARAN = TokenDefinition.RightParenthesis.value - LBRACKET = TokenDefinition.LeftBracket.value - RBRACKET = TokenDefinition.RightBracket.value - SEMICOLON = TokenDefinition.Semicolon.value - COLON = TokenDefinition.Colon.value - COMMA = TokenDefinition.Comma.value - POINT = TokenDefinition.Point.value - PLUS = TokenDefinition.Plus.value - MINUS = TokenDefinition.Minus.value - ASTERIK = TokenDefinition.Asterisk.value - SLASH = TokenDefinition.Slash.value - EQUAL = TokenDefinition.Equal.value - CARET = TokenDefinition.Caret.value - TRUE = TokenDefinition.BoolTrue.value - FALSE = TokenDefinition.BoolFalse.value - STRING = TokenDefinition.String.value - NUMBER = TokenDefinition.Number.value - EMPTY = TokenDefinition.Empty.value - - NAME = TokenDefinition.Name.value - - def error(self, t): - print("Illegal character '%s'" % t.value[0]) - # self.index += 1 diff --git a/src/CCLang_sly/Parser.py b/src/CCLang_sly/Parser.py deleted file mode 100644 index c2f20e8..0000000 --- a/src/CCLang_sly/Parser.py +++ /dev/null @@ -1,61 +0,0 @@ -from sly import Parser as SlyParser - -from CCLang_sly.Lexer import Lexer - - -class Parser(SlyParser): - tokens = Lexer.tokens - - #precedence = ( - # ('left', '+', '-'), - # ('left', '*', '/'), - # ('right', 'UMINUS'), - #) - - def __init__(self): - self.env = {} - - @_('') - def statement(self, p): - pass - - def error(self, p): - print(f'ERROR: {p}') - pass - - # lib definition - @_('PUBLIC LIBRARY NAME LBRACE') - def statement(self, p): - return ('lib_def', p.NAME, True) - - @_('LIBRARY NAME LBRACE') - def statement(self, p): - return ('lib_def', p.NAME, False) - - # class definition - @_('PUBLIC CLASS NAME LBRACE') - def statement(self, p): - return ('class_def', p.NAME, True) - - @_('CLASS NAME LBRACE') - def statement(self, p): - return ('class_def', p.NAME, False) - - # func definition - @_('PUBLIC FUNCTION NAME LPARAN statement RPARAN COLON type LBRACE') - def statement(self, p): - return ('func_def', p.NAME, True) - - @_('FUNCTION NAME LPARAN RPARAN COLON type LBRACE') - def statement(self, p): - return ('func_def', p.NAME, False) - - # types - @_('EMPTY') - def type(self, p): - return ('type', p.EMPTY) - - # right brace - @_('RBRACE') - def statement(self, p): - return ('end', p.RBRACE) diff --git a/src/CCLang_sly/__init__.py b/src/CCLang_sly/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/First.cc b/src/First.cc deleted file mode 100644 index cac1b3e..0000000 --- a/src/First.cc +++ /dev/null @@ -1,22 +0,0 @@ -# hi1 -// hi2 - -public lib Main { - class Program { - var test: bool = false; - var test2: Program2 = empty; - var test3: Program2 = Test(34); - - func Main(): empty { - #func Main { - var hallo: any; - #output('Hello'); - #output(this.isTrue(false)); - } - - func isTrue(value: bool): bool { - #func isTrue { - #return value; - } - } -} \ No newline at end of file diff --git a/src/Interpreter/AbstractSyntaxTree.py b/src/Interpreter/AbstractSyntaxTree.py new file mode 100644 index 0000000..231c555 --- /dev/null +++ b/src/Interpreter/AbstractSyntaxTree.py @@ -0,0 +1,59 @@ +from rply.token import BaseBox + + +class AbstractSyntaxTree: + class BinaryOp(BaseBox): + def __init__(self, left, right): + self.left = left + self.right = right + + class Number(BaseBox): + def __init__(self, value): + self.value = value + + def eval(self): + return self.value + + class String(BaseBox): + def __init__(self, value): + self.value = value + + def eval(self): + return self.value + + class Bool(BaseBox): + def __init__(self, value): + self.value = value + + def eval(self): + return self.value + + class Add(BinaryOp): + def eval(self): + return self.left.eval() + self.right.eval() + + class Sub(BinaryOp): + def eval(self): + return self.left.eval() - self.right.eval() + + class Mul(BinaryOp): + def eval(self): + return self.left.eval() * self.right.eval() + + class Div(BinaryOp): + def eval(self): + return self.left.eval() / self.right.eval() + + class Output(BaseBox): + def __init__(self, value): + self.value = value + + def eval(self): + print('>>', self.value.eval()) + + class Input(BaseBox): + def __init__(self, value): + self.value = value + + def eval(self): + return input(f'<< {self.value.eval()}') diff --git a/src/Interpreter/Interpreter.py b/src/Interpreter/Interpreter.py index ce3a1d9..6966cf4 100644 --- a/src/Interpreter/Interpreter.py +++ b/src/Interpreter/Interpreter.py @@ -13,8 +13,10 @@ 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.__lexer = Lexer().get_lexer() + parser = Parser() + parser.parse() + self.__parser = parser.get_parser() self.__validator = Validator(repo, utils) def interpret(self, line_str: str) -> None: @@ -23,35 +25,9 @@ class Interpreter: :param line_str: :return: """ - tokens = [] - ast: Optional[AbstractSyntaxTree] = None + tokens = self.__lexer.lex(line_str) + #for t in tokens: + # print(t) - if self.__repo.error is None: - tokens = self.__lexer.tokenize(line_str) - - if self.__repo.error is None: - ast = self.__parser.parse(tokens) - - """ print('#####\n') - if ast is not None: - for lib in ast.libraries: - print('lib', lib.name) - for cl in lib.classes: - print('class', cl.name) - for var in cl.variables: - print('cl var', var.name) - - for func in cl.functions: - print('func', func.name) - for arg in func.args: - print('func arg', arg.name) - - for var in func.variables: - print('func var', var.name) - - for ins in func.instructions: - print('ins', ins) - """ - - # if self.__repo.is_error is None: - # self.__validator.validate(self.__repo.AST) + ast = self.__parser.parse(tokens) + ast.eval() diff --git a/src/Interpreter/Lexer.py b/src/Interpreter/Lexer.py index 21bc554..b881953 100644 --- a/src/Interpreter/Lexer.py +++ b/src/Interpreter/Lexer.py @@ -1,171 +1,19 @@ -from typing import List +from rply import LexerGenerator -from Interpreter.Repo import Repo -from Interpreter.Utils import Utils -from Models.Token.Token import Token -from Models.Token.TokenTypes import TokenTypes, UnresolvedTokenTypes +from Models.CCLang.TokenDefinition import TokenDefinition class Lexer: + def __init__(self): + self.lexer = LexerGenerator() - def __init__(self, repo: Repo, utils: Utils) -> None: - self.__repo = repo - self.__utils = utils + def _add_tokens(self): + for t in TokenDefinition: + self.lexer.add(t.name, t.value) - self.__is_ml_comment = False + # Ignore spaces + self.lexer.ignore('\s+') - def __add_tok(self, tokens: List[Token], value: str, input_token_type: UnresolvedTokenTypes) -> None: - """ - Creates token object - :param value: - :param input_token_type: - :return: - """ - token_type: TokenTypes = TokenTypes.Empty - - if value != '': - if input_token_type == UnresolvedTokenTypes.Word: - if value in self.__repo.keywords: - token_type = TokenTypes.Keyword - - elif value in self.__repo.datatypes: - token_type = TokenTypes.Type - - elif value in self.__repo.bool_values: - token_type = TokenTypes.Bool - - elif value == UnresolvedTokenTypes.Empty: - token_type = TokenTypes.Empty - - else: - token_type = TokenTypes.Name - - elif input_token_type == UnresolvedTokenTypes.Number: - token_type = TokenTypes.Number - - elif input_token_type == UnresolvedTokenTypes.String: - token_type = TokenTypes.String - - elif input_token_type == UnresolvedTokenTypes.Expression_Character: - token_type = TokenTypes.Expression_Character - - elif input_token_type == UnresolvedTokenTypes.Bool_Expression_Character: - token_type = TokenTypes.Bool_Expression_Character - - elif input_token_type == UnresolvedTokenTypes.Format_Character: - token_type = TokenTypes.Format_Character - - tokens.append(Token(token_type, value)) - - def tokenize(self, line: str) -> List[Token]: - """ - Creates token list from code line - :param line: - :return: - """ - tokens: List[Token] = [] - 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.__is_ml_comment: - # comment filtering - if c == '#' and not is_string1 and not is_string2: - ol_comment = True - - elif line[i - 1] == '/' and c == '/': - ol_comment = True - - elif line[i - 1] == '/' and c == '*': - self.__is_ml_comment = True - i += 2 - - # end of number - elif not c.isdigit() and c != '.' and is_number: - self.__add_tok(tokens, word, UnresolvedTokenTypes.Number) - local_tokens = self.tokenize(c) - for local_token in local_tokens: - tokens.append(local_token) - - word = '' - is_number = False - - # end of expression char - elif c not in self.__repo.expr_chars and is_expr_char: - self.__add_tok(tokens, word, UnresolvedTokenTypes.Expression_Character) - word = '' - is_expr_char = False - - # 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(tokens, word, UnresolvedTokenTypes.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(tokens, word, UnresolvedTokenTypes.String) - word = '' - - # format char - elif c in self.__repo.format_chars: - self.__add_tok(tokens, word, UnresolvedTokenTypes.Word) - self.__add_tok(tokens, c, UnresolvedTokenTypes.Format_Character) - word = '' - - # begin of number - elif c.isdigit() and not is_number and word == '': - word += c - is_number = True - - # continue number - elif (c.isdigit() or c == '.') 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.bool_expr_chars: - self.__add_tok(tokens, word, UnresolvedTokenTypes.Word) - self.__add_tok(tokens, c, UnresolvedTokenTypes.Bool_Expression_Character) - word = '' - - # end of word - elif c == ' ' and not is_string1 and not is_string2 or c == '\n': - self.__add_tok(tokens, word, UnresolvedTokenTypes.Word) - word = '' - - else: - word += c - - if c == '\n' and ol_comment: - ol_comment = False - - if line[i - 1] == '*' and c == '/': - self.__is_ml_comment = False - - return tokens + def get_lexer(self): + self._add_tokens() + return self.lexer.build() diff --git a/src/Interpreter/Parser.py b/src/Interpreter/Parser.py index 7c9e4bb..483b865 100644 --- a/src/Interpreter/Parser.py +++ b/src/Interpreter/Parser.py @@ -1,415 +1,106 @@ -from typing import List, Optional, Union - -from Interpreter.Repo import Repo -from Interpreter.Utils import Utils -from Models.AbstractSyntaxTree.AbstractSyntaxTree import LibraryDefinitionNode, ClassDefinitionNode, AbstractSyntaxTree, \ - FunctionDefinitionNode, VariableDefinitionNode, CallDefinitionNode, ValueNode, ASTElement -from Models.Interpreter.Datatypes import Datatypes -from Models.Interpreter.Error import Error, ErrorCodes -from Models.Token.Token import Token -from Models.Token.TokenTypes import TokenTypes -from Models.Token.TokenValueTypes import Keywords, FormatCharacters, ExpressionCharacters +from rply import ParserGenerator +from Interpreter.AbstractSyntaxTree import AbstractSyntaxTree +from Models.CCLang.TokenDefinition import TokenDefinition class Parser: + def __init__(self): + tokens = [] + for t in TokenDefinition: + tokens.append(t.name) - def __init__(self, repo: Repo, utils: Utils) -> None: - self.__repo = repo - self.__utils = utils + self.pg = ParserGenerator( + # A list of all token names accepted by the parser. + [ + TokenDefinition.ValueNumber.name, + TokenDefinition.Plus.name, + TokenDefinition.Minus.name, + TokenDefinition.Asterisk.name, + TokenDefinition.Slash.name, + TokenDefinition.LeftParenthesis.name, + TokenDefinition.RightParenthesis.name, + TokenDefinition.Output.name, + TokenDefinition.Semicolon.name, + TokenDefinition.ValueString.name, + TokenDefinition.BoolTrue.name, + TokenDefinition.BoolFalse.name, + TokenDefinition.Input.name + ], + precedence=[ + ('left', ['Plus', 'Minus']), + ('left', ['Slash', 'Asterisk']) + ] + ) - self.__ast: AbstractSyntaxTree = AbstractSyntaxTree() - self.__saved_tokens: List[Token] = [] - self.__expected_tokens: List[Token] = [] + def parse(self): + #@self.pg.production('input : Input LeftParenthesis expression RightParenthesis Semicolon') + #def statement(p): + # return AbstractSyntaxTree.Input(p[2]) - # for validation if type is created - self.__is_saving_type = False - self.__is_saving_value = False - self.__is_saving_call = False - self.__is_end = False + @self.pg.production('builtin : Output LeftParenthesis expression RightParenthesis Semicolon') + @self.pg.production('builtin : Input LeftParenthesis expression RightParenthesis Semicolon') + def builtin(p): + if p[0].gettokentype() == 'Output': + return AbstractSyntaxTree.Output(p[2]) + elif p[0].gettokentype() == 'Input': + return AbstractSyntaxTree.Input(p[2]) - self.__saved_ast_elements: List[ASTElement] = [] + @self.pg.production('expression : ValueString') + def expression(p): + try: + string = p[0].value + if '\"' in p[0].value: + string = str(p[0].value).replace('\"', '') + elif '\'' in p[0].value: + string = str(p[0].value).replace('\'', '') - def parse(self, tokens: List[Token]) -> AbstractSyntaxTree: - self.__is_end = False + return AbstractSyntaxTree.String(string) + except Exception as e: + print(e) + raise ValueError(p) - if len(tokens) > 0: - toks = [] - for tok in tokens: - toks.append({tok.type.name, tok.value}) + @self.pg.production('expression : BoolTrue') + @self.pg.production('expression : BoolFalse') + def expression(p): + try: + return AbstractSyntaxTree.Bool(p[0].value) + except Exception as e: + print(e) + raise ValueError(p) - print(self.__repo.line_number, toks) + @self.pg.production('expression : ValueNumber') + def expression(p): + try: + return AbstractSyntaxTree.Number(int(p[0].value)) + except Exception as e: + print(e) + raise ValueError(p) - for i in range(0, len(tokens)): - token = tokens[i] + @self.pg.production('expression : LeftParenthesis expression RightParenthesis') + def expression(p): + return p[1] - self.__check_for_expected_tokens(token) - - # keywords - if token.type == TokenTypes.Keyword: - if token.value == Keywords.Public.value: - self.__saved_tokens.append(token) - print('save public') - self.__add_expected_token(TokenTypes.Keyword, Keywords.Library.value) - self.__add_expected_token(TokenTypes.Keyword, Keywords.Class.value) - self.__add_expected_token(TokenTypes.Keyword, Keywords.Function.value) - self.__add_expected_token(TokenTypes.Keyword, Keywords.Variable.value) - - elif token.value == Keywords.Library.value: - self.__saved_tokens.append(token) - print('save lib') - self.__add_expected_token(TokenTypes.Name) - - elif token.value == Keywords.Class.value: - self.__saved_tokens.append(token) - print('save class') - self.__add_expected_token(TokenTypes.Name) - - elif token.value == Keywords.Function.value: - self.__saved_tokens.append(token) - print('save function') - self.__add_expected_token(TokenTypes.Name) - - elif token.value == Keywords.Variable.value: - self.__saved_tokens.append(token) - print('save var') - self.__add_expected_token(TokenTypes.Name) - - # names - elif token.type == TokenTypes.Name: - if self.__is_saving_variable() and self.__is_saving_value: - self.__save_name(token) - if self.__is_saving_variable(): - self.__is_saving_call = True - - # names could be variable types, validation check in evaluator - elif self.__is_saving_variable() and self.__is_saving_type: - self.__save_type(token) - self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Left_Parenthesis.value) - - elif self.__is_saving_variable(): - self.__save_name(token) - self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Colon.value) - - elif self.__is_saving_function(): - self.__save_name(token) - self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Left_Parenthesis.value) - - elif self.__is_saving_library() or self.__is_saving_class(): - self.__save_name(token) - self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Left_Brace.value) - - # format chars - elif token.type == TokenTypes.Format_Character: - if token.value == FormatCharacters.Left_Brace.value: - if self.__is_saving_library(): - self.__save_library() - - elif self.__is_saving_class(): - self.__save_class() - - elif token.value == FormatCharacters.Colon.value: - if self.__is_saving_variable(): - self.__is_saving_type = True - self.__add_expected_token(TokenTypes.Type) - self.__add_expected_token(TokenTypes.Name) - - elif token.value == FormatCharacters.Semicolon.value: - self.__end_line() - - elif token.value == FormatCharacters.Left_Parenthesis.value: - self.__add_expected_token(TokenTypes.Name) - self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Right_Parenthesis.value) - self.__add_expected_token(TokenTypes.Keyword, Keywords.This.value) - self.__add_expected_token(TokenTypes.Name) - self.__add_expected_token(TokenTypes.Empty) - self.__add_expected_token(TokenTypes.Number) - self.__add_expected_token(TokenTypes.String) - self.__add_expected_token(TokenTypes.Bool) - - if self.__is_saving_call: - self.__saved_tokens.append(token) - - elif token.value == FormatCharacters.Right_Parenthesis.value: - self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Semicolon.value) - self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Colon.value) - - if self.__is_saving_call: - self.__saved_tokens.append(token) - self.__save_call() - self.__is_saving_call = False - - # expr chars - elif token.type == TokenTypes.Expression_Character: - if token.value == ExpressionCharacters.Equal.value: - self.__is_saving_value = True - self.__add_expected_token(TokenTypes.Bool) - self.__add_expected_token(TokenTypes.Number) - self.__add_expected_token(TokenTypes.String) - self.__add_expected_token(TokenTypes.Empty) - self.__add_expected_token(TokenTypes.Name) - self.__add_expected_token(TokenTypes.Keyword, Keywords.This.value) - self.__add_expected_token(TokenTypes.Keyword, Keywords.Input.value) - self.__add_expected_token(TokenTypes.Keyword, Keywords.Range.value) - self.__add_expected_token(TokenTypes.Keyword, Keywords.Length.value) - self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Left_Parenthesis.value) - self.__add_expected_token(TokenTypes.Type, Datatypes.Empty.value) - - # types - elif token.type == TokenTypes.Type: - if self.__is_saving_variable() and self.__is_saving_value: - self.__save_value(token) - - elif self.__is_saving_variable(): - self.__save_type(token) - - # values - elif token.type == TokenTypes.Bool or token.type == TokenTypes.Number or token.type == TokenTypes.String: - if self.__is_saving_call: - self.__saved_tokens.append(token) - - elif self.__is_saving_value: - self.__save_value(token) - - return self.__ast - - """ - Utils - """ - - def __save_name(self, token: Token): - self.__saved_tokens.append(token) - print('save name') - - def __add_expected_token(self, token_type: TokenTypes, value: str = ''): - self.__expected_tokens.append(Token(token_type, value)) - - def __check_for_expected_tokens(self, token: Token): - error_token: Optional[Token] = None - is_error = True - - for expected_token in self.__expected_tokens: - if self.__is_end or token.type != expected_token.type or expected_token.value != '' and token.value != expected_token.value: - error_token = token + @self.pg.production('expression : expression Plus expression') + @self.pg.production('expression : expression Minus expression') + @self.pg.production('expression : expression Asterisk expression') + @self.pg.production('expression : expression Slash expression') + def expression(p): + left = p[0] + right = p[2] + if p[1].gettokentype() == 'Plus': + return AbstractSyntaxTree.Add(left, right) + elif p[1].gettokentype() == 'Minus': + return AbstractSyntaxTree.Sub(left, right) + elif p[1].gettokentype() == 'Asterisk': + return AbstractSyntaxTree.Mul(left, right) + elif p[1].gettokentype() == 'Slash': + return AbstractSyntaxTree.Div(left, right) else: - is_error = False + raise AssertionError('Oops, this should not be possible!') - if error_token is not None and is_error: - self.__utils.error(Error(ErrorCodes.Unexpected, f'{error_token.type.name} {error_token.value}')) + @self.pg.error + def error_handle(token): + raise ValueError(token) - self.__expected_tokens = [] - - def __end_line(self): - if self.__is_saving_variable(): - self.__save_variable() - - self.__is_end = True - self.__expected_tokens = [] - self.__is_saving_type = False - self.__is_saving_value = False - - """ - Library - """ - - def __is_saving_library(self) -> bool: - found = False - for token in self.__saved_tokens: - if token.type == TokenTypes.Keyword and token.value == Keywords.Library.value: - found = True - - return found - - def __save_library(self) -> None: - is_public = False - name_token: Optional[Token] = None - - for token in self.__saved_tokens: - if token.type == TokenTypes.Name: - name_token = token - elif token.type == TokenTypes.Keyword and token.value == Keywords.Public.value: - is_public = True - - if name_token is not None: - self.__ast.libraries.append(LibraryDefinitionNode(is_public, name_token.value)) - self.__saved_tokens = [] - self.__add_expected_token(TokenTypes.Keyword, Keywords.Public.value) - self.__add_expected_token(TokenTypes.Keyword, Keywords.Class.value) - print('saved library') - - """ - Class - """ - - def __is_saving_class(self) -> bool: - found = False - for token in self.__saved_tokens: - if token.type == TokenTypes.Keyword and token.value == Keywords.Class.value: - found = True - - return found - - def __save_class(self) -> None: - is_public = False - name_token: Optional[Token] = None - - for token in self.__saved_tokens: - if token.type == TokenTypes.Name: - name_token = token - elif token.type == TokenTypes.Keyword and token.value == Keywords.Public.value: - is_public = True - - if name_token is not None: - self.__ast.libraries[len(self.__ast.libraries) - 1].classes.append(ClassDefinitionNode(is_public, name_token.value)) - self.__saved_tokens = [] - self.__add_expected_token(TokenTypes.Keyword, Keywords.Public.value) - self.__add_expected_token(TokenTypes.Keyword, Keywords.Variable.value) - self.__add_expected_token(TokenTypes.Keyword, Keywords.Function.value) - print('saved class') - - """ - Call - """ - def __save_call(self) -> None: - name_token: Optional[Token] = None - args: List[ValueNode] = [] - remove_tokens = [] - is_call = False - - for i in range(0, len(self.__saved_tokens)): - token = self.__saved_tokens[i] - last_token: Optional[Token] = None - if i-1 > 0: - last_token = self.__saved_tokens[i-1] - - if token.type == TokenTypes.Name and last_token is not None and last_token.type == TokenTypes.Format_Character and last_token.value == FormatCharacters.Left_Parenthesis.value: - pass - - if token.type == TokenTypes.Format_Character and token.value == FormatCharacters.Left_Parenthesis.value and last_token is not None and last_token.type == TokenTypes.Name: - name_token = last_token - remove_tokens.append(last_token) - remove_tokens.append(token) - is_call = True - elif is_call and token.type == TokenTypes.Format_Character and token.value == FormatCharacters.Right_Parenthesis.value: - remove_tokens.append(token) - elif is_call and token.type == TokenTypes.Bool or token.type == TokenTypes.Number or token.type == TokenTypes.String: - args.append(ValueNode(token.value, Datatypes[token.type.name])) - remove_tokens.append(token) - - if name_token is not None: - call = CallDefinitionNode(name_token.value) - call.args = args - self.__saved_ast_elements.append(call) - - for token in remove_tokens: - self.__saved_tokens.remove(token) - - self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Semicolon.value) - print('saved call') - - """ - Function - """ - - def __is_saving_function(self) -> bool: - found = False - for token in self.__saved_tokens: - if token.type == TokenTypes.Keyword and token.value == Keywords.Function.value: - found = True - - return found - - def __save_function(self) -> None: - is_public = False - name_token: Optional[Token] = None - return_type: Optional[Token] = None - - for token in self.__saved_tokens: - if token.type == TokenTypes.Name: - name_token = token - elif token.type == TokenTypes.Keyword and token.value == Keywords.Public.value: - is_public = True - elif token.type == TokenTypes.Type: - return_type = token - - if name_token is not None and return_type is not None: - self.__ast.libraries[len(self.__ast.libraries) - 1].classes[len(self.__ast.libraries) - 1].functions.append( - FunctionDefinitionNode(is_public, name_token.value, Datatypes[return_type.value])) - self.__saved_tokens = [] - print('saved function') - - """ - Variable - """ - - def __is_saving_variable(self) -> bool: - found = False - for token in self.__saved_tokens: - if token.type == TokenTypes.Keyword and token.value == Keywords.Variable.value: - found = True - - return found - - def __save_type(self, token: Token) -> None: - self.__saved_tokens.append(token) - self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Semicolon.value) - self.__add_expected_token(TokenTypes.Expression_Character, ExpressionCharacters.Equal.value) - self.__is_saving_type = False - print('save type') - - def __save_variable(self): - is_public = False - name_token: Optional[Token] = None - datatype: Optional[Token] = None - value: Optional[Union[str, Token, CallDefinitionNode]] = None - - reset_saved_ast = False - - for token in self.__saved_tokens: - if token.type == TokenTypes.Name and name_token is None: - name_token = token - elif token.type == TokenTypes.Keyword and token.value == Keywords.Public.value: - is_public = True - elif token.type == TokenTypes.Type or name_token is not None and token.type == TokenTypes.Name: - datatype = token - - value = Token(TokenTypes.Empty, TokenTypes.Empty.value) - - for saved_ast_element in self.__saved_ast_elements: - if isinstance(saved_ast_element, CallDefinitionNode): - value = saved_ast_element - reset_saved_ast = True - - if reset_saved_ast: - self.__saved_ast_elements = [] - - if name_token is not None and datatype is not None and value is not None: - if not isinstance(value, CallDefinitionNode): - value = value.value - - if datatype.type == TokenTypes.Name: - variable = VariableDefinitionNode(is_public, name_token.value, datatype.value, value) - else: - variable = VariableDefinitionNode(is_public, name_token.value, Datatypes[str(datatype.value).capitalize()], value) - - if len(self.__ast.libraries) > 0: - lib = self.__ast.libraries[len(self.__ast.libraries) - 1] - if len(lib.classes) > 0: - cl = lib.classes[len(lib.classes) - 1] - if len(cl.functions) == 0: - cl.variables.append(variable) - else: - cl.functions[len(cl.functions) - 1].variables.append(variable) - - self.__saved_tokens = [] - print('saved variable') - - """ - Value - """ - - def __save_value(self, token: Token): - self.__saved_tokens.append(token) - self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Left_Parenthesis.value) - self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Semicolon.value) - self.__is_saving_value = False - print('save value') + def get_parser(self): + return self.pg.build() diff --git a/src/ServiceInitializer.py b/src/ServiceInitializer.py index a2faea2..5d4b655 100644 --- a/src/ServiceInitializer.py +++ b/src/ServiceInitializer.py @@ -1,5 +1,4 @@ from Interpreter.Interpreter import Interpreter -from CCLang_sly.Interpreter import Interpreter as SlyCCLangInterpreter from Interpreter.Utils import Utils from Interpreter.Repo import Repo @@ -10,4 +9,3 @@ class ServiceInitializer: self.repo = Repo() self.utils = Utils(self.repo) self.interpreter = Interpreter(self.repo, self.utils) - self.sly_cclang_interpreter = SlyCCLangInterpreter(self.repo, self.utils) diff --git a/src/cclang.py b/src/cclang.py index e33045d..eecfb5b 100644 --- a/src/cclang.py +++ b/src/cclang.py @@ -12,7 +12,6 @@ class Main: self.__utils = self.__services.utils self.__repo = self.__services.repo self.__interpreter = self.__services.interpreter - self.__sly_cclang_interpreter = self.__services.sly_cclang_interpreter def console(self) -> None: """ @@ -22,8 +21,7 @@ class Main: i = 0 while self.__repo.error is None: self.__repo.line_number = i + 1 - #self.__interpreter.interpret(input('> ')) - self.__sly_cclang_interpreter.interpret(input('> ')) + self.__interpreter.interpret(input('> ')) i += 1 def files(self, file: str) -> None: @@ -43,8 +41,7 @@ class Main: f = open(file, 'r', encoding='utf-8').readlines() for i in range(0, len(f)): self.__repo.line_number = i + 1 - # self.__interpreter.interpret(f[i]) - self.__sly_cclang_interpreter.interpret(f[i]) + self.__interpreter.interpret(f[i]) if __name__ == '__main__': diff --git a/src/test.cc b/src/test.cc new file mode 100644 index 0000000..e49e376 --- /dev/null +++ b/src/test.cc @@ -0,0 +1,6 @@ +output(3+3+3); +output(3); +output("Hallo"); +output(false); +output(true); +output(input("Name: ")); \ No newline at end of file