diff --git a/README.md b/README.md index 35c9fdd..45b1ec5 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ DEFINI fib x UT { } ALUID SI x EST I TUNC { REDI I } ALUID { - REDI (INVOCA fib (x-II) + INVOCA fib (x-I)) + REDI ((INVOCA fib (x-II)) + (INVOCA fib (x-I))) } } ``` @@ -30,13 +30,13 @@ DEFINI fib x UT { VOCA FORS DESIGNA correct UT FORTIS_NUMERUS I C -DESIGNA guess UT NULLUS +DESIGNA gvess UT NULLUS DUM FALSITAS FACE { - DESIGNA guess UT AUDI_NUMERUS - SI guess MINUS correct TUNC { + DESIGNA gvess UT AUDI_NUMERUS + SI gvess MINUS correct TUNC { DICE "Too low!" - } ALUID SI guess PLUS correct TUNC { + } ALUID SI gvess PLUS correct TUNC { DICE "Too high!" } ALUID { ERUMPE @@ -170,8 +170,8 @@ SI x ET y TUNC { ### DONICUM loops ``` -DESIGNA x UT NULLUM -DONICUM y UT NULLUM USQUE X FACE { +DESIGNA x UT NULLUS +DONICUM y UT NULLUS USQUE X FACE { DESIGNA x UT x + y } DICE x @@ -181,7 +181,7 @@ DICE x ### DUM loops ``` -DESIGNA x UT NULLUM +DESIGNA x UT NULLUS DUM x PLUS X FACE { DESIGNA x UT x+I } diff --git a/ast_nodes.py b/ast_nodes.py index ba48f5e..2eed3d5 100644 --- a/ast_nodes.py +++ b/ast_nodes.py @@ -23,6 +23,7 @@ def rep_join(l): return format_string +# TODO: Magnum def num_to_int(n): return roman.fromRoman(n) @@ -31,6 +32,8 @@ def make_string(n): return n elif isinstance(n, int): return roman.toRoman(n) + elif isinstance(n, list): + return f"[{' '.join([make_string(i) for i in n])}]" else: raise Exception(n) @@ -45,6 +48,31 @@ class ExpressionStatement(BaseBox): self.expression.eval(vtable.copy(), ftable.copy(), modules) return vtable, ftable +class DataArray(BaseBox): + def __init__(self, content) -> None: + self.content = content + + def __repr__(self) -> str: + content_string = rep_join(self.content) + return f"Array([{content_string}])" + + def eval(self, vtable, ftable, modules): + content = [i.eval(vtable, ftable, modules) for i in self.content] + return content + +class DataRangeArray(BaseBox): + def __init__(self, from_value, to_value) -> None: + self.from_value = from_value + self.to_value = to_value + + def __repr__(self) -> str: + content_string = rep_join([self.from_value, self.to_value]) + return f"RangeArray([{content_string}])" + + def eval(self, vtable, ftable, modules): + content = list(range(self.from_value.eval(), self.to_value.eval())) + return content + class String(BaseBox): def __init__(self, value) -> None: self.value = value @@ -122,7 +150,7 @@ class Defini(BaseBox): ) return f"Defini({def_string})" - def eval(self, vtable, ftable, modules): + def eval(self, vtable, ftable, _): ftable[self.name.name] = ( self.parameters, self.statements ) @@ -180,6 +208,11 @@ class BinOp(BaseBox): return left + right case "SYMBOL_MINUS": return left - right + case "SYMBOL_TIMES": + return left * right + case "SYMBOL_DIVIDE": + # TODO: Fractio + return left // right case "KEYWORD_MINUS": return left < right case "KEYWORD_PLUS": @@ -242,6 +275,37 @@ class DumStatement(BaseBox): return vtable, ftable +class PerStatement(BaseBox): + def __init__(self, data_list, variable_name, statements) -> None: + self.data_list = data_list + self.variable_name = variable_name + self.statements = statements + + def __repr__(self) -> str: + test = repr(self.data_list) + variable_name = repr(self.variable_name) + statements = f"statements([{rep_join(self.statements)}])" + dum_string = rep_join([test, variable_name, statements]) + return f"Per({dum_string})" + + def eval(self, vtable, ftable, modules): + data_array = self.data_list.eval(vtable, ftable, modules) + variable_name = self.variable_name.name + for i in data_array: + vtable[variable_name] = i + for statement in self.statements: + vtable, ftable = statement.eval( + vtable, ftable, modules + ) + if vtable["ERUMPE"]: + break + + if vtable["ERUMPE"]: + vtable["ERUMPE"] = False + break + + return vtable, ftable + class Invoca(BaseBox): def __init__(self, name, parameters) -> None: self.name = name @@ -294,6 +358,7 @@ class BuiltIn(BaseBox): vtable["ERUMPE"] = True return None case "FORTIS_NUMERUS": + # TODO: Fors return random.randint(parameters[0], parameters[1]) case _: raise Exception(self.builtin) diff --git a/lexer.py b/lexer.py index 64ff8ba..6657df0 100644 --- a/lexer.py +++ b/lexer.py @@ -13,6 +13,7 @@ keyword_tokens = [("KEYWORD_"+i, i) for i in [ "FACE", "FALSITAS", "INVOCA", + "IN", "MINUS", "NULLUS", "PER", diff --git a/main.py b/main.py index 398b1dc..0cb5b72 100644 --- a/main.py +++ b/main.py @@ -2,18 +2,23 @@ from lexer import Lexer from parser import Parser text_input = """ -DEFINI fib x UT { - SI x EST NULLUS TUNC { - REDI NULLUS - } ALUID SI x EST I TUNC { - REDI I +VOCA FORS + +DESIGNA correct UT FORTIS_NUMERUS I C +DESIGNA gvess UT NULLUS + +DUM FALSITAS FACE { + DESIGNA gvess UT AUDI_NUMERUS + SI gvess MINUS correct TUNC { + DICE "Too low!" + } ALUID SI gvess PLUS correct TUNC { + DICE "Too high!" } ALUID { - REDI ((INVOCA fib (x-II)) + (INVOCA fib (x-I))) + ERUMPE } } -DICE "Input n:" -DICE (INVOCA fib AUDI_NUMERUS) +DICE "You guessed correctly!" """ lexer = Lexer().get_lexer() @@ -22,6 +27,9 @@ pg.parse() parser = pg.get_parser() tokens = lexer.lex(text_input) +#for token in tokens: +# print(token) x = parser.parse(tokens) +#print(x) x.eval() diff --git a/parser.py b/parser.py index 1700a84..cc73107 100644 --- a/parser.py +++ b/parser.py @@ -1,3 +1,4 @@ +from multiprocessing.dummy import Array from rply import ParserGenerator from lexer import all_tokens @@ -7,7 +8,13 @@ ALL_TOKENS = list(set([i[0] for i in all_tokens])) class Parser(): def __init__(self): - self.pg = ParserGenerator(ALL_TOKENS) + self.pg = ParserGenerator( + ALL_TOKENS, + precedence=[ + ('left', ["SYMBOL_PLUS", "SYMBOL_MINUS"]), + ('left', ["SYMBOL_TIMES", "SYMBOL_DIVIDE"]) + ] + ) def parse(self): @self.pg.production('program : opt_newline module_calls statements') @@ -94,6 +101,8 @@ class Parser(): @self.pg.production('expression : expression SYMBOL_MINUS expression') @self.pg.production('expression : expression SYMBOL_PLUS expression') + @self.pg.production('expression : expression SYMBOL_TIMES expression') + @self.pg.production('expression : expression SYMBOL_DIVIDE expression') @self.pg.production('expression : expression KEYWORD_EST expression') @self.pg.production('expression : expression KEYWORD_MINUS expression') @self.pg.production('expression : expression KEYWORD_PLUS expression') @@ -116,8 +125,10 @@ class Parser(): def si_statement(tokens): return tokens[0] + @self.pg.production('statement : per_statement') @self.pg.production('statement : dum_statement') - def dum_statement(tokens): + @self.pg.production('statement : donicum_statement') + def loops(tokens): return tokens[0] @self.pg.production('statement : KEYWORD_ERUMPE') @@ -132,6 +143,15 @@ class Parser(): def dum(tokens): return ast_nodes.DumStatement(tokens[1], tokens[5]) + @self.pg.production('per_statement : KEYWORD_PER id KEYWORD_IN expression KEYWORD_FACE SYMBOL_LCURL opt_newline statements opt_newline SYMBOL_RCURL') + def per(tokens): + return ast_nodes.PerStatement(tokens[3], tokens[1], tokens[7]) + + @self.pg.production('donicum_statement : KEYWORD_DONICUM id KEYWORD_UT expression KEYWORD_USQUE expression KEYWORD_FACE SYMBOL_LCURL opt_newline statements opt_newline SYMBOL_RCURL') + def donicum(tokens): + range_array = ast_nodes.DataRangeArray(tokens[3], tokens[5]) + return ast_nodes.PerStatement(range_array, tokens[1], tokens[9]) + @self.pg.production('aluid_statement : ') def aluid_empty(_): return None @@ -148,6 +168,14 @@ class Parser(): def parens(tokens): return tokens[1] + @self.pg.production('expression : SYMBOL_LBRACKET expressions SYMBOL_RBRACKET') + def array(tokens): + return ast_nodes.DataArray(tokens[1]) + + @self.pg.production('expression : SYMBOL_LBRACKET expression KEYWORD_USQUE expression SYMBOL_RBRACKET') + def range_array(tokens): + return ast_nodes.DataRangeArray(tokens[1], tokens[3]) + @self.pg.error def error_handle(token): raise ValueError(token)