summaryrefslogtreecommitdiff
path: root/nandgame/assembler/parser.py
diff options
context:
space:
mode:
Diffstat (limited to 'nandgame/assembler/parser.py')
-rw-r--r--nandgame/assembler/parser.py115
1 files changed, 115 insertions, 0 deletions
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()