""" parser.py simple parsing library spec: :== + :== + !-- this has to have IFID at least --! :== "\" * :== "link" | "start" | "author" | "title" | "ifid" :== "\passage" { } :== [^\\\{\}] :== "{" (+ | ) "}" :== * {} {} nick creel | nov 26 2019 | mit license """ import lexer def next_token(tokenQueue): token = tokenQueue.dequeue() return token def parse(tokenQueue): ast = story(tokenQueue) return ast def story(tokenQueue): story = lexer.Token(token_type = "STORY") pre = None pre, tokenQueue = preamble(tokenQueue) if pre: story.children.append(pre) passages = [] while tokens.isEmpty() is False: passage, tokens = passage(tokens) passages.append(passage) for passage in passages: story.children.append(passage) return story def preamble(tokenQueue): preamble_commands = ["ifid", "start", "title", "author"] token = next_token(tokenQueue) pre = lexer.Token(token_type = "PREAMBLE") while token.value in preamble_commands: mac = macro(token, tokenQueue) pre.children.append(mac) else: tokenQueue.put(token) # put the passage token back !? # is this better than just calling passage here? # certainly, calling passage here wouldn't fit the spec. # also, this might not be a passage command! (if a person # didn't write safe input) return (pre, tokenQueue) def passage(tokenQueue): token = next_token(tokenQueue) if token.value is "passage": mypassage = lexer.Token(token_type = "PASSAGE") token = next_token(tokenQueue) while token.token_type() != "CHARACTER": arg, tokenQueue = argument(tokenQueue) passage.children.append(arg) while token.value != "passage": text, tokenQueue = text(tokenQueue) passage.children.append(text) else: tokenQueue.put(token) return (passage, tokenQueue) def macro(token, tokenQueue): macro_commands = ["ifid", "title", "start", "author", "link"] mac = lexer.Token(token_type = "MACRO") if token.value in macro_commands: mac.children.append(token) token = next_token(tokenQueue) while token.token_type != "CHARACTER": if token.token_type == "LEFTCURLY": arg, tokenQueue = argument(tokenQueue) token = next_token(tokenQueue) if token.token_type == "RIGHTCURLY": mac.children.append(argument) else: raise Exception("Mismatched curly braces") else: raise Exception("Macro Missing Argument") return(mac, tokenQueue) def argument(tokenQueue): """ >>> token = lexer.Token("hello", "CHARACTER", "hello") >>> queue = lexer.Queue >>> queue.enqueue(token) >>> arg = argument(queue) >>> print(arg) # what does this look like? tuple of token and queue object. """ arg = lexer.Token(token_type = "ARGUMENT") token = next_token(tokenQueue) if token.token_type is "CHARACTER": arg.children.append(token) return (arg, tokenQueue) elif token.token_type is "COMMAND": mac, tokenQueue = macro(token, tokenQueue) return (arg, tokenQueue)