mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-31 04:40:52 +00:00
165 lines
4.1 KiB
Plaintext
165 lines
4.1 KiB
Plaintext
mod std;
|
|
|
|
type_alias Tok: struct {
|
|
type: string,
|
|
value: string,
|
|
};
|
|
|
|
fn lex(text: string) -> [Tok] {
|
|
let i = 0;
|
|
let len = std::string_length(text);
|
|
|
|
let toks = std::array_new::<Tok>();
|
|
|
|
while i < len {
|
|
if std::string_contains(" \t\n", text[i]) {
|
|
i += 1;
|
|
if i >= len {
|
|
break;
|
|
}
|
|
}
|
|
if text[i] >= '1' and text[i] <= '9' {
|
|
let value = std::ctos(text[i]);
|
|
i += 1;
|
|
while i < len and text[i] >= '0' and text[i] <= '9' {
|
|
value = std::string_push_char(value, text[i]);
|
|
i += 1;
|
|
}
|
|
let tok = struct { type: "int", value: value };
|
|
std::array_push(toks, tok);
|
|
} else if text[i] == '0' {
|
|
i += 1;
|
|
let tok = struct { type: "int", value: "0" };
|
|
std::array_push(toks, tok);
|
|
} else if text[i] == '+' {
|
|
i += 1;
|
|
let tok = struct { type: "+", value: "+" };
|
|
std::array_push(toks, tok);
|
|
} else if text[i] == '-' {
|
|
i += 1;
|
|
let tok = struct { type: "-", value: "-" };
|
|
std::array_push(toks, tok);
|
|
} else if text[i] == '*' {
|
|
i += 1;
|
|
let tok = struct { type: "*", value: "*" };
|
|
std::array_push(toks, tok);
|
|
} else if text[i] == '/' {
|
|
i += 1;
|
|
let tok = struct { type: "/", value: "/" };
|
|
std::array_push(toks, tok);
|
|
} else if text[i] == '(' {
|
|
i += 1;
|
|
let tok = struct { type: "(", value: "(" };
|
|
std::array_push(toks, tok);
|
|
} else if text[i] == ')' {
|
|
i += 1;
|
|
let tok = struct { type: ")", value: ")" };
|
|
std::array_push(toks, tok);
|
|
} else {
|
|
std::println("error: illegal character '" + std::ctos(text[i]) + "'");
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
toks
|
|
}
|
|
|
|
type_alias Calc: struct {
|
|
toks: [Tok],
|
|
toks_len: int,
|
|
i: int,
|
|
};
|
|
|
|
fn calc_new(text: string) -> Calc {
|
|
let toks = lex(text);
|
|
let toks_len = std::array_length(toks);
|
|
struct { toks: toks, toks_len: toks_len, i: 0 }
|
|
}
|
|
|
|
fn calc_expr(self: Calc) -> int {
|
|
calc_add_sub(self)
|
|
}
|
|
|
|
fn calc_add_sub(self: Calc) -> int {
|
|
let left = calc_mul_div(self);
|
|
loop {
|
|
if self.toks[self.i].type == "+" {
|
|
self.i += 1;
|
|
let right = calc_mul_div(self);
|
|
left = left + right;
|
|
} else if self.toks[self.i].type == "-" {
|
|
self.i += 1;
|
|
let right = calc_mul_div(self);
|
|
left = left - right;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
left
|
|
}
|
|
|
|
fn calc_mul_div(self: Calc) -> int {
|
|
let left = calc_unary(self);
|
|
loop {
|
|
if self.toks[self.i].type == "*" {
|
|
self.i += 1;
|
|
let right = calc_unary(self);
|
|
left = left * right;
|
|
} else if self.toks[self.i].type == "/" {
|
|
self.i += 1;
|
|
let right = calc_unary(self);
|
|
left = left / right;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
left
|
|
|
|
}
|
|
|
|
fn calc_unary(self: Calc) -> int {
|
|
if self.toks[self.i].type == "-" {
|
|
self.i += 1;
|
|
let subject = calc_unary(self);
|
|
-subject
|
|
} else {
|
|
calc_operand(self)
|
|
}
|
|
}
|
|
|
|
fn calc_operand(self: Calc) -> int {
|
|
if self.i >= self.toks_len {
|
|
std::println("error: expected expr");
|
|
0
|
|
} else if self.toks[self.i].type == "int" {
|
|
let val = std::stoi(self.toks[self.i].value);
|
|
self.i += 1;
|
|
val
|
|
} else if self.toks[self.i].type == "(" {
|
|
self.i += 1;
|
|
let val = calc_expr(self);
|
|
if self.i >= self.toks_len or self.toks[self.i].type != ")" {
|
|
std::println("error: missing ')'");
|
|
return 0;
|
|
}
|
|
self.i += 1;
|
|
val
|
|
} else {
|
|
std::println("error: expected expr");
|
|
self.i += 1;
|
|
0
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
loop {
|
|
let line = std::input("> ");
|
|
if line == "exit" {
|
|
break;
|
|
}
|
|
let calc = calc_new(line);
|
|
let val = calc_expr(calc);
|
|
std::println(line);
|
|
}
|
|
}
|