diff --git a/log.py b/log.py new file mode 100644 index 0000000..ba91794 --- /dev/null +++ b/log.py @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT +# Copyright 2021 Jookia + +LEXER = 0 +PARSER = 1 + +NORMAL = 0 # messages always shown +DEBUG = 1 # high-level information about what's happening +TRACE = 2 # trace output + +def log(module, level, text): + if module == LEXER: + module_name = "LEXER" + elif module == PARSER: + module_name = "PARSER" + else: + module_name = "UNKNOWN" + + if level == NORMAL: + level_name = "NORMAL" + elif level == DEBUG: + level_name = "DEBUG" + elif level == TRACE: + level_name = "TRACE" + else: + level_name = "UNKNOWN" + + print("%s %s: %s" % (level_name, module_name, text)) diff --git a/parse.py b/parse.py index 2c26a6a..e47488c 100644 --- a/parse.py +++ b/parse.py @@ -1,23 +1,37 @@ # SPDX-License-Identifier: MIT # Copyright 2021 Jookia +import log + def tokenize(code): tokens = [] token = "" text = "" mode = "normal" # normal/note/text for symbol in code: + if symbol == '\n': + symbol_print = "new line" + else: + symbol_print = "symbol '%s'" % (symbol) + log.log(log.LEXER, log.TRACE, "Read %s" % (symbol_print)) if symbol == " " or symbol == "\t" or symbol == "\n": + log.log(log.LEXER, log.TRACE, "Read token '%s'" % (token)) if token == "": pass elif token == "BeginNote": + log.log(log.LEXER, log.TRACE, "Switching to note mode") mode = "note" elif token == "EndNote": + log.log(log.LEXER, log.TRACE, "Ending note mode") mode = "normal" elif token == "BeginText": + log.log(log.LEXER, log.TRACE, "Switching to text mode") mode = "text" elif token == "EndText": - tokens.append(("text", text[1:-8])) + log.log(log.LEXER, log.TRACE, "Ending text mode") + content = text[1:-8] + log.log(log.LEXER, log.DEBUG, "Appending text '%s'" % (content)) + tokens.append(("text", content)) mode = "normal" text = "" elif token != "": @@ -26,15 +40,19 @@ "If", "Then", "Else", "EndIf"] if token in keywords: type = "keyword" - tokens.append((type, token.lower())) + token = token.lower() else: type = "symbol" - tokens.append((type, token)) + log.log(log.LEXER, log.DEBUG, "Appending token type %s value %s" % (type, token)) + tokens.append((type, token)) + else: + log.log(log.LEXER, log.TRACE, "Skipping token '%s'" % (token)) token = "" else: token += symbol if mode == "text": text += symbol + log.log(log.LEXER, log.TRACE, "Done lexing, added EOF") tokens.append(('EOF', None)) return tokens @@ -47,21 +65,21 @@ (type, value) = self.tokens[self.pos] if self.pos < (len(self.tokens) - 1): self.pos += 1 - print("Read %s %s" % (type, value)) + log.log(log.PARSER, log.TRACE, "Read %s %s" % (type, value)) return (type, value) def peek(self): (type, value) = self.tokens[self.pos] - print("Peeked %s %s" % (type, value)) + log.log(log.PARSER, log.TRACE, "Peeked %s %s" % (type, value)) return (type, value) def parse_version(self): (type, value) = self.next() if type != "keyword" or value != "newlang": - print("Expected NewLang keyword") + log.log(log.PARSER, log.NORMAL, "Expected NewLang keyword") return None (type, value) = self.next() - print("Parsed language version %s" % (value)) + log.log(log.PARSER, log.DEBUG, "Parsed language version %s" % (value)) return value def parse_value(self, type, value): @@ -70,7 +88,7 @@ elif type == "text": return ('text', value) else: - print("Unexpected type %s" % (type)) + log.log(log.PARSER, log.NORMAL, "Unexpected type %s" % (type)) return None def parse_arguments(self, terminator): @@ -81,12 +99,12 @@ if value == terminator: return args else: - print("Unexpected keyword %s" % (value)) + log.log(log.PARSER, log.NORMAL, "Unexpected keyword %s" % (value)) return None else: arg = self.parse_value(type, value) if not arg: - print("While parsing argument") + log.log(log.PARSER, log.NORMAL, "While parsing argument") return None args.append(arg) @@ -94,14 +112,14 @@ (type, value) = self.next() subject = self.parse_value(type, value) if not subject: - print("While parsing subject") + log.log(log.PARSER, log.NORMAL, "While parsing subject") return None (type, value) = self.next() if type == "keyword": if value == terminator: verb = None else: - print("Unexpected keyword %s" % (value)) + log.log(log.PARSER, log.NORMAL, "Unexpected keyword %s" % (value)) return None elif type == "symbol": verb = value @@ -110,97 +128,97 @@ if verb: arguments = self.parse_arguments(terminator) if arguments is None: - print("While parsing arguments") + log.log(log.PARSER, log.NORMAL, "While parsing arguments") return None else: arguments = [] - print("Parsed statement: subject %s verb %s args %s" % (subject, verb, arguments)) + log.log(log.PARSER, log.DEBUG, "Parsed statement: subject %s verb %s args %s" % (subject, verb, arguments)) return ('statement', subject, verb, arguments) def parse_set(self): (type, value) = self.next() if type != "symbol": - print("Expect symbol, got %s" % (type)) + log.log(log.PARSER, log.NORMAL, "Expect symbol, got %s" % (type)) return None subject = value (type, value) = self.next() if type != "keyword" or value != "to": - print("Expected To, got %s %s" % (type, value)) + log.log(log.PARSER, log.NORMAL, "Expected To, got %s %s" % (type, value)) return None - print("Parsing set value...") + log.log(log.PARSER, log.TRACE, "Parsing set value...") ast = self.parse_statement("endset") if not ast: - print("While parsing statement") + log.log(log.PARSER, log.NORMAL, "While parsing statement") return None - print("Parsed set for %s" % (subject)) + log.log(log.PARSER, log.DEBUG, "Parsed set for %s" % (subject)) return ('set', subject, ast) def parse_if(self): - print("Parsing if test condition...") + log.log(log.PARSER, log.TRACE, "Parsing if test condition...") test = self.parse_statement("then") if not test: - print("While parsing test condition") + log.log(log.PARSER, log.NORMAL, "While parsing test condition") return None - print("Parsing if success statement...") + log.log(log.PARSER, log.TRACE, "Parsing if success statement...") success = self.parse_statement("else") if not success: - print("While parsing success statement") + log.log(log.PARSER, log.NORMAL, "While parsing success statement") return None - print("Parsing if failure statement...") + log.log(log.PARSER, log.TRACE, "Parsing if failure statement...") failure = self.parse_statement("endif") if not failure: - print("While parsing failure statement") + log.log(log.PARSER, log.NORMAL, "While parsing failure statement") return None - print("Parsed conditional") + log.log(log.PARSER, log.DEBUG, "Parsed conditional") return ('if', test, success, failure) def parse_directive(self): (type, value) = self.peek() if type != "keyword" and type != "symbol": - print("Expected keyword or symbol here, got %s" % (type)) + log.log(log.PARSER, log.NORMAL, "Expected keyword or symbol here, got %s" % (type)) return None if type == "keyword": self.next() if value == "set": ast = self.parse_set() if not ast: - print("While parsing set directive") + log.log(log.PARSER, log.NORMAL, "While parsing set directive") return None return ast elif value == "if": ast = self.parse_if() if not ast: - print("While parsing set directive") + log.log(log.PARSER, log.NORMAL, "While parsing set directive") return None return ast else: - print("Unexpected keyword %s" % (value)) + log.log(log.PARSER, log.NORMAL, "Unexpected keyword %s" % (value)) return None else: ast = self.parse_statement("done") if not ast: - print("While parsing statement") + log.log(log.PARSER, log.NORMAL, "While parsing statement") return None return ast def parse_file(self): - print("Parsing file...") + log.log(log.PARSER, log.TRACE, "Parsing file...") ast = [] version = self.parse_version() if not version: - print("While parsing version identifier at start of file") + log.log(log.PARSER, log.NORMAL, "While parsing version identifier at start of file") return None if version != "0": - print("Invalid version identifier %s" % (version)) + log.log(log.PARSER, log.NORMAL, "Invalid version identifier %s" % (version)) return None while self.peek()[0] != 'EOF': directive = self.parse_directive() if directive == None: - print("While parsing directive in file") + log.log(log.PARSER, log.NORMAL, "While parsing directive in file") return None else: ast.append(directive) - print("Parsed file") + log.log(log.PARSER, log.DEBUG, "Parsed file") return ast def parse_file(code):