From 9bf03c52be41d24988b9876f21cdef1b96fb2eec Mon Sep 17 00:00:00 2001 From: Lephe Date: Sun, 6 Oct 2019 10:57:58 +0200 Subject: [PATCH] allow atoms --- fx92.py | 5 ++++- fx92/lexer.py | 20 ++++++++++++++------ fx92/parser.py | 12 +++++++++--- tests.py | 4 +++- tests/function-atom.out | 4 ++++ tests/function-atom.txt | 4 ++++ 6 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 tests/function-atom.out create mode 100644 tests/function-atom.txt diff --git a/fx92.py b/fx92.py index 0618ea1..8c06154 100755 --- a/fx92.py +++ b/fx92.py @@ -93,7 +93,10 @@ def main(): ast = parser.parse_program() ast = ast.simplify() - print_ast(ast, lang="ast") + # Parser debug mode, print the AST + if debug == "parser": + print_ast(ast, lang="ast") + return 0 with Window(width=192, height=47, scale=scale, quiet=quiet) as w: ctx = Context(w) diff --git a/fx92/lexer.py b/fx92/lexer.py index 7057d6a..40e646d 100644 --- a/fx92/lexer.py +++ b/fx92/lexer.py @@ -301,9 +301,10 @@ class TextLexer(LexerBase): r"PRINT|STYLE|WAIT|REPEAT_END|REPEAT|WHILE_END|WHILE|IF_END|ELSE|" r"IFELSE_END|IFELSE|IF", re.IGNORECASE) - RE_CONST = re.compile( r"([0-9]+(?:\.[0-9]+)?(?:[eE][0-9]+)?)(%?)") + RE_FUN = re.compile( + r"([a-zA-Z]+)\(") def __init__(self, code): """Initialize the lexer with text code.""" @@ -384,6 +385,13 @@ class TextLexer(LexerBase): self.pending_param = True return Token(T.CONST, f) + # Functions + m = re.match(self.RE_FUN, c) + if m is not None: + self.code = c[len(m[0]):] + self.pending_param = True + return Token(T.FUN, m[1]) + # Variables if c[0] in "MABCDEFxXyY": var = c[0].lower() if c[0] in "xXyY" else c[0] @@ -391,11 +399,6 @@ class TextLexer(LexerBase): self.pending_param = True return Token(T.VAR, c[0]) - # If nothing can be found, raise an exception - s = c.split(maxsplit=1) - err = s[0] - self.code = s[1] if len(s) > 1 else "" - # Comments if c[0] == "#": splits = c.split('\n', maxsplit=1) @@ -404,6 +407,11 @@ class TextLexer(LexerBase): self.position -= 1 return self.lex() + # If nothing can be found, raise an exception + s = c.split(maxsplit=1) + err = s[0] + self.code = s[1] if len(s) > 1 else "" + raise Exception("Lexical error near '{}'".format(err)) def at_end(self): diff --git a/fx92/parser.py b/fx92/parser.py index 9438c59..39f7dde 100644 --- a/fx92/parser.py +++ b/fx92/parser.py @@ -215,10 +215,16 @@ class Parser: # atom -> const (VAR | "(" expr ")")* | (VAR | "(" expr ")")+ def atom(self): factors = [] - lat = self.la.type - # Case of constants - if lat == T.PLUS or lat == T.MINUS or lat == T.CONST: + # Initial sign + if self.la.type == T.PLUS: + self.expect(T.PLUS) + elif self.la.type == T.MINUS: + self.expect(T.MINUS) + factors.append(Node(N.CONST, -1)) + + # Optional constant + if self.la.type == T.CONST: factors.append(self.const()) while 1: diff --git a/tests.py b/tests.py index c5ce8aa..4674ffe 100755 --- a/tests.py +++ b/tests.py @@ -27,12 +27,14 @@ def runtest(program, refout=None, refimg=None): success = True if refout is not None: - with open(refout, "r") as fp: + with open(refout, "rb") as fp: refout = fp.read() if st.stdout == refout: print(" Output is correct.") else: print(" -> Output is incorrect!") + print(" ref:", repr(refout)) + print(" out:", repr(st.stdout)) success = False if refimg is not None: diff --git a/tests/function-atom.out b/tests/function-atom.out new file mode 100644 index 0000000..4672473 --- /dev/null +++ b/tests/function-atom.out @@ -0,0 +1,4 @@ +-2.0 +1.0 +1.0 +-1.0 diff --git a/tests/function-atom.txt b/tests/function-atom.txt new file mode 100644 index 0000000..57f00f3 --- /dev/null +++ b/tests/function-atom.txt @@ -0,0 +1,4 @@ +print -2cos(0) +print 1cos(0) +print +cos(0) +print -cos(0)