-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.zig
More file actions
126 lines (108 loc) · 4.28 KB
/
parser.zig
File metadata and controls
126 lines (108 loc) · 4.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
const std = @import("std");
const InstructionType = enum {
A_INSTRUCTION,
C_INSTRUCTION,
L_INSTRUCTION,
NO_INSTRUCTION,
};
pub const Parser = struct {
// parse line by line..
reader: std.io.BufferedReader(4096, std.fs.File.Reader),
line_buffer: [4096]u8 = undefined,
line_len: usize = 0,
instruction_type: InstructionType = .NO_INSTRUCTION,
symbol_or_value: []const u8 = "", // for A-Instruction / L-Instruction
current_dest: ?[]const u8 = null,
current_comp: ?[]const u8 = null,
current_jump: ?[]const u8 = null,
eof_reached: bool = false,
current_line: u32 = 0,
pub fn init(file: std.fs.File) Parser {
// buffered reader for reading line by line
return Parser{
.reader = std.io.bufferedReader(file.reader()),
};
}
pub fn hasMoreLines(self: *Parser) bool {
return !self.eof_reached;
}
pub fn instructionType(self: Parser) InstructionType {
return self.instruction_type;
}
pub fn advance(self: *Parser) !void {
while (true) {
// get a line from file & stores it to `line_buffer`
if (try self.reader.reader().readUntilDelimiterOrEof(self.line_buffer[0..], '\n')) |line| {
self.line_len = line.len;
} else {
self.eof_reached = true;
self.instruction_type = .NO_INSTRUCTION;
return;
}
// remove comment & space of parsing line
var line: []const u8 = self.line_buffer[0..self.line_len];
if (std.mem.indexOf(u8, line, "//")) |idx| {
line = line[0..idx];
}
line = std.mem.trim(u8, line, " \t\r\n");
// continue since we didn't read anything
if (line.len == 0) continue;
// initialize
self.symbol_or_value = "";
self.current_dest = null;
self.current_comp = null;
self.current_jump = null;
if (line[0] == '@') {
// A-Instruction ! parse something like @xxx
self.instruction_type = InstructionType.A_INSTRUCTION;
self.symbol_or_value = line[1..];
self.current_line += 1;
} else if (line[0] == '(' and line[line.len - 1] == ')') {
// L-Instruction ! parse something like (xxx) <-- which is label
self.instruction_type = InstructionType.L_INSTRUCTION;
self.symbol_or_value = line[1 .. line.len - 1];
} else {
// C-Instruction ! parse something like M=A+D
// ..There are no spaces between operator & operand
self.instruction_type = InstructionType.C_INSTRUCTION;
const eq_idx = std.mem.indexOf(u8, line, "=");
const semicolon_idx = std.mem.indexOf(u8, line, ";");
var comp_idx: usize = 0;
if (eq_idx) |idx| {
// dest=comp
self.current_dest = line[0..idx];
comp_idx = idx + 1;
} else {
// comp;jump || comp
comp_idx = 0;
}
if (semicolon_idx) |idx| {
// comp;jump
self.current_comp = line[comp_idx..idx];
self.current_jump = line[idx + 1 ..];
} else {
// comp
self.current_comp = line[comp_idx..];
}
self.current_line += 1;
}
break;
}
}
pub fn dest(self: Parser) ?[]const u8 {
std.debug.assert(self.instruction_type == InstructionType.C_INSTRUCTION);
return self.current_dest;
}
pub fn comp(self: Parser) ?[]const u8 {
std.debug.assert(self.instruction_type == InstructionType.C_INSTRUCTION);
return self.current_comp;
}
pub fn jump(self: Parser) ?[]const u8 {
std.debug.assert(self.instruction_type == InstructionType.C_INSTRUCTION);
return self.current_jump;
}
pub fn symbol(self: Parser) []const u8 {
std.debug.assert(self.instruction_type == InstructionType.A_INSTRUCTION or self.instruction_type == InstructionType.L_INSTRUCTION);
return self.symbol_or_value;
}
};