Skip to content

Commit 7f76b95

Browse files
Merge pull request #13 from ian-h-chamberlain/parse-pseudo-opcodes
Parse pseudo opcodes ORG + END
2 parents 0e9e848 + cf2bd0c commit 7f76b95

28 files changed

+947
-687
lines changed

Cargo.lock

Lines changed: 61 additions & 56 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,6 @@
1-
[package]
2-
name = "corewa_rs"
3-
version = "0.1.0"
4-
authors = ["Ian Chamberlain <[email protected]>"]
5-
edition = "2018"
1+
[workspace]
62

7-
[dependencies]
8-
itertools = "0.8.0"
9-
lazy_static = "1.2.0"
10-
pest_derive = "2.1.0"
11-
pest = "2.1.0"
12-
structopt = "0.3.5"
13-
14-
[dev-dependencies]
15-
assert_cmd = "0.11.1"
16-
predicates = "1.0.2"
17-
assert_fs = "0.13.1"
18-
indoc = "0.3.4"
3+
members = [
4+
"corewa_rs",
5+
"testutils",
6+
]

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@
22
A Rust implementation of [Core Wars](http://www.koth.org/index.html).
33

44
The implementation is based on [this introductory guide](http://vyznev.net/corewar/guide.html) to Redcode, as well as the [pMARS '94 reference](http://www.koth.org/info/pmars-redcode-94.txt) and an [annotated version](http://corewar.co.uk/standards/icws94.txt) of the ICWS '94 draft.
5+
6+
## Crates
7+
* `corewa_rs` - the main implementation
8+
* `testutils` - some utilities for working with load files and testing complex predicates

corewa_rs/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "corewa_rs"
3+
version = "0.1.0"
4+
authors = ["Ian Chamberlain <[email protected]>"]
5+
edition = "2018"
6+
7+
[dependencies]
8+
itertools = "0.8.0"
9+
lazy_static = "1.2.0"
10+
pest_derive = "2.1.0"
11+
pest = "2.1.0"
12+
structopt = "0.3.5"
13+
14+
[dev-dependencies]
15+
assert_cmd = "0.11.1"
16+
assert_fs = "0.13.1"
17+
predicates = "1.0.2"
18+
testutils = { path = "../testutils" }
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

corewa_rs/src/load_file.rs

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
use std::fmt;
2+
3+
use lazy_static::lazy_static;
4+
5+
mod program;
6+
mod types;
7+
8+
pub use program::{LabelMap, Program};
9+
pub use types::{AddressMode, Modifier, Opcode, Value};
10+
11+
lazy_static! {
12+
pub static ref DEFAULT_CONSTANTS: LabelMap = {
13+
let mut constants = LabelMap::new();
14+
constants.insert("CORESIZE".into(), 8000);
15+
constants.insert("MAXPROCESSES".into(), 8000);
16+
constants.insert("MAXCYCLES".into(), 80_000);
17+
constants.insert("MAXLENGTH".into(), 100);
18+
constants.insert("MINDISTANCE".into(), 100);
19+
constants.insert("ROUNDS".into(), 1);
20+
21+
// TODO: handle command-line constant redefinition and things like
22+
// CURLINE, VERSION, WARRIORS, PSPACESIZE
23+
constants
24+
};
25+
}
26+
27+
#[derive(Clone, Debug, PartialEq)]
28+
pub struct Field {
29+
pub address_mode: AddressMode,
30+
pub value: Value,
31+
}
32+
33+
impl Default for Field {
34+
fn default() -> Self {
35+
Self {
36+
address_mode: AddressMode::Immediate,
37+
value: Default::default(),
38+
}
39+
}
40+
}
41+
42+
impl fmt::Display for Field {
43+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
44+
f.pad(&format!("{}{}", self.address_mode, self.value))
45+
}
46+
}
47+
48+
impl Field {
49+
pub fn direct(value: i32) -> Self {
50+
Self {
51+
address_mode: AddressMode::Direct,
52+
value: Value::Literal(value),
53+
}
54+
}
55+
56+
pub fn direct_label<S: ToString>(label: S) -> Self {
57+
Self {
58+
address_mode: AddressMode::Direct,
59+
value: Value::Label(label.to_string()),
60+
}
61+
}
62+
63+
pub fn immediate(value: i32) -> Self {
64+
Self {
65+
address_mode: AddressMode::Immediate,
66+
value: Value::Literal(value),
67+
}
68+
}
69+
70+
pub fn resolve(&self, from: usize, labels: &LabelMap) -> Result<Self, String> {
71+
match &self.value {
72+
Value::Literal(_) => Ok(self.clone()),
73+
Value::Label(label) => {
74+
let label_value = labels
75+
.get(label)
76+
.ok_or_else(|| format!("Label '{}' not found", &label))?;
77+
78+
let value = Value::Literal((*label_value as i32) - (from as i32));
79+
80+
Ok(Self {
81+
value,
82+
..self.clone()
83+
})
84+
}
85+
}
86+
}
87+
}
88+
89+
#[derive(Clone, Debug, Default, PartialEq)]
90+
pub struct Instruction {
91+
pub opcode: Opcode,
92+
pub modifier: Modifier,
93+
pub field_a: Field,
94+
pub field_b: Field,
95+
}
96+
97+
impl fmt::Display for Instruction {
98+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99+
f.pad(&format!(
100+
"{}.{:<2} {}, {}",
101+
self.opcode, self.modifier, self.field_a, self.field_b,
102+
))
103+
}
104+
}
105+
106+
impl Instruction {
107+
pub fn new(opcode: Opcode, field_a: Field, field_b: Field) -> Self {
108+
let modifier =
109+
Modifier::default_88_to_94(opcode, field_a.address_mode, field_b.address_mode);
110+
111+
Instruction {
112+
opcode,
113+
modifier,
114+
field_a,
115+
field_b,
116+
}
117+
}
118+
119+
pub fn resolve(&self, from: usize, labels: &LabelMap) -> Result<Self, String> {
120+
let field_a = self.field_a.resolve(from, labels)?;
121+
let field_b = self.field_b.resolve(from, labels)?;
122+
Ok(Self {
123+
field_a,
124+
field_b,
125+
..self.clone()
126+
})
127+
}
128+
}
129+
130+
#[cfg(test)]
131+
mod tests {
132+
use super::*;
133+
134+
#[test]
135+
fn default_instruction() {
136+
let expected_instruction = Instruction {
137+
opcode: Opcode::Dat,
138+
modifier: Modifier::F,
139+
field_a: Field {
140+
address_mode: AddressMode::Immediate,
141+
value: Value::Literal(0),
142+
},
143+
field_b: Field {
144+
address_mode: AddressMode::Immediate,
145+
value: Value::Literal(0),
146+
},
147+
};
148+
149+
assert_eq!(Instruction::default(), expected_instruction)
150+
}
151+
}

0 commit comments

Comments
 (0)