diff --git a/doc/tokens.txt b/doc/tokens.txt index 9b93e30..f2f4df6 100644 --- a/doc/tokens.txt +++ b/doc/tokens.txt @@ -14,7 +14,7 @@ Hexadecimal Description Feature BitcodeLexer TextLexer 22 π Yes Yes - 23 : - - - 25 ? - - - -2C ; - - - +2C ; Yes Yes Yes 2D ×10 Yes Yes Yes 2E , Yes Yes Yes 30 0 Yes Yes Yes @@ -146,4 +146,4 @@ FB18 →x - - - FB19 →y - - - FB1A M+ - - - FB1B M- - - - -FD18 Ran# - - - +FD18 Ran# - - - diff --git a/fx92/ast.py b/fx92/ast.py index df7b432..358adda 100644 --- a/fx92/ast.py +++ b/fx92/ast.py @@ -116,4 +116,8 @@ class Node: if self.type == N.MINUS and self.constchildren(): return Node(N.CONST, -self.args[0].value) + if self.type == N.FUN: + newargs = [simpl(arg) for arg in self.args[1]] + return Node(N.FUN, self.args[0], newargs) + return self diff --git a/fx92/interpreter.py b/fx92/interpreter.py index 59e8080..45a4a79 100644 --- a/fx92/interpreter.py +++ b/fx92/interpreter.py @@ -172,7 +172,7 @@ class Context: return n.value elif n.type == N.FUN: - arg = self.run(n.args[1]) + args = [self.run(arg) for arg in n.args[1]] f = { "Abs": abs, @@ -196,15 +196,15 @@ class Context: "Ent": lambda x: float(int(x)), "EntEx": lambda x: float(int(x)) - (x < 0), "RanInt": None, - "GCD": None, - "LCM": None, + "GCD": lambda x, y: float(math.gcd(int(x), int(y))), + "LCM": lambda x, y: x * y / math.gcd(int(x), int(y)), "Arond": None, }[n.args[0]] if f is None: raise Exception( "Function {} not there yet x_x".format(n.args[0])) - return f(arg) + return f(*args) elif n.type == N.REL: left = self.run(n.args[0]) diff --git a/fx92/lexer.py b/fx92/lexer.py index fca309a..ae49e4d 100644 --- a/fx92/lexer.py +++ b/fx92/lexer.py @@ -55,6 +55,7 @@ class T(enum.IntEnum): PARAM = 0x00 COLON = 0x23 QUEST = 0x25 + SEMI = 0x2C LPAR = 0x60 RPAR = 0xD0 EQUAL = 0xA5 @@ -256,8 +257,8 @@ class BitcodeLexer(LexerBase): 0x83: "Ent", 0x84: "EntEx", 0x87: "RanInt", -# 0x88: "GCD", -# 0x89: "LCM", + 0x88: "GCD", + 0x89: "LCM", 0x8A: "Arond", } @@ -332,7 +333,7 @@ class TextLexer(LexerBase): def __init__(self, code): """Initialize the lexer with text code.""" - self.base_code = code.replace(";", "\n") + self.base_code = code self.rewind() def rewind(self): @@ -382,6 +383,7 @@ class TextLexer(LexerBase): punct = { ",": T.PARAM, ":": T.COLON, + ";": T.SEMI, "?": T.QUEST, "(": T.LPAR, ")": T.RPAR, diff --git a/fx92/parser.py b/fx92/parser.py index 39f7dde..8a5be40 100644 --- a/fx92/parser.py +++ b/fx92/parser.py @@ -28,8 +28,9 @@ class Parser: cond -> expr REL expr expr -> factor | factor + expr | factor - expr factor -> atom | atom * factor | atom / factor - atom -> const (var | "(" expr ")" | FUN expr ")")* | - (var | "(" expr ")" | FUN expr ")")+ + atom -> const (var | "(" expr ")" | FUN funargs ")")* | + (var | "(" expr ")" | FUN funargs ")")+ + funargs -> expr | expr ; funargs const -> (+|-)? CONST var -> VAR @@ -242,18 +243,25 @@ class Parser: elif lat == T.FUN: name = self.expect(T.FUN).args[0] - e = self.expr() + a = self.funargs() # Allow a parenthesis to be removed at the end of a parameter optional = (self.la.type == T.PARAM) self.expect(T.RPAR, optional=optional) - factors.append(Node(N.FUN, name, e)) + factors.append(Node(N.FUN, name, a)) else: break return Node(N.MUL, *factors) + # funargs -> expr | expr; funargs + def funargs(self): + a = [self.expr()] + while self.expect(T.SEMI, optional=True) is not None: + a.append(self.expr()) + return a + # const -> (+|-)? CONST def const(self): t = self.expect(T.PLUS, T.MINUS, optional=True) diff --git a/fx92/printer.py b/fx92/printer.py index 768b9b9..d3a9a4c 100644 --- a/fx92/printer.py +++ b/fx92/printer.py @@ -49,6 +49,12 @@ def print_ast(n, lang="en", indent=0): print(n.args[0]) return + if n.type == N.FUN: + print(n.args[0] + "()") + for arg in n.args[1]: + print_ast(arg, lang=lang, indent=indent+2) + return + id = n.type.name.lower() if hasattr(lang, id): diff --git a/tests/corners.txt b/tests/corners.txt index ddbbc7c..4c89aef 100644 --- a/tests/corners.txt +++ b/tests/corners.txt @@ -1,4 +1,23 @@ -goto -90, 23; pendown; goto x-5, y; goto x, y-5; penup -goto -90, -23; pendown; goto x-5, y; goto x, y+5; penup -goto 91, 23; pendown; goto x+5, y; goto x, y-5; penup -goto 91, -23; pendown; goto x+5, y; goto x, y+5; penup +goto -90, 23 +pendown +goto x-5, y +goto x, y-5 +penup + +goto -90, -23 +pendown +goto x-5, y +goto x, y+5 +penup + +goto 91, 23 +pendown +goto x+5, y +goto x, y-5 +penup + +goto 91, -23 +pendown +goto x+5, y +goto x, y+5 +penup diff --git a/tests/functions.out b/tests/functions.out new file mode 100644 index 0000000..03b6389 --- /dev/null +++ b/tests/functions.out @@ -0,0 +1 @@ +17.0 diff --git a/tests/functions.txt b/tests/functions.txt new file mode 100644 index 0000000..6f0501f --- /dev/null +++ b/tests/functions.txt @@ -0,0 +1 @@ +print GCD(3*17; 2*17*5) diff --git a/tests/line-patterns.txt b/tests/line-patterns.txt index c87e603..5e432eb 100644 --- a/tests/line-patterns.txt +++ b/tests/line-patterns.txt @@ -1,11 +1,37 @@ -goto -60, 9 ; pendown ; goto x+13, y+13 ; penup -goto -60, 6 ; pendown ; goto x+13, y+8 ; penup -goto -60, 3 ; pendown ; goto x+13, y+5 ; penup -goto -60, 0 ; pendown ; goto x+13, y ; penup +goto -60, 9 +pendown +goto x+13, y+13 +penup -goto -47, -8 ; pendown ; goto x-13, y+5 ; penup -goto -47, -14 ; pendown ; goto x-13, y+8 ; penup -goto -47, -22 ; pendown ; goto x-13, y+13 ; penup +goto -60, 6 +pendown +goto x+13, y+8 +penup + +goto -60, 3 +pendown +goto x+13, y+5 +penup + +goto -60, 0 +pendown +goto x+13, y +penup + +goto -47, -8 +pendown +goto x-13, y+5 +penup + +goto -47, -14 +pendown +goto x-13, y+8 +penup + +goto -47, -22 +pendown +goto x-13, y+13 +penup setvar 0, A