Skip to content

Commit b717695

Browse files
Major grammar changes to allow END statement
Also some general cleanup of parser code (avoid some unnecessary nesting)
1 parent 3520620 commit b717695

File tree

4 files changed

+205
-115
lines changed

4 files changed

+205
-115
lines changed

src/data/redcode.pest

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
WHITESPACE = _{ " " | "\t" }
22

3-
COMMENT = @{ ";" ~ (!NEWLINE ~ ANY)* ~ &NEWLINE }
3+
COMMENT = @{ ";" ~ (!NEWLINE ~ ANY)* }
44

5-
File = { SOI ~ (Line ~ NEWLINE)+ ~ Line? ~ EOI }
5+
Program = { SOI ~ (Line ~ NEWLINE+)+ ~ Line? ~ (EndProgram | EOI) }
66

7-
Line = { LabelDeclaration* ~ Instruction? }
7+
EndProgram = { ^"END" ~ Expr? }
88

9-
Instruction = _{ Operation ~ Field ~ ("," ~ Field)? }
9+
Line = _{ LabelDeclaration* ~ Instruction? }
1010

11-
LabelDeclaration = _{ !Operation ~ Label ~ (":")? }
11+
Instruction = { Operation ~ Field ~ ("," ~ Field)? }
12+
13+
LabelDeclaration = _{ !(Operation | EndProgram) ~ Label ~ (":")? }
1214

1315
Label = @{ Alpha ~ Alphanumeral* }
1416

@@ -19,7 +21,7 @@ Field = !{ AddressMode? ~ Expr }
1921
Opcode = {
2022
^"DAT" | ^"MOV" | ^"ADD" | ^"SUB" | ^"MUL" | ^"DIV" | ^"MOD" |
2123
^"JMP" | ^"JMZ" | ^"JMN" | ^"DJN" | ^"CMP" | ^"SEQ" | ^"SNE" |
22-
^"SLT" | ^"SPL" | ^"NOP" | ^"ORG" | ^"EQU" | ^"END"
24+
^"SLT" | ^"SPL" | ^"NOP" | ^"ORG" | ^"EQU"
2325
}
2426

2527
Modifier = { ^"AB" | ^"BA" | ^"A" | ^"B" | ^"F" | ^"X" | ^"I" }

src/parser.rs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::{error, fmt, str::FromStr};
22

3-
use itertools::Itertools;
43
use pest::iterators::{Pair, Pairs};
54

65
use crate::load_file::{AddressMode, Field, Instruction, Modifier, Opcode, Program, Value};
@@ -63,29 +62,26 @@ pub fn parse(file_contents: &str) -> Result<ParsedProgram, Error> {
6362

6463
let mut program = Program::new();
6564

66-
let parse_result = grammar::parse(grammar::Rule::File, file_contents)?
65+
let parse_result = grammar::parse(grammar::Rule::Program, file_contents)?
6766
.next()
6867
.ok_or_else(Error::no_input)?;
6968

7069
let mut i = 0;
71-
for mut line_pair in parse_result
70+
for pair in parse_result
7271
.into_inner()
73-
.map(Pair::into_inner)
74-
.filter(|line_pair| line_pair.peek().is_some())
72+
.take_while(|pair| pair.as_rule() != grammar::Rule::EndProgram)
7573
{
76-
let label_pairs = line_pair
77-
.take_while_ref(|pair| pair.as_rule() == grammar::Rule::Label)
78-
.map(|pair| pair.as_str().to_owned());
79-
80-
for label in label_pairs {
81-
if let Err(failed_add) = program.add_label(i, label.to_string()) {
82-
warnings.push(failed_add.into())
74+
match &pair.as_rule() {
75+
grammar::Rule::Label => {
76+
if let Err(failed_add) = program.add_label(i, pair.as_str().to_string()) {
77+
warnings.push(failed_add.into());
78+
}
8379
}
84-
}
85-
86-
if line_pair.peek().is_some() {
87-
program.set(i, parse_instruction(line_pair));
88-
i += 1;
80+
grammar::Rule::Instruction => {
81+
program.set(i, parse_instruction(pair.into_inner()));
82+
i += 1;
83+
}
84+
_ => (),
8985
}
9086
}
9187

@@ -255,7 +251,9 @@ mod tests {
255251
.resolve()
256252
.expect("Should resolve a core with no labels");
257253

258-
let mut parsed = parse(simple_input).expect("Should parse simple file");
254+
let mut parsed = parse(simple_input)
255+
.unwrap_or_else(|err| panic!("Failed to parse simple file: {}", err));
256+
259257
parsed.result.resolve().expect("Parsed file should resolve");
260258

261259
assert!(parsed.warnings.is_empty());

0 commit comments

Comments
 (0)