diff options
| author | uvok | 2026-01-12 19:36:04 +0100 |
|---|---|---|
| committer | uvok | 2026-01-12 19:36:04 +0100 |
| commit | 3d8c953f57d68b1db169554a22c21819ef4690c1 (patch) | |
| tree | c9ec41f3a564fec08df6e4ab3f803e36985c4862 /nandgame | |
| parent | 126f8afd68fd590ba96d6c94667b6fc29f89bbb2 (diff) | |
Add previous parser experiments
Diffstat (limited to 'nandgame')
| -rw-r--r-- | nandgame/assembler/experiments/lexer1.py | 52 | ||||
| -rw-r--r-- | nandgame/assembler/experiments/parser1.py | 57 | ||||
| -rw-r--r-- | nandgame/assembler/experiments/parser2.py | 67 | ||||
| -rw-r--r-- | nandgame/assembler/experiments/parser3.py | 82 |
4 files changed, 258 insertions, 0 deletions
diff --git a/nandgame/assembler/experiments/lexer1.py b/nandgame/assembler/experiments/lexer1.py new file mode 100644 index 0000000..515a792 --- /dev/null +++ b/nandgame/assembler/experiments/lexer1.py @@ -0,0 +1,52 @@ +# lexer.py +import ply.lex as lex + +tokens = ( + "MOV", + "ADD", + "JMP", + "REGISTER", + "NUMBER", + "IDENT", + "COMMA", + "COLON", +) + +t_COMMA = r"," +t_COLON = r":" + +t_MOV = r"mov" +t_ADD = r"add" +t_JMP = r"jmp" + + +def t_REGISTER(t): + r"[A-Z]" + return t + + +def t_NUMBER(t): + r"\#[0-9]+" + t.value = int(t.value[1:]) + return t + + +def t_IDENT(t): + r"[a-zA-Z_][a-zA-Z0-9_]*" + return t + + +t_ignore = " \t" + + +def t_newline(t): + r"\n+" + lexer.lineno += 1 + pass + + +def t_error(t): + raise SyntaxError(f"Illegal character {t.value[0]!r}") + + +lexer = lex.lex() diff --git a/nandgame/assembler/experiments/parser1.py b/nandgame/assembler/experiments/parser1.py new file mode 100644 index 0000000..b845688 --- /dev/null +++ b/nandgame/assembler/experiments/parser1.py @@ -0,0 +1,57 @@ +# parser.py +import ply.yacc as yacc +from lexer import tokens + + +# AST node types +class Label: + def __init__(self, name): + self.name = name + + +class Instr: + def __init__(self, op, args): + self.op = op + self.args = args + + +def p_program(p): + """program : program line + | line""" + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[2]] + + +def p_line(p): + """line : label + | instruction + | empty""" + p[0] = p[1] + + +def p_label(p): + """label : IDENT COLON""" + p[0] = Label(p[1]) + + +def p_instruction(p): + """instruction : MOV REGISTER COMMA NUMBER + | ADD REGISTER COMMA REGISTER + | JMP IDENT""" + op = p[1] + args = p[2:] + p[0] = Instr(op, args) + + +def p_empty(p): + "empty :" + p[0] = None + + +def p_error(p): + raise SyntaxError("Syntax error") + + +parser = yacc.yacc() diff --git a/nandgame/assembler/experiments/parser2.py b/nandgame/assembler/experiments/parser2.py new file mode 100644 index 0000000..af793fa --- /dev/null +++ b/nandgame/assembler/experiments/parser2.py @@ -0,0 +1,67 @@ +# parser.py +import ply.yacc as yacc +from lexer import tokens + + +class Label: + def __init__(self, name): + self.name = name + + +class Instr: + def __init__(self, op, args): + self.op = op + self.args = args + + +def p_program(p): + """program : lines""" + p[0] = p[1] + + +def p_lines(p): + """lines : lines line + | line""" + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[2]] + + +def p_line(p): + """line : label + | instruction + | empty""" + p[0] = p[1] + + +def p_label(p): + """label : IDENT COLON""" + p[0] = Label(p[1]) + + +def p_instruction_mov(p): + """instruction : MOV REGISTER COMMA NUMBER""" + p[0] = Instr("mov", [p[2], p[4]]) + + +def p_instruction_add(p): + """instruction : ADD REGISTER COMMA REGISTER""" + p[0] = Instr("add", [p[2], p[4]]) + + +def p_instruction_jmp(p): + """instruction : JMP IDENT""" + p[0] = Instr("jmp", [p[2]]) + + +def p_empty(p): + "empty :" + p[0] = None + + +def p_error(p): + raise SyntaxError("Syntax error") + + +parser = yacc.yacc() diff --git a/nandgame/assembler/experiments/parser3.py b/nandgame/assembler/experiments/parser3.py new file mode 100644 index 0000000..f62f2e7 --- /dev/null +++ b/nandgame/assembler/experiments/parser3.py @@ -0,0 +1,82 @@ +# parser.py +import ply.yacc as yacc +from lexer import tokens + +# --- AST node types --- + + +class Label: + def __init__(self, name): + self.name = name + + def __repr__(self): + return f"Label({self.name!r})" + + +class Instr: + def __init__(self, op, args): + self.op = op # "mov", "add", "jmp" + self.args = args # list of operands + + def __repr__(self): + return f"Instr({self.op!r}, {self.args!r})" + + +# --- Grammar --- + + +def p_program(p): + """program : lines""" + p[0] = p[1] + + +def p_lines_multi(p): + """lines : lines line""" + # p[1] is the list so far, p[2] is a single line (Label or Instr) + p[0] = p[1] + if p[2] is not None: + p[0].append(p[2]) + + +def p_lines_single(p): + """lines : line""" + # start list with the single line (unless it's None; but we never produce None here) + p[0] = [p[1]] if p[1] is not None else [] + + +def p_line(p): + """line : label + | instruction""" + p[0] = p[1] + + +def p_label(p): + """label : IDENT COLON""" + p[0] = Label(p[1]) + + +def p_instruction_mov(p): + """instruction : MOV REGISTER COMMA NUMBER""" + # mov A, #123 + p[0] = Instr("mov", [p[2], p[4]]) + + +def p_instruction_add(p): + """instruction : ADD REGISTER COMMA REGISTER""" + # add B, A + p[0] = Instr("add", [p[2], p[4]]) + + +def p_instruction_jmp(p): + """instruction : JMP IDENT""" + # jmp label + p[0] = Instr("jmp", [p[2]]) + + +def p_error(p): + if p is None: + raise SyntaxError("Syntax error at EOF") + else: + raise SyntaxError(f"Syntax error at {p.value!r} (type {p.type})") + +parser = yacc.yacc() |
