diff options
author | jjanzen <jjanzen@jjanzen.ca> | 2025-02-27 17:40:58 -0600 |
---|---|---|
committer | jjanzen <jjanzen@jjanzen.ca> | 2025-02-27 17:40:58 -0600 |
commit | 4af81abcc1c9555011677da25b89061ce6bc605e (patch) | |
tree | ab4a5bdc6d0b0f831bbece809ea809f929579073 | |
parent | a316be56e292baa2599cc6f08f616196d44c08a6 (diff) |
handle more edge cases
-rw-r--r-- | src/parser.zig | 159 | ||||
-rw-r--r-- | src/temp.py | 153 |
2 files changed, 124 insertions, 188 deletions
diff --git a/src/parser.zig b/src/parser.zig index 9445fee..51ea0ac 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -240,6 +240,16 @@ pub const Parser = struct { const SymbolError = error{ UnexpectedSymbol, + ForwardReference0, + ForwardReference1, + ForwardReference2, + ForwardReference3, + ForwardReference4, + ForwardReference5, + ForwardReference6, + ForwardReference7, + ForwardReference8, + ForwardReference9, }; /// Determine whether the cursor points at a symbol @@ -270,8 +280,25 @@ pub const Parser = struct { } /// Get the number associated with a given symbol - fn handleSymbol(self: *Parser, symbol: []const u8) SymbolError!NumberValue { - // TODO: handle xH, XF, xB + fn readSymbol(self: *Parser, symbol: []const u8) SymbolError!NumberValue { + if (symbol.len == 2 and symbol[0] >= '0' and symbol[0] <= '9' and symbol[1] != 'B') { + if (symbol[1] != 'F') return SymbolError.UnexpectedSymbol; + + return switch (symbol[0]) { + '0' => SymbolError.ForwardReference0, + '1' => SymbolError.ForwardReference1, + '2' => SymbolError.ForwardReference2, + '3' => SymbolError.ForwardReference3, + '4' => SymbolError.ForwardReference4, + '5' => SymbolError.ForwardReference5, + '6' => SymbolError.ForwardReference6, + '7' => SymbolError.ForwardReference7, + '8' => SymbolError.ForwardReference8, + '9' => SymbolError.ForwardReference9, + else => unreachable, + }; + } + const n = self.symbols.get(symbol); if (n == null) return SymbolError.UnexpectedSymbol; return n.?; @@ -289,7 +316,7 @@ pub const Parser = struct { NoEndingDelimiter, UnaryOperationOnString, BinaryOperationOnString, - InvalidOperationOnRegister, + IllegalOperationOnRegister, DivisionByZero, FractionalDivisionOversizedNumerator, }; @@ -300,16 +327,23 @@ pub const Parser = struct { var result: u64 = 0; var last_op = WeakOp.none; var done = false; + var started = false; var register_result: ?u8 = null; var string_result: ?[]const u8 = null; while (!done) { if (string_result != null) return ExpressionError.BinaryOperationOnString; - if (register_result != null) return ExpressionError.InvalidOperationOnRegister; + if (register_result != null) return ExpressionError.IllegalOperationOnRegister; const term = try self.identifyTerm(); switch (term) { - .string => string_result = term.string, + .string => { + if (!started) { + string_result = term.string; + } else { + return ExpressionError.BinaryOperationOnString; + } + }, .number => |nv| { switch (nv) { .pure => |n| { @@ -321,7 +355,13 @@ pub const Parser = struct { WeakOp.none => n, }; }, - .register => register_result = nv.register, + .register => { + if (!started) { + register_result = nv.register; + } else { + return ExpressionError.IllegalOperationOnRegister; + } + }, } }, } @@ -339,6 +379,8 @@ pub const Parser = struct { } else { self.ch_pos += 1; } + + started = true; } if (string_result != null) { @@ -373,7 +415,7 @@ pub const Parser = struct { var done = false; while (!done) { if (string_result != null) return ExpressionError.BinaryOperationOnString; - if (register_result != null) return ExpressionError.InvalidOperationOnRegister; + if (register_result != null) return ExpressionError.IllegalOperationOnRegister; const primary = try self.identifyPrimary(); @@ -415,7 +457,7 @@ pub const Parser = struct { if (!started) { register_result = nv.register; } else { - return ExpressionError.InvalidOperationOnRegister; + return ExpressionError.IllegalOperationOnRegister; } }, } @@ -485,7 +527,7 @@ pub const Parser = struct { const symbol = try self.identifySymbol(); if (symbol.len != 2) return SymbolError.UnexpectedSymbol; if (symbol[1] == 'H') return SymbolError.UnexpectedSymbol; - const symbol_val = try self.handleSymbol(symbol); + const symbol_val = try self.readSymbol(symbol); return ExpressionResult{ .number = symbol_val }; } @@ -555,7 +597,7 @@ pub const Parser = struct { }, else => { const symbol = try self.identifySymbol(); - const symbol_value = try self.handleSymbol(symbol); + const symbol_value = try self.readSymbol(symbol); return ExpressionResult{ .number = symbol_value }; }, } @@ -574,8 +616,8 @@ pub const Parser = struct { return opcodes.parseOp(self.allocator, self.input[start..end]); } - pub fn init(allocator: std.mem.Allocator, input: []const u8) Parser { - return Parser{ + pub fn init(allocator: std.mem.Allocator, input: []const u8) !Parser { + var p = Parser{ .allocator = allocator, .input = input, .location = 0, @@ -583,6 +625,19 @@ pub const Parser = struct { .symbols = std.StringHashMap(NumberValue).init(allocator), .object = std.ArrayList(u8).init(allocator), }; + + try p.symbols.put("0B", NumberValue{ .pure = 0 }); + try p.symbols.put("1B", NumberValue{ .pure = 0 }); + try p.symbols.put("2B", NumberValue{ .pure = 0 }); + try p.symbols.put("3B", NumberValue{ .pure = 0 }); + try p.symbols.put("4B", NumberValue{ .pure = 0 }); + try p.symbols.put("5B", NumberValue{ .pure = 0 }); + try p.symbols.put("6B", NumberValue{ .pure = 0 }); + try p.symbols.put("7B", NumberValue{ .pure = 0 }); + try p.symbols.put("8B", NumberValue{ .pure = 0 }); + try p.symbols.put("9B", NumberValue{ .pure = 0 }); + + return p; } pub fn deinit(self: *Parser) void { @@ -635,7 +690,7 @@ test "symbols are identified" { }; for (0..6) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); const symbol = try parser.identifySymbol(); try std.testing.expect(std.mem.eql(u8, expected[i], symbol)); parser.deinit(); @@ -650,7 +705,7 @@ test "no symbols are found successfully" { }; for (test_cases) |case| { - var parser = Parser.init(std.testing.allocator, case); + var parser = try Parser.init(std.testing.allocator, case); const symbol = parser.identifySymbol(); try std.testing.expectEqual(error.UnexpectedSymbol, symbol); parser.deinit(); @@ -675,7 +730,7 @@ test "opcodes are identified" { }; for (0..5) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); const op = try parser.identifyOperation(); try std.testing.expectEqual(expected[i], op); parser.deinit(); @@ -691,7 +746,7 @@ test "no opcodes are found successfully" { }; for (test_cases) |case| { - var parser = Parser.init(std.testing.allocator, case); + var parser = try Parser.init(std.testing.allocator, case); const symbol = parser.identifyOperation(); try std.testing.expectEqual(error.NoOpcode, symbol); parser.deinit(); @@ -712,7 +767,7 @@ test "decimals are recognized" { }; for (0..3) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); const symbol = try parser.identifyDecimal(); try std.testing.expectEqual(expected[i], symbol); parser.deinit(); @@ -735,7 +790,7 @@ test "malformed decimals are not recognized" { }; for (0..test_cases.len) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); const symbol = parser.identifyDecimal(); try std.testing.expectEqual(expected[i], symbol); parser.deinit(); @@ -756,7 +811,7 @@ test "hexadecimals are recognized" { }; for (0..3) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); const symbol = try parser.identifyHexadecimal(); try std.testing.expectEqual(expected[i], symbol); parser.deinit(); @@ -781,7 +836,7 @@ test "malformed hexadecimals are not recognized" { }; for (0..test_cases.len) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); const symbol = parser.identifyHexadecimal(); try std.testing.expectEqual(expected[i], symbol); parser.deinit(); @@ -802,7 +857,7 @@ test "characters are recognized" { }; for (0..3) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); const symbol = try parser.identifyChar(); try std.testing.expectEqual(expected[i], symbol); parser.deinit(); @@ -829,7 +884,7 @@ test "invalid unicode sequences are not characters" { }; for (0..test_cases.len) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); const symbol = parser.identifyChar(); try std.testing.expectEqual(expected[i], symbol); parser.deinit(); @@ -848,7 +903,7 @@ test "strings are recognized" { }; for (0..2) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); const symbol = try parser.identifyString(); try std.testing.expect(std.mem.eql(u8, expected[i], symbol)); parser.deinit(); @@ -871,7 +926,7 @@ test "invalid strings are not recognized" { }; for (0..test_cases.len) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); const symbol = parser.identifyString(); try std.testing.expectEqual(expected[i], symbol); parser.deinit(); @@ -894,7 +949,7 @@ test "constants are recognized" { }; for (0..4) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); defer parser.deinit(); const symbol = try parser.identifyConstant(); switch (symbol) { @@ -918,7 +973,7 @@ test "invalid constants are recognized" { }; for (0..test_cases.len) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); defer parser.deinit(); const symbol = parser.identifyConstant(); try std.testing.expectEqual(expected[i], symbol); @@ -949,7 +1004,7 @@ test "basic primaries are identified" { }; for (0..test_cases.len) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); defer parser.deinit(); const symbol = try parser.identifyPrimary(); switch (symbol) { @@ -973,7 +1028,7 @@ test "invalid primaries are detected" { }; for (0..test_cases.len) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); defer parser.deinit(); const symbol = parser.identifyPrimary(); try std.testing.expectEqual(expected[i], symbol); @@ -1006,7 +1061,7 @@ test "valid terms are recognized" { }; for (0..test_cases.len) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); defer parser.deinit(); const symbol = try parser.identifyTerm(); @@ -1031,7 +1086,7 @@ test "terms compute the entire chain" { }; for (0..test_cases.len) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); defer parser.deinit(); const symbol = try parser.identifyTerm(); try std.testing.expectEqual(expected[i], symbol); @@ -1049,10 +1104,10 @@ test "strong operations do not work on registers" { }; for (test_cases) |case| { - var parser = Parser.init(std.testing.allocator, case); + var parser = try Parser.init(std.testing.allocator, case); defer parser.deinit(); const symbol = parser.identifyTerm(); - try std.testing.expectEqual(Parser.ExpressionError.InvalidOperationOnRegister, symbol); + try std.testing.expectEqual(Parser.ExpressionError.IllegalOperationOnRegister, symbol); } } @@ -1063,7 +1118,7 @@ test "strong operations do not work on strings" { }; for (test_cases) |case| { - var parser = Parser.init(std.testing.allocator, case); + var parser = try Parser.init(std.testing.allocator, case); defer parser.deinit(); const symbol = parser.identifyTerm(); try std.testing.expectEqual(Parser.ExpressionError.BinaryOperationOnString, symbol); @@ -1079,9 +1134,10 @@ test "expressions are recognized" { "#AA^#FF", "5*5+5", "5*5+5*5", - "#ab<<32+#cdef00&~(#cdef00-1)", + "#ab<<32+k&~(k-1)", "\"hello\"", "$12", + "$$12", }; const expected = [_]ExpressionResult{ @@ -1095,11 +1151,15 @@ test "expressions are recognized" { ExpressionResult{ .number = NumberValue{ .pure = 0xab00000100 } }, ExpressionResult{ .string = "hello" }, ExpressionResult{ .number = NumberValue{ .register = 12 } }, + ExpressionResult{ .number = NumberValue{ .register = 12 } }, }; for (0..test_cases.len) |i| { - var parser = Parser.init(std.testing.allocator, test_cases[i]); + var parser = try Parser.init(std.testing.allocator, test_cases[i]); defer parser.deinit(); + + try parser.symbols.put("k", NumberValue{ .pure = 0xcdef00 }); + const symbol = try parser.identifyExpression(); switch (symbol) { @@ -1108,3 +1168,32 @@ test "expressions are recognized" { } } } + +test "weak operations cannot be applied to strings and registers" { + const test_cases = [_][]const u8{ + "$1+$1", + "2-$2", + "$3|3", + "$4^$4", + "1+\"hello\"", + "\"hello\"-2", + "3|\"hello\"^4", + }; + + const expected = [_]Parser.ExpressionError{ + Parser.ExpressionError.IllegalOperationOnRegister, + Parser.ExpressionError.IllegalOperationOnRegister, + Parser.ExpressionError.IllegalOperationOnRegister, + Parser.ExpressionError.IllegalOperationOnRegister, + Parser.ExpressionError.BinaryOperationOnString, + Parser.ExpressionError.BinaryOperationOnString, + Parser.ExpressionError.BinaryOperationOnString, + }; + + for (0..test_cases.len) |i| { + var parser = try Parser.init(std.testing.allocator, test_cases[i]); + defer parser.deinit(); + const symbol = parser.identifyExpression(); + try std.testing.expectEqual(expected[i], symbol); + } +} diff --git a/src/temp.py b/src/temp.py deleted file mode 100644 index 5577e9e..0000000 --- a/src/temp.py +++ /dev/null @@ -1,153 +0,0 @@ -x = [ - "TRAP", - "FCMP", - "FUN", - "FEQL", - "FADD", - "FIX", - "FSUB", - "FIXU", - "FLOT", - "FLOTU", - "SFLOT", - "SFLOTU", - "FMUL", - "FCMPE", - "FUNE", - "FEQLE", - "FDIV", - "FSQRT", - "FREM", - "FINT", - "MUL", - "MULU", - "DIV", - "DIVU", - "ADD", - "ADDU", - "SUB", - "SUBU", - "2ADDU", - "4ADDU", - "8ADDU", - "16ADDU", - "CMP", - "CMPU", - "NEG", - "NEGU", - "SL", - "SLU", - "SR", - "SRU", - "BN", - "BZ", - "BP", - "BOD", - "BNN", - "BNZ", - "BNP", - "BEV", - "PBN", - "PBZ", - "PBP", - "PBOD", - "PBNN", - "PBNZ", - "PBNP", - "PBEV", - "CSN", - "CSZ", - "CSP", - "CSOD", - "CSNN", - "CSNZ", - "CSNP", - "CSEV", - "ZSN", - "ZSZ", - "ZSP", - "ZSOD", - "ZSNN", - "ZSNZ", - "ZSNP", - "ZSEV", - "LDB", - "LDBU", - "LDW", - "LDWU", - "LDT", - "LDTU", - "LDO", - "LDOU", - "LDSF", - "LDHT", - "CSWAP", - "LDUNC", - "LDVTS", - "PRELD", - "PREGO", - "GO", - "STB", - "STBU", - "STW", - "STWU", - "STT", - "STTU", - "STO", - "STOU", - "STSF", - "STHT", - "STCO", - "STUNC", - "SYNCD", - "PREST", - "SYNCID", - "PUSHGO", - "OR", - "ORN", - "NOR", - "XOR", - "AND", - "ANDN", - "NAND", - "NXOR", - "BDIF", - "WDIF", - "TDIF", - "ODIF", - "MUX", - "SADD", - "MOR", - "MXOR", - "SETH", - "SETMH", - "SETML", - "SETL", - "INCH", - "INCMH", - "INCML", - "INCL", - "ORH", - "ORMH", - "ORML", - "ORL", - "ANDNH", - "ANDNMH", - "ANDNML", - "ANDNL", - "JMP", - "PUSHJ", - "GETA", - "PUT", - "POP", - "RESUME", - "SAVE", - "UNSAVE", - "SYNC", - "SWYM", - "GET", - "TRIP", -] - -for val in x: - print(f"Operation{{.opcode = Opcode.{val}}},") |