#!/usr/bin/env python3 import sys import ply.yacc as yacc from ply.lex import LexToken # Get the token map from the lexer. This is required. from lexer import tokens import parsetypes as pt # Error rule for syntax errors def p_program(p): """program : instruction_list | empty """ pass def p_empty(p): """empty :""" pass def p_instructions(p): """instruction_list : instruction_list line | line """ if len(p) == 2: p[0] = [p[1]] else: p[0] = p[1] + [p[2]] pass # try right-recursive? def p_instructions2(p): """instruction_list2 : line instruction_list2 | line """ if len(p) == 2: p[0] = [p[1]] else: p[0] = [p[1]] + p[2] print(f"INSes2: {len(p)}") print(f" {p[1]}") if len(p) > 2: print(f" {p[2]}") pass def p_line(p): """line : instruction NL | NL """ if len(p) == 2: pass else: p[0] = p[1] def p_instruction(p): """instruction : no_args | two_arg | three_arg | jumpdest | one_arg_invalid """ print(f"Item: {p[1]}") p[0] = p[1] pass def p_jumpdest(p): """jumpdest : symbol COLON""" p[0] = (p[1],) def p_no_arg(p): """no_args : opcode""" p[0] = (*p[1], None, None, None) pass def p_onearg_invalid(p): """one_arg_invalid : opcode argument""" print(f"Invalid number of arguments: {p[1:]}") sys.exit(1) pass def p_two_arg(p): """two_arg : opcode register COMMA argument""" p[0] = (*p[1], p[2], p[4], None) pass def p_three_arg(p): """three_arg : opcode register COMMA argument COMMA argument""" p[0] = (*p[1], p[2], p[4], p[6]) pass # checks which combinations are allowed is done one level up def p_argument(p): """argument : number | register | symbol """ p[0] = p[1] def p_symbol(p): """symbol : SYMBOL""" p[0] = pt.Symbol(p[1]) def p_register(p): """register : REG""" p[0] = pt.Register(p[1]) def p_opcode(p): """opcode : OP DOT JUMP | OP """ if len(p) == 2: p[0] = (p[1], None) else: p[0] = (p[1], p[3]) def p_number(p): """number : NUMBER | HEXNUMBER """ p[0] = p[1] def p_error(p: LexToken): if p: print(f"Unexpected {repr(p.value)} on line {p.lineno}") else: print("Unexpected end of file.") parser = yacc.yacc()