From 053c1ebfaf59dab25f84897ffb81cb90f7ec02a1 Mon Sep 17 00:00:00 2001 From: Lephe Date: Tue, 8 Oct 2019 22:32:27 +0200 Subject: [PATCH] add exponentation in the bitcode lexer --- doc/tokens.txt | 2 +- fx92/lexer.py | 1 + fx92/parser.py | 98 +++++++++++++++++++++++++++++++++----------------- 3 files changed, 67 insertions(+), 34 deletions(-) diff --git a/doc/tokens.txt b/doc/tokens.txt index f2f4df6..5726375 100644 --- a/doc/tokens.txt +++ b/doc/tokens.txt @@ -78,7 +78,7 @@ AD P - - - AE C - - - C0 - Yes Yes Yes C8 ⌋ - - - -C9 ^( - - - +C9 ^( Yes Yes - CA [x]√( - - - D0 ) Yes Yes Yes D4 ⁻¹ - - - diff --git a/fx92/lexer.py b/fx92/lexer.py index ae49e4d..0ccac25 100644 --- a/fx92/lexer.py +++ b/fx92/lexer.py @@ -63,6 +63,7 @@ class T(enum.IntEnum): MINUS = 0xA7 STAR = 0xA8 SLASH = 0xA9 + EXP = 0xC9 BANG = 0xD8 # Tokens with parameters diff --git a/fx92/parser.py b/fx92/parser.py index 8a5be40..ceb6e65 100644 --- a/fx92/parser.py +++ b/fx92/parser.py @@ -27,6 +27,11 @@ class Parser: cond -> expr REL expr expr -> factor | factor + expr | factor - expr + factor -> chunk | chunk * factor | chunk / factor + chunk -> power+ + power -> atom | atom "^(" expr ")" + atom -> const | var | "(" expr ")" | FUN( funargs ")" + factor -> atom | atom * factor | atom / factor atom -> const (var | "(" expr ")" | FUN funargs ")")* | (var | "(" expr ")" | FUN funargs ")")+ @@ -201,20 +206,20 @@ class Parser: if t.type == T.MINUS: f.append(Node(N.MINUS, self.factor())) - # factor -> atom | atom * factor | atom / factor + # factor -> chunk | chunk * factor | chunk / factor def factor(self): - atom = self.atom() + chunk = self.chunk() t = self.expect(T.STAR, T.SLASH, optional=True) if t is None: - return atom + return chunk if t.type == T.STAR: - return Node(N.MUL, atom, self.factor()) + return Node(N.MUL, chunk, self.factor()) if t.type == T.SLASH: - return Node(N.DIV, atom, self.factor()) + return Node(N.DIV, chunk, self.factor()) - # atom -> const (VAR | "(" expr ")")* | (VAR | "(" expr ")")+ - def atom(self): + # chunk -> power+ + def chunk(self): factors = [] # Initial sign @@ -224,37 +229,64 @@ class Parser: self.expect(T.MINUS) factors.append(Node(N.CONST, -1)) - # Optional constant - if self.la.type == T.CONST: - factors.append(self.const()) - while 1: - lat = self.la.type - - if lat == T.VAR: - factors.append(self.var()) - elif lat == T.LPAR: - self.expect(T.LPAR) - factors.append(self.expr()) - - # Allow a parenthesis to be removed at the end of a parameter - optional = (self.la.type == T.PARAM) - self.expect(T.RPAR, optional=optional) - - elif lat == T.FUN: - name = self.expect(T.FUN).args[0] - 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, a)) - else: + optional = len(factors) > 0 + f = self.power(optional=optional) + if f is None: break + factors.append(f) return Node(N.MUL, *factors) + # power -> atom | atom "^(" expr ")" + def power(self, optional=False): + a = self.atom(optional=optional) + if a is None: + return None + + if self.expect(T.EXP, optional=True) is not None: + e = self.expr() + + # Allow a parenthesis to be removed at the end of a parameter + optional = (self.la.type == T.PARAM) + self.expect(T.RPAR, optional=optional) + return Node(N.EXP, a, e) + + return a + + # atom -> const | var | "(" expr ")" | FUN( funargs ")" + def atom(self, optional=False): + lat = self.la.type + + if lat == T.CONST: + return self.const() + + if lat == T.VAR: + return self.var() + + if lat == T.LPAR: + self.expect(T.LPAR) + e = self.expr() + + # Allow a parenthesis to be removed at the end of a parameter + optional = (self.la.type == T.PARAM) + self.expect(T.RPAR, optional=optional) + return e + + if lat == T.FUN: + name = self.expect(T.FUN).args[0] + 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) + + return Node(N.FUN, name, a) + + if not optional: + raise Exception("Empty atom") + return None + # funargs -> expr | expr; funargs def funargs(self): a = [self.expr()]