1use std::str::FromStr;
4use std::fmt::{Display, Formatter, Error};
5use std::collections::HashMap;
6use core::*;
7use core::Instruction::*;
8use lex::{lex_program, Label, Line};
9
10#[derive(Debug, PartialEq)]
12pub enum ParseProgramError {
13 InvalidLabel,
14 UndefinedLabel(String),
15 DuplicateLabel(String),
16 InvalidOpcode(String),
17 InvalidExpression(String),
18 InvalidRegister(String),
19 MissingOperand(String),
20 TooManyOperands(String),
21}
22
23impl Display for ParseProgramError {
24 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
25 match self {
26 &InvalidLabel => f.write_str("Invalid label"),
27 &UndefinedLabel(ref lbl) => f.write_fmt(format_args!("Undefined label: '{}'", lbl)),
28 &DuplicateLabel(ref lbl) => f.write_fmt(format_args!("Label is already defined: '{}'", lbl)),
29 &InvalidOpcode(ref op) => f.write_fmt(format_args!("Invalid opcode: '{}'", op)),
30 &InvalidExpression(ref expr) => f.write_fmt(format_args!("Invalid expression: '{}'", expr)),
31 &InvalidRegister(ref reg) => f.write_fmt(format_args!("Invalid register: '{}'", reg)),
32 &MissingOperand(ref op) => f.write_fmt(format_args!("Missing operand: '{}'", op)),
33 &TooManyOperands(ref ops) => f.write_fmt(format_args!("Too many operands: '{}'", ops)),
34 }
35 }
36}
37
38pub type ProgramErrors = Vec<(usize, ParseProgramError)>;
40
41use self::ParseProgramError::*;
42
43type ParseResult<T> = Result<T, ParseProgramError>;
45
46pub fn parse_program(src: &str) -> Result<Program, ProgramErrors> {
66 let mut label_map = HashMap::new();
72 let mut instructions = Vec::new();
73 let mut errors = Vec::new();
74
75 let lines = lex_program(src);
76
77 for &Line(line_num, ref maybe_label, _) in lines.iter() {
79 if let &Some(Label(ref name, index)) = maybe_label {
80 if name.len() == 0 {
81 errors.push((line_num, InvalidLabel));
82 } else if let None = label_map.get(name) {
83 label_map.insert(name.clone(), index as isize);
84 } else {
85 errors.push((line_num, DuplicateLabel(name.clone())));
86 }
87 }
88 }
89
90 for &Line(line_num, _, ref lexemes) in lines.iter() {
92 if lexemes.len() > 0 {
93 match parse_instruction(&lexemes[0], &lexemes[1..], &label_map) {
94 Ok(instruction) => instructions.push(instruction),
95 Err(err) => errors.push((line_num, err)),
96 }
97 }
98 }
99
100 if errors.len() > 0 {
101 Err(errors)
102 } else {
103 Ok(instructions)
104 }
105}
106
107fn parse_instruction(opcode: &str, operands: &[String], labels: &HashMap<String, isize>) -> ParseResult<Instruction> {
109 match str::parse::<Opcode>(opcode) {
110 Ok(NOP) => parse_no_operands(Nop, operands),
111 Ok(MOV) => parse_two_operands(Mov, opcode, operands),
112 Ok(SWP) => parse_no_operands(Swp, operands),
113 Ok(SAV) => parse_no_operands(Sav, operands),
114 Ok(ADD) => parse_one_operand(Add, opcode, operands),
115 Ok(SUB) => parse_one_operand(Sub, opcode, operands),
116 Ok(NEG) => parse_no_operands(Neg, operands),
117 Ok(JMP) => parse_jump(Jmp, opcode, operands, labels),
118 Ok(JEZ) => parse_jump(Jez, opcode, operands, labels),
119 Ok(JNZ) => parse_jump(Jnz, opcode, operands, labels),
120 Ok(JGZ) => parse_jump(Jgz, opcode, operands, labels),
121 Ok(JLZ) => parse_jump(Jlz, opcode, operands, labels),
122 Ok(JRO) => parse_one_operand(Jro, opcode, operands),
123 _ => Err(InvalidOpcode(opcode.to_string())),
124 }
125}
126
127fn resolve_label<'a>(label: &str, labels: &'a HashMap<String, isize>) -> ParseResult<&'a isize> {
129 labels.get(label).ok_or(UndefinedLabel(label.to_string()))
130}
131
132fn parse_jump<F: Fn(isize) -> Instruction>(f: F, opcode: &str, operands: &[String], labels: &HashMap<String, isize>) -> ParseResult<Instruction> {
134 if operands.len() < 1 {
135 Err(MissingOperand(opcode.to_string()))
136 } else if operands.len() == 1 {
137 resolve_label(&operands[0], labels).map(|&i| f(i))
138 } else {
139 Err(TooManyOperands(operands[1..].join(" ")))
140 }
141}
142
143fn parse_no_operands(instruction: Instruction, operands: &[String]) -> ParseResult<Instruction> {
145 if operands.len() == 0 {
146 Ok(instruction)
147 } else {
148 Err(TooManyOperands(operands.join(" ")))
149 }
150}
151
152fn parse_one_operand<T: FromStr, F: Fn(T) -> Instruction>(f: F, opcode: &str, operands: &[String]) -> ParseResult<Instruction> {
154 if operands.len() < 1 {
155 Err(MissingOperand(opcode.to_string()))
156 } else if operands.len() == 1 {
157 match str::parse::<T>(&operands[0]) {
158 Ok(op) => Ok(f(op)),
159 Err(_) => Err(InvalidExpression(operands[0].clone())),
160 }
161 } else {
162 Err(TooManyOperands(operands[1..].join(" ")))
163 }
164}
165
166fn parse_two_operands<T: FromStr, U: FromStr, F: Fn(T, U) -> Instruction>(f: F, opcode: &str, operands: &[String]) -> ParseResult<Instruction> {
168 if operands.len() < 2 {
169 Err(MissingOperand(opcode.to_string() + " " + &operands.join(" ")))
170 } else if operands.len() == 2 {
171 match str::parse::<T>(&operands[0]) {
172 Ok(op1) => match str::parse::<U>(&operands[1]) {
173 Ok(op2) => Ok(f(op1, op2)),
174 Err(_) => Err(InvalidRegister(operands[1].clone())),
175 },
176 Err(_) => Err(InvalidExpression(operands[0].clone())),
177 }
178 } else {
179 Err(TooManyOperands(operands[2..].join(" ")))
180 }
181}
182
183#[derive(Debug, PartialEq, Copy, Clone)]
185pub enum Opcode {
186 NOP,
187 MOV,
188 SWP,
189 SAV,
190 ADD,
191 SUB,
192 NEG,
193 JMP,
194 JEZ,
195 JNZ,
196 JGZ,
197 JLZ,
198 JRO,
199}
200
201use self::Opcode::*;
202
203#[derive(Debug, PartialEq)]
205pub struct ParseOpcodeError;
206
207impl FromStr for Opcode {
208 type Err = ParseOpcodeError;
209
210 fn from_str(s: &str) -> Result<Self, Self::Err> {
211 match s {
212 "NOP" => Ok(NOP),
213 "MOV" => Ok(MOV),
214 "SWP" => Ok(SWP),
215 "SAV" => Ok(SAV),
216 "ADD" => Ok(ADD),
217 "SUB" => Ok(SUB),
218 "NEG" => Ok(NEG),
219 "JMP" => Ok(JMP),
220 "JEZ" => Ok(JEZ),
221 "JNZ" => Ok(JNZ),
222 "JGZ" => Ok(JGZ),
223 "JLZ" => Ok(JLZ),
224 "JRO" => Ok(JRO),
225 _ => Err(ParseOpcodeError),
226 }
227 }
228}
229
230#[test]
231fn test_parse_opcode() {
232 assert_eq!(str::parse::<Opcode>("NOP"), Ok(NOP));
233 assert_eq!(str::parse::<Opcode>("MOV"), Ok(MOV));
234 assert_eq!(str::parse::<Opcode>("SWP"), Ok(SWP));
235 assert_eq!(str::parse::<Opcode>("SAV"), Ok(SAV));
236 assert_eq!(str::parse::<Opcode>("ADD"), Ok(ADD));
237 assert_eq!(str::parse::<Opcode>("SUB"), Ok(SUB));
238 assert_eq!(str::parse::<Opcode>("NEG"), Ok(NEG));
239 assert_eq!(str::parse::<Opcode>("JMP"), Ok(JMP));
240 assert_eq!(str::parse::<Opcode>("JEZ"), Ok(JEZ));
241 assert_eq!(str::parse::<Opcode>("JNZ"), Ok(JNZ));
242 assert_eq!(str::parse::<Opcode>("JGZ"), Ok(JGZ));
243 assert_eq!(str::parse::<Opcode>("JLZ"), Ok(JLZ));
244 assert_eq!(str::parse::<Opcode>("JRO"), Ok(JRO));
245 assert_eq!(str::parse::<Opcode>("nop"), Err(ParseOpcodeError));
246 assert_eq!(str::parse::<Opcode>("bad"), Err(ParseOpcodeError));
247}