From 7e2ecc6e1f9e49439696adc72dcbefd699168e44 Mon Sep 17 00:00:00 2001 From: uvok Date: Mon, 12 Jan 2026 19:16:17 +0100 Subject: Add first version of assembler --- nandgame/assembler/parser.py | 115 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 nandgame/assembler/parser.py (limited to 'nandgame/assembler/parser.py') diff --git a/nandgame/assembler/parser.py b/nandgame/assembler/parser.py new file mode 100644 index 0000000..b2cc3f9 --- /dev/null +++ b/nandgame/assembler/parser.py @@ -0,0 +1,115 @@ +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 + +# Error rule for syntax errors + +def p_error(p: LexToken): + if p: + print(f"Unexpected {p.value} on line {p.lineno}") + else: + print("Unexpected end of file.") + +def p_program(p): + '''program : instruction_list + | empty''' + pass + +def p_empty(p): + '''empty :''' + pass + +def p_inss(p): + '''instruction_list : instruction_list instruction + | instruction + ''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[2]] + + # print(f"INSes: {len(p)}") + # print(f" {p[1]}") + # if len(p) > 2: + # print(f" {p[2]}") + pass + +def p_inss2(p): + '''instruction_list2 : instruction instruction_list2 + | instruction + ''' + 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_instruction(p): + '''instruction : noarg + | onearg + | twoarg + | jumpdest + ''' + # | invalid_arg + print(f"INS: {p[1]}") + p[0] = p[1] + pass + +def p_jumpdest(p): + '''jumpdest : SYMBOL COLON''' + p[0] = (p[1], ) + +def p_twoarg(p): + '''twoarg : op REG COMMA argument COMMA argument''' + p[0] = (*p[1], p[2], p[4], p[6]) + pass + +def p_argument(p): + '''argument : number + | REG + | SYMBOL + ''' + pass + +def p_onearg(p): + '''onearg : op REG COMMA argument''' + p[0] = (*p[1], p[2], p[4], None) + pass + +def p_noarg(p): + '''noarg : op''' + p[0] = (*p[1], None, None, None) + pass + +def p_invalid_arg(p): + '''invalid_arg : op argument''' + print(f"Invalid opcode, destination missing: {p[1:]}") + sys.exit(1) + pass + +def p_op(p): + '''op : 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] + +parser = yacc.yacc() -- cgit v1.2.3