diff --git a/ChironCore/BallLarus/__init__.py b/ChironCore/BallLarus/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ChironCore/BallLarus/ballLarus.py b/ChironCore/BallLarus/ballLarus.py new file mode 100644 index 0000000..8976be1 --- /dev/null +++ b/ChironCore/BallLarus/ballLarus.py @@ -0,0 +1,691 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Ball-Larus path profiling implementation for the Chiron Framework. +""" + +from operator import is_ +from os import path +import sys +from tabnanny import check +import networkx as nx +from networkx import MultiDiGraph +from networkx import efficiency +from ChironAST import ChironAST +from irhandler import IRHandler +from interpreter import ConcreteInterpreter +from BallLarus.bl_interpreter import BallLarusInterpreter +import turtle +from networkx.drawing.nx_agraph import to_agraph +import json + +class BallLarusProfiler: + """ + Implements Ball-Larus path profiling algorithm. + """ + + def __init__(self, irHandler, args): + """ + Initialize the Ball-Larus profiler. + """ + self.irHandler = irHandler + self.ir = irHandler.ir + self.cfg = irHandler.cfg + self.original_ir = None # To store the original IR before instrumentation + self.back_edges = [] # List of back edges in the CFG + self.args = args + + def run_profiling(self): + """ + Run the Ball-Larus path profiling algorithm. + + This involves: + 1. Saving the original IR + 2. Identifying paths in the CFG + 3. Computing edge weights + 4. Instrumenting the IR + 5. Running the instrumented program + 6. Reporting the results + """ + # Save the original IR + self.original_ir = self.ir.copy() + + # Identify paths and compute edge weights + self.compute_edge_weights() + + # Instrument the IR + self.instrument_ir() + + def execute(self, predictor_hashMap = {}, flag = False, is_training = False): + """ + Execute the instrumented program. + """ + inptr = BallLarusInterpreter(self.irHandler, self.args, predictor_hashMap, flag, is_training) + terminated = False + inptr.initProgramContext(self.args.params) + while True: + terminated = inptr.interpret() + if terminated: + break + print("Program Ended.") + print() + print("Press ESCAPE to exit") + + turtle.listen() + if flag == False: + turtle.onkeypress(stopTurtle, "Escape") + turtle.mainloop() + + def compute_edge_weights(self): + """ + Compute edge weights using the Ball-Larus algorithm. + + The algorithm works as follows: + 1. Make the CFG acyclic by removing back edges + 2. Assign a value NumPaths(v) to each node v, which is the number of paths from v to the exit node + 3. Assign weights to edges such that the sum of weights along any path gives a unique path number + """ + # Create an acyclic version of the CFG + self.acyclic_cfg = self.create_acyclic_cfg() + + # Compute NumPaths for each node using a topological sort + # NumPaths(exit) = 1 + # NumPaths(v) = sum(NumPaths(w)) for all edges v->w + num_paths = {self.exit_node: 1} + + # Get nodes in reverse topological order (from exit to entry) + try: + for node in reversed(list(nx.topological_sort(self.acyclic_cfg))): + if node not in num_paths: + num_paths[node] = 0 + + for edge in self.acyclic_cfg.out_edges(node): + successor = edge[1] + if successor in num_paths: + num_paths[node] += num_paths[successor] + except nx.NetworkXUnfeasible: + print("Error: Could not perform topological sort on the CFG") + return + + # Assign weights to edges + # For each node v (except exit), in topological order: + # val = 0 + # For each edge v->w: + # weight(v->w) = val + # val += NumPaths(w) + for node in reversed(list(nx.topological_sort(self.acyclic_cfg))): + if node == self.exit_node: + continue + + val = 0 + for edge in self.acyclic_cfg.out_edges(node, data=True): + successor = edge[1] + edge[2]['weight'] = val + edge[2]['chord_edge'] = False + if successor in num_paths: + val += num_paths[successor] + + assert val == num_paths[node] + + # DEBUG: Print the acyclic CFG with edge weights + # print("Edge weights computed successfully") + # for node in self.acyclic_cfg.nodes(): + # for edge in self.acyclic_cfg.out_edges(node, data=True): + # print(f"{node.name} -> {edge[1].name}: {edge[2]['weight']}") + + self.efficient_event_counting() + # Now we will use the efficient event counting algorithm to compute the edge weights + + def efficient_event_counting(self): + # Create a copy of the acyclic CFG as a MultiDiGraph + mst_graph = nx.MultiDiGraph(self.acyclic_cfg) + + # Add an edge from exit to entry with very high weight (practically infinity) + inf = 1000000000 + mst_graph.add_edge(self.exit_node, self.entry_node, weight=inf) #inf = 1e9 + + # Implement Kruskal's algorithm for maximum spanning tree + # 1. Get all edges with their weights and sort by weight in descending order + edges = [] + for u, v, data in mst_graph.edges(data=True): + weight = data.get('weight', 0) + edges.append((u, v, weight, data)) + + # Sort edges by weight in descending order (for maximum spanning tree) + edges.sort(key=lambda x: x[2], reverse=True) + + # Initialize a disjoint-set data structure for cycle detection + # We'll use a simple dictionary for this + parent = {node: node for node in mst_graph.nodes()} + + def find(node): + # Find the root/representative of the set containing node + if parent[node] != node: + parent[node] = find(parent[node]) # Path compression + return parent[node] + + def union(node1, node2): + # Merge the sets containing node1 and node2 + root1 = find(node1) + root2 = find(node2) + if root1 != root2: + parent[root2] = root1 + + # Build the MST + mst_edges = [] + for u, v, weight, data in edges: + # Skip adding this edge if it would create a cycle + if find(u) != find(v): + mst_edges.append((u, v, data)) + union(u, v) + + # Mark all edges as chord_edge=True by default + for u, v, data in mst_graph.edges(data=True): + data['chord_edge'] = True + + for u, v, data in mst_edges: + for edge in mst_graph.out_edges(u, data=True): + if edge[1] == v and edge[2] == data: + edge[2]['chord_edge'] = False + + # print("---------------------------------") + # print("Chord edges:") + # for u,v,data in mst_graph.edges(data=True): + # if data['chord_edge']: + # print(f"{u.name} -> {v.name}: {data['weight']}") + + # mst_tree will be an undirected graph + mst_tree = nx.DiGraph() + for u,v,data in mst_graph.edges(data=True): + if(data['chord_edge'] == False): + weight = data['weight'] + if(u == self.exit_node and v == self.entry_node): + # print("Dummy edge from exit to entry") + weight = 0 + # mst_tree.add_edge(u,v,weight) + mst_tree.add_edge(u,v,weight=weight) + mst_tree.add_edge(v,u,weight= -weight) + + for u, v, data in mst_graph.edges(data=True): + if data['chord_edge']: + # Use DFS to calculate the path weight sum from u to v in the MST + path_weight_sum = 0 + vis = {} + def dfs_path(node, target, weight_sum): + """ + Recursive DFS to find a path and its weight sum from node to target. + Returns True if a path is found, False otherwise. + """ + if node in vis: + return False + vis[node] = True + nonlocal path_weight_sum + if node == target: + path_weight_sum = weight_sum + return True + + # print(len(mst_tree.out_edges(node))) + for edge in mst_tree.out_edges(node, data=True): + successor = edge[1] + # print(f" {node.name} -> {successor.name}: {edge[2]['weight']}") + if dfs_path(successor, target, weight_sum + edge[2]['weight']): + return True + + return False + + # Start DFS from u to find a path to v + # print(f"Finding path from {u.name} to {v.name}") + path_found = dfs_path(v, u, 0) + if path_found == False: + assert False + path_found = dfs_path(u, v, 0) + assert path_found == True + + data['weight2'] = data['weight'] + data['weight'] += path_weight_sum + # print(f"{u.name} ----> {v.name}: {data['weight']}") + + for u, v, data in mst_graph.edges(data=True): + if data['chord_edge'] == False: + data['weight2'] = data['weight'] + data['weight'] = 0 + + # Remove the dummy edge from exit to entry + mst_graph.remove_edge(self.exit_node, self.entry_node) + # print("---------------------- New weights ----------------------") + # for u,v,data in mst_graph.edges(data=True): + # print(f"{u.name} -> {v.name}: {data['weight']}") + + self.acyclic_cfg = mst_graph + + def instrument_ir(self): + """ + Instrument the IR to track path execution. + + This involves: + 1. Adding a path register variable. + 2. For each "flow_edge" and "Cond_True": + - Locate the last IR index of the source basic block and insert an update + instruction immediately after. + 3. For each "Cond_False": + - Append at the end of the IR two instructions: + a) an update to the path register, + b) a goto command that jumps to the target basic block's first instruction. + 4. The instrumentation for the back edges were handled separately. + 5. After adding instructions, the offsets were updated simultaneously. + """ + + # DEBUG: Print the original IR + # print("Original IR:") + # for instr, idx in self.ir: + # print(f"instr: {instr}, target: {idx}") + # print("--------------------------------") + + # Save original IR copy + if self.original_ir is None: + self.original_ir = self.ir.copy() + + # Create a path register variable + path_register_var = ChironAST.Var(":blPathRegister") + + # Insert an initialization instruction at the beginning + init_path_register = ChironAST.AssignmentCommand( + path_register_var, + ChironAST.Num(0) + ) + + # Build mapping from each basic block to its first and last IR indices + bb_last_index = {} + bb_first_index = {} + for bb in self.cfg.nodes(): + if bb.instrlist: + bb_first_index[bb] = bb.instrlist[0][1] + bb_last_index[bb] = bb.instrlist[-1][1] + + # Helper function to update bb indices and IR targets after an insertion. + def update_offsets(insertion_index, delta=1): + # Update basic block first and last indices + for bb in bb_first_index: + if bb_first_index[bb] >= insertion_index: + bb_first_index[bb] += delta + if bb_last_index[bb] >= insertion_index: + bb_last_index[bb] += delta + # Update each IR instruction's jump offset + for idx, (instr, tgt) in enumerate(new_ir): + jump_target = idx + tgt + if(idx == insertion_index - 1): + if isinstance(instr, ChironAST.ConditionCommand) and jump_target >= insertion_index: + new_tgt = tgt + delta + new_ir[idx] = (instr, new_tgt) + continue + if(idx == insertion_index): + continue + # For instructions before the insertion: + if idx < insertion_index and jump_target >= insertion_index: + new_tgt = tgt + delta + new_ir[idx] = (instr, new_tgt) + # For instructions at/after the insertion: + elif idx >= insertion_index and jump_target <= insertion_index: + new_tgt = tgt - delta + new_ir[idx] = (instr, new_tgt) + + # Work on a copy of the IR list for insertions + new_ir = self.irHandler.ir.copy() + new_ir.insert(0, (init_path_register, 1)) + update_offsets(0) + + # Iterate over CFG edges + for source, target, attrs in self.cfg.nxgraph.edges(data=True): + + if (source, target) in self.back_edges: + continue + + edge_label = attrs.get('label') + weight = 0 + for edge in self.acyclic_cfg.out_edges(source, data=True): + if edge[1] == target and edge[2].get('new_edge') is None: + weight = edge[2]['weight'] + break + # if weight == 0: + # continue + # Create the update instruction: path_register = path_register + weight + update_instr = ChironAST.AssignmentCommand( + path_register_var, + ChironAST.Sum(path_register_var, ChironAST.Num(weight)) + ) + + if edge_label in ('flow_edge', 'Cond_True'): + last_idx = bb_last_index.get(source) + if last_idx is not None: + insertion_index = last_idx + 1 + new_ir.insert(insertion_index, (update_instr, 1)) + # After each insertion update indices and offsets. + update_offsets(insertion_index) + + elif edge_label == 'Cond_False': + assert target.name != "END" + + if(target.name == "END"): + jump_instr = ChironAST.ConditionCommand(ChironAST.BoolFalse()) + new_ir.append((jump_instr, 1)) + update_offsets(len(new_ir)-1) + + # Iterate over CFG edges 2nd time to handle Cond_False edges + for source, target, attrs in self.cfg.nxgraph.edges(data=True): + if (source, target) in self.back_edges: + + # Part 1 + weight = 0 + check_flag = 0 + for edge in self.acyclic_cfg.out_edges(source, data=True): + if edge[1] == self.exit_node and edge[2].get('new_edge') is True: + check_flag = 1 + weight = edge[2]['weight'] + break + assert check_flag == 1 + update_instr = ChironAST.AssignmentCommand( + path_register_var, + ChironAST.Sum(path_register_var, ChironAST.Num(weight)) + ) + insertion_index = len(new_ir) + new_ir.append((update_instr, 1)) + update_offsets(insertion_index) + source_end = bb_last_index.get(source, 0) + instr, old_offset = new_ir[source_end] + new_offset = len(new_ir) - source_end - 1 + new_ir[source_end] = (instr, new_offset) + + inc_instr = ChironAST.IncrementCommand(path_register_var) + new_ir.append((inc_instr, 1)) + update_offsets(len(new_ir)-1) + + # Part 2 + check_flag = 0 + for edge in self.acyclic_cfg.out_edges(self.entry_node, data=True): + if edge[1] == target and edge[2].get('new_edge') is True: + weight = edge[2]['weight'] + check_flag = 1 + break + + assert check_flag == 1 + update_instr = ChironAST.AssignmentCommand( + path_register_var, + ChironAST.Num(weight) + ) + insertion_index = len(new_ir) + new_ir.append((update_instr, 1)) + update_offsets(insertion_index) + jump_instr = ChironAST.ConditionCommand(ChironAST.BoolFalse()) + target_first = bb_first_index.get(target, 0) + val = target_first - len(new_ir) + new_ir.append((jump_instr, val)) + update_offsets(len(new_ir)-1) + + continue + + + edge_label = attrs.get('label') + weight = 0 + for edge in self.acyclic_cfg.out_edges(source, data=True): + if edge[1] == target and edge[2].get('new_edge') is None: + weight = edge[2]['weight'] + break + + update_instr = ChironAST.AssignmentCommand( + path_register_var, + ChironAST.Sum(path_register_var, ChironAST.Num(weight)) + ) + + if edge_label == 'Cond_False': + insertion_index = len(new_ir) + new_ir.append((update_instr, 1)) + update_offsets(insertion_index) + source_end = bb_last_index.get(source, 0) + target_first = bb_first_index.get(target, 0) + instr, old_offset = new_ir[source_end] + new_offset = len(new_ir) - source_end - 1 + new_ir[source_end] = (instr, new_offset) + jump_instr = ChironAST.ConditionCommand(ChironAST.BoolFalse()) + val = target_first - len(new_ir) + new_ir.append((jump_instr, val)) + update_offsets(len(new_ir)-1) + + # Dump the HashMap to a file + inc_instr = ChironAST.IncrementCommand(path_register_var) + new_ir.append((inc_instr, 1)) + dump_instr = ChironAST.DumpCommand() + new_ir.append((dump_instr, 1)) + + # Replace IR with instrumented version + self.irHandler.ir = new_ir + + print("--------------------------------") + print("IR:") + for instr, idx in self.irHandler.ir: + print(f"instr: {instr}, target: {idx}") + print("--------------------------------") + print("IR instrumented successfully for Ball-Larus path profiling") + + def regenerate_path(self, path_number): + """ + Regenerate the path from the path number. + + This method uses the edge weights to reconstruct the path taken + in the CFG to reach the given path number. + + Args: + path_number: The path number to regenerate + + Returns: + A list of basic block names representing the path + """ + + path = [] + current_node = self.entry_node + while current_node is not None and current_node.name != "END": + path.append(current_node.name) + max_weight = -1 + next_node = None + new_edge = False + for edge in self.acyclic_cfg.out_edges(current_node, data=True): + weight = edge[2].get('weight2', 0) + if weight > max_weight and path_number >= weight: + max_weight = weight + next_node = edge[1] + new_edge = edge[2].get('new_edge', False) + + if new_edge and path[-1] == "START": + path.pop() + path_number -= max_weight + current_node = next_node + + if new_edge == False: + path.append("END") + + return path + + def report_results(self): + """ + Report the results of path profiling. + + This method should be called after the instrumented program has been executed. + """ + # Open hash_dump.txt and read the hash map contents + # example contents -> + # 4: 3 + # 15: 12 + # for each key: value pair, we will replace the key with the actual path in the CFG by implementing the path regeneration algorithm + # then write back the path: value pair to hash_dump.txt + list_of_paths = [] + with open("hash_dump.txt", "r") as f: + lines = f.readlines() + for line in lines: + key, value = line.split(":") + path = self.regenerate_path(int(key)) + #store the path: value pair in the hash_dump.txt file + list_of_paths.append((path, value)) + with open("path_profile_data.txt", "w") as f: + for path, value in list_of_paths: + f.write(f"{path}: {value}") + + def identify_back_edges(self): + """ + Identify back edges in the CFG. + + Back edges are edges that point from a node to one of its ancestors + in a depth-first traversal of the graph. These edges typically + represent loops in the program. + + Returns: + A list of tuples (source, target) representing back edges + """ + # Get the NetworkX graph from the CFG + G = self.cfg.nxgraph + + # Initialize variables for DFS + visited = set() + dfs_stack = [] # Stack to track the current DFS path + back_edges = [] + + # Define a recursive DFS function + def dfs(node): + visited.add(node) + dfs_stack.append(node) + + for successor in self.cfg.successors(node): + if successor not in visited: + # Recursive DFS call + dfs(successor) + elif successor in dfs_stack: + # Found a back edge + back_edges.append((node, successor)) + + dfs_stack.pop() + + # Find the entry node (usually named "START") + entry_node = None + for node in self.cfg.nodes(): + if node.name == "START": + entry_node = node + break + + if entry_node is None: + print("Warning: Could not find entry node in CFG") + return [] + + # Start DFS from the entry node + dfs(entry_node) + self.entry_node = entry_node + + # print(f"Identified {len(back_edges)} back edges in the CFG") + # for source, target in back_edges: + # print(f" {source.name} -> {target.name}") + return back_edges + + def create_acyclic_cfg(self): + """ + Create an acyclic version of the CFG by removing back edges. + + Returns: + A new NetworkX DiGraph that is acyclic + """ + # Get the original graph + G = nx.MultiDiGraph(self.cfg.nxgraph) + + # Identify back edges + self.back_edges = self.identify_back_edges() + + exit_node = None + for node in self.cfg.nodes(): + if node.name == "END": + exit_node = node + break + + self.exit_node = exit_node + + # Remove back edges from the graph + for source, target in self.back_edges: + if G.has_edge(source, target): + G.remove_edge(source, target) + G.add_edge(self.entry_node, target, new_edge=True) + G.add_edge(source, self.exit_node, new_edge=True) + + # Verify that the graph is acyclic + if nx.is_directed_acyclic_graph(G): + print("Successfully created acyclic CFG") + else: + print("Warning: CFG is still cyclic after removing back edges") + + self.dumpCFG2(G, "acyclic_cfg.dot") + return G + + def dumpCFG2(self,G,filename="out"): + A = to_agraph(G) + A.layout('dot') + A.draw(filename + ".png") + +def stopTurtle(): + turtle.bye() + +def run_ball_larus_profiling(irHandler, args): + """ + Main function to run Ball-Larus path profiling. + + If args.ballLarus_op is a filename, read one JSON dict per line, + set args.params, and run profiling for each. Otherwise do one run. + """ + if irHandler.cfg is None: + print("Error: Control Flow Graph is required for Ball-Larus path profiling.") + return + + # Always start with an empty hash_dump.txt + with open("hash_dump.txt", "w") as dumpf: + # open in write mode to create/clear the file + pass + with open("predictor_accuracy.txt", "w") as dumpf: + # open in write mode to create/clear the file + pass + with open("predictions_pc.txt", "w") as dumpf: + # open in write mode to create/clear the file + pass + + # if -bl_op was passed, args.ballLarus_op holds the inputs‐file path + profiler = BallLarusProfiler(irHandler, args) + profiler.run_profiling() + + predictor_hashMap = {} + if args.ballLarus_op: + with open(args.ballLarus_op, 'r') as f: + lines = [ln.strip() for ln in f + if ln.strip() and not ln.strip().startswith("#")] + + num_inputs = len(lines) + #print(f"Found {num_inputs} inputs in {args.ballLarus_op}") + # training_input is floor of num_inputs*0.8 + training_input = int(num_inputs * 0.8) + + # Now iterate over those lines + for idx, ln in enumerate(lines): + try: + params = json.loads(ln) + except json.JSONDecodeError as e: + print(f"Skipping invalid line: {ln}\n {e}") + continue + + args.params = params + turtle.clearscreen() + turtle.reset() + + # first 80% are training runs + is_train = (idx < training_input) + print(f"\n=== Run #{idx+1}/{num_inputs} " + f"{'(training)' if is_train else '(testing)'} with params {params} ===") + profiler.execute(predictor_hashMap,flag=True, is_training=is_train) + + profiler.report_results() + turtle.onkeypress(stopTurtle, "Escape") + turtle.mainloop() + else: + # single‐input mode + profiler.execute() + profiler.report_results() \ No newline at end of file diff --git a/ChironCore/BallLarus/bl_interpreter.py b/ChironCore/BallLarus/bl_interpreter.py new file mode 100644 index 0000000..208734e --- /dev/null +++ b/ChironCore/BallLarus/bl_interpreter.py @@ -0,0 +1,162 @@ +from interpreter import ConcreteInterpreter, Interpreter, ProgramContext, addContext +from ChironAST import ChironAST +from ChironHooks import Chironhooks +import os + +class BallLarusInterpreter(ConcreteInterpreter): + """ + A specialized interpreter that extends ConcreteInterpreter with Ball-Larus path profiling. + It preserves all original functionality while adding support for PrintCommand, IncrementCommand, + and DumpCommand instructions. + """ + + def __init__(self, irHandler, params,predictor_hashMap = {}, is_bl_op = False, is_training=False): + super().__init__(irHandler, params) + # Initialize the hashMap for path register tracking + self.hashMap = {} + self.predictor = predictor_hashMap + self.bl_op = is_bl_op + self.isTraining = is_training + self.total_cnt = 0 + self.correct_cnt = 0 + def interpret(self): + """ + Executes one instruction at the current program counter. Returns True when the program finishes, + False otherwise. + """ + print("Program counter : ", self.pc) + stmt, tgt = self.ir[self.pc] + print(stmt, stmt.__class__.__name__, tgt) + + self.sanityCheck(self.ir[self.pc]) + + if isinstance(stmt, ChironAST.AssignmentCommand): + ntgt = self.handleAssignment(stmt, tgt) + elif isinstance(stmt, ChironAST.ConditionCommand): + if self.bl_op: + ntgt = self.handleCondition_bl(stmt, tgt) + else: + ntgt = self.handleCondition(stmt, tgt) + elif isinstance(stmt, ChironAST.MoveCommand): + ntgt = self.handleMove(stmt, tgt) + elif isinstance(stmt, ChironAST.PenCommand): + ntgt = self.handlePen(stmt, tgt) + elif isinstance(stmt, ChironAST.GotoCommand): + ntgt = self.handleGotoCommand(stmt, tgt) + elif isinstance(stmt, ChironAST.NoOpCommand): + ntgt = self.handleNoOpCommand(stmt, tgt) + elif isinstance(stmt, ChironAST.PrintCommand): + ntgt = self.handlePrintCommand(stmt, tgt) + elif isinstance(stmt, ChironAST.IncrementCommand): + ntgt = self.handleIncrementCommand(stmt, tgt) + elif isinstance(stmt, ChironAST.DumpCommand): + ntgt = self.handleDumpCommand(stmt, tgt) + else: + raise NotImplementedError("Unknown instruction: %s, %s." % (type(stmt), stmt)) + + self.pc += ntgt + + if self.pc >= len(self.ir): + # This is the ending of the interpreter. + if self.bl_op and self.isTraining == False: + with open("predictor_accuracy.txt", "a") as f: + f.write(f"Total Count: {self.total_cnt}\n") + f.write(f"Correct Count: {self.correct_cnt}\n") + f.write(f"Accuracy: {self.correct_cnt / self.total_cnt if self.total_cnt > 0 else 0}\n") + f.write("-----------------------\n") + + with open("predictions_pc.txt", "a") as f: + f.write("-------------------------\n") + f.write("\n") + + self.trtl.write("End, Press ESC", font=("Arial", 15, "bold")) + if self.args is not None and self.args.hooks: + self.chironhook.ChironEndHook(self) + return True + else: + return False + + def handleCondition_bl(self, stmt, tgt): + print(" Branch Instruction") + condstr = addContext(stmt) + exec("self.cond_eval = %s" % (condstr)) + exprStr = addContext(":blPathRegister") + path_reg_val = eval(exprStr) + if(self.isTraining): + if self.cond_eval: + self.predictor[(path_reg_val, self.pc)] = self.predictor.get((path_reg_val, self.pc), 0) + 1 + else: + self.predictor[(path_reg_val, self.pc)] = self.predictor.get((path_reg_val, self.pc), 0) - 1 + else: + self.total_cnt += 1 + predictor_val = self.predictor.get((path_reg_val, self.pc), 0) + prediction = "Taken" if predictor_val >= 0 else "Not Taken" + actual = "Taken" if self.cond_eval else "Not Taken" + is_correct = False + if predictor_val >= 0 and self.cond_eval: + self.correct_cnt += 1 + is_correct = True + elif predictor_val < 0 and not self.cond_eval: + self.correct_cnt += 1 + is_correct = True + with open("predictions_pc.txt","a") as f: + f.write(f"PC: {self.pc}, Prediction: {prediction}, Actual: {actual}, Correct: {is_correct}\n") + return 1 if self.cond_eval else tgt + + def handlePrintCommand(self, stmt, tgt): + """ + Handles a PrintCommand by evaluating the expression and writing the result to print_output.txt. + """ + print(" PrintCommand") + # Convert the expression to a string that can be evaluated + exprStr = addContext(stmt.expr) + # Evaluate the expression in the current program context + result = eval(exprStr) + # Dump the result to a file instead of printing to the console + with open("print_output.txt", "a") as f: + f.write(str(exprStr) + " = " + str(result) + "\n") + return 1 + + def handleIncrementCommand(self, stmt, tgt): + """ + Handles an IncrementCommand by incrementing the value for the specified key in the hashMap. + """ + print(" IncrementCommand") + exprStr = addContext(stmt.var) + key = eval(exprStr) + current_value = self.hashMap.get(key, 0) + self.hashMap[key] = current_value + 1 + return 1 + + def handleDumpCommand(self, stmt, tgt): + """ + Merge current self.hashMap into hash_dump.txt: + - For keys already in the file, add the new count. + - For new keys, append them. + """ + print(" DumpCommand") + dump_file = "hash_dump.txt" + + # 1) Load existing counts from disk (if the file exists) + existing = {} + + if os.path.exists(dump_file): + with open(dump_file, "r") as f: + for line in f: + line = line.strip() + if not line: + continue + # Expect lines like "key: value" + key, val = line.split(":", 1) + existing[key.strip()] = existing.get(key.strip(), 0) + int(val.strip()) + + # 2) Merge in-memory hashMap counts + for k, v in self.hashMap.items(): + existing[str(k)] = existing.get(str(k), 0) + v + + # 3) Write the merged result back out + with open(dump_file, "w") as f: + for key, val in existing.items(): + f.write(f"{key}: {val}\n") + + return 1 diff --git a/ChironCore/BallLarus/generate_inputs.py b/ChironCore/BallLarus/generate_inputs.py new file mode 100644 index 0000000..7e97e49 --- /dev/null +++ b/ChironCore/BallLarus/generate_inputs.py @@ -0,0 +1,34 @@ +import json +import random +import argparse + + +# Usage - python generate_inputs.py -n 20 -o inputs.txt --min 1 --max 50 -v :x :y :z :p +# Generates 20 random input lines for exampl1.tl +def main(): + p = argparse.ArgumentParser( + description="Generate N random input‐dict lines for Ball‑Larus profiling" + ) + p.add_argument("-n", "--num", type=int, default=10, + help="Number of input lines to generate") + p.add_argument("-o", "--out", default="inputs.txt", + help="Output filename") + p.add_argument("--min", type=int, default=0, + help="Minimum random value (inclusive)") + p.add_argument("--max", type=int, default=100, + help="Maximum random value (inclusive)") + p.add_argument("-v", "--vars", nargs="+", + default=[":x", ":y", ":z", ":p"], + help="List of variable names (include leading colon)") + args = p.parse_args() + + with open(args.out, "w") as f: + for _ in range(args.num): + data = {var: random.randint(args.min, args.max) for var in args.vars} + json.dump(data, f) + f.write("\n") + + print(f"Wrote {args.num} random inputs to {args.out}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ChironCore/BallLarus/inputs.txt b/ChironCore/BallLarus/inputs.txt new file mode 100644 index 0000000..07ebdba --- /dev/null +++ b/ChironCore/BallLarus/inputs.txt @@ -0,0 +1,10 @@ +{":x": 34, ":y": 2, ":z": 40, ":p": 23} +{":x": 32, ":y": 17, ":z": 49, ":p": 18} +{":x": 34, ":y": 26, ":z": 46, ":p": 18} +{":x": 16, ":y": 24, ":z": 50, ":p": 45} +{":x": 28, ":y": 26, ":z": 34, ":p": 4} +{":x": 34, ":y": 19, ":z": 20, ":p": 3} +{":x": 7, ":y": 32, ":z": 28, ":p": 36} +{":x": 39, ":y": 34, ":z": 38, ":p": 40} +{":x": 33, ":y": 1, ":z": 7, ":p": 22} +{":x": 39, ":y": 1, ":z": 8, ":p": 10} \ No newline at end of file diff --git a/ChironCore/ChironAST/ChironAST.py b/ChironCore/ChironAST/ChironAST.py index f86c5da..33f6d2a 100644 --- a/ChironCore/ChironAST/ChironAST.py +++ b/ChironCore/ChironAST/ChironAST.py @@ -74,6 +74,24 @@ def __init__(self): def __str__(self): return "pause" +class PrintCommand(Instruction): + def __init__(self, expr): + self.expr = expr + + def __str__(self): + return f"PrintCommand({self.expr})" + +class IncrementCommand(Instruction): + def __init__(self, var): + self.var = var # e.g. ":__path_register_var" + def __str__(self): + return f"IncrementCommand({self.var})" + + +class DumpCommand(Instruction): + def __str__(self): + return "DumpCommand()" + class Expression(AST): pass diff --git a/ChironCore/ChironAST/builder.py b/ChironCore/ChironAST/builder.py index b38265e..96fd755 100644 --- a/ChironCore/ChironAST/builder.py +++ b/ChironCore/ChironAST/builder.py @@ -172,3 +172,14 @@ def visitMoveCommand(self, ctx:tlangParser.MoveCommandContext): def visitPenCommand(self, ctx:tlangParser.PenCommandContext): return [(ChironAST.PenCommand(ctx.getText()), 1)] + + def visitPrintCommand(self, ctx:tlangParser.PrintCommandContext): + expr = self.visit(ctx.expression()) + return [(ChironAST.PrintCommand(expr), 1)] + + def visitIncrementCommand(self, ctx:tlangParser.IncrementCommandContext): + var = ctx.VAR().getText() + return [(ChironAST.IncrementCommand(var), 1)] + + def visitDumpCommand(self, ctx:tlangParser.DumpCommandContext): + return [(ChironAST.DumpCommand(), 1)] diff --git a/ChironCore/acyclic_cfg.dot.png b/ChironCore/acyclic_cfg.dot.png new file mode 100644 index 0000000..f512079 Binary files /dev/null and b/ChironCore/acyclic_cfg.dot.png differ diff --git a/ChironCore/chiron.py b/ChironCore/chiron.py index 2eca801..4a9260b 100755 --- a/ChironCore/chiron.py +++ b/ChironCore/chiron.py @@ -196,6 +196,21 @@ def stopTurtle(): type=bool, ) + cmdparser.add_argument( + "-bl", + "--ballLarus", + action="store_true", + help="Run Ball-Larus path profiling on a Chiron program", + ) + + cmdparser.add_argument( + "-bl_op", + "--ballLarus_op", + metavar="INPUTS_FILE", + type=str, + help="File containing multiple input parameter sets (one JSON dict per line) for Ball-Larus path profiling", + ) + args = cmdparser.parse_args() ir = "" @@ -392,3 +407,18 @@ def stopTurtle(): writer = csv.writer(file) writer.writerows(spectrum) print("DONE..") + + if args.ballLarus: + cfg = cfgB.buildCFG(ir, "control_flow_graph") + irHandler.setCFG(cfg) + cfgB.dumpCFG(cfg, "control_flow_graph") + import BallLarus.ballLarus as bl + bl.run_ball_larus_profiling(irHandler, args) + + if args.ballLarus_op: + cfg = cfgB.buildCFG(ir, "control_flow_graph") + irHandler.setCFG(cfg) + cfgB.dumpCFG(cfg, "control_flow_graph") + import BallLarus.ballLarus as bl + print(args) + bl.run_ball_larus_profiling(irHandler, args) diff --git a/ChironCore/control_flow_graph.png b/ChironCore/control_flow_graph.png new file mode 100644 index 0000000..0e4feaf Binary files /dev/null and b/ChironCore/control_flow_graph.png differ diff --git a/ChironCore/hash_dump.txt b/ChironCore/hash_dump.txt new file mode 100644 index 0000000..8795bee --- /dev/null +++ b/ChironCore/hash_dump.txt @@ -0,0 +1,4 @@ +1: 5 +3: 1 +2: 1 +0: 3 diff --git a/ChironCore/interpreter.py b/ChironCore/interpreter.py index bb30bcb..006e55d 100644 --- a/ChironCore/interpreter.py +++ b/ChironCore/interpreter.py @@ -163,4 +163,4 @@ def handleGotoCommand(self, stmt, tgt): xcor = addContext(stmt.xcor) ycor = addContext(stmt.ycor) exec("self.trtl.goto(%s, %s)" % (xcor, ycor)) - return 1 + return 1 \ No newline at end of file diff --git a/ChironCore/path_profile_data.txt b/ChironCore/path_profile_data.txt new file mode 100644 index 0000000..ed9951e --- /dev/null +++ b/ChironCore/path_profile_data.txt @@ -0,0 +1,4 @@ +['START', '2', '7', '11', '13', 'END']: 5 +['START', '5', '7', '11', '13', 'END']: 1 +['START', '5', '7', '8', '13', 'END']: 1 +['START', '2', '7', '8', '13', 'END']: 3 diff --git a/ChironCore/path_profiling_op_tests/cfg6.png b/ChironCore/path_profiling_op_tests/cfg6.png new file mode 100644 index 0000000..0e4feaf Binary files /dev/null and b/ChironCore/path_profiling_op_tests/cfg6.png differ diff --git a/ChironCore/path_profiling_op_tests/testcase1.tl b/ChironCore/path_profiling_op_tests/testcase1.tl new file mode 100644 index 0000000..7d15f80 --- /dev/null +++ b/ChironCore/path_profiling_op_tests/testcase1.tl @@ -0,0 +1,38 @@ +pendown + +repeat 3 [ + + if (:x > :y) [ + penup + goto (:x, :y) + pendown + repeat 4 [ + forward :x + left 90 + ] + ] else [ + penup + goto (:y, :x) + pendown + repeat 5 [ + forward :p + left 72 + ] + ] + + if (:z >= :p) [ + penup + goto (:p, :x + :z) + pendown + repeat 6 [ + backward :x + left 60 + ] + ] + + :x = :x + 10 + :y = :y + 10 + :z = :z + 10 +] + +penup \ No newline at end of file diff --git a/ChironCore/path_profiling_op_tests/testcase2.tl b/ChironCore/path_profiling_op_tests/testcase2.tl new file mode 100644 index 0000000..1ba1981 --- /dev/null +++ b/ChironCore/path_profiling_op_tests/testcase2.tl @@ -0,0 +1,19 @@ +pendown + +repeat 2 [ + if (:x > :y) [ + repeat 3 [ + forward :p + right 120 + ] + ] else [ + repeat 4 [ + forward :z + left 90 + ] + ] + :x = :x - 5 + :z = :z + 5 +] + +penup \ No newline at end of file diff --git a/ChironCore/path_profiling_op_tests/testcase3.tl b/ChironCore/path_profiling_op_tests/testcase3.tl new file mode 100644 index 0000000..c448454 --- /dev/null +++ b/ChironCore/path_profiling_op_tests/testcase3.tl @@ -0,0 +1,21 @@ +pendown + +if (:x < :z) [ + penup + goto (:x, :z) + pendown + repeat 4 [ + forward :y + right 90 + ] +] else [ + penup + goto (:z, :x) + pendown + repeat 5 [ + forward :p + left 72 + ] +] + +penup \ No newline at end of file diff --git a/ChironCore/path_profiling_op_tests/testcase4.tl b/ChironCore/path_profiling_op_tests/testcase4.tl new file mode 100644 index 0000000..6d83efa --- /dev/null +++ b/ChironCore/path_profiling_op_tests/testcase4.tl @@ -0,0 +1,16 @@ +pendown + +repeat 3 [ + repeat 3 [ + if (:y <= :p) [ + forward :x + ] else [ + backward :z + ] + right 120 + ] + left 60 + :y = :y + 15 +] + +penup \ No newline at end of file diff --git a/ChironCore/path_profiling_op_tests/testcase5.tl b/ChironCore/path_profiling_op_tests/testcase5.tl new file mode 100644 index 0000000..c1b4fe3 --- /dev/null +++ b/ChironCore/path_profiling_op_tests/testcase5.tl @@ -0,0 +1,27 @@ +pendown + +repeat 2 [ + if (:x < :z) [ + forward :x + left 30 + ] else [ + forward :p + right 60 + ] + if (:y >= :p) [ + backward :z + right 45 + ] else [ + forward :y + left 45 + ] + :x = :x + 10 + :z = :z - 5 +] + +repeat 3 [ + forward (:x + :y) + left 120 +] + +penup \ No newline at end of file diff --git a/ChironCore/path_profiling_op_tests/testcase6.tl b/ChironCore/path_profiling_op_tests/testcase6.tl new file mode 100644 index 0000000..1473991 --- /dev/null +++ b/ChironCore/path_profiling_op_tests/testcase6.tl @@ -0,0 +1,18 @@ +pendown +if(:x > :y)[ + forward 50 + left 60 +] +else[ + backward 50 + right 60 +] +if(:z < :p)[ + backward 100 + left 90 +] +else[ + forward 100 + right 90 +] +penup \ No newline at end of file diff --git a/ChironCore/path_profiling_tests/cfg0.png b/ChironCore/path_profiling_tests/cfg0.png new file mode 100644 index 0000000..fc9593d Binary files /dev/null and b/ChironCore/path_profiling_tests/cfg0.png differ diff --git a/ChironCore/path_profiling_tests/testcase0.tl b/ChironCore/path_profiling_tests/testcase0.tl new file mode 100644 index 0000000..0ab1655 --- /dev/null +++ b/ChironCore/path_profiling_tests/testcase0.tl @@ -0,0 +1,13 @@ +pendown +:var1 = 15 +:var2 = 30 +if (:var1 < :var2) [ + if (:var1 > 10) [ + forward 50 + ] else [ + left 90 + ] +] else [ + right 45 +] +penup \ No newline at end of file diff --git a/ChironCore/path_profiling_tests/testcase1.tl b/ChironCore/path_profiling_tests/testcase1.tl new file mode 100644 index 0000000..e2e780c --- /dev/null +++ b/ChironCore/path_profiling_tests/testcase1.tl @@ -0,0 +1,6 @@ +pendown +repeat 3 [ + forward 50 + right 120 +] +penup diff --git a/ChironCore/path_profiling_tests/testcase2.tl b/ChironCore/path_profiling_tests/testcase2.tl new file mode 100644 index 0000000..d7e11de --- /dev/null +++ b/ChironCore/path_profiling_tests/testcase2.tl @@ -0,0 +1,9 @@ +pendown +repeat 3 [ + repeat 4 [ + forward 50 + right 90 + ] + right 120 +] +penup \ No newline at end of file diff --git a/ChironCore/path_profiling_tests/testcase3.tl b/ChironCore/path_profiling_tests/testcase3.tl new file mode 100644 index 0000000..5eba574 --- /dev/null +++ b/ChironCore/path_profiling_tests/testcase3.tl @@ -0,0 +1,12 @@ +pendown +:angle = 45 +repeat 5 [ + forward 100 + if (:angle > 30) [ + right 90 + ] else [ + left 90 + ] + :angle = :angle + 15 +] +penup \ No newline at end of file diff --git a/ChironCore/path_profiling_tests/testcase4.tl b/ChironCore/path_profiling_tests/testcase4.tl new file mode 100644 index 0000000..22d4db4 --- /dev/null +++ b/ChironCore/path_profiling_tests/testcase4.tl @@ -0,0 +1,18 @@ +pendown +:counter = 0 +repeat 3 [ + if (:counter < 2) [ + repeat 4 [ + forward 50 + right 90 + ] + ] else [ + repeat 3 [ + forward 70 + right 120 + ] + ] + :counter = :counter + 1 + right 30 +] +penup \ No newline at end of file diff --git a/ChironCore/path_profiling_tests/testcase5.tl b/ChironCore/path_profiling_tests/testcase5.tl new file mode 100644 index 0000000..7d2984e --- /dev/null +++ b/ChironCore/path_profiling_tests/testcase5.tl @@ -0,0 +1,40 @@ +penup +goto (50, 50) +pendown +:two = 200 +:one = 100 +forward 50 +right 90 +forward 50 +right 90 +forward 50 +right 90 +forward 50 +penup + +:vara = 20 +:varb = 100 +:varc = 60 +repeat 1 [ + goto (0, 0) + pendown + repeat 6 [ + if (:vara != :varb) [ + if ( :vara > :varb) [ right :vara ] + else [ left :varb ] + ] + else [ + if ((:vara <= :varc) || (:varb <= :varc)) [ + :vara = :varc / :vara + :varb = :varb / :varc + :varc = :varb + ] + ] + forward :vara + right :varb + forward :varc + left :varc + ] + left 45 +] +penup \ No newline at end of file diff --git a/ChironCore/path_profiling_tests/testcase6.tl b/ChironCore/path_profiling_tests/testcase6.tl new file mode 100644 index 0000000..14f731f --- /dev/null +++ b/ChironCore/path_profiling_tests/testcase6.tl @@ -0,0 +1,5 @@ +pendown +repeat 1 [ + pendown +] +penup diff --git a/ChironCore/path_profiling_tests/testcase7.tl b/ChironCore/path_profiling_tests/testcase7.tl new file mode 100644 index 0000000..5383a90 --- /dev/null +++ b/ChironCore/path_profiling_tests/testcase7.tl @@ -0,0 +1,11 @@ +pendown +:var1 = 15 +:var2 = 30 +if (:var1 > :var2) [ + left 90 + forward 50 +] else [ + right 45 + forward 50 +] +penup \ No newline at end of file diff --git a/ChironCore/predictions_pc.txt b/ChironCore/predictions_pc.txt new file mode 100644 index 0000000..bed118c --- /dev/null +++ b/ChironCore/predictions_pc.txt @@ -0,0 +1,18 @@ +PC: 2, Prediction: Taken, Actual: Taken, Correct: True +PC: 6, Prediction: Not Taken, Actual: Not Taken, Correct: True +PC: 24, Prediction: Not Taken, Actual: Not Taken, Correct: True +PC: 10, Prediction: Not Taken, Actual: Taken, Correct: False +PC: 14, Prediction: Not Taken, Actual: Not Taken, Correct: True +PC: 28, Prediction: Not Taken, Actual: Not Taken, Correct: True +PC: 20, Prediction: Not Taken, Actual: Not Taken, Correct: True +------------------------- + +PC: 2, Prediction: Taken, Actual: Taken, Correct: True +PC: 6, Prediction: Not Taken, Actual: Not Taken, Correct: True +PC: 24, Prediction: Not Taken, Actual: Not Taken, Correct: True +PC: 10, Prediction: Not Taken, Actual: Taken, Correct: False +PC: 14, Prediction: Not Taken, Actual: Not Taken, Correct: True +PC: 28, Prediction: Not Taken, Actual: Not Taken, Correct: True +PC: 20, Prediction: Not Taken, Actual: Not Taken, Correct: True +------------------------- + diff --git a/ChironCore/predictor_accuracy.txt b/ChironCore/predictor_accuracy.txt new file mode 100644 index 0000000..ac4d3e1 --- /dev/null +++ b/ChironCore/predictor_accuracy.txt @@ -0,0 +1,8 @@ +Total Count: 7 +Correct Count: 6 +Accuracy: 0.8571428571428571 +----------------------- +Total Count: 7 +Correct Count: 6 +Accuracy: 0.8571428571428571 +----------------------- diff --git a/ChironCore/turtparse/tlang.g4 b/ChironCore/turtparse/tlang.g4 index ff3a2f6..1cf6dc7 100644 --- a/ChironCore/turtparse/tlang.g4 +++ b/ChironCore/turtparse/tlang.g4 @@ -17,6 +17,9 @@ instruction : assignment | penCommand | gotoCommand | pauseCommand + | printCommand + | incrementCommand + | dumpCommand ; conditional : ifConditional | ifElseConditional ; @@ -39,6 +42,12 @@ penCommand : 'penup' | 'pendown' ; pauseCommand : 'pause' ; +printCommand : 'print' '(' expression ')' ; + +incrementCommand : 'inc' '(' VAR ')' ; + +dumpCommand : 'dumpMap' ; + expression : unaryArithOp expression #unaryExpr | expression multiplicative expression #mulExpr diff --git a/ChironCore/turtparse/tlang.interp b/ChironCore/turtparse/tlang.interp index f3cba53..f5cae5c 100644 --- a/ChironCore/turtparse/tlang.interp +++ b/ChironCore/turtparse/tlang.interp @@ -17,6 +17,9 @@ null 'penup' 'pendown' 'pause' +'print' +'inc' +'dumpMap' '+' '-' '*' @@ -55,6 +58,9 @@ null null null null +null +null +null PLUS MINUS MUL @@ -89,6 +95,9 @@ moveCommand moveOp penCommand pauseCommand +printCommand +incrementCommand +dumpCommand expression multiplicative additive @@ -100,4 +109,4 @@ value atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 37, 175, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 3, 2, 3, 2, 3, 2, 3, 3, 7, 3, 51, 10, 3, 12, 3, 14, 3, 54, 11, 3, 3, 4, 6, 4, 57, 10, 4, 13, 4, 14, 4, 58, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 68, 10, 5, 3, 6, 3, 6, 5, 6, 72, 10, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 5, 16, 125, 10, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 7, 16, 135, 10, 16, 12, 16, 14, 16, 138, 11, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 5, 20, 158, 10, 20, 3, 20, 3, 20, 3, 20, 3, 20, 7, 20, 164, 10, 20, 12, 20, 14, 20, 167, 11, 20, 3, 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 2, 4, 30, 38, 24, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 2, 9, 3, 2, 13, 16, 3, 2, 17, 18, 3, 2, 22, 23, 3, 2, 20, 21, 3, 2, 25, 30, 3, 2, 31, 32, 3, 2, 34, 35, 2, 169, 2, 46, 3, 2, 2, 2, 4, 52, 3, 2, 2, 2, 6, 56, 3, 2, 2, 2, 8, 67, 3, 2, 2, 2, 10, 71, 3, 2, 2, 2, 12, 73, 3, 2, 2, 2, 14, 79, 3, 2, 2, 2, 16, 89, 3, 2, 2, 2, 18, 95, 3, 2, 2, 2, 20, 102, 3, 2, 2, 2, 22, 106, 3, 2, 2, 2, 24, 109, 3, 2, 2, 2, 26, 111, 3, 2, 2, 2, 28, 113, 3, 2, 2, 2, 30, 124, 3, 2, 2, 2, 32, 139, 3, 2, 2, 2, 34, 141, 3, 2, 2, 2, 36, 143, 3, 2, 2, 2, 38, 157, 3, 2, 2, 2, 40, 168, 3, 2, 2, 2, 42, 170, 3, 2, 2, 2, 44, 172, 3, 2, 2, 2, 46, 47, 5, 4, 3, 2, 47, 48, 7, 2, 2, 3, 48, 3, 3, 2, 2, 2, 49, 51, 5, 8, 5, 2, 50, 49, 3, 2, 2, 2, 51, 54, 3, 2, 2, 2, 52, 50, 3, 2, 2, 2, 52, 53, 3, 2, 2, 2, 53, 5, 3, 2, 2, 2, 54, 52, 3, 2, 2, 2, 55, 57, 5, 8, 5, 2, 56, 55, 3, 2, 2, 2, 57, 58, 3, 2, 2, 2, 58, 56, 3, 2, 2, 2, 58, 59, 3, 2, 2, 2, 59, 7, 3, 2, 2, 2, 60, 68, 5, 20, 11, 2, 61, 68, 5, 10, 6, 2, 62, 68, 5, 16, 9, 2, 63, 68, 5, 22, 12, 2, 64, 68, 5, 26, 14, 2, 65, 68, 5, 18, 10, 2, 66, 68, 5, 28, 15, 2, 67, 60, 3, 2, 2, 2, 67, 61, 3, 2, 2, 2, 67, 62, 3, 2, 2, 2, 67, 63, 3, 2, 2, 2, 67, 64, 3, 2, 2, 2, 67, 65, 3, 2, 2, 2, 67, 66, 3, 2, 2, 2, 68, 9, 3, 2, 2, 2, 69, 72, 5, 12, 7, 2, 70, 72, 5, 14, 8, 2, 71, 69, 3, 2, 2, 2, 71, 70, 3, 2, 2, 2, 72, 11, 3, 2, 2, 2, 73, 74, 7, 3, 2, 2, 74, 75, 5, 38, 20, 2, 75, 76, 7, 4, 2, 2, 76, 77, 5, 6, 4, 2, 77, 78, 7, 5, 2, 2, 78, 13, 3, 2, 2, 2, 79, 80, 7, 3, 2, 2, 80, 81, 5, 38, 20, 2, 81, 82, 7, 4, 2, 2, 82, 83, 5, 6, 4, 2, 83, 84, 7, 5, 2, 2, 84, 85, 7, 6, 2, 2, 85, 86, 7, 4, 2, 2, 86, 87, 5, 6, 4, 2, 87, 88, 7, 5, 2, 2, 88, 15, 3, 2, 2, 2, 89, 90, 7, 7, 2, 2, 90, 91, 5, 44, 23, 2, 91, 92, 7, 4, 2, 2, 92, 93, 5, 6, 4, 2, 93, 94, 7, 5, 2, 2, 94, 17, 3, 2, 2, 2, 95, 96, 7, 8, 2, 2, 96, 97, 7, 9, 2, 2, 97, 98, 5, 30, 16, 2, 98, 99, 7, 10, 2, 2, 99, 100, 5, 30, 16, 2, 100, 101, 7, 11, 2, 2, 101, 19, 3, 2, 2, 2, 102, 103, 7, 35, 2, 2, 103, 104, 7, 12, 2, 2, 104, 105, 5, 30, 16, 2, 105, 21, 3, 2, 2, 2, 106, 107, 5, 24, 13, 2, 107, 108, 5, 30, 16, 2, 108, 23, 3, 2, 2, 2, 109, 110, 9, 2, 2, 2, 110, 25, 3, 2, 2, 2, 111, 112, 9, 3, 2, 2, 112, 27, 3, 2, 2, 2, 113, 114, 7, 19, 2, 2, 114, 29, 3, 2, 2, 2, 115, 116, 8, 16, 1, 2, 116, 117, 5, 36, 19, 2, 117, 118, 5, 30, 16, 7, 118, 125, 3, 2, 2, 2, 119, 125, 5, 44, 23, 2, 120, 121, 7, 9, 2, 2, 121, 122, 5, 30, 16, 2, 122, 123, 7, 11, 2, 2, 123, 125, 3, 2, 2, 2, 124, 115, 3, 2, 2, 2, 124, 119, 3, 2, 2, 2, 124, 120, 3, 2, 2, 2, 125, 136, 3, 2, 2, 2, 126, 127, 12, 6, 2, 2, 127, 128, 5, 32, 17, 2, 128, 129, 5, 30, 16, 7, 129, 135, 3, 2, 2, 2, 130, 131, 12, 5, 2, 2, 131, 132, 5, 34, 18, 2, 132, 133, 5, 30, 16, 6, 133, 135, 3, 2, 2, 2, 134, 126, 3, 2, 2, 2, 134, 130, 3, 2, 2, 2, 135, 138, 3, 2, 2, 2, 136, 134, 3, 2, 2, 2, 136, 137, 3, 2, 2, 2, 137, 31, 3, 2, 2, 2, 138, 136, 3, 2, 2, 2, 139, 140, 9, 4, 2, 2, 140, 33, 3, 2, 2, 2, 141, 142, 9, 5, 2, 2, 142, 35, 3, 2, 2, 2, 143, 144, 7, 21, 2, 2, 144, 37, 3, 2, 2, 2, 145, 146, 8, 20, 1, 2, 146, 147, 7, 33, 2, 2, 147, 158, 5, 38, 20, 7, 148, 149, 5, 30, 16, 2, 149, 150, 5, 40, 21, 2, 150, 151, 5, 30, 16, 2, 151, 158, 3, 2, 2, 2, 152, 158, 7, 24, 2, 2, 153, 154, 7, 9, 2, 2, 154, 155, 5, 38, 20, 2, 155, 156, 7, 11, 2, 2, 156, 158, 3, 2, 2, 2, 157, 145, 3, 2, 2, 2, 157, 148, 3, 2, 2, 2, 157, 152, 3, 2, 2, 2, 157, 153, 3, 2, 2, 2, 158, 165, 3, 2, 2, 2, 159, 160, 12, 5, 2, 2, 160, 161, 5, 42, 22, 2, 161, 162, 5, 38, 20, 6, 162, 164, 3, 2, 2, 2, 163, 159, 3, 2, 2, 2, 164, 167, 3, 2, 2, 2, 165, 163, 3, 2, 2, 2, 165, 166, 3, 2, 2, 2, 166, 39, 3, 2, 2, 2, 167, 165, 3, 2, 2, 2, 168, 169, 9, 6, 2, 2, 169, 41, 3, 2, 2, 2, 170, 171, 9, 7, 2, 2, 171, 43, 3, 2, 2, 2, 172, 173, 9, 8, 2, 2, 173, 45, 3, 2, 2, 2, 11, 52, 58, 67, 71, 124, 134, 136, 157, 165] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 40, 196, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 3, 2, 3, 2, 3, 2, 3, 3, 7, 3, 57, 10, 3, 12, 3, 14, 3, 60, 11, 3, 3, 4, 6, 4, 63, 10, 4, 13, 4, 14, 4, 64, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 77, 10, 5, 3, 6, 3, 6, 5, 6, 81, 10, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 5, 19, 146, 10, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 7, 19, 156, 10, 19, 12, 19, 14, 19, 159, 11, 19, 3, 20, 3, 20, 3, 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 5, 23, 179, 10, 23, 3, 23, 3, 23, 3, 23, 3, 23, 7, 23, 185, 10, 23, 12, 23, 14, 23, 188, 11, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 2, 4, 36, 44, 27, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 2, 9, 3, 2, 13, 16, 3, 2, 17, 18, 3, 2, 25, 26, 3, 2, 23, 24, 3, 2, 28, 33, 3, 2, 34, 35, 3, 2, 37, 38, 2, 190, 2, 52, 3, 2, 2, 2, 4, 58, 3, 2, 2, 2, 6, 62, 3, 2, 2, 2, 8, 76, 3, 2, 2, 2, 10, 80, 3, 2, 2, 2, 12, 82, 3, 2, 2, 2, 14, 88, 3, 2, 2, 2, 16, 98, 3, 2, 2, 2, 18, 104, 3, 2, 2, 2, 20, 111, 3, 2, 2, 2, 22, 115, 3, 2, 2, 2, 24, 118, 3, 2, 2, 2, 26, 120, 3, 2, 2, 2, 28, 122, 3, 2, 2, 2, 30, 124, 3, 2, 2, 2, 32, 129, 3, 2, 2, 2, 34, 134, 3, 2, 2, 2, 36, 145, 3, 2, 2, 2, 38, 160, 3, 2, 2, 2, 40, 162, 3, 2, 2, 2, 42, 164, 3, 2, 2, 2, 44, 178, 3, 2, 2, 2, 46, 189, 3, 2, 2, 2, 48, 191, 3, 2, 2, 2, 50, 193, 3, 2, 2, 2, 52, 53, 5, 4, 3, 2, 53, 54, 7, 2, 2, 3, 54, 3, 3, 2, 2, 2, 55, 57, 5, 8, 5, 2, 56, 55, 3, 2, 2, 2, 57, 60, 3, 2, 2, 2, 58, 56, 3, 2, 2, 2, 58, 59, 3, 2, 2, 2, 59, 5, 3, 2, 2, 2, 60, 58, 3, 2, 2, 2, 61, 63, 5, 8, 5, 2, 62, 61, 3, 2, 2, 2, 63, 64, 3, 2, 2, 2, 64, 62, 3, 2, 2, 2, 64, 65, 3, 2, 2, 2, 65, 7, 3, 2, 2, 2, 66, 77, 5, 20, 11, 2, 67, 77, 5, 10, 6, 2, 68, 77, 5, 16, 9, 2, 69, 77, 5, 22, 12, 2, 70, 77, 5, 26, 14, 2, 71, 77, 5, 18, 10, 2, 72, 77, 5, 28, 15, 2, 73, 77, 5, 30, 16, 2, 74, 77, 5, 32, 17, 2, 75, 77, 5, 34, 18, 2, 76, 66, 3, 2, 2, 2, 76, 67, 3, 2, 2, 2, 76, 68, 3, 2, 2, 2, 76, 69, 3, 2, 2, 2, 76, 70, 3, 2, 2, 2, 76, 71, 3, 2, 2, 2, 76, 72, 3, 2, 2, 2, 76, 73, 3, 2, 2, 2, 76, 74, 3, 2, 2, 2, 76, 75, 3, 2, 2, 2, 77, 9, 3, 2, 2, 2, 78, 81, 5, 12, 7, 2, 79, 81, 5, 14, 8, 2, 80, 78, 3, 2, 2, 2, 80, 79, 3, 2, 2, 2, 81, 11, 3, 2, 2, 2, 82, 83, 7, 3, 2, 2, 83, 84, 5, 44, 23, 2, 84, 85, 7, 4, 2, 2, 85, 86, 5, 6, 4, 2, 86, 87, 7, 5, 2, 2, 87, 13, 3, 2, 2, 2, 88, 89, 7, 3, 2, 2, 89, 90, 5, 44, 23, 2, 90, 91, 7, 4, 2, 2, 91, 92, 5, 6, 4, 2, 92, 93, 7, 5, 2, 2, 93, 94, 7, 6, 2, 2, 94, 95, 7, 4, 2, 2, 95, 96, 5, 6, 4, 2, 96, 97, 7, 5, 2, 2, 97, 15, 3, 2, 2, 2, 98, 99, 7, 7, 2, 2, 99, 100, 5, 50, 26, 2, 100, 101, 7, 4, 2, 2, 101, 102, 5, 6, 4, 2, 102, 103, 7, 5, 2, 2, 103, 17, 3, 2, 2, 2, 104, 105, 7, 8, 2, 2, 105, 106, 7, 9, 2, 2, 106, 107, 5, 36, 19, 2, 107, 108, 7, 10, 2, 2, 108, 109, 5, 36, 19, 2, 109, 110, 7, 11, 2, 2, 110, 19, 3, 2, 2, 2, 111, 112, 7, 38, 2, 2, 112, 113, 7, 12, 2, 2, 113, 114, 5, 36, 19, 2, 114, 21, 3, 2, 2, 2, 115, 116, 5, 24, 13, 2, 116, 117, 5, 36, 19, 2, 117, 23, 3, 2, 2, 2, 118, 119, 9, 2, 2, 2, 119, 25, 3, 2, 2, 2, 120, 121, 9, 3, 2, 2, 121, 27, 3, 2, 2, 2, 122, 123, 7, 19, 2, 2, 123, 29, 3, 2, 2, 2, 124, 125, 7, 20, 2, 2, 125, 126, 7, 9, 2, 2, 126, 127, 5, 36, 19, 2, 127, 128, 7, 11, 2, 2, 128, 31, 3, 2, 2, 2, 129, 130, 7, 21, 2, 2, 130, 131, 7, 9, 2, 2, 131, 132, 7, 38, 2, 2, 132, 133, 7, 11, 2, 2, 133, 33, 3, 2, 2, 2, 134, 135, 7, 22, 2, 2, 135, 35, 3, 2, 2, 2, 136, 137, 8, 19, 1, 2, 137, 138, 5, 42, 22, 2, 138, 139, 5, 36, 19, 7, 139, 146, 3, 2, 2, 2, 140, 146, 5, 50, 26, 2, 141, 142, 7, 9, 2, 2, 142, 143, 5, 36, 19, 2, 143, 144, 7, 11, 2, 2, 144, 146, 3, 2, 2, 2, 145, 136, 3, 2, 2, 2, 145, 140, 3, 2, 2, 2, 145, 141, 3, 2, 2, 2, 146, 157, 3, 2, 2, 2, 147, 148, 12, 6, 2, 2, 148, 149, 5, 38, 20, 2, 149, 150, 5, 36, 19, 7, 150, 156, 3, 2, 2, 2, 151, 152, 12, 5, 2, 2, 152, 153, 5, 40, 21, 2, 153, 154, 5, 36, 19, 6, 154, 156, 3, 2, 2, 2, 155, 147, 3, 2, 2, 2, 155, 151, 3, 2, 2, 2, 156, 159, 3, 2, 2, 2, 157, 155, 3, 2, 2, 2, 157, 158, 3, 2, 2, 2, 158, 37, 3, 2, 2, 2, 159, 157, 3, 2, 2, 2, 160, 161, 9, 4, 2, 2, 161, 39, 3, 2, 2, 2, 162, 163, 9, 5, 2, 2, 163, 41, 3, 2, 2, 2, 164, 165, 7, 24, 2, 2, 165, 43, 3, 2, 2, 2, 166, 167, 8, 23, 1, 2, 167, 168, 7, 36, 2, 2, 168, 179, 5, 44, 23, 7, 169, 170, 5, 36, 19, 2, 170, 171, 5, 46, 24, 2, 171, 172, 5, 36, 19, 2, 172, 179, 3, 2, 2, 2, 173, 179, 7, 27, 2, 2, 174, 175, 7, 9, 2, 2, 175, 176, 5, 44, 23, 2, 176, 177, 7, 11, 2, 2, 177, 179, 3, 2, 2, 2, 178, 166, 3, 2, 2, 2, 178, 169, 3, 2, 2, 2, 178, 173, 3, 2, 2, 2, 178, 174, 3, 2, 2, 2, 179, 186, 3, 2, 2, 2, 180, 181, 12, 5, 2, 2, 181, 182, 5, 48, 25, 2, 182, 183, 5, 44, 23, 6, 183, 185, 3, 2, 2, 2, 184, 180, 3, 2, 2, 2, 185, 188, 3, 2, 2, 2, 186, 184, 3, 2, 2, 2, 186, 187, 3, 2, 2, 2, 187, 45, 3, 2, 2, 2, 188, 186, 3, 2, 2, 2, 189, 190, 9, 6, 2, 2, 190, 47, 3, 2, 2, 2, 191, 192, 9, 7, 2, 2, 192, 49, 3, 2, 2, 2, 193, 194, 9, 8, 2, 2, 194, 51, 3, 2, 2, 2, 11, 58, 64, 76, 80, 145, 155, 157, 178, 186] \ No newline at end of file diff --git a/ChironCore/turtparse/tlang.tokens b/ChironCore/turtparse/tlang.tokens index 78f9526..086b392 100644 --- a/ChironCore/turtparse/tlang.tokens +++ b/ChironCore/turtparse/tlang.tokens @@ -15,24 +15,27 @@ T__13=14 T__14=15 T__15=16 T__16=17 -PLUS=18 -MINUS=19 -MUL=20 -DIV=21 -PENCOND=22 -LT=23 -GT=24 -EQ=25 -NEQ=26 -LTE=27 -GTE=28 -AND=29 -OR=30 -NOT=31 -NUM=32 -VAR=33 -NAME=34 -Whitespace=35 +T__17=18 +T__18=19 +T__19=20 +PLUS=21 +MINUS=22 +MUL=23 +DIV=24 +PENCOND=25 +LT=26 +GT=27 +EQ=28 +NEQ=29 +LTE=30 +GTE=31 +AND=32 +OR=33 +NOT=34 +NUM=35 +VAR=36 +NAME=37 +Whitespace=38 'if'=1 '['=2 ']'=3 @@ -50,17 +53,20 @@ Whitespace=35 'penup'=15 'pendown'=16 'pause'=17 -'+'=18 -'-'=19 -'*'=20 -'/'=21 -'pendown?'=22 -'<'=23 -'>'=24 -'=='=25 -'!='=26 -'<='=27 -'>='=28 -'&&'=29 -'||'=30 -'!'=31 +'print'=18 +'inc'=19 +'dumpMap'=20 +'+'=21 +'-'=22 +'*'=23 +'/'=24 +'pendown?'=25 +'<'=26 +'>'=27 +'=='=28 +'!='=29 +'<='=30 +'>='=31 +'&&'=32 +'||'=33 +'!'=34 diff --git a/ChironCore/turtparse/tlangLexer.interp b/ChironCore/turtparse/tlangLexer.interp index 106eae4..de36ae9 100644 --- a/ChironCore/turtparse/tlangLexer.interp +++ b/ChironCore/turtparse/tlangLexer.interp @@ -17,6 +17,9 @@ null 'penup' 'pendown' 'pause' +'print' +'inc' +'dumpMap' '+' '-' '*' @@ -55,6 +58,9 @@ null null null null +null +null +null PLUS MINUS MUL @@ -92,6 +98,9 @@ T__13 T__14 T__15 T__16 +T__17 +T__18 +T__19 PLUS MINUS MUL @@ -119,4 +128,4 @@ mode names: DEFAULT_MODE atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 37, 219, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 6, 33, 196, 10, 33, 13, 33, 14, 33, 197, 3, 34, 3, 34, 3, 34, 7, 34, 203, 10, 34, 12, 34, 14, 34, 206, 11, 34, 3, 35, 6, 35, 209, 10, 35, 13, 35, 14, 35, 210, 3, 36, 6, 36, 214, 10, 36, 13, 36, 14, 36, 215, 3, 36, 3, 36, 2, 2, 37, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 3, 2, 7, 3, 2, 50, 59, 5, 2, 67, 92, 97, 97, 99, 124, 5, 2, 50, 59, 67, 92, 99, 124, 4, 2, 67, 92, 99, 124, 5, 2, 11, 12, 15, 15, 34, 34, 2, 222, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 3, 73, 3, 2, 2, 2, 5, 76, 3, 2, 2, 2, 7, 78, 3, 2, 2, 2, 9, 80, 3, 2, 2, 2, 11, 85, 3, 2, 2, 2, 13, 92, 3, 2, 2, 2, 15, 97, 3, 2, 2, 2, 17, 99, 3, 2, 2, 2, 19, 101, 3, 2, 2, 2, 21, 103, 3, 2, 2, 2, 23, 105, 3, 2, 2, 2, 25, 113, 3, 2, 2, 2, 27, 122, 3, 2, 2, 2, 29, 127, 3, 2, 2, 2, 31, 133, 3, 2, 2, 2, 33, 139, 3, 2, 2, 2, 35, 147, 3, 2, 2, 2, 37, 153, 3, 2, 2, 2, 39, 155, 3, 2, 2, 2, 41, 157, 3, 2, 2, 2, 43, 159, 3, 2, 2, 2, 45, 161, 3, 2, 2, 2, 47, 170, 3, 2, 2, 2, 49, 172, 3, 2, 2, 2, 51, 174, 3, 2, 2, 2, 53, 177, 3, 2, 2, 2, 55, 180, 3, 2, 2, 2, 57, 183, 3, 2, 2, 2, 59, 186, 3, 2, 2, 2, 61, 189, 3, 2, 2, 2, 63, 192, 3, 2, 2, 2, 65, 195, 3, 2, 2, 2, 67, 199, 3, 2, 2, 2, 69, 208, 3, 2, 2, 2, 71, 213, 3, 2, 2, 2, 73, 74, 7, 107, 2, 2, 74, 75, 7, 104, 2, 2, 75, 4, 3, 2, 2, 2, 76, 77, 7, 93, 2, 2, 77, 6, 3, 2, 2, 2, 78, 79, 7, 95, 2, 2, 79, 8, 3, 2, 2, 2, 80, 81, 7, 103, 2, 2, 81, 82, 7, 110, 2, 2, 82, 83, 7, 117, 2, 2, 83, 84, 7, 103, 2, 2, 84, 10, 3, 2, 2, 2, 85, 86, 7, 116, 2, 2, 86, 87, 7, 103, 2, 2, 87, 88, 7, 114, 2, 2, 88, 89, 7, 103, 2, 2, 89, 90, 7, 99, 2, 2, 90, 91, 7, 118, 2, 2, 91, 12, 3, 2, 2, 2, 92, 93, 7, 105, 2, 2, 93, 94, 7, 113, 2, 2, 94, 95, 7, 118, 2, 2, 95, 96, 7, 113, 2, 2, 96, 14, 3, 2, 2, 2, 97, 98, 7, 42, 2, 2, 98, 16, 3, 2, 2, 2, 99, 100, 7, 46, 2, 2, 100, 18, 3, 2, 2, 2, 101, 102, 7, 43, 2, 2, 102, 20, 3, 2, 2, 2, 103, 104, 7, 63, 2, 2, 104, 22, 3, 2, 2, 2, 105, 106, 7, 104, 2, 2, 106, 107, 7, 113, 2, 2, 107, 108, 7, 116, 2, 2, 108, 109, 7, 121, 2, 2, 109, 110, 7, 99, 2, 2, 110, 111, 7, 116, 2, 2, 111, 112, 7, 102, 2, 2, 112, 24, 3, 2, 2, 2, 113, 114, 7, 100, 2, 2, 114, 115, 7, 99, 2, 2, 115, 116, 7, 101, 2, 2, 116, 117, 7, 109, 2, 2, 117, 118, 7, 121, 2, 2, 118, 119, 7, 99, 2, 2, 119, 120, 7, 116, 2, 2, 120, 121, 7, 102, 2, 2, 121, 26, 3, 2, 2, 2, 122, 123, 7, 110, 2, 2, 123, 124, 7, 103, 2, 2, 124, 125, 7, 104, 2, 2, 125, 126, 7, 118, 2, 2, 126, 28, 3, 2, 2, 2, 127, 128, 7, 116, 2, 2, 128, 129, 7, 107, 2, 2, 129, 130, 7, 105, 2, 2, 130, 131, 7, 106, 2, 2, 131, 132, 7, 118, 2, 2, 132, 30, 3, 2, 2, 2, 133, 134, 7, 114, 2, 2, 134, 135, 7, 103, 2, 2, 135, 136, 7, 112, 2, 2, 136, 137, 7, 119, 2, 2, 137, 138, 7, 114, 2, 2, 138, 32, 3, 2, 2, 2, 139, 140, 7, 114, 2, 2, 140, 141, 7, 103, 2, 2, 141, 142, 7, 112, 2, 2, 142, 143, 7, 102, 2, 2, 143, 144, 7, 113, 2, 2, 144, 145, 7, 121, 2, 2, 145, 146, 7, 112, 2, 2, 146, 34, 3, 2, 2, 2, 147, 148, 7, 114, 2, 2, 148, 149, 7, 99, 2, 2, 149, 150, 7, 119, 2, 2, 150, 151, 7, 117, 2, 2, 151, 152, 7, 103, 2, 2, 152, 36, 3, 2, 2, 2, 153, 154, 7, 45, 2, 2, 154, 38, 3, 2, 2, 2, 155, 156, 7, 47, 2, 2, 156, 40, 3, 2, 2, 2, 157, 158, 7, 44, 2, 2, 158, 42, 3, 2, 2, 2, 159, 160, 7, 49, 2, 2, 160, 44, 3, 2, 2, 2, 161, 162, 7, 114, 2, 2, 162, 163, 7, 103, 2, 2, 163, 164, 7, 112, 2, 2, 164, 165, 7, 102, 2, 2, 165, 166, 7, 113, 2, 2, 166, 167, 7, 121, 2, 2, 167, 168, 7, 112, 2, 2, 168, 169, 7, 65, 2, 2, 169, 46, 3, 2, 2, 2, 170, 171, 7, 62, 2, 2, 171, 48, 3, 2, 2, 2, 172, 173, 7, 64, 2, 2, 173, 50, 3, 2, 2, 2, 174, 175, 7, 63, 2, 2, 175, 176, 7, 63, 2, 2, 176, 52, 3, 2, 2, 2, 177, 178, 7, 35, 2, 2, 178, 179, 7, 63, 2, 2, 179, 54, 3, 2, 2, 2, 180, 181, 7, 62, 2, 2, 181, 182, 7, 63, 2, 2, 182, 56, 3, 2, 2, 2, 183, 184, 7, 64, 2, 2, 184, 185, 7, 63, 2, 2, 185, 58, 3, 2, 2, 2, 186, 187, 7, 40, 2, 2, 187, 188, 7, 40, 2, 2, 188, 60, 3, 2, 2, 2, 189, 190, 7, 126, 2, 2, 190, 191, 7, 126, 2, 2, 191, 62, 3, 2, 2, 2, 192, 193, 7, 35, 2, 2, 193, 64, 3, 2, 2, 2, 194, 196, 9, 2, 2, 2, 195, 194, 3, 2, 2, 2, 196, 197, 3, 2, 2, 2, 197, 195, 3, 2, 2, 2, 197, 198, 3, 2, 2, 2, 198, 66, 3, 2, 2, 2, 199, 200, 7, 60, 2, 2, 200, 204, 9, 3, 2, 2, 201, 203, 9, 4, 2, 2, 202, 201, 3, 2, 2, 2, 203, 206, 3, 2, 2, 2, 204, 202, 3, 2, 2, 2, 204, 205, 3, 2, 2, 2, 205, 68, 3, 2, 2, 2, 206, 204, 3, 2, 2, 2, 207, 209, 9, 5, 2, 2, 208, 207, 3, 2, 2, 2, 209, 210, 3, 2, 2, 2, 210, 208, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 70, 3, 2, 2, 2, 212, 214, 9, 6, 2, 2, 213, 212, 3, 2, 2, 2, 214, 215, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 217, 3, 2, 2, 2, 217, 218, 8, 36, 2, 2, 218, 72, 3, 2, 2, 2, 7, 2, 197, 204, 210, 215, 3, 8, 2, 2] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 40, 243, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 6, 36, 220, 10, 36, 13, 36, 14, 36, 221, 3, 37, 3, 37, 3, 37, 7, 37, 227, 10, 37, 12, 37, 14, 37, 230, 11, 37, 3, 38, 6, 38, 233, 10, 38, 13, 38, 14, 38, 234, 3, 39, 6, 39, 238, 10, 39, 13, 39, 14, 39, 239, 3, 39, 3, 39, 2, 2, 40, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 3, 2, 7, 3, 2, 50, 59, 5, 2, 67, 92, 97, 97, 99, 124, 5, 2, 50, 59, 67, 92, 99, 124, 4, 2, 67, 92, 99, 124, 5, 2, 11, 12, 15, 15, 34, 34, 2, 246, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 3, 79, 3, 2, 2, 2, 5, 82, 3, 2, 2, 2, 7, 84, 3, 2, 2, 2, 9, 86, 3, 2, 2, 2, 11, 91, 3, 2, 2, 2, 13, 98, 3, 2, 2, 2, 15, 103, 3, 2, 2, 2, 17, 105, 3, 2, 2, 2, 19, 107, 3, 2, 2, 2, 21, 109, 3, 2, 2, 2, 23, 111, 3, 2, 2, 2, 25, 119, 3, 2, 2, 2, 27, 128, 3, 2, 2, 2, 29, 133, 3, 2, 2, 2, 31, 139, 3, 2, 2, 2, 33, 145, 3, 2, 2, 2, 35, 153, 3, 2, 2, 2, 37, 159, 3, 2, 2, 2, 39, 165, 3, 2, 2, 2, 41, 169, 3, 2, 2, 2, 43, 177, 3, 2, 2, 2, 45, 179, 3, 2, 2, 2, 47, 181, 3, 2, 2, 2, 49, 183, 3, 2, 2, 2, 51, 185, 3, 2, 2, 2, 53, 194, 3, 2, 2, 2, 55, 196, 3, 2, 2, 2, 57, 198, 3, 2, 2, 2, 59, 201, 3, 2, 2, 2, 61, 204, 3, 2, 2, 2, 63, 207, 3, 2, 2, 2, 65, 210, 3, 2, 2, 2, 67, 213, 3, 2, 2, 2, 69, 216, 3, 2, 2, 2, 71, 219, 3, 2, 2, 2, 73, 223, 3, 2, 2, 2, 75, 232, 3, 2, 2, 2, 77, 237, 3, 2, 2, 2, 79, 80, 7, 107, 2, 2, 80, 81, 7, 104, 2, 2, 81, 4, 3, 2, 2, 2, 82, 83, 7, 93, 2, 2, 83, 6, 3, 2, 2, 2, 84, 85, 7, 95, 2, 2, 85, 8, 3, 2, 2, 2, 86, 87, 7, 103, 2, 2, 87, 88, 7, 110, 2, 2, 88, 89, 7, 117, 2, 2, 89, 90, 7, 103, 2, 2, 90, 10, 3, 2, 2, 2, 91, 92, 7, 116, 2, 2, 92, 93, 7, 103, 2, 2, 93, 94, 7, 114, 2, 2, 94, 95, 7, 103, 2, 2, 95, 96, 7, 99, 2, 2, 96, 97, 7, 118, 2, 2, 97, 12, 3, 2, 2, 2, 98, 99, 7, 105, 2, 2, 99, 100, 7, 113, 2, 2, 100, 101, 7, 118, 2, 2, 101, 102, 7, 113, 2, 2, 102, 14, 3, 2, 2, 2, 103, 104, 7, 42, 2, 2, 104, 16, 3, 2, 2, 2, 105, 106, 7, 46, 2, 2, 106, 18, 3, 2, 2, 2, 107, 108, 7, 43, 2, 2, 108, 20, 3, 2, 2, 2, 109, 110, 7, 63, 2, 2, 110, 22, 3, 2, 2, 2, 111, 112, 7, 104, 2, 2, 112, 113, 7, 113, 2, 2, 113, 114, 7, 116, 2, 2, 114, 115, 7, 121, 2, 2, 115, 116, 7, 99, 2, 2, 116, 117, 7, 116, 2, 2, 117, 118, 7, 102, 2, 2, 118, 24, 3, 2, 2, 2, 119, 120, 7, 100, 2, 2, 120, 121, 7, 99, 2, 2, 121, 122, 7, 101, 2, 2, 122, 123, 7, 109, 2, 2, 123, 124, 7, 121, 2, 2, 124, 125, 7, 99, 2, 2, 125, 126, 7, 116, 2, 2, 126, 127, 7, 102, 2, 2, 127, 26, 3, 2, 2, 2, 128, 129, 7, 110, 2, 2, 129, 130, 7, 103, 2, 2, 130, 131, 7, 104, 2, 2, 131, 132, 7, 118, 2, 2, 132, 28, 3, 2, 2, 2, 133, 134, 7, 116, 2, 2, 134, 135, 7, 107, 2, 2, 135, 136, 7, 105, 2, 2, 136, 137, 7, 106, 2, 2, 137, 138, 7, 118, 2, 2, 138, 30, 3, 2, 2, 2, 139, 140, 7, 114, 2, 2, 140, 141, 7, 103, 2, 2, 141, 142, 7, 112, 2, 2, 142, 143, 7, 119, 2, 2, 143, 144, 7, 114, 2, 2, 144, 32, 3, 2, 2, 2, 145, 146, 7, 114, 2, 2, 146, 147, 7, 103, 2, 2, 147, 148, 7, 112, 2, 2, 148, 149, 7, 102, 2, 2, 149, 150, 7, 113, 2, 2, 150, 151, 7, 121, 2, 2, 151, 152, 7, 112, 2, 2, 152, 34, 3, 2, 2, 2, 153, 154, 7, 114, 2, 2, 154, 155, 7, 99, 2, 2, 155, 156, 7, 119, 2, 2, 156, 157, 7, 117, 2, 2, 157, 158, 7, 103, 2, 2, 158, 36, 3, 2, 2, 2, 159, 160, 7, 114, 2, 2, 160, 161, 7, 116, 2, 2, 161, 162, 7, 107, 2, 2, 162, 163, 7, 112, 2, 2, 163, 164, 7, 118, 2, 2, 164, 38, 3, 2, 2, 2, 165, 166, 7, 107, 2, 2, 166, 167, 7, 112, 2, 2, 167, 168, 7, 101, 2, 2, 168, 40, 3, 2, 2, 2, 169, 170, 7, 102, 2, 2, 170, 171, 7, 119, 2, 2, 171, 172, 7, 111, 2, 2, 172, 173, 7, 114, 2, 2, 173, 174, 7, 79, 2, 2, 174, 175, 7, 99, 2, 2, 175, 176, 7, 114, 2, 2, 176, 42, 3, 2, 2, 2, 177, 178, 7, 45, 2, 2, 178, 44, 3, 2, 2, 2, 179, 180, 7, 47, 2, 2, 180, 46, 3, 2, 2, 2, 181, 182, 7, 44, 2, 2, 182, 48, 3, 2, 2, 2, 183, 184, 7, 49, 2, 2, 184, 50, 3, 2, 2, 2, 185, 186, 7, 114, 2, 2, 186, 187, 7, 103, 2, 2, 187, 188, 7, 112, 2, 2, 188, 189, 7, 102, 2, 2, 189, 190, 7, 113, 2, 2, 190, 191, 7, 121, 2, 2, 191, 192, 7, 112, 2, 2, 192, 193, 7, 65, 2, 2, 193, 52, 3, 2, 2, 2, 194, 195, 7, 62, 2, 2, 195, 54, 3, 2, 2, 2, 196, 197, 7, 64, 2, 2, 197, 56, 3, 2, 2, 2, 198, 199, 7, 63, 2, 2, 199, 200, 7, 63, 2, 2, 200, 58, 3, 2, 2, 2, 201, 202, 7, 35, 2, 2, 202, 203, 7, 63, 2, 2, 203, 60, 3, 2, 2, 2, 204, 205, 7, 62, 2, 2, 205, 206, 7, 63, 2, 2, 206, 62, 3, 2, 2, 2, 207, 208, 7, 64, 2, 2, 208, 209, 7, 63, 2, 2, 209, 64, 3, 2, 2, 2, 210, 211, 7, 40, 2, 2, 211, 212, 7, 40, 2, 2, 212, 66, 3, 2, 2, 2, 213, 214, 7, 126, 2, 2, 214, 215, 7, 126, 2, 2, 215, 68, 3, 2, 2, 2, 216, 217, 7, 35, 2, 2, 217, 70, 3, 2, 2, 2, 218, 220, 9, 2, 2, 2, 219, 218, 3, 2, 2, 2, 220, 221, 3, 2, 2, 2, 221, 219, 3, 2, 2, 2, 221, 222, 3, 2, 2, 2, 222, 72, 3, 2, 2, 2, 223, 224, 7, 60, 2, 2, 224, 228, 9, 3, 2, 2, 225, 227, 9, 4, 2, 2, 226, 225, 3, 2, 2, 2, 227, 230, 3, 2, 2, 2, 228, 226, 3, 2, 2, 2, 228, 229, 3, 2, 2, 2, 229, 74, 3, 2, 2, 2, 230, 228, 3, 2, 2, 2, 231, 233, 9, 5, 2, 2, 232, 231, 3, 2, 2, 2, 233, 234, 3, 2, 2, 2, 234, 232, 3, 2, 2, 2, 234, 235, 3, 2, 2, 2, 235, 76, 3, 2, 2, 2, 236, 238, 9, 6, 2, 2, 237, 236, 3, 2, 2, 2, 238, 239, 3, 2, 2, 2, 239, 237, 3, 2, 2, 2, 239, 240, 3, 2, 2, 2, 240, 241, 3, 2, 2, 2, 241, 242, 8, 39, 2, 2, 242, 78, 3, 2, 2, 2, 7, 2, 221, 228, 234, 239, 3, 8, 2, 2] \ No newline at end of file diff --git a/ChironCore/turtparse/tlangLexer.py b/ChironCore/turtparse/tlangLexer.py index fc951de..07744f4 100644 --- a/ChironCore/turtparse/tlangLexer.py +++ b/ChironCore/turtparse/tlangLexer.py @@ -5,93 +5,104 @@ import sys + def serializedATN(): with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2%") - buf.write("\u00db\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7") + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2(") + buf.write("\u00f3\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7") buf.write("\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r") buf.write("\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23") buf.write("\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30") buf.write("\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36") - buf.write("\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\3\2\3") - buf.write("\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3\6") - buf.write("\3\6\3\6\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3\t\3\t\3") - buf.write("\n\3\n\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\r\3") - buf.write("\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3\16") - buf.write("\3\17\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20\3\20") - buf.write("\3\20\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\22\3\22") - buf.write("\3\22\3\22\3\22\3\22\3\23\3\23\3\24\3\24\3\25\3\25\3\26") - buf.write("\3\26\3\27\3\27\3\27\3\27\3\27\3\27\3\27\3\27\3\27\3\30") - buf.write("\3\30\3\31\3\31\3\32\3\32\3\32\3\33\3\33\3\33\3\34\3\34") - buf.write("\3\34\3\35\3\35\3\35\3\36\3\36\3\36\3\37\3\37\3\37\3 ") - buf.write("\3 \3!\6!\u00c4\n!\r!\16!\u00c5\3\"\3\"\3\"\7\"\u00cb") - buf.write("\n\"\f\"\16\"\u00ce\13\"\3#\6#\u00d1\n#\r#\16#\u00d2\3") - buf.write("$\6$\u00d6\n$\r$\16$\u00d7\3$\3$\2\2%\3\3\5\4\7\5\t\6") - buf.write("\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20") - buf.write("\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33\65") - buf.write("\34\67\359\36;\37= ?!A\"C#E$G%\3\2\7\3\2\62;\5\2C\\aa") - buf.write("c|\5\2\62;C\\c|\4\2C\\c|\5\2\13\f\17\17\"\"\2\u00de\2") - buf.write("\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3") - buf.write("\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2") - buf.write("\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2") - buf.write("\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%") - buf.write("\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2") - buf.write("\2/\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67") - buf.write("\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2") - buf.write("A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\3I\3\2\2\2") - buf.write("\5L\3\2\2\2\7N\3\2\2\2\tP\3\2\2\2\13U\3\2\2\2\r\\\3\2") - buf.write("\2\2\17a\3\2\2\2\21c\3\2\2\2\23e\3\2\2\2\25g\3\2\2\2\27") - buf.write("i\3\2\2\2\31q\3\2\2\2\33z\3\2\2\2\35\177\3\2\2\2\37\u0085") - buf.write("\3\2\2\2!\u008b\3\2\2\2#\u0093\3\2\2\2%\u0099\3\2\2\2") - buf.write("\'\u009b\3\2\2\2)\u009d\3\2\2\2+\u009f\3\2\2\2-\u00a1") - buf.write("\3\2\2\2/\u00aa\3\2\2\2\61\u00ac\3\2\2\2\63\u00ae\3\2") - buf.write("\2\2\65\u00b1\3\2\2\2\67\u00b4\3\2\2\29\u00b7\3\2\2\2") - buf.write(";\u00ba\3\2\2\2=\u00bd\3\2\2\2?\u00c0\3\2\2\2A\u00c3\3") - buf.write("\2\2\2C\u00c7\3\2\2\2E\u00d0\3\2\2\2G\u00d5\3\2\2\2IJ") - buf.write("\7k\2\2JK\7h\2\2K\4\3\2\2\2LM\7]\2\2M\6\3\2\2\2NO\7_\2") - buf.write("\2O\b\3\2\2\2PQ\7g\2\2QR\7n\2\2RS\7u\2\2ST\7g\2\2T\n\3") - buf.write("\2\2\2UV\7t\2\2VW\7g\2\2WX\7r\2\2XY\7g\2\2YZ\7c\2\2Z[") - buf.write("\7v\2\2[\f\3\2\2\2\\]\7i\2\2]^\7q\2\2^_\7v\2\2_`\7q\2") - buf.write("\2`\16\3\2\2\2ab\7*\2\2b\20\3\2\2\2cd\7.\2\2d\22\3\2\2") - buf.write("\2ef\7+\2\2f\24\3\2\2\2gh\7?\2\2h\26\3\2\2\2ij\7h\2\2") - buf.write("jk\7q\2\2kl\7t\2\2lm\7y\2\2mn\7c\2\2no\7t\2\2op\7f\2\2") - buf.write("p\30\3\2\2\2qr\7d\2\2rs\7c\2\2st\7e\2\2tu\7m\2\2uv\7y") - buf.write("\2\2vw\7c\2\2wx\7t\2\2xy\7f\2\2y\32\3\2\2\2z{\7n\2\2{") - buf.write("|\7g\2\2|}\7h\2\2}~\7v\2\2~\34\3\2\2\2\177\u0080\7t\2") - buf.write("\2\u0080\u0081\7k\2\2\u0081\u0082\7i\2\2\u0082\u0083\7") - buf.write("j\2\2\u0083\u0084\7v\2\2\u0084\36\3\2\2\2\u0085\u0086") - buf.write("\7r\2\2\u0086\u0087\7g\2\2\u0087\u0088\7p\2\2\u0088\u0089") - buf.write("\7w\2\2\u0089\u008a\7r\2\2\u008a \3\2\2\2\u008b\u008c") - buf.write("\7r\2\2\u008c\u008d\7g\2\2\u008d\u008e\7p\2\2\u008e\u008f") - buf.write("\7f\2\2\u008f\u0090\7q\2\2\u0090\u0091\7y\2\2\u0091\u0092") - buf.write("\7p\2\2\u0092\"\3\2\2\2\u0093\u0094\7r\2\2\u0094\u0095") - buf.write("\7c\2\2\u0095\u0096\7w\2\2\u0096\u0097\7u\2\2\u0097\u0098") - buf.write("\7g\2\2\u0098$\3\2\2\2\u0099\u009a\7-\2\2\u009a&\3\2\2") - buf.write("\2\u009b\u009c\7/\2\2\u009c(\3\2\2\2\u009d\u009e\7,\2") - buf.write("\2\u009e*\3\2\2\2\u009f\u00a0\7\61\2\2\u00a0,\3\2\2\2") - buf.write("\u00a1\u00a2\7r\2\2\u00a2\u00a3\7g\2\2\u00a3\u00a4\7p") - buf.write("\2\2\u00a4\u00a5\7f\2\2\u00a5\u00a6\7q\2\2\u00a6\u00a7") - buf.write("\7y\2\2\u00a7\u00a8\7p\2\2\u00a8\u00a9\7A\2\2\u00a9.\3") - buf.write("\2\2\2\u00aa\u00ab\7>\2\2\u00ab\60\3\2\2\2\u00ac\u00ad") - buf.write("\7@\2\2\u00ad\62\3\2\2\2\u00ae\u00af\7?\2\2\u00af\u00b0") - buf.write("\7?\2\2\u00b0\64\3\2\2\2\u00b1\u00b2\7#\2\2\u00b2\u00b3") - buf.write("\7?\2\2\u00b3\66\3\2\2\2\u00b4\u00b5\7>\2\2\u00b5\u00b6") - buf.write("\7?\2\2\u00b68\3\2\2\2\u00b7\u00b8\7@\2\2\u00b8\u00b9") - buf.write("\7?\2\2\u00b9:\3\2\2\2\u00ba\u00bb\7(\2\2\u00bb\u00bc") - buf.write("\7(\2\2\u00bc<\3\2\2\2\u00bd\u00be\7~\2\2\u00be\u00bf") - buf.write("\7~\2\2\u00bf>\3\2\2\2\u00c0\u00c1\7#\2\2\u00c1@\3\2\2") - buf.write("\2\u00c2\u00c4\t\2\2\2\u00c3\u00c2\3\2\2\2\u00c4\u00c5") - buf.write("\3\2\2\2\u00c5\u00c3\3\2\2\2\u00c5\u00c6\3\2\2\2\u00c6") - buf.write("B\3\2\2\2\u00c7\u00c8\7<\2\2\u00c8\u00cc\t\3\2\2\u00c9") - buf.write("\u00cb\t\4\2\2\u00ca\u00c9\3\2\2\2\u00cb\u00ce\3\2\2\2") - buf.write("\u00cc\u00ca\3\2\2\2\u00cc\u00cd\3\2\2\2\u00cdD\3\2\2") - buf.write("\2\u00ce\u00cc\3\2\2\2\u00cf\u00d1\t\5\2\2\u00d0\u00cf") - buf.write("\3\2\2\2\u00d1\u00d2\3\2\2\2\u00d2\u00d0\3\2\2\2\u00d2") - buf.write("\u00d3\3\2\2\2\u00d3F\3\2\2\2\u00d4\u00d6\t\6\2\2\u00d5") - buf.write("\u00d4\3\2\2\2\u00d6\u00d7\3\2\2\2\u00d7\u00d5\3\2\2\2") - buf.write("\u00d7\u00d8\3\2\2\2\u00d8\u00d9\3\2\2\2\u00d9\u00da\b") - buf.write("$\2\2\u00daH\3\2\2\2\7\2\u00c5\u00cc\u00d2\u00d7\3\b\2") - buf.write("\2") + buf.write("\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\4%\t%") + buf.write("\4&\t&\4\'\t\'\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\5") + buf.write("\3\5\3\5\3\6\3\6\3\6\3\6\3\6\3\6\3\6\3\7\3\7\3\7\3\7\3") + buf.write("\7\3\b\3\b\3\t\3\t\3\n\3\n\3\13\3\13\3\f\3\f\3\f\3\f\3") + buf.write("\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\16") + buf.write("\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\17\3\20") + buf.write("\3\20\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\21\3\21") + buf.write("\3\21\3\21\3\22\3\22\3\22\3\22\3\22\3\22\3\23\3\23\3\23") + buf.write("\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\25\3\25\3\25\3\25") + buf.write("\3\25\3\25\3\25\3\25\3\26\3\26\3\27\3\27\3\30\3\30\3\31") + buf.write("\3\31\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\33") + buf.write("\3\33\3\34\3\34\3\35\3\35\3\35\3\36\3\36\3\36\3\37\3\37") + buf.write("\3\37\3 \3 \3 \3!\3!\3!\3\"\3\"\3\"\3#\3#\3$\6$\u00dc") + buf.write("\n$\r$\16$\u00dd\3%\3%\3%\7%\u00e3\n%\f%\16%\u00e6\13") + buf.write("%\3&\6&\u00e9\n&\r&\16&\u00ea\3\'\6\'\u00ee\n\'\r\'\16") + buf.write("\'\u00ef\3\'\3\'\2\2(\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21") + buf.write("\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24") + buf.write("\'\25)\26+\27-\30/\31\61\32\63\33\65\34\67\359\36;\37") + buf.write("= ?!A\"C#E$G%I&K\'M(\3\2\7\3\2\62;\5\2C\\aac|\5\2\62;") + buf.write("C\\c|\4\2C\\c|\5\2\13\f\17\17\"\"\2\u00f6\2\3\3\2\2\2") + buf.write("\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r") + buf.write("\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3") + buf.write("\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2") + buf.write("\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'") + buf.write("\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2") + buf.write("\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29") + buf.write("\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2") + buf.write("C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2") + buf.write("\2M\3\2\2\2\3O\3\2\2\2\5R\3\2\2\2\7T\3\2\2\2\tV\3\2\2") + buf.write("\2\13[\3\2\2\2\rb\3\2\2\2\17g\3\2\2\2\21i\3\2\2\2\23k") + buf.write("\3\2\2\2\25m\3\2\2\2\27o\3\2\2\2\31w\3\2\2\2\33\u0080") + buf.write("\3\2\2\2\35\u0085\3\2\2\2\37\u008b\3\2\2\2!\u0091\3\2") + buf.write("\2\2#\u0099\3\2\2\2%\u009f\3\2\2\2\'\u00a5\3\2\2\2)\u00a9") + buf.write("\3\2\2\2+\u00b1\3\2\2\2-\u00b3\3\2\2\2/\u00b5\3\2\2\2") + buf.write("\61\u00b7\3\2\2\2\63\u00b9\3\2\2\2\65\u00c2\3\2\2\2\67") + buf.write("\u00c4\3\2\2\29\u00c6\3\2\2\2;\u00c9\3\2\2\2=\u00cc\3") + buf.write("\2\2\2?\u00cf\3\2\2\2A\u00d2\3\2\2\2C\u00d5\3\2\2\2E\u00d8") + buf.write("\3\2\2\2G\u00db\3\2\2\2I\u00df\3\2\2\2K\u00e8\3\2\2\2") + buf.write("M\u00ed\3\2\2\2OP\7k\2\2PQ\7h\2\2Q\4\3\2\2\2RS\7]\2\2") + buf.write("S\6\3\2\2\2TU\7_\2\2U\b\3\2\2\2VW\7g\2\2WX\7n\2\2XY\7") + buf.write("u\2\2YZ\7g\2\2Z\n\3\2\2\2[\\\7t\2\2\\]\7g\2\2]^\7r\2\2") + buf.write("^_\7g\2\2_`\7c\2\2`a\7v\2\2a\f\3\2\2\2bc\7i\2\2cd\7q\2") + buf.write("\2de\7v\2\2ef\7q\2\2f\16\3\2\2\2gh\7*\2\2h\20\3\2\2\2") + buf.write("ij\7.\2\2j\22\3\2\2\2kl\7+\2\2l\24\3\2\2\2mn\7?\2\2n\26") + buf.write("\3\2\2\2op\7h\2\2pq\7q\2\2qr\7t\2\2rs\7y\2\2st\7c\2\2") + buf.write("tu\7t\2\2uv\7f\2\2v\30\3\2\2\2wx\7d\2\2xy\7c\2\2yz\7e") + buf.write("\2\2z{\7m\2\2{|\7y\2\2|}\7c\2\2}~\7t\2\2~\177\7f\2\2\177") + buf.write("\32\3\2\2\2\u0080\u0081\7n\2\2\u0081\u0082\7g\2\2\u0082") + buf.write("\u0083\7h\2\2\u0083\u0084\7v\2\2\u0084\34\3\2\2\2\u0085") + buf.write("\u0086\7t\2\2\u0086\u0087\7k\2\2\u0087\u0088\7i\2\2\u0088") + buf.write("\u0089\7j\2\2\u0089\u008a\7v\2\2\u008a\36\3\2\2\2\u008b") + buf.write("\u008c\7r\2\2\u008c\u008d\7g\2\2\u008d\u008e\7p\2\2\u008e") + buf.write("\u008f\7w\2\2\u008f\u0090\7r\2\2\u0090 \3\2\2\2\u0091") + buf.write("\u0092\7r\2\2\u0092\u0093\7g\2\2\u0093\u0094\7p\2\2\u0094") + buf.write("\u0095\7f\2\2\u0095\u0096\7q\2\2\u0096\u0097\7y\2\2\u0097") + buf.write("\u0098\7p\2\2\u0098\"\3\2\2\2\u0099\u009a\7r\2\2\u009a") + buf.write("\u009b\7c\2\2\u009b\u009c\7w\2\2\u009c\u009d\7u\2\2\u009d") + buf.write("\u009e\7g\2\2\u009e$\3\2\2\2\u009f\u00a0\7r\2\2\u00a0") + buf.write("\u00a1\7t\2\2\u00a1\u00a2\7k\2\2\u00a2\u00a3\7p\2\2\u00a3") + buf.write("\u00a4\7v\2\2\u00a4&\3\2\2\2\u00a5\u00a6\7k\2\2\u00a6") + buf.write("\u00a7\7p\2\2\u00a7\u00a8\7e\2\2\u00a8(\3\2\2\2\u00a9") + buf.write("\u00aa\7f\2\2\u00aa\u00ab\7w\2\2\u00ab\u00ac\7o\2\2\u00ac") + buf.write("\u00ad\7r\2\2\u00ad\u00ae\7O\2\2\u00ae\u00af\7c\2\2\u00af") + buf.write("\u00b0\7r\2\2\u00b0*\3\2\2\2\u00b1\u00b2\7-\2\2\u00b2") + buf.write(",\3\2\2\2\u00b3\u00b4\7/\2\2\u00b4.\3\2\2\2\u00b5\u00b6") + buf.write("\7,\2\2\u00b6\60\3\2\2\2\u00b7\u00b8\7\61\2\2\u00b8\62") + buf.write("\3\2\2\2\u00b9\u00ba\7r\2\2\u00ba\u00bb\7g\2\2\u00bb\u00bc") + buf.write("\7p\2\2\u00bc\u00bd\7f\2\2\u00bd\u00be\7q\2\2\u00be\u00bf") + buf.write("\7y\2\2\u00bf\u00c0\7p\2\2\u00c0\u00c1\7A\2\2\u00c1\64") + buf.write("\3\2\2\2\u00c2\u00c3\7>\2\2\u00c3\66\3\2\2\2\u00c4\u00c5") + buf.write("\7@\2\2\u00c58\3\2\2\2\u00c6\u00c7\7?\2\2\u00c7\u00c8") + buf.write("\7?\2\2\u00c8:\3\2\2\2\u00c9\u00ca\7#\2\2\u00ca\u00cb") + buf.write("\7?\2\2\u00cb<\3\2\2\2\u00cc\u00cd\7>\2\2\u00cd\u00ce") + buf.write("\7?\2\2\u00ce>\3\2\2\2\u00cf\u00d0\7@\2\2\u00d0\u00d1") + buf.write("\7?\2\2\u00d1@\3\2\2\2\u00d2\u00d3\7(\2\2\u00d3\u00d4") + buf.write("\7(\2\2\u00d4B\3\2\2\2\u00d5\u00d6\7~\2\2\u00d6\u00d7") + buf.write("\7~\2\2\u00d7D\3\2\2\2\u00d8\u00d9\7#\2\2\u00d9F\3\2\2") + buf.write("\2\u00da\u00dc\t\2\2\2\u00db\u00da\3\2\2\2\u00dc\u00dd") + buf.write("\3\2\2\2\u00dd\u00db\3\2\2\2\u00dd\u00de\3\2\2\2\u00de") + buf.write("H\3\2\2\2\u00df\u00e0\7<\2\2\u00e0\u00e4\t\3\2\2\u00e1") + buf.write("\u00e3\t\4\2\2\u00e2\u00e1\3\2\2\2\u00e3\u00e6\3\2\2\2") + buf.write("\u00e4\u00e2\3\2\2\2\u00e4\u00e5\3\2\2\2\u00e5J\3\2\2") + buf.write("\2\u00e6\u00e4\3\2\2\2\u00e7\u00e9\t\5\2\2\u00e8\u00e7") + buf.write("\3\2\2\2\u00e9\u00ea\3\2\2\2\u00ea\u00e8\3\2\2\2\u00ea") + buf.write("\u00eb\3\2\2\2\u00ebL\3\2\2\2\u00ec\u00ee\t\6\2\2\u00ed") + buf.write("\u00ec\3\2\2\2\u00ee\u00ef\3\2\2\2\u00ef\u00ed\3\2\2\2") + buf.write("\u00ef\u00f0\3\2\2\2\u00f0\u00f1\3\2\2\2\u00f1\u00f2\b") + buf.write("\'\2\2\u00f2N\3\2\2\2\7\2\u00dd\u00e4\u00ea\u00ef\3\b") + buf.write("\2\2") return buf.getvalue() @@ -118,24 +129,27 @@ class tlangLexer(Lexer): T__14 = 15 T__15 = 16 T__16 = 17 - PLUS = 18 - MINUS = 19 - MUL = 20 - DIV = 21 - PENCOND = 22 - LT = 23 - GT = 24 - EQ = 25 - NEQ = 26 - LTE = 27 - GTE = 28 - AND = 29 - OR = 30 - NOT = 31 - NUM = 32 - VAR = 33 - NAME = 34 - Whitespace = 35 + T__17 = 18 + T__18 = 19 + T__19 = 20 + PLUS = 21 + MINUS = 22 + MUL = 23 + DIV = 24 + PENCOND = 25 + LT = 26 + GT = 27 + EQ = 28 + NEQ = 29 + LTE = 30 + GTE = 31 + AND = 32 + OR = 33 + NOT = 34 + NUM = 35 + VAR = 36 + NAME = 37 + Whitespace = 38 channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] @@ -144,9 +158,9 @@ class tlangLexer(Lexer): literalNames = [ "", "'if'", "'['", "']'", "'else'", "'repeat'", "'goto'", "'('", "','", "')'", "'='", "'forward'", "'backward'", "'left'", "'right'", - "'penup'", "'pendown'", "'pause'", "'+'", "'-'", "'*'", "'/'", - "'pendown?'", "'<'", "'>'", "'=='", "'!='", "'<='", "'>='", - "'&&'", "'||'", "'!'" ] + "'penup'", "'pendown'", "'pause'", "'print'", "'inc'", "'dumpMap'", + "'+'", "'-'", "'*'", "'/'", "'pendown?'", "'<'", "'>'", "'=='", + "'!='", "'<='", "'>='", "'&&'", "'||'", "'!'" ] symbolicNames = [ "", "PLUS", "MINUS", "MUL", "DIV", "PENCOND", "LT", "GT", "EQ", @@ -155,9 +169,10 @@ class tlangLexer(Lexer): ruleNames = [ "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", "T__7", "T__8", "T__9", "T__10", "T__11", "T__12", "T__13", - "T__14", "T__15", "T__16", "PLUS", "MINUS", "MUL", "DIV", - "PENCOND", "LT", "GT", "EQ", "NEQ", "LTE", "GTE", "AND", - "OR", "NOT", "NUM", "VAR", "NAME", "Whitespace" ] + "T__14", "T__15", "T__16", "T__17", "T__18", "T__19", + "PLUS", "MINUS", "MUL", "DIV", "PENCOND", "LT", "GT", + "EQ", "NEQ", "LTE", "GTE", "AND", "OR", "NOT", "NUM", + "VAR", "NAME", "Whitespace" ] grammarFileName = "tlang.g4" diff --git a/ChironCore/turtparse/tlangLexer.tokens b/ChironCore/turtparse/tlangLexer.tokens index 78f9526..086b392 100644 --- a/ChironCore/turtparse/tlangLexer.tokens +++ b/ChironCore/turtparse/tlangLexer.tokens @@ -15,24 +15,27 @@ T__13=14 T__14=15 T__15=16 T__16=17 -PLUS=18 -MINUS=19 -MUL=20 -DIV=21 -PENCOND=22 -LT=23 -GT=24 -EQ=25 -NEQ=26 -LTE=27 -GTE=28 -AND=29 -OR=30 -NOT=31 -NUM=32 -VAR=33 -NAME=34 -Whitespace=35 +T__17=18 +T__18=19 +T__19=20 +PLUS=21 +MINUS=22 +MUL=23 +DIV=24 +PENCOND=25 +LT=26 +GT=27 +EQ=28 +NEQ=29 +LTE=30 +GTE=31 +AND=32 +OR=33 +NOT=34 +NUM=35 +VAR=36 +NAME=37 +Whitespace=38 'if'=1 '['=2 ']'=3 @@ -50,17 +53,20 @@ Whitespace=35 'penup'=15 'pendown'=16 'pause'=17 -'+'=18 -'-'=19 -'*'=20 -'/'=21 -'pendown?'=22 -'<'=23 -'>'=24 -'=='=25 -'!='=26 -'<='=27 -'>='=28 -'&&'=29 -'||'=30 -'!'=31 +'print'=18 +'inc'=19 +'dumpMap'=20 +'+'=21 +'-'=22 +'*'=23 +'/'=24 +'pendown?'=25 +'<'=26 +'>'=27 +'=='=28 +'!='=29 +'<='=30 +'>='=31 +'&&'=32 +'||'=33 +'!'=34 diff --git a/ChironCore/turtparse/tlangParser.py b/ChironCore/turtparse/tlangParser.py index b02d4a2..f0bab63 100644 --- a/ChironCore/turtparse/tlangParser.py +++ b/ChironCore/turtparse/tlangParser.py @@ -5,71 +5,82 @@ from typing.io import TextIO import sys + def serializedATN(): with StringIO() as buf: - buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3%") - buf.write("\u00af\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") + buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3(") + buf.write("\u00c4\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") buf.write("\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r\4\16") buf.write("\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23\t\23") - buf.write("\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\3\2\3\2\3\2\3") - buf.write("\3\7\3\63\n\3\f\3\16\3\66\13\3\3\4\6\49\n\4\r\4\16\4:") - buf.write("\3\5\3\5\3\5\3\5\3\5\3\5\3\5\5\5D\n\5\3\6\3\6\5\6H\n\6") - buf.write("\3\7\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3") - buf.write("\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\n") - buf.write("\3\n\3\n\3\13\3\13\3\13\3\13\3\f\3\f\3\f\3\r\3\r\3\16") - buf.write("\3\16\3\17\3\17\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\20") - buf.write("\3\20\5\20}\n\20\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3") - buf.write("\20\7\20\u0087\n\20\f\20\16\20\u008a\13\20\3\21\3\21\3") - buf.write("\22\3\22\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\24\3\24") - buf.write("\3\24\3\24\3\24\3\24\3\24\5\24\u009e\n\24\3\24\3\24\3") - buf.write("\24\3\24\7\24\u00a4\n\24\f\24\16\24\u00a7\13\24\3\25\3") - buf.write("\25\3\26\3\26\3\27\3\27\3\27\2\4\36&\30\2\4\6\b\n\f\16") - buf.write("\20\22\24\26\30\32\34\36 \"$&(*,\2\t\3\2\r\20\3\2\21\22") - buf.write("\3\2\26\27\3\2\24\25\3\2\31\36\3\2\37 \3\2\"#\2\u00a9") - buf.write("\2.\3\2\2\2\4\64\3\2\2\2\68\3\2\2\2\bC\3\2\2\2\nG\3\2") - buf.write("\2\2\fI\3\2\2\2\16O\3\2\2\2\20Y\3\2\2\2\22_\3\2\2\2\24") - buf.write("f\3\2\2\2\26j\3\2\2\2\30m\3\2\2\2\32o\3\2\2\2\34q\3\2") - buf.write("\2\2\36|\3\2\2\2 \u008b\3\2\2\2\"\u008d\3\2\2\2$\u008f") - buf.write("\3\2\2\2&\u009d\3\2\2\2(\u00a8\3\2\2\2*\u00aa\3\2\2\2") - buf.write(",\u00ac\3\2\2\2./\5\4\3\2/\60\7\2\2\3\60\3\3\2\2\2\61") - buf.write("\63\5\b\5\2\62\61\3\2\2\2\63\66\3\2\2\2\64\62\3\2\2\2") - buf.write("\64\65\3\2\2\2\65\5\3\2\2\2\66\64\3\2\2\2\679\5\b\5\2") - buf.write("8\67\3\2\2\29:\3\2\2\2:8\3\2\2\2:;\3\2\2\2;\7\3\2\2\2") - buf.write("D\5\20\t\2?D\5\26\f\2@D\5\32\16") - buf.write("\2AD\5\22\n\2BD\5\34\17\2C<\3\2\2\2C=\3\2\2\2C>\3\2\2") - buf.write("\2C?\3\2\2\2C@\3\2\2\2CA\3\2\2\2CB\3\2\2\2D\t\3\2\2\2") - buf.write("EH\5\f\7\2FH\5\16\b\2GE\3\2\2\2GF\3\2\2\2H\13\3\2\2\2") - buf.write("IJ\7\3\2\2JK\5&\24\2KL\7\4\2\2LM\5\6\4\2MN\7\5\2\2N\r") - buf.write("\3\2\2\2OP\7\3\2\2PQ\5&\24\2QR\7\4\2\2RS\5\6\4\2ST\7\5") - buf.write("\2\2TU\7\6\2\2UV\7\4\2\2VW\5\6\4\2WX\7\5\2\2X\17\3\2\2") - buf.write("\2YZ\7\7\2\2Z[\5,\27\2[\\\7\4\2\2\\]\5\6\4\2]^\7\5\2\2") - buf.write("^\21\3\2\2\2_`\7\b\2\2`a\7\t\2\2ab\5\36\20\2bc\7\n\2\2") - buf.write("cd\5\36\20\2de\7\13\2\2e\23\3\2\2\2fg\7#\2\2gh\7\f\2\2") - buf.write("hi\5\36\20\2i\25\3\2\2\2jk\5\30\r\2kl\5\36\20\2l\27\3") - buf.write("\2\2\2mn\t\2\2\2n\31\3\2\2\2op\t\3\2\2p\33\3\2\2\2qr\7") - buf.write("\23\2\2r\35\3\2\2\2st\b\20\1\2tu\5$\23\2uv\5\36\20\7v") - buf.write("}\3\2\2\2w}\5,\27\2xy\7\t\2\2yz\5\36\20\2z{\7\13\2\2{") - buf.write("}\3\2\2\2|s\3\2\2\2|w\3\2\2\2|x\3\2\2\2}\u0088\3\2\2\2") - buf.write("~\177\f\6\2\2\177\u0080\5 \21\2\u0080\u0081\5\36\20\7") - buf.write("\u0081\u0087\3\2\2\2\u0082\u0083\f\5\2\2\u0083\u0084\5") - buf.write("\"\22\2\u0084\u0085\5\36\20\6\u0085\u0087\3\2\2\2\u0086") - buf.write("~\3\2\2\2\u0086\u0082\3\2\2\2\u0087\u008a\3\2\2\2\u0088") - buf.write("\u0086\3\2\2\2\u0088\u0089\3\2\2\2\u0089\37\3\2\2\2\u008a") - buf.write("\u0088\3\2\2\2\u008b\u008c\t\4\2\2\u008c!\3\2\2\2\u008d") - buf.write("\u008e\t\5\2\2\u008e#\3\2\2\2\u008f\u0090\7\25\2\2\u0090") - buf.write("%\3\2\2\2\u0091\u0092\b\24\1\2\u0092\u0093\7!\2\2\u0093") - buf.write("\u009e\5&\24\7\u0094\u0095\5\36\20\2\u0095\u0096\5(\25") - buf.write("\2\u0096\u0097\5\36\20\2\u0097\u009e\3\2\2\2\u0098\u009e") - buf.write("\7\30\2\2\u0099\u009a\7\t\2\2\u009a\u009b\5&\24\2\u009b") - buf.write("\u009c\7\13\2\2\u009c\u009e\3\2\2\2\u009d\u0091\3\2\2") - buf.write("\2\u009d\u0094\3\2\2\2\u009d\u0098\3\2\2\2\u009d\u0099") - buf.write("\3\2\2\2\u009e\u00a5\3\2\2\2\u009f\u00a0\f\5\2\2\u00a0") - buf.write("\u00a1\5*\26\2\u00a1\u00a2\5&\24\6\u00a2\u00a4\3\2\2\2") - buf.write("\u00a3\u009f\3\2\2\2\u00a4\u00a7\3\2\2\2\u00a5\u00a3\3") - buf.write("\2\2\2\u00a5\u00a6\3\2\2\2\u00a6\'\3\2\2\2\u00a7\u00a5") - buf.write("\3\2\2\2\u00a8\u00a9\t\6\2\2\u00a9)\3\2\2\2\u00aa\u00ab") - buf.write("\t\7\2\2\u00ab+\3\2\2\2\u00ac\u00ad\t\b\2\2\u00ad-\3\2") - buf.write("\2\2\13\64:CG|\u0086\u0088\u009d\u00a5") + buf.write("\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31") + buf.write("\t\31\4\32\t\32\3\2\3\2\3\2\3\3\7\39\n\3\f\3\16\3<\13") + buf.write("\3\3\4\6\4?\n\4\r\4\16\4@\3\5\3\5\3\5\3\5\3\5\3\5\3\5") + buf.write("\3\5\3\5\3\5\5\5M\n\5\3\6\3\6\5\6Q\n\6\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3") + buf.write("\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\13\3") + buf.write("\13\3\13\3\13\3\f\3\f\3\f\3\r\3\r\3\16\3\16\3\17\3\17") + buf.write("\3\20\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\21\3\22") + buf.write("\3\22\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\5\23") + buf.write("\u0092\n\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\7") + buf.write("\23\u009c\n\23\f\23\16\23\u009f\13\23\3\24\3\24\3\25\3") + buf.write("\25\3\26\3\26\3\27\3\27\3\27\3\27\3\27\3\27\3\27\3\27") + buf.write("\3\27\3\27\3\27\3\27\5\27\u00b3\n\27\3\27\3\27\3\27\3") + buf.write("\27\7\27\u00b9\n\27\f\27\16\27\u00bc\13\27\3\30\3\30\3") + buf.write("\31\3\31\3\32\3\32\3\32\2\4$,\33\2\4\6\b\n\f\16\20\22") + buf.write("\24\26\30\32\34\36 \"$&(*,.\60\62\2\t\3\2\r\20\3\2\21") + buf.write("\22\3\2\31\32\3\2\27\30\3\2\34!\3\2\"#\3\2%&\2\u00be\2") + buf.write("\64\3\2\2\2\4:\3\2\2\2\6>\3\2\2\2\bL\3\2\2\2\nP\3\2\2") + buf.write("\2\fR\3\2\2\2\16X\3\2\2\2\20b\3\2\2\2\22h\3\2\2\2\24o") + buf.write("\3\2\2\2\26s\3\2\2\2\30v\3\2\2\2\32x\3\2\2\2\34z\3\2\2") + buf.write("\2\36|\3\2\2\2 \u0081\3\2\2\2\"\u0086\3\2\2\2$\u0091\3") + buf.write("\2\2\2&\u00a0\3\2\2\2(\u00a2\3\2\2\2*\u00a4\3\2\2\2,\u00b2") + buf.write("\3\2\2\2.\u00bd\3\2\2\2\60\u00bf\3\2\2\2\62\u00c1\3\2") + buf.write("\2\2\64\65\5\4\3\2\65\66\7\2\2\3\66\3\3\2\2\2\679\5\b") + buf.write("\5\28\67\3\2\2\29<\3\2\2\2:8\3\2\2\2:;\3\2\2\2;\5\3\2") + buf.write("\2\2<:\3\2\2\2=?\5\b\5\2>=\3\2\2\2?@\3\2\2\2@>\3\2\2\2") + buf.write("@A\3\2\2\2A\7\3\2\2\2BM\5\24\13\2CM\5\n\6\2DM\5\20\t\2") + buf.write("EM\5\26\f\2FM\5\32\16\2GM\5\22\n\2HM\5\34\17\2IM\5\36") + buf.write("\20\2JM\5 \21\2KM\5\"\22\2LB\3\2\2\2LC\3\2\2\2LD\3\2\2") + buf.write("\2LE\3\2\2\2LF\3\2\2\2LG\3\2\2\2LH\3\2\2\2LI\3\2\2\2L") + buf.write("J\3\2\2\2LK\3\2\2\2M\t\3\2\2\2NQ\5\f\7\2OQ\5\16\b\2PN") + buf.write("\3\2\2\2PO\3\2\2\2Q\13\3\2\2\2RS\7\3\2\2ST\5,\27\2TU\7") + buf.write("\4\2\2UV\5\6\4\2VW\7\5\2\2W\r\3\2\2\2XY\7\3\2\2YZ\5,\27") + buf.write("\2Z[\7\4\2\2[\\\5\6\4\2\\]\7\5\2\2]^\7\6\2\2^_\7\4\2\2") + buf.write("_`\5\6\4\2`a\7\5\2\2a\17\3\2\2\2bc\7\7\2\2cd\5\62\32\2") + buf.write("de\7\4\2\2ef\5\6\4\2fg\7\5\2\2g\21\3\2\2\2hi\7\b\2\2i") + buf.write("j\7\t\2\2jk\5$\23\2kl\7\n\2\2lm\5$\23\2mn\7\13\2\2n\23") + buf.write("\3\2\2\2op\7&\2\2pq\7\f\2\2qr\5$\23\2r\25\3\2\2\2st\5") + buf.write("\30\r\2tu\5$\23\2u\27\3\2\2\2vw\t\2\2\2w\31\3\2\2\2xy") + buf.write("\t\3\2\2y\33\3\2\2\2z{\7\23\2\2{\35\3\2\2\2|}\7\24\2\2") + buf.write("}~\7\t\2\2~\177\5$\23\2\177\u0080\7\13\2\2\u0080\37\3") + buf.write("\2\2\2\u0081\u0082\7\25\2\2\u0082\u0083\7\t\2\2\u0083") + buf.write("\u0084\7&\2\2\u0084\u0085\7\13\2\2\u0085!\3\2\2\2\u0086") + buf.write("\u0087\7\26\2\2\u0087#\3\2\2\2\u0088\u0089\b\23\1\2\u0089") + buf.write("\u008a\5*\26\2\u008a\u008b\5$\23\7\u008b\u0092\3\2\2\2") + buf.write("\u008c\u0092\5\62\32\2\u008d\u008e\7\t\2\2\u008e\u008f") + buf.write("\5$\23\2\u008f\u0090\7\13\2\2\u0090\u0092\3\2\2\2\u0091") + buf.write("\u0088\3\2\2\2\u0091\u008c\3\2\2\2\u0091\u008d\3\2\2\2") + buf.write("\u0092\u009d\3\2\2\2\u0093\u0094\f\6\2\2\u0094\u0095\5") + buf.write("&\24\2\u0095\u0096\5$\23\7\u0096\u009c\3\2\2\2\u0097\u0098") + buf.write("\f\5\2\2\u0098\u0099\5(\25\2\u0099\u009a\5$\23\6\u009a") + buf.write("\u009c\3\2\2\2\u009b\u0093\3\2\2\2\u009b\u0097\3\2\2\2") + buf.write("\u009c\u009f\3\2\2\2\u009d\u009b\3\2\2\2\u009d\u009e\3") + buf.write("\2\2\2\u009e%\3\2\2\2\u009f\u009d\3\2\2\2\u00a0\u00a1") + buf.write("\t\4\2\2\u00a1\'\3\2\2\2\u00a2\u00a3\t\5\2\2\u00a3)\3") + buf.write("\2\2\2\u00a4\u00a5\7\30\2\2\u00a5+\3\2\2\2\u00a6\u00a7") + buf.write("\b\27\1\2\u00a7\u00a8\7$\2\2\u00a8\u00b3\5,\27\7\u00a9") + buf.write("\u00aa\5$\23\2\u00aa\u00ab\5.\30\2\u00ab\u00ac\5$\23\2") + buf.write("\u00ac\u00b3\3\2\2\2\u00ad\u00b3\7\33\2\2\u00ae\u00af") + buf.write("\7\t\2\2\u00af\u00b0\5,\27\2\u00b0\u00b1\7\13\2\2\u00b1") + buf.write("\u00b3\3\2\2\2\u00b2\u00a6\3\2\2\2\u00b2\u00a9\3\2\2\2") + buf.write("\u00b2\u00ad\3\2\2\2\u00b2\u00ae\3\2\2\2\u00b3\u00ba\3") + buf.write("\2\2\2\u00b4\u00b5\f\5\2\2\u00b5\u00b6\5\60\31\2\u00b6") + buf.write("\u00b7\5,\27\6\u00b7\u00b9\3\2\2\2\u00b8\u00b4\3\2\2\2") + buf.write("\u00b9\u00bc\3\2\2\2\u00ba\u00b8\3\2\2\2\u00ba\u00bb\3") + buf.write("\2\2\2\u00bb-\3\2\2\2\u00bc\u00ba\3\2\2\2\u00bd\u00be") + buf.write("\t\6\2\2\u00be/\3\2\2\2\u00bf\u00c0\t\7\2\2\u00c0\61\3") + buf.write("\2\2\2\u00c1\u00c2\t\b\2\2\u00c2\63\3\2\2\2\13:@LP\u0091") + buf.write("\u009b\u009d\u00b2\u00ba") return buf.getvalue() @@ -86,17 +97,18 @@ class tlangParser ( Parser ): literalNames = [ "", "'if'", "'['", "']'", "'else'", "'repeat'", "'goto'", "'('", "','", "')'", "'='", "'forward'", "'backward'", "'left'", "'right'", "'penup'", "'pendown'", - "'pause'", "'+'", "'-'", "'*'", "'/'", "'pendown?'", - "'<'", "'>'", "'=='", "'!='", "'<='", "'>='", "'&&'", - "'||'", "'!'" ] + "'pause'", "'print'", "'inc'", "'dumpMap'", "'+'", + "'-'", "'*'", "'/'", "'pendown?'", "'<'", "'>'", "'=='", + "'!='", "'<='", "'>='", "'&&'", "'||'", "'!'" ] symbolicNames = [ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", - "", "", "PLUS", "MINUS", "MUL", - "DIV", "PENCOND", "LT", "GT", "EQ", "NEQ", "LTE", - "GTE", "AND", "OR", "NOT", "NUM", "VAR", "NAME", "Whitespace" ] + "", "", "", "", + "", "PLUS", "MINUS", "MUL", "DIV", "PENCOND", + "LT", "GT", "EQ", "NEQ", "LTE", "GTE", "AND", "OR", + "NOT", "NUM", "VAR", "NAME", "Whitespace" ] RULE_start = 0 RULE_instruction_list = 1 @@ -112,21 +124,25 @@ class tlangParser ( Parser ): RULE_moveOp = 11 RULE_penCommand = 12 RULE_pauseCommand = 13 - RULE_expression = 14 - RULE_multiplicative = 15 - RULE_additive = 16 - RULE_unaryArithOp = 17 - RULE_condition = 18 - RULE_binCondOp = 19 - RULE_logicOp = 20 - RULE_value = 21 + RULE_printCommand = 14 + RULE_incrementCommand = 15 + RULE_dumpCommand = 16 + RULE_expression = 17 + RULE_multiplicative = 18 + RULE_additive = 19 + RULE_unaryArithOp = 20 + RULE_condition = 21 + RULE_binCondOp = 22 + RULE_logicOp = 23 + RULE_value = 24 ruleNames = [ "start", "instruction_list", "strict_ilist", "instruction", "conditional", "ifConditional", "ifElseConditional", "loop", "gotoCommand", "assignment", "moveCommand", "moveOp", - "penCommand", "pauseCommand", "expression", "multiplicative", - "additive", "unaryArithOp", "condition", "binCondOp", - "logicOp", "value" ] + "penCommand", "pauseCommand", "printCommand", "incrementCommand", + "dumpCommand", "expression", "multiplicative", "additive", + "unaryArithOp", "condition", "binCondOp", "logicOp", + "value" ] EOF = Token.EOF T__0=1 @@ -146,24 +162,27 @@ class tlangParser ( Parser ): T__14=15 T__15=16 T__16=17 - PLUS=18 - MINUS=19 - MUL=20 - DIV=21 - PENCOND=22 - LT=23 - GT=24 - EQ=25 - NEQ=26 - LTE=27 - GTE=28 - AND=29 - OR=30 - NOT=31 - NUM=32 - VAR=33 - NAME=34 - Whitespace=35 + T__17=18 + T__18=19 + T__19=20 + PLUS=21 + MINUS=22 + MUL=23 + DIV=24 + PENCOND=25 + LT=26 + GT=27 + EQ=28 + NEQ=29 + LTE=30 + GTE=31 + AND=32 + OR=33 + NOT=34 + NUM=35 + VAR=36 + NAME=37 + Whitespace=38 def __init__(self, input:TokenStream, output:TextIO = sys.stdout): super().__init__(input, output) @@ -173,6 +192,7 @@ def __init__(self, input:TokenStream, output:TextIO = sys.stdout): + class StartContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -204,9 +224,9 @@ def start(self): self.enterRule(localctx, 0, self.RULE_start) try: self.enterOuterAlt(localctx, 1) - self.state = 44 + self.state = 50 self.instruction_list() - self.state = 45 + self.state = 51 self.match(tlangParser.EOF) except RecognitionException as re: localctx.exception = re @@ -216,6 +236,7 @@ def start(self): self.exitRule() return localctx + class Instruction_listContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -248,13 +269,13 @@ def instruction_list(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 50 + self.state = 56 self._errHandler.sync(self) _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << tlangParser.T__0) | (1 << tlangParser.T__4) | (1 << tlangParser.T__5) | (1 << tlangParser.T__10) | (1 << tlangParser.T__11) | (1 << tlangParser.T__12) | (1 << tlangParser.T__13) | (1 << tlangParser.T__14) | (1 << tlangParser.T__15) | (1 << tlangParser.T__16) | (1 << tlangParser.VAR))) != 0): - self.state = 47 + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << tlangParser.T__0) | (1 << tlangParser.T__4) | (1 << tlangParser.T__5) | (1 << tlangParser.T__10) | (1 << tlangParser.T__11) | (1 << tlangParser.T__12) | (1 << tlangParser.T__13) | (1 << tlangParser.T__14) | (1 << tlangParser.T__15) | (1 << tlangParser.T__16) | (1 << tlangParser.T__17) | (1 << tlangParser.T__18) | (1 << tlangParser.T__19) | (1 << tlangParser.VAR))) != 0): + self.state = 53 self.instruction() - self.state = 52 + self.state = 58 self._errHandler.sync(self) _la = self._input.LA(1) @@ -266,6 +287,7 @@ def instruction_list(self): self.exitRule() return localctx + class Strict_ilistContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -298,16 +320,16 @@ def strict_ilist(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 54 + self.state = 60 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 53 + self.state = 59 self.instruction() - self.state = 56 + self.state = 62 self._errHandler.sync(self) _la = self._input.LA(1) - if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << tlangParser.T__0) | (1 << tlangParser.T__4) | (1 << tlangParser.T__5) | (1 << tlangParser.T__10) | (1 << tlangParser.T__11) | (1 << tlangParser.T__12) | (1 << tlangParser.T__13) | (1 << tlangParser.T__14) | (1 << tlangParser.T__15) | (1 << tlangParser.T__16) | (1 << tlangParser.VAR))) != 0)): + if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << tlangParser.T__0) | (1 << tlangParser.T__4) | (1 << tlangParser.T__5) | (1 << tlangParser.T__10) | (1 << tlangParser.T__11) | (1 << tlangParser.T__12) | (1 << tlangParser.T__13) | (1 << tlangParser.T__14) | (1 << tlangParser.T__15) | (1 << tlangParser.T__16) | (1 << tlangParser.T__17) | (1 << tlangParser.T__18) | (1 << tlangParser.T__19) | (1 << tlangParser.VAR))) != 0)): break except RecognitionException as re: @@ -318,6 +340,7 @@ def strict_ilist(self): self.exitRule() return localctx + class InstructionContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -352,6 +375,18 @@ def pauseCommand(self): return self.getTypedRuleContext(tlangParser.PauseCommandContext,0) + def printCommand(self): + return self.getTypedRuleContext(tlangParser.PrintCommandContext,0) + + + def incrementCommand(self): + return self.getTypedRuleContext(tlangParser.IncrementCommandContext,0) + + + def dumpCommand(self): + return self.getTypedRuleContext(tlangParser.DumpCommandContext,0) + + def getRuleIndex(self): return tlangParser.RULE_instruction @@ -369,44 +404,59 @@ def instruction(self): localctx = tlangParser.InstructionContext(self, self._ctx, self.state) self.enterRule(localctx, 6, self.RULE_instruction) try: - self.state = 65 + self.state = 74 self._errHandler.sync(self) token = self._input.LA(1) if token in [tlangParser.VAR]: self.enterOuterAlt(localctx, 1) - self.state = 58 + self.state = 64 self.assignment() pass elif token in [tlangParser.T__0]: self.enterOuterAlt(localctx, 2) - self.state = 59 + self.state = 65 self.conditional() pass elif token in [tlangParser.T__4]: self.enterOuterAlt(localctx, 3) - self.state = 60 + self.state = 66 self.loop() pass elif token in [tlangParser.T__10, tlangParser.T__11, tlangParser.T__12, tlangParser.T__13]: self.enterOuterAlt(localctx, 4) - self.state = 61 + self.state = 67 self.moveCommand() pass elif token in [tlangParser.T__14, tlangParser.T__15]: self.enterOuterAlt(localctx, 5) - self.state = 62 + self.state = 68 self.penCommand() pass elif token in [tlangParser.T__5]: self.enterOuterAlt(localctx, 6) - self.state = 63 + self.state = 69 self.gotoCommand() pass elif token in [tlangParser.T__16]: self.enterOuterAlt(localctx, 7) - self.state = 64 + self.state = 70 self.pauseCommand() pass + elif token in [tlangParser.T__17]: + self.enterOuterAlt(localctx, 8) + self.state = 71 + self.printCommand() + pass + elif token in [tlangParser.T__18]: + self.enterOuterAlt(localctx, 9) + self.state = 72 + self.incrementCommand() + pass + elif token in [tlangParser.T__19]: + self.enterOuterAlt(localctx, 10) + self.state = 73 + self.dumpCommand() + pass else: raise NoViableAltException(self) @@ -418,6 +468,7 @@ def instruction(self): self.exitRule() return localctx + class ConditionalContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -449,18 +500,18 @@ def conditional(self): localctx = tlangParser.ConditionalContext(self, self._ctx, self.state) self.enterRule(localctx, 8, self.RULE_conditional) try: - self.state = 69 + self.state = 78 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,3,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 67 + self.state = 76 self.ifConditional() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 68 + self.state = 77 self.ifElseConditional() pass @@ -473,6 +524,7 @@ def conditional(self): self.exitRule() return localctx + class IfConditionalContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -505,15 +557,15 @@ def ifConditional(self): self.enterRule(localctx, 10, self.RULE_ifConditional) try: self.enterOuterAlt(localctx, 1) - self.state = 71 + self.state = 80 self.match(tlangParser.T__0) - self.state = 72 + self.state = 81 self.condition(0) - self.state = 73 + self.state = 82 self.match(tlangParser.T__1) - self.state = 74 + self.state = 83 self.strict_ilist() - self.state = 75 + self.state = 84 self.match(tlangParser.T__2) except RecognitionException as re: localctx.exception = re @@ -523,6 +575,7 @@ def ifConditional(self): self.exitRule() return localctx + class IfElseConditionalContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -558,23 +611,23 @@ def ifElseConditional(self): self.enterRule(localctx, 12, self.RULE_ifElseConditional) try: self.enterOuterAlt(localctx, 1) - self.state = 77 + self.state = 86 self.match(tlangParser.T__0) - self.state = 78 + self.state = 87 self.condition(0) - self.state = 79 + self.state = 88 self.match(tlangParser.T__1) - self.state = 80 + self.state = 89 self.strict_ilist() - self.state = 81 + self.state = 90 self.match(tlangParser.T__2) - self.state = 82 + self.state = 91 self.match(tlangParser.T__3) - self.state = 83 + self.state = 92 self.match(tlangParser.T__1) - self.state = 84 + self.state = 93 self.strict_ilist() - self.state = 85 + self.state = 94 self.match(tlangParser.T__2) except RecognitionException as re: localctx.exception = re @@ -584,6 +637,7 @@ def ifElseConditional(self): self.exitRule() return localctx + class LoopContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -616,15 +670,15 @@ def loop(self): self.enterRule(localctx, 14, self.RULE_loop) try: self.enterOuterAlt(localctx, 1) - self.state = 87 + self.state = 96 self.match(tlangParser.T__4) - self.state = 88 + self.state = 97 self.value() - self.state = 89 + self.state = 98 self.match(tlangParser.T__1) - self.state = 90 + self.state = 99 self.strict_ilist() - self.state = 91 + self.state = 100 self.match(tlangParser.T__2) except RecognitionException as re: localctx.exception = re @@ -634,6 +688,7 @@ def loop(self): self.exitRule() return localctx + class GotoCommandContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -665,17 +720,17 @@ def gotoCommand(self): self.enterRule(localctx, 16, self.RULE_gotoCommand) try: self.enterOuterAlt(localctx, 1) - self.state = 93 + self.state = 102 self.match(tlangParser.T__5) - self.state = 94 + self.state = 103 self.match(tlangParser.T__6) - self.state = 95 + self.state = 104 self.expression(0) - self.state = 96 + self.state = 105 self.match(tlangParser.T__7) - self.state = 97 + self.state = 106 self.expression(0) - self.state = 98 + self.state = 107 self.match(tlangParser.T__8) except RecognitionException as re: localctx.exception = re @@ -685,6 +740,7 @@ def gotoCommand(self): self.exitRule() return localctx + class AssignmentContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -716,11 +772,11 @@ def assignment(self): self.enterRule(localctx, 18, self.RULE_assignment) try: self.enterOuterAlt(localctx, 1) - self.state = 100 + self.state = 109 self.match(tlangParser.VAR) - self.state = 101 + self.state = 110 self.match(tlangParser.T__9) - self.state = 102 + self.state = 111 self.expression(0) except RecognitionException as re: localctx.exception = re @@ -730,6 +786,7 @@ def assignment(self): self.exitRule() return localctx + class MoveCommandContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -762,9 +819,9 @@ def moveCommand(self): self.enterRule(localctx, 20, self.RULE_moveCommand) try: self.enterOuterAlt(localctx, 1) - self.state = 104 + self.state = 113 self.moveOp() - self.state = 105 + self.state = 114 self.expression(0) except RecognitionException as re: localctx.exception = re @@ -774,6 +831,7 @@ def moveCommand(self): self.exitRule() return localctx + class MoveOpContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -800,7 +858,7 @@ def moveOp(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 107 + self.state = 116 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << tlangParser.T__10) | (1 << tlangParser.T__11) | (1 << tlangParser.T__12) | (1 << tlangParser.T__13))) != 0)): self._errHandler.recoverInline(self) @@ -815,6 +873,7 @@ def moveOp(self): self.exitRule() return localctx + class PenCommandContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -841,7 +900,7 @@ def penCommand(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 109 + self.state = 118 _la = self._input.LA(1) if not(_la==tlangParser.T__14 or _la==tlangParser.T__15): self._errHandler.recoverInline(self) @@ -856,6 +915,7 @@ def penCommand(self): self.exitRule() return localctx + class PauseCommandContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -881,7 +941,7 @@ def pauseCommand(self): self.enterRule(localctx, 26, self.RULE_pauseCommand) try: self.enterOuterAlt(localctx, 1) - self.state = 111 + self.state = 120 self.match(tlangParser.T__16) except RecognitionException as re: localctx.exception = re @@ -891,6 +951,132 @@ def pauseCommand(self): self.exitRule() return localctx + + class PrintCommandContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def expression(self): + return self.getTypedRuleContext(tlangParser.ExpressionContext,0) + + + def getRuleIndex(self): + return tlangParser.RULE_printCommand + + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitPrintCommand" ): + return visitor.visitPrintCommand(self) + else: + return visitor.visitChildren(self) + + + + + def printCommand(self): + + localctx = tlangParser.PrintCommandContext(self, self._ctx, self.state) + self.enterRule(localctx, 28, self.RULE_printCommand) + try: + self.enterOuterAlt(localctx, 1) + self.state = 122 + self.match(tlangParser.T__17) + self.state = 123 + self.match(tlangParser.T__6) + self.state = 124 + self.expression(0) + self.state = 125 + self.match(tlangParser.T__8) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class IncrementCommandContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def VAR(self): + return self.getToken(tlangParser.VAR, 0) + + def getRuleIndex(self): + return tlangParser.RULE_incrementCommand + + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitIncrementCommand" ): + return visitor.visitIncrementCommand(self) + else: + return visitor.visitChildren(self) + + + + + def incrementCommand(self): + + localctx = tlangParser.IncrementCommandContext(self, self._ctx, self.state) + self.enterRule(localctx, 30, self.RULE_incrementCommand) + try: + self.enterOuterAlt(localctx, 1) + self.state = 127 + self.match(tlangParser.T__18) + self.state = 128 + self.match(tlangParser.T__6) + self.state = 129 + self.match(tlangParser.VAR) + self.state = 130 + self.match(tlangParser.T__8) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class DumpCommandContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + + def getRuleIndex(self): + return tlangParser.RULE_dumpCommand + + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitDumpCommand" ): + return visitor.visitDumpCommand(self) + else: + return visitor.visitChildren(self) + + + + + def dumpCommand(self): + + localctx = tlangParser.DumpCommandContext(self, self._ctx, self.state) + self.enterRule(localctx, 32, self.RULE_dumpCommand) + try: + self.enterOuterAlt(localctx, 1) + self.state = 132 + self.match(tlangParser.T__19) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class ExpressionContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -1012,11 +1198,11 @@ def expression(self, _p:int=0): _parentState = self.state localctx = tlangParser.ExpressionContext(self, self._ctx, _parentState) _prevctx = localctx - _startState = 28 - self.enterRecursionRule(localctx, 28, self.RULE_expression, _p) + _startState = 34 + self.enterRecursionRule(localctx, 34, self.RULE_expression, _p) try: self.enterOuterAlt(localctx, 1) - self.state = 122 + self.state = 143 self._errHandler.sync(self) token = self._input.LA(1) if token in [tlangParser.MINUS]: @@ -1024,34 +1210,34 @@ def expression(self, _p:int=0): self._ctx = localctx _prevctx = localctx - self.state = 114 + self.state = 135 self.unaryArithOp() - self.state = 115 + self.state = 136 self.expression(5) pass elif token in [tlangParser.NUM, tlangParser.VAR]: localctx = tlangParser.ValueExprContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 117 + self.state = 138 self.value() pass elif token in [tlangParser.T__6]: localctx = tlangParser.ParenExprContext(self, localctx) self._ctx = localctx _prevctx = localctx - self.state = 118 + self.state = 139 self.match(tlangParser.T__6) - self.state = 119 + self.state = 140 self.expression(0) - self.state = 120 + self.state = 141 self.match(tlangParser.T__8) pass else: raise NoViableAltException(self) self._ctx.stop = self._input.LT(-1) - self.state = 134 + self.state = 155 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,6,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: @@ -1059,37 +1245,37 @@ def expression(self, _p:int=0): if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx - self.state = 132 + self.state = 153 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,5,self._ctx) if la_ == 1: localctx = tlangParser.MulExprContext(self, tlangParser.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 124 + self.state = 145 if not self.precpred(self._ctx, 4): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 4)") - self.state = 125 + self.state = 146 self.multiplicative() - self.state = 126 + self.state = 147 self.expression(5) pass elif la_ == 2: localctx = tlangParser.AddExprContext(self, tlangParser.ExpressionContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 128 + self.state = 149 if not self.precpred(self._ctx, 3): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 3)") - self.state = 129 + self.state = 150 self.additive() - self.state = 130 + self.state = 151 self.expression(4) pass - self.state = 136 + self.state = 157 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,6,self._ctx) @@ -1101,6 +1287,7 @@ def expression(self, _p:int=0): self.unrollRecursionContexts(_parentctx) return localctx + class MultiplicativeContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -1128,11 +1315,11 @@ def accept(self, visitor:ParseTreeVisitor): def multiplicative(self): localctx = tlangParser.MultiplicativeContext(self, self._ctx, self.state) - self.enterRule(localctx, 30, self.RULE_multiplicative) + self.enterRule(localctx, 36, self.RULE_multiplicative) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 137 + self.state = 158 _la = self._input.LA(1) if not(_la==tlangParser.MUL or _la==tlangParser.DIV): self._errHandler.recoverInline(self) @@ -1147,6 +1334,7 @@ def multiplicative(self): self.exitRule() return localctx + class AdditiveContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -1174,11 +1362,11 @@ def accept(self, visitor:ParseTreeVisitor): def additive(self): localctx = tlangParser.AdditiveContext(self, self._ctx, self.state) - self.enterRule(localctx, 32, self.RULE_additive) + self.enterRule(localctx, 38, self.RULE_additive) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 139 + self.state = 160 _la = self._input.LA(1) if not(_la==tlangParser.PLUS or _la==tlangParser.MINUS): self._errHandler.recoverInline(self) @@ -1193,6 +1381,7 @@ def additive(self): self.exitRule() return localctx + class UnaryArithOpContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -1217,10 +1406,10 @@ def accept(self, visitor:ParseTreeVisitor): def unaryArithOp(self): localctx = tlangParser.UnaryArithOpContext(self, self._ctx, self.state) - self.enterRule(localctx, 34, self.RULE_unaryArithOp) + self.enterRule(localctx, 40, self.RULE_unaryArithOp) try: self.enterOuterAlt(localctx, 1) - self.state = 141 + self.state = 162 self.match(tlangParser.MINUS) except RecognitionException as re: localctx.exception = re @@ -1230,6 +1419,7 @@ def unaryArithOp(self): self.exitRule() return localctx + class ConditionContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -1280,46 +1470,46 @@ def condition(self, _p:int=0): _parentState = self.state localctx = tlangParser.ConditionContext(self, self._ctx, _parentState) _prevctx = localctx - _startState = 36 - self.enterRecursionRule(localctx, 36, self.RULE_condition, _p) + _startState = 42 + self.enterRecursionRule(localctx, 42, self.RULE_condition, _p) try: self.enterOuterAlt(localctx, 1) - self.state = 155 + self.state = 176 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,7,self._ctx) if la_ == 1: - self.state = 144 + self.state = 165 self.match(tlangParser.NOT) - self.state = 145 + self.state = 166 self.condition(5) pass elif la_ == 2: - self.state = 146 + self.state = 167 self.expression(0) - self.state = 147 + self.state = 168 self.binCondOp() - self.state = 148 + self.state = 169 self.expression(0) pass elif la_ == 3: - self.state = 150 + self.state = 171 self.match(tlangParser.PENCOND) pass elif la_ == 4: - self.state = 151 + self.state = 172 self.match(tlangParser.T__6) - self.state = 152 + self.state = 173 self.condition(0) - self.state = 153 + self.state = 174 self.match(tlangParser.T__8) pass self._ctx.stop = self._input.LT(-1) - self.state = 163 + self.state = 184 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,8,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: @@ -1329,15 +1519,15 @@ def condition(self, _p:int=0): _prevctx = localctx localctx = tlangParser.ConditionContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_condition) - self.state = 157 + self.state = 178 if not self.precpred(self._ctx, 3): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 3)") - self.state = 158 + self.state = 179 self.logicOp() - self.state = 159 + self.state = 180 self.condition(4) - self.state = 165 + self.state = 186 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,8,self._ctx) @@ -1349,6 +1539,7 @@ def condition(self, _p:int=0): self.unrollRecursionContexts(_parentctx) return localctx + class BinCondOpContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -1388,11 +1579,11 @@ def accept(self, visitor:ParseTreeVisitor): def binCondOp(self): localctx = tlangParser.BinCondOpContext(self, self._ctx, self.state) - self.enterRule(localctx, 38, self.RULE_binCondOp) + self.enterRule(localctx, 44, self.RULE_binCondOp) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 166 + self.state = 187 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << tlangParser.LT) | (1 << tlangParser.GT) | (1 << tlangParser.EQ) | (1 << tlangParser.NEQ) | (1 << tlangParser.LTE) | (1 << tlangParser.GTE))) != 0)): self._errHandler.recoverInline(self) @@ -1407,6 +1598,7 @@ def binCondOp(self): self.exitRule() return localctx + class LogicOpContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -1434,11 +1626,11 @@ def accept(self, visitor:ParseTreeVisitor): def logicOp(self): localctx = tlangParser.LogicOpContext(self, self._ctx, self.state) - self.enterRule(localctx, 40, self.RULE_logicOp) + self.enterRule(localctx, 46, self.RULE_logicOp) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 168 + self.state = 189 _la = self._input.LA(1) if not(_la==tlangParser.AND or _la==tlangParser.OR): self._errHandler.recoverInline(self) @@ -1453,6 +1645,7 @@ def logicOp(self): self.exitRule() return localctx + class ValueContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -1480,11 +1673,11 @@ def accept(self, visitor:ParseTreeVisitor): def value(self): localctx = tlangParser.ValueContext(self, self._ctx, self.state) - self.enterRule(localctx, 42, self.RULE_value) + self.enterRule(localctx, 48, self.RULE_value) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 170 + self.state = 191 _la = self._input.LA(1) if not(_la==tlangParser.NUM or _la==tlangParser.VAR): self._errHandler.recoverInline(self) @@ -1504,8 +1697,8 @@ def value(self): def sempred(self, localctx:RuleContext, ruleIndex:int, predIndex:int): if self._predicates == None: self._predicates = dict() - self._predicates[14] = self.expression_sempred - self._predicates[18] = self.condition_sempred + self._predicates[17] = self.expression_sempred + self._predicates[21] = self.condition_sempred pred = self._predicates.get(ruleIndex, None) if pred is None: raise Exception("No predicate with index:" + str(ruleIndex)) diff --git a/ChironCore/turtparse/tlangVisitor.py b/ChironCore/turtparse/tlangVisitor.py index 7ac289a..68574ed 100644 --- a/ChironCore/turtparse/tlangVisitor.py +++ b/ChironCore/turtparse/tlangVisitor.py @@ -79,6 +79,21 @@ def visitPauseCommand(self, ctx:tlangParser.PauseCommandContext): return self.visitChildren(ctx) + # Visit a parse tree produced by tlangParser#printCommand. + def visitPrintCommand(self, ctx:tlangParser.PrintCommandContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by tlangParser#incrementCommand. + def visitIncrementCommand(self, ctx:tlangParser.IncrementCommandContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by tlangParser#dumpCommand. + def visitDumpCommand(self, ctx:tlangParser.DumpCommandContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by tlangParser#unaryExpr. def visitUnaryExpr(self, ctx:tlangParser.UnaryExprContext): return self.visitChildren(ctx) diff --git a/pull_request_template.md b/pull_request_template.md new file mode 100644 index 0000000..3fa175c --- /dev/null +++ b/pull_request_template.md @@ -0,0 +1,277 @@ +# Pull Request Template for Feature Additions. + +## Brief description feature + +The path profiling is being done as discussed in the Ball Larus Path Profiling paper. + +This involves: +1. Saving the original IR +2. Identifying paths in the CFG +3. Computing edge weights +4. Instrumenting the IR +5. Running the instrumented program +6. Reporting the results + +The static branch predictor is build by indexing the predictor table with the (path id, program counter) \ +On running any program, the control flow graph is generated in the file **`control_flow_graph.png`** using which we can track down the paths shown in the file **`path_profile_data.txt`** + +We have added **two new flags** in our project: + +1. **`-bl`** – for generating Ball-Larus path profiling data. +2. **`-bl_op`** – for generating Ball-Larus path profiling data with **branch predictor optimization**. + +## Example + +### Running Ball-Larus Path Profiling Only + +To generate only the Ball-Larus path profiling data, use the command: + +```bash +./chiron.py -bl ./path_profiling_tests/testcase2.tl +``` + +--- + +### Running Ball-Larus Path Profiling with Branch Predictor Optimization + +To generate profiling data along with branch prediction optimization: + +```bash +./chiron.py -bl_op ./BallLarus/inputs.txt ./example/example1.tl +``` + +The directory `path_profiling_tests` contains testcases including if-else, loops, nested loops, and other control flow constructs. These tests can be used for the `-bl` flag.\ +The `inputs.txt` file contains the input parameters for the program, and these parameters can be generated using the `generate_inputs.py` script. + +The directory `path_profiling_op_tests` contains testcases for the `-bl_op` flag. + + + + +On running: + +```bash +./chiron.py -bl ./path_profiling_tests/testcase0.tl +``` + +The following output is generated: + +\*\*File: \*\***`path_profile_data.txt`** + +``` +['START', '4', '5', '8', '10', 'END']: 1 +``` +![CFG Output for testcase0](https://raw.githubusercontent.com/SamyakSinghania/Ball-Larus-PathProfiling/master/ChironCore/path_profiling_tests/cfg0.png) + +**`Explanation:`** From the code and the cfg, we can clearly verify that the path profile generated for the execution is indeed correct.\ + Since, `:var1 = 15` and `:var2 = 30`, the path `START->4->5->8->10->END` is taken. The path profile data is generated based on the execution of the program. + +On running: + +```bash +./chiron.py -bl_op ./BallLarus/inputs.txt ./path_profiling_op_tests/testcase6.tl +``` + +The following output is generated: + +\*\*File: \*\***`predictor_accuracy.txt`** + +``` +Total Count: 7 +Correct Count: 6 +Accuracy: 0.8571428571428571 +----------------------- +Total Count: 7 +Correct Count: 6 +Accuracy: 0.8571428571428571 +----------------------- +``` + +\*\*File: \*\***`path_profile_data.txt`** + +``` +['START', '2', '7', '11', '13', 'END']: 5 +['START', '5', '7', '11', '13', 'END']: 1 +['START', '5', '7', '8', '13', 'END']: 1 +['START', '2', '7', '8', '13', 'END']: 3 +``` + +![CFG Output for testcase6](https://raw.githubusercontent.com/SamyakSinghania/Ball-Larus-PathProfiling/master/ChironCore/path_profiling_op_tests/cfg6.png) + +**`Explanation:`** The values of x,y,z,p were randomly generated based on which a specific path will be taken in the double diamond CFG. These inputs are present in the file `./BallLarus/inputs.txt`. Based on the path profile and execution of branch instructions of the training inputs, a static branch predictor was learned which gives the predictions for the branch instructions of the test inputs. The accuracy of the predictor is also shown in the file **`predictor_accuracy.txt`**. The accuracy is calculated based on the number of correct predictions made by the predictor. + +On running: + +```bash +./chiron.py -bl ./path_profiling_tests/testcase1.tl +``` + +The following output is generated: + +\*\*File: \*\***`path_profile_data.txt`** + +``` +['START', '2', '3']: 1 +['2', '3']: 2 +['2', '7', 'END']: 1  +``` + +On running: + +```bash +./chiron.py -bl ./path_profiling_tests/testcase2.tl +``` + +The following output is generated: + +\*\*File: \*\***`path_profile_data.txt`** + +``` +['START', '2', '3', '4', '5']: 1 +['4', '5']: 9 +['4', '9']: 3 +['2', '3', '4', '5']: 2 +['2', '12', 'END']: 1 +``` + +On running: + +```bash +./chiron.py -bl_op ./BallLarus/inputs.txt ./path_profiling_op_tests/testcase1.tl +```` + +The following output is generated: + +\*\*File: \*\***`predictor_accuracy.txt`** + +``` +Total Count: 88 +Correct Count: 81 +Accuracy: 0.9204545454545454 +------------------------ +Total Count: 107 +Correct Count: 100 +Accuracy: 0.9345794392523364 +------------------------ +``` + +\*\*File: \*\***`path_profile_data.txt`** + +``` +['START', '2', '3', '4', '8', '9']: 8 +['8', '9']: 72 +['8', '13', '23', '24', '28', '29']: 20 +['28', '29']: 125 +['28', '33']: 25 +['2', '3', '4', '8', '9']: 16 +['2', '38', 'END']: 10 +['START', '2', '3', '14', '18', '19']: 2 +['18', '19']: 24 +['18', '23', '24', '28', '29']: 5 +['2', '3', '14', '18', '19']: 4 +['18', '23', '33']: 1 +['8', '13', '23', '33']: 4 +``` + +On running: + +```bash +./chiron.py -bl_op ./BallLarus/inputs.txt ./path_profiling_op_tests/testcase2.tl +``` + +The following output is generated: + +\*\*File: \*\***`predictor_accuracy.txt`** + +``` +Total Count: 37 +Correct Count: 34 +Accuracy: 0.918918918918919 +------------------------ +Total Count: 37 +Correct Count: 34 +Accuracy: 0.918918918918919 +------------------------ +``` + +\*\*File: \*\***`path_profile_data.txt`** + +``` +['START', '2', '3', '4', '5', '6']: 8 +['5', '6']: 28 +['5', '10', '17']: 14 +['2', '3', '4', '5', '6']: 6 +['2', '21', 'END']: 10 +['START', '2', '3', '11', '12', '13']: 2 +['12', '13']: 18 +['12', '17']: 6 +['2', '3', '11', '12', '13']: 4 +``` + +On running: + +```bash +./chiron.py -bl_op ./BallLarus/inputs.txt ./path_profiling_op_tests/testcase3.tl +``` + +The following output is generated: + +\*\*File: \*\***`predictor_accuracy.txt`** + +``` +Total Count: 20 +Correct Count: 18 +Accuracy: 0.9 +------------------------ +Total Count: 20 +Correct Count: 18 +Accuracy: 0.9 +------------------------ +``` + +\*\*File: \*\***`path_profile_data.txt`** + +``` +['START', '2', '6', '7']: 6 +['6', '7']: 18 +['6', '11', '21', 'END']: 6 +['START', '12', '16', '17']: 4 +['16', '17']: 16 +['16', '21', 'END']: 4 +``` + +### Why is the feature interesting? + +Give use cases for the feature. + +```c +Path profiling can be used to perform optimizations like inlining and loop unrolling along frequently executed paths (hot paths). It can also support building a branch predictor or enable speculative optimizations along likely execution paths. +``` + +## Other Details + + +The source code lies in the directory `BallLarus`. The main implementation of the algorithm is in the file: + +``` +/ChironCore/BallLarus/ballLarus.py +``` + +This directory also includes a dedicated interpreter for Ball-Larus, derived from the pre-existing interpreter for better modularity. + +The file generate_inputs.py in ChironCore/BallLarus/ can be used to generate multiple input flags for usage of -bl_op flag. + +The following files are generated upon running the profiling: + +1. **`hash_dump.txt`**\ + Contains the path indexes along with their frequencies. + +2. **`path_profile_data.txt`**\ + Contains the actual path profile data along with their frequencies. + +3. **`predictions_pc.txt`**\ + Contains the program counter (PC) values and corresponding branch predictor predictions. + +4. **`predictor_accuracy.txt`**\ + Contains the final accuracy of the branch predictor based on the profiling data. +