handle more edge cases
This commit is contained in:
parent
a316be56e2
commit
4af81abcc1
2 changed files with 124 additions and 188 deletions
159
src/parser.zig
159
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);
|
||||
}
|
||||
}
|
||||
|
|
153
src/temp.py
153
src/temp.py
|
@ -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}}},")
|
Loading…
Add table
Reference in a new issue