upload code
This commit is contained in:
commit
7e10d070b3
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
219
Cargo.lock
generated
Normal file
219
Cargo.lock
generated
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.152"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pest"
|
||||||
|
version = "2.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"thiserror",
|
||||||
|
"ucd-trie",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pest_derive"
|
||||||
|
version = "2.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bcd6ab1236bbdb3a49027e920e693192ebfe8913f6d60e294de57463a493cfde"
|
||||||
|
dependencies = [
|
||||||
|
"pest",
|
||||||
|
"pest_generator",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pest_generator"
|
||||||
|
version = "2.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275"
|
||||||
|
dependencies = [
|
||||||
|
"pest",
|
||||||
|
"pest_meta",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pest_meta"
|
||||||
|
version = "2.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7ff62f5259e53b78d1af898941cdcdccfae7385cf7d793a6e55de5d05bb4b7d"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"pest",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.76"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.48"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ucd-trie"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zkevm"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"pest",
|
||||||
|
"pest_derive",
|
||||||
|
]
|
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "zkevm"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
either = "1.9.0"
|
||||||
|
pest = "2.7.6"
|
||||||
|
pest_derive = "2.7.6"
|
1112
src/execution.rs
Normal file
1112
src/execution.rs
Normal file
File diff suppressed because it is too large
Load Diff
91
src/main.rs
Normal file
91
src/main.rs
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
use std::fs;
|
||||||
|
|
||||||
|
mod execution;
|
||||||
|
mod zkasm;
|
||||||
|
|
||||||
|
use crate::zkasm::{parse_instruction_list, parse_expr, Definition, Program, Rule, Subroutine, ZkasmParser};
|
||||||
|
use pest::Parser;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let filepath = std::env::args().nth(1).expect("dude, pass a file to decompile");
|
||||||
|
let input = fs::read_to_string(filepath).expect("cannot read file");
|
||||||
|
|
||||||
|
let program = ZkasmParser::parse(Rule::program, &input)
|
||||||
|
.expect("file format is wrong or the parser is wrong")
|
||||||
|
.next()
|
||||||
|
.expect("cannot parse input file as a zkasm program");
|
||||||
|
|
||||||
|
let definitions = program
|
||||||
|
.into_inner()
|
||||||
|
.find_map(|x| match x.as_rule() {
|
||||||
|
Rule::definition_list => Some(x),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut program_ast = Program {
|
||||||
|
constants: Vec::new(),
|
||||||
|
definitions: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for definition in definitions.into_inner() {
|
||||||
|
match definition.as_rule() {
|
||||||
|
Rule::variable => {
|
||||||
|
let mut var = definition.into_inner();
|
||||||
|
let vartype = var.next().unwrap();
|
||||||
|
let varname = var.next().unwrap().as_str();
|
||||||
|
if vartype.as_str() == "GLOBAL" {
|
||||||
|
program_ast
|
||||||
|
.definitions
|
||||||
|
.push(Definition::VariableGlobal(varname.into(), var.next().map(parse_expr)));
|
||||||
|
} else if vartype.as_str() == "CTX" {
|
||||||
|
program_ast
|
||||||
|
.definitions
|
||||||
|
.push(Definition::VariableCTX(varname.into(), var.next().map(parse_expr)));
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::constant => {
|
||||||
|
let mut var = definition.into_inner();
|
||||||
|
let constid = var.next().unwrap().as_str();
|
||||||
|
if let Some(constexpr) = var.next() {
|
||||||
|
program_ast.constants.push((constid.into(), format!("{}", parse_expr(constexpr))));
|
||||||
|
} else {
|
||||||
|
program_ast.constants.push((constid.into(), "0".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::subroutine => {
|
||||||
|
let mut subroutine = definition.into_inner();
|
||||||
|
let name = subroutine.next().unwrap().as_str();
|
||||||
|
if let Some(instructions) = subroutine.next() {
|
||||||
|
let subroutine_ast = Subroutine {
|
||||||
|
name: name.to_string(),
|
||||||
|
instructions: parse_instruction_list(instructions),
|
||||||
|
};
|
||||||
|
program_ast
|
||||||
|
.definitions
|
||||||
|
.push(Definition::Subroutine(subroutine_ast));
|
||||||
|
} else {
|
||||||
|
// empty instruction list, or just a label that is alias to the next
|
||||||
|
let subroutine_ast = Subroutine {
|
||||||
|
name: name.to_string(),
|
||||||
|
instructions: Vec::new(),
|
||||||
|
};
|
||||||
|
program_ast
|
||||||
|
.definitions
|
||||||
|
.push(Definition::Subroutine(subroutine_ast));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::include => {
|
||||||
|
let file = definition.into_inner().next().unwrap().as_str().to_string().replace("\"", "");
|
||||||
|
program_ast.definitions.push(Definition::Include(file));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
program_ast.decompile();
|
||||||
|
}
|
269
src/zkasm.pest
Normal file
269
src/zkasm.pest
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
identifier = @{
|
||||||
|
ASCII_ALPHA ~ ("_" | ASCII_ALPHANUMERIC)*
|
||||||
|
}
|
||||||
|
|
||||||
|
reference = @{
|
||||||
|
"@" ~ identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction_name = @{
|
||||||
|
ASCII_ALPHA_UPPER ~ ("_" | ASCII_ALPHANUMERIC)*
|
||||||
|
}
|
||||||
|
|
||||||
|
register = @{
|
||||||
|
"CTX"
|
||||||
|
| "A"
|
||||||
|
| "B"
|
||||||
|
| "C"
|
||||||
|
| "D"
|
||||||
|
| "E"
|
||||||
|
| "F"
|
||||||
|
| "RR"
|
||||||
|
| "SR"
|
||||||
|
| "SP"
|
||||||
|
| "PC"
|
||||||
|
| "RCX"
|
||||||
|
| "GAS"
|
||||||
|
| "HASHPOS"
|
||||||
|
| "HASH_LEFT"
|
||||||
|
| "HASH_RIGHT"
|
||||||
|
| "OLD_ROOT"
|
||||||
|
| "NEW_ROOT"
|
||||||
|
| "VALUE_LOW"
|
||||||
|
| "VALUE_HIGH"
|
||||||
|
| "SIBLING_VALUE_HASH"
|
||||||
|
| "RKEY_BIT"
|
||||||
|
| "RKEY"
|
||||||
|
| "SIBLING_RKEY"
|
||||||
|
| "LEVEL"
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_scope = {
|
||||||
|
"MEM"
|
||||||
|
| "STACK"
|
||||||
|
| "SYS"
|
||||||
|
}
|
||||||
|
memory_access = {
|
||||||
|
memory_scope ~ ":" ~ expr
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction_right_param_atomic = {
|
||||||
|
memory_access
|
||||||
|
| expr
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction_right_param_list = _{
|
||||||
|
instruction_right_param_atomic ~ "," ~ instruction_right_param_list
|
||||||
|
| instruction_right_param_atomic
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction_right = {
|
||||||
|
instruction_name ~ "(" ~ instruction_right_param_list? ~ ")"
|
||||||
|
| instruction_name
|
||||||
|
}
|
||||||
|
|
||||||
|
assignment = {
|
||||||
|
expr ~ "=>" ~ register ~ ("," ~ register)*
|
||||||
|
}
|
||||||
|
|
||||||
|
dotaccess = @{
|
||||||
|
identifier ~ "." ~ identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
invocation_param_atomic = {
|
||||||
|
dotaccess
|
||||||
|
| identifier
|
||||||
|
| register
|
||||||
|
}
|
||||||
|
|
||||||
|
params = {
|
||||||
|
invocation_param_atomic ~ ("," ~ invocation_param_atomic)*
|
||||||
|
}
|
||||||
|
|
||||||
|
invocation = {
|
||||||
|
identifier ~ "(" ~ params? ~ ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
freeinput_param = {
|
||||||
|
invocation
|
||||||
|
| expr
|
||||||
|
}
|
||||||
|
|
||||||
|
freeinput = {
|
||||||
|
|
||||||
|
| "$${" ~ (!("}") ~ ANY)* ~ "}"
|
||||||
|
| "$0{" ~ (!("}") ~ ANY)* ~ "}"
|
||||||
|
| "${" ~ (!("}") ~ ANY)* ~ "}"
|
||||||
|
| "$"
|
||||||
|
}
|
||||||
|
|
||||||
|
binop = _{
|
||||||
|
power
|
||||||
|
| add
|
||||||
|
| sub
|
||||||
|
| mul
|
||||||
|
| div
|
||||||
|
| mod
|
||||||
|
| shl
|
||||||
|
| shr
|
||||||
|
| xor
|
||||||
|
| and
|
||||||
|
| or
|
||||||
|
| lt
|
||||||
|
| gt
|
||||||
|
| lte
|
||||||
|
| gte
|
||||||
|
| eq
|
||||||
|
| neq
|
||||||
|
| land
|
||||||
|
| lor
|
||||||
|
}
|
||||||
|
power = { "**" }
|
||||||
|
add = { "+" }
|
||||||
|
sub = { "-" }
|
||||||
|
mul = { "*" }
|
||||||
|
div = { "/" }
|
||||||
|
mod = { "%" }
|
||||||
|
shl = { "<<" }
|
||||||
|
shr = { ">>" }
|
||||||
|
xor = { "^" }
|
||||||
|
and = { "&" }
|
||||||
|
or = { "|" }
|
||||||
|
lt = { "<" }
|
||||||
|
gt = { ">" }
|
||||||
|
lte = { "<=" }
|
||||||
|
gte = { ">=" }
|
||||||
|
eq = { "==" }
|
||||||
|
neq = { "!=" }
|
||||||
|
land = { "&&" }
|
||||||
|
lor = { "||" }
|
||||||
|
|
||||||
|
special_variable = @{
|
||||||
|
!("VAR") ~ !("INCLUDE") ~ ("_" | ASCII_ALPHANUMERIC)+ ~ !(":")
|
||||||
|
}
|
||||||
|
|
||||||
|
number = @{
|
||||||
|
"0x" ~ ASCII_HEX_DIGIT+ ~ "n"?
|
||||||
|
| ASCII_DIGIT+ ~ "n"?
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_operand = _{
|
||||||
|
number
|
||||||
|
| constid
|
||||||
|
| freeinput
|
||||||
|
| special_variable
|
||||||
|
| reference
|
||||||
|
| register
|
||||||
|
}
|
||||||
|
|
||||||
|
selfmodifying = _{
|
||||||
|
increment | decrement
|
||||||
|
}
|
||||||
|
increment = {"++"}
|
||||||
|
decrement = {"--"}
|
||||||
|
|
||||||
|
|
||||||
|
exprfragment = _{
|
||||||
|
atomic_operand ~ binop ~ atomic_operand
|
||||||
|
| atomic_operand ~ selfmodifying?
|
||||||
|
| negate_expr
|
||||||
|
| "(" ~ expr_all ~ ")"
|
||||||
|
}
|
||||||
|
expr = {
|
||||||
|
exprfragment ~ (binop ~ exprfragment)*
|
||||||
|
}
|
||||||
|
|
||||||
|
not = { "!" }
|
||||||
|
negate = { "-" }
|
||||||
|
negate_expr = _{
|
||||||
|
(not | negate) ~ expr
|
||||||
|
}
|
||||||
|
|
||||||
|
tenary_expr = {
|
||||||
|
expr ~ "?" ~ expr ~ ":" ~ expr
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_all = _{
|
||||||
|
tenary_expr
|
||||||
|
| negate_expr
|
||||||
|
| expr
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction_type1 = {
|
||||||
|
assignment
|
||||||
|
| expr
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction_type2 = {
|
||||||
|
instruction_right ~ ("," ~ instruction_right)*
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction_type3 = {
|
||||||
|
instruction_type1 ~ ":" ~ instruction_type2
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction = _{
|
||||||
|
instruction_type3
|
||||||
|
| instruction_type1
|
||||||
|
| ":" ~ instruction_type2
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction_list = {
|
||||||
|
instruction ~ (NEWLINE* ~ instruction)*
|
||||||
|
}
|
||||||
|
|
||||||
|
subroutine_id = @{ ("_" | ASCII_ALPHANUMERIC)* }
|
||||||
|
|
||||||
|
subroutine = {
|
||||||
|
subroutine_id ~ ":" ~ NEWLINE* ~ instruction_list?
|
||||||
|
}
|
||||||
|
|
||||||
|
definition = _{
|
||||||
|
constant
|
||||||
|
| variable
|
||||||
|
| subroutine
|
||||||
|
| include
|
||||||
|
}
|
||||||
|
|
||||||
|
definition_list = {
|
||||||
|
definition ~ (NEWLINE* ~ definition)*
|
||||||
|
}
|
||||||
|
|
||||||
|
variable_type = {
|
||||||
|
"GLOBAL"
|
||||||
|
| "CTX"
|
||||||
|
}
|
||||||
|
variable = {
|
||||||
|
"VAR" ~ variable_type ~ identifier ~ ("[" ~ expr ~ "]")?
|
||||||
|
}
|
||||||
|
|
||||||
|
constid = @{
|
||||||
|
"%" ~ identifier
|
||||||
|
}
|
||||||
|
constant = {
|
||||||
|
("CONSTL" | "CONST") ~ constid ~ ("=" ~ expr)?
|
||||||
|
}
|
||||||
|
|
||||||
|
file_path_component = @{
|
||||||
|
(ASCII_ALPHANUMERIC | "_" | "-" | ".")+
|
||||||
|
}
|
||||||
|
file_path = @{
|
||||||
|
file_path_component ~ ("/" ~ file_path_component)*
|
||||||
|
}
|
||||||
|
include_name = @{
|
||||||
|
"\"" ~ file_path ~ "\""
|
||||||
|
}
|
||||||
|
include = {
|
||||||
|
"INCLUDE" ~ include_name
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow newline between
|
||||||
|
program = {
|
||||||
|
SOI ~ NEWLINE* ~ definition_list ~ NEWLINE* ~ EOI
|
||||||
|
}
|
||||||
|
|
||||||
|
WHITESPACE = _{ " " | "\t" }
|
||||||
|
|
||||||
|
comment_type1 = _{ ";" ~ (!NEWLINE ~ ANY)* ~ NEWLINE? }
|
||||||
|
comment_type2 = _{ "/*" ~ (!"*/" ~ ANY)* ~ "*/" }
|
||||||
|
COMMENT = _{ comment_type1 | comment_type2 }
|
623
src/zkasm.rs
Normal file
623
src/zkasm.rs
Normal file
@ -0,0 +1,623 @@
|
|||||||
|
#[derive(pest_derive::Parser)]
|
||||||
|
#[grammar = "zkasm.pest"]
|
||||||
|
pub struct ZkasmParser;
|
||||||
|
|
||||||
|
use pest::iterators::Pair;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::execution::Execution;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum UnaryOp {
|
||||||
|
Negate,
|
||||||
|
Not,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for UnaryOp {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
UnaryOp::Negate => write!(f, "-"),
|
||||||
|
UnaryOp::Not => write!(f, "!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum BinaryOp {
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
|
Lt,
|
||||||
|
Gt,
|
||||||
|
Le,
|
||||||
|
Ge,
|
||||||
|
Eq,
|
||||||
|
Neq,
|
||||||
|
LogicalXor,
|
||||||
|
LogicalAnd,
|
||||||
|
LogicalOr,
|
||||||
|
ArithAnd,
|
||||||
|
ArithOr,
|
||||||
|
ShiftLeft,
|
||||||
|
ShiftRight,
|
||||||
|
Power,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BinaryOp {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let s = match self {
|
||||||
|
BinaryOp::Add => "+",
|
||||||
|
BinaryOp::Sub => "-",
|
||||||
|
BinaryOp::Mul => "*",
|
||||||
|
BinaryOp::Div => "/",
|
||||||
|
BinaryOp::Lt => "<",
|
||||||
|
BinaryOp::Gt => ">",
|
||||||
|
BinaryOp::Le => "<=",
|
||||||
|
BinaryOp::Ge => ">=",
|
||||||
|
BinaryOp::Eq => "==",
|
||||||
|
BinaryOp::Neq => "!=",
|
||||||
|
BinaryOp::ArithOr => "|",
|
||||||
|
BinaryOp::ArithAnd => "&",
|
||||||
|
BinaryOp::LogicalOr => "||",
|
||||||
|
BinaryOp::LogicalAnd => "&&",
|
||||||
|
BinaryOp::ShiftLeft => "<<",
|
||||||
|
BinaryOp::ShiftRight => ">>",
|
||||||
|
BinaryOp::Power => "**",
|
||||||
|
BinaryOp::Mod => "%",
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
write!(f, "{}", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<BinaryOp> for String {
|
||||||
|
fn into(self) -> BinaryOp {
|
||||||
|
match self.as_str() {
|
||||||
|
"+" => BinaryOp::Add,
|
||||||
|
"-" => BinaryOp::Sub,
|
||||||
|
"*" => BinaryOp::Mul,
|
||||||
|
"/" => BinaryOp::Div,
|
||||||
|
"%" => BinaryOp::Mod,
|
||||||
|
"<" => BinaryOp::Lt,
|
||||||
|
">" => BinaryOp::Gt,
|
||||||
|
"<=" => BinaryOp::Le,
|
||||||
|
">=" => BinaryOp::Ge,
|
||||||
|
"==" => BinaryOp::Eq,
|
||||||
|
"!=" => BinaryOp::Neq,
|
||||||
|
"|" => BinaryOp::ArithOr,
|
||||||
|
"&" => BinaryOp::ArithAnd,
|
||||||
|
"||" => BinaryOp::LogicalOr,
|
||||||
|
"&&" => BinaryOp::LogicalAnd,
|
||||||
|
"<<" => BinaryOp::ShiftLeft,
|
||||||
|
">>" => BinaryOp::ShiftRight,
|
||||||
|
"**" => BinaryOp::Power,
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Expr {
|
||||||
|
Unary(UnaryOp, Box<Expr>),
|
||||||
|
Binary(Box<Expr>, BinaryOp, Box<Expr>),
|
||||||
|
Tenary(Box<Expr>, Box<Expr>, Box<Expr>),
|
||||||
|
FreeInput(String),
|
||||||
|
Register(Register),
|
||||||
|
Value(u64),
|
||||||
|
ValueComplex(String), // for hex number
|
||||||
|
NameVariable(String),
|
||||||
|
Increment(Box<Expr>),
|
||||||
|
Decrement(Box<Expr>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Expr {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Expr::Unary(op, expr) => {
|
||||||
|
write!(f, "{}({})", op, expr)
|
||||||
|
}
|
||||||
|
Expr::Binary(lhs, op, rhs) => {
|
||||||
|
write!(f, "({} {} {})", lhs, op, rhs)
|
||||||
|
}
|
||||||
|
Expr::Tenary(expr, ifbranch, elsebranch) => {
|
||||||
|
write!(f, "({} ? {} : {})", expr, ifbranch, elsebranch)
|
||||||
|
}
|
||||||
|
Expr::Register(r) => {
|
||||||
|
write!(f, "{}", r.name())
|
||||||
|
}
|
||||||
|
Expr::Value(v) => {
|
||||||
|
write!(f, "{}", v)
|
||||||
|
}
|
||||||
|
Expr::ValueComplex(v) => {
|
||||||
|
if v.starts_with("0x") {
|
||||||
|
match u64::from_str_radix(v.strip_prefix("0x").unwrap(), 16).ok() {
|
||||||
|
Some(s) => write!(f, "{}/* {} */", s, v),
|
||||||
|
None => write!(f, "{}", v),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::NameVariable(v) => {
|
||||||
|
write!(f, "{}", v)
|
||||||
|
}
|
||||||
|
Expr::FreeInput(free) => {
|
||||||
|
write!(f, "{}", free)
|
||||||
|
}
|
||||||
|
Expr::Increment(e) => {
|
||||||
|
write!(f, "({})++", e)
|
||||||
|
}
|
||||||
|
Expr::Decrement(e) => {
|
||||||
|
write!(f, "({})--", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
pub enum Register {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
D,
|
||||||
|
E,
|
||||||
|
SP,
|
||||||
|
RR,
|
||||||
|
SR,
|
||||||
|
PC,
|
||||||
|
CTX,
|
||||||
|
RCX,
|
||||||
|
GAS,
|
||||||
|
HASHPOS,
|
||||||
|
HASH_LEFT,
|
||||||
|
HASH_RIGHT,
|
||||||
|
OLD_ROOT,
|
||||||
|
NEW_ROOT,
|
||||||
|
VALUE_LOW,
|
||||||
|
VALUE_HIGH,
|
||||||
|
SIBLING_VALUE_HASH,
|
||||||
|
RKEY,
|
||||||
|
SIBLING_RKEY,
|
||||||
|
RKEY_BIT,
|
||||||
|
LEVEL,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Register {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
_ if self.is_special() => write!(f, "{}", self.name()),
|
||||||
|
Register::A => write!(f, "A"),
|
||||||
|
Register::B => write!(f, "B"),
|
||||||
|
Register::C => write!(f, "C"),
|
||||||
|
Register::D => write!(f, "D"),
|
||||||
|
Register::E => write!(f, "E"),
|
||||||
|
Register::SP => write!(f, "SP"),
|
||||||
|
Register::SR => write!(f, "SR"),
|
||||||
|
Register::RR => write!(f, "RR"),
|
||||||
|
Register::PC => write!(f, "PC"),
|
||||||
|
Register::GAS => write!(f, "GAS"),
|
||||||
|
Register::CTX => write!(f, "CTX"),
|
||||||
|
Register::RCX => write!(f, "RCX"),
|
||||||
|
Register::HASHPOS => write!(f, "HASHPOS"),
|
||||||
|
Register::HASH_LEFT => write!(f, "HASH_LEFT"),
|
||||||
|
Register::HASH_RIGHT => write!(f, "HASH_RIGHT"),
|
||||||
|
Register::OLD_ROOT => write!(f, "OLD_ROOT"),
|
||||||
|
Register::NEW_ROOT => write!(f, "NEW_ROOT"),
|
||||||
|
Register::VALUE_LOW => write!(f, "VALUE_LOW"),
|
||||||
|
Register::VALUE_HIGH => write!(f, "VALUE_HIGH"),
|
||||||
|
Register::SIBLING_VALUE_HASH => write!(f, "SIBLING_VALUE_HASH"),
|
||||||
|
Register::RKEY => write!(f, "RKEY"),
|
||||||
|
Register::SIBLING_RKEY => write!(f, "SIBLING_RKEY"),
|
||||||
|
Register::RKEY_BIT => write!(f, "RKEY_BIT"),
|
||||||
|
Register::LEVEL => write!(f, "LEVEL"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Register {
|
||||||
|
pub fn is_special(self) -> bool {
|
||||||
|
match self {
|
||||||
|
Register::A | Register::B | Register::C | Register::D | Register::E => false,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(self) -> String {
|
||||||
|
match self {
|
||||||
|
Register::SR => "StateRoot".to_string(),
|
||||||
|
Register::RR => "ReturnRegister".to_string(),
|
||||||
|
Register::GAS => "GAS".to_string(),
|
||||||
|
Register::HASHPOS => "HASHPOS".to_string(),
|
||||||
|
Register::CTX => "CONTEXT".to_string(),
|
||||||
|
Register::PC => "EVM(ProgramCounter)".to_string(),
|
||||||
|
Register::SP => "EVM(StackPointer)".to_string(),
|
||||||
|
_ => format!("{:?}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_name(name: &str) -> Self {
|
||||||
|
match name {
|
||||||
|
"A" => Register::A,
|
||||||
|
"B" => Register::B,
|
||||||
|
"C" => Register::C,
|
||||||
|
"D" => Register::D,
|
||||||
|
"E" => Register::E,
|
||||||
|
"SP" => Register::SP,
|
||||||
|
"RR" => Register::RR,
|
||||||
|
"SR" => Register::SR,
|
||||||
|
"PC" => Register::PC,
|
||||||
|
"CTX" => Register::CTX,
|
||||||
|
"RCX" => Register::RCX,
|
||||||
|
"GAS" => Register::GAS,
|
||||||
|
"HASHPOS" => Register::HASHPOS,
|
||||||
|
"HASH_LEFT" => Register::HASH_LEFT,
|
||||||
|
"HASH_RIGHT" => Register::HASH_RIGHT,
|
||||||
|
"OLD_ROOT" => Register::OLD_ROOT,
|
||||||
|
"NEW_ROOT" => Register::NEW_ROOT,
|
||||||
|
"VALUE_LOW" => Register::VALUE_LOW,
|
||||||
|
"VALUE_HIGH" => Register::VALUE_HIGH,
|
||||||
|
"SIBLING_VALUE_HASH" => Register::SIBLING_VALUE_HASH,
|
||||||
|
"RKEY" => Register::RKEY,
|
||||||
|
"SIBLING_RKEY" => Register::SIBLING_RKEY,
|
||||||
|
"RKEY_BIT" => Register::RKEY_BIT,
|
||||||
|
"LEVEL" => Register::LEVEL,
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum AccessPlace {
|
||||||
|
Memory,
|
||||||
|
Stack,
|
||||||
|
System,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for AccessPlace {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
AccessPlace::Memory => write!(f, "MEM"),
|
||||||
|
AccessPlace::Stack => write!(f, "STACK"),
|
||||||
|
AccessPlace::System => write!(f, "SYS"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum InstructionOpcodeParam {
|
||||||
|
NameVariable(String),
|
||||||
|
Accessor(AccessPlace, Expr),
|
||||||
|
Calculated(Expr),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for InstructionOpcodeParam {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
InstructionOpcodeParam::NameVariable(name) => {
|
||||||
|
write!(f, "{}", name)
|
||||||
|
}
|
||||||
|
InstructionOpcodeParam::Accessor(access, expr) => {
|
||||||
|
write!(f, "{}:{}", access, expr)
|
||||||
|
}
|
||||||
|
InstructionOpcodeParam::Calculated(expr) => {
|
||||||
|
write!(f, "{}", expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InstructionOpcode {
|
||||||
|
pub name: String,
|
||||||
|
pub params: Vec<InstructionOpcodeParam>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstructionOpcode {
|
||||||
|
pub fn get_single(&self) -> InstructionOpcodeParam {
|
||||||
|
self.params[0].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_at(&self, idx: usize) -> Option<InstructionOpcodeParam> {
|
||||||
|
self.params.get(idx).map(|x| x.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Instruction {
|
||||||
|
Expr(Expr),
|
||||||
|
Assignment(Expr, Vec<Register>),
|
||||||
|
Opcode(InstructionOpcode),
|
||||||
|
Compound(Box<Instruction>, Vec<Instruction>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Subroutine {
|
||||||
|
pub name: String,
|
||||||
|
pub instructions: Vec<Instruction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Definition {
|
||||||
|
VariableGlobal(String, Option<Expr>),
|
||||||
|
VariableCTX(String, Option<Expr>),
|
||||||
|
Subroutine(Subroutine),
|
||||||
|
Include(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
// temporarily use display as a decompile printer
|
||||||
|
impl fmt::Display for Definition {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Definition::VariableCTX(var, Some(array)) => {
|
||||||
|
write!(f, "VAR CTX {}[{}]", var, array)
|
||||||
|
}
|
||||||
|
Definition::VariableGlobal(var, Some(array)) => {
|
||||||
|
write!(f, "VAR GLOBAL {}[{}]", var, array)
|
||||||
|
}
|
||||||
|
Definition::VariableCTX(var, None) => {
|
||||||
|
write!(f, "VAR CTX {}", var)
|
||||||
|
}
|
||||||
|
Definition::VariableGlobal(var, None) => {
|
||||||
|
write!(f, "VAR GLOBAL {}", var)
|
||||||
|
}
|
||||||
|
Definition::Include(include) => {
|
||||||
|
write!(f, "INCLUDE {}", include)
|
||||||
|
}
|
||||||
|
Definition::Subroutine(subroutine) => {
|
||||||
|
// subroutine will be decompiled
|
||||||
|
let mut run = Execution::new();
|
||||||
|
run.start(subroutine);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Program {
|
||||||
|
pub constants: Vec<(String, String)>,
|
||||||
|
pub definitions: Vec<Definition>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Program {
|
||||||
|
pub fn decompile(self) {
|
||||||
|
for c in self.constants {
|
||||||
|
println!("CONST {} = {}", c.0, c.1);
|
||||||
|
}
|
||||||
|
for def in self.definitions {
|
||||||
|
println!("{}", def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_long_expr(expr: Pair<Rule>) -> Expr {
|
||||||
|
use pest::pratt_parser::PrattParser;
|
||||||
|
use pest::pratt_parser::{Assoc, Op};
|
||||||
|
|
||||||
|
assert!(expr.as_rule() == Rule::expr);
|
||||||
|
|
||||||
|
let pratt =
|
||||||
|
PrattParser::new()
|
||||||
|
.op(Op::infix(Rule::r#mod, Assoc::Left))
|
||||||
|
.op(Op::infix(Rule::add, Assoc::Left) | Op::infix(Rule::sub, Assoc::Left))
|
||||||
|
.op(Op::infix(Rule::mul, Assoc::Left) | Op::infix(Rule::div, Assoc::Left))
|
||||||
|
.op(Op::infix(Rule::and, Assoc::Left) | Op::infix(Rule::or, Assoc::Left) | Op::infix(Rule::xor, Assoc::Left))
|
||||||
|
.op(Op::infix(Rule::shl, Assoc::Left) | Op::infix(Rule::shr, Assoc::Left))
|
||||||
|
.op(Op::infix(Rule::power, Assoc::Left))
|
||||||
|
.op(Op::prefix(Rule::not) | Op::prefix(Rule::negate))
|
||||||
|
.op(Op::postfix(Rule::increment) | Op::postfix(Rule::decrement))
|
||||||
|
;
|
||||||
|
|
||||||
|
// println!("{:?}", expr);
|
||||||
|
|
||||||
|
pratt
|
||||||
|
.map_primary(|primary| match primary.as_rule() {
|
||||||
|
Rule::expr => {
|
||||||
|
// ( expr )
|
||||||
|
parse_expr(primary)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
parse_expr_atomic(primary)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map_prefix(|op, rhs| {
|
||||||
|
match op.as_str() {
|
||||||
|
"-" => {
|
||||||
|
Expr::Unary(UnaryOp::Negate, Box::new(rhs))
|
||||||
|
}
|
||||||
|
"!" => {
|
||||||
|
Expr::Unary(UnaryOp::Not, Box::new(rhs))
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}})
|
||||||
|
.map_infix(|lhs, op, rhs| {
|
||||||
|
let binop: BinaryOp = op.as_str().to_string().into();
|
||||||
|
Expr::Binary(Box::new(lhs.clone()), binop, Box::new(rhs.clone()))
|
||||||
|
})
|
||||||
|
.map_postfix(|expr, op| {
|
||||||
|
match op.as_rule() {
|
||||||
|
Rule::decrement => Expr::Decrement(Box::new(expr.clone())),
|
||||||
|
Rule::increment => Expr::Increment(Box::new(expr.clone())),
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.parse(expr.into_inner())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_expr_atomic(expr: Pair<Rule>) -> Expr {
|
||||||
|
match expr.as_rule() {
|
||||||
|
Rule::register => Expr::Register(Register::from_name(expr.as_str())),
|
||||||
|
Rule::number => {
|
||||||
|
match expr.as_str().to_string().parse::<u64>().ok() {
|
||||||
|
Some(v) => Expr::Value(v),
|
||||||
|
None => Expr::ValueComplex(expr.as_str().into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::freeinput => Expr::FreeInput(expr.as_str().into()),
|
||||||
|
Rule::special_variable => {
|
||||||
|
let v = expr.as_str();
|
||||||
|
match v {
|
||||||
|
"A" | "B" | "C" | "D" | "E" | "SR" | "RR" | "SP" | "CTX" | "HASHPOS" => {
|
||||||
|
Expr::Register(Register::from_name(v))
|
||||||
|
}
|
||||||
|
_ => Expr::NameVariable(v.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::constid => {
|
||||||
|
let v = expr.as_str();
|
||||||
|
match v {
|
||||||
|
"A" | "B" | "C" | "D" | "E" | "SR" | "RR" | "SP" | "CTX" | "HASHPOS" => {
|
||||||
|
Expr::Register(Register::from_name(v))
|
||||||
|
}
|
||||||
|
_ => Expr::NameVariable(v.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::reference => {
|
||||||
|
let v = expr.as_str();
|
||||||
|
Expr::NameVariable(v.into())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("parse atomic {:?}", expr);
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_expr(inst: Pair<Rule>) -> Expr {
|
||||||
|
match inst.as_rule() {
|
||||||
|
Rule::expr => {
|
||||||
|
parse_long_expr(inst)
|
||||||
|
// let mut peak = inst.clone().into_inner();
|
||||||
|
|
||||||
|
// if peak.len() > 1 {
|
||||||
|
// return parse_long_expr(inst);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let expr = peak.next().unwrap();
|
||||||
|
// parse_expr_atomic(expr)
|
||||||
|
}
|
||||||
|
Rule::negate_expr => {
|
||||||
|
let mut p = inst.into_inner();
|
||||||
|
let op = match p.next().unwrap().as_str() {
|
||||||
|
"-" => UnaryOp::Negate,
|
||||||
|
"!" => UnaryOp::Not,
|
||||||
|
_ => unreachable!()
|
||||||
|
};
|
||||||
|
let expr = parse_expr(p.next().unwrap());
|
||||||
|
Expr::Unary(op, Box::new(expr))
|
||||||
|
}
|
||||||
|
Rule::tenary_expr => {
|
||||||
|
let mut p = inst.into_inner();
|
||||||
|
let condition = parse_expr(p.next().unwrap());
|
||||||
|
let ifbranch = parse_expr(p.next().unwrap());
|
||||||
|
let elsebranch = parse_expr(p.next().unwrap());
|
||||||
|
Expr::Tenary(Box::new(condition), Box::new(ifbranch), Box::new(elsebranch))
|
||||||
|
}
|
||||||
|
Rule::register | Rule::number | Rule::freeinput | Rule::special_variable | Rule::constid | Rule::reference => {
|
||||||
|
parse_expr_atomic(inst)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_param(param: Pair<Rule>) -> InstructionOpcodeParam {
|
||||||
|
match param.as_rule() {
|
||||||
|
Rule::identifier => InstructionOpcodeParam::NameVariable(param.as_str().into()),
|
||||||
|
Rule::memory_access => {
|
||||||
|
let mut p = param.into_inner();
|
||||||
|
let scope = match p.next().unwrap().as_str() {
|
||||||
|
"MEM" => AccessPlace::Memory,
|
||||||
|
"STACK" => AccessPlace::Stack,
|
||||||
|
"SYS" => AccessPlace::System,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let expr = parse_expr(p.next().unwrap());
|
||||||
|
InstructionOpcodeParam::Accessor(scope, expr)
|
||||||
|
}
|
||||||
|
Rule::expr => {
|
||||||
|
let e = parse_expr(param);
|
||||||
|
if let Expr::NameVariable(name) = e {
|
||||||
|
InstructionOpcodeParam::NameVariable(name)
|
||||||
|
} else {
|
||||||
|
InstructionOpcodeParam::Calculated(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse a single instruction, could be type 1, 2 or 3
|
||||||
|
pub fn parse_instruction(instruction: Pair<Rule>) -> Instruction {
|
||||||
|
// println!("parsing inst {:?}", instruction);
|
||||||
|
match instruction.as_rule() {
|
||||||
|
Rule::instruction_type1 => {
|
||||||
|
let inst = instruction.into_inner().next().unwrap();
|
||||||
|
if inst.as_rule() == Rule::expr {
|
||||||
|
Instruction::Expr(parse_expr(inst))
|
||||||
|
} else if inst.as_rule() == Rule::negate_expr {
|
||||||
|
Instruction::Expr(parse_expr(inst))
|
||||||
|
} else if inst.as_rule() == Rule::assignment {
|
||||||
|
let mut p = inst.into_inner();
|
||||||
|
let expr = parse_expr(p.next().unwrap());
|
||||||
|
let registers: Vec<Register> = p.map(|r| Register::from_name(r.as_str())).collect();
|
||||||
|
Instruction::Assignment(expr, registers)
|
||||||
|
} else {
|
||||||
|
println!("parsing inst {:?}", inst);
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
// println!("typ1 {:?}", inst)
|
||||||
|
}
|
||||||
|
// instruction_type2 is a list of instruction_right and will be resolved using parse_instruction_list
|
||||||
|
Rule::instruction_right => {
|
||||||
|
let mut inst = instruction.into_inner();
|
||||||
|
let name = inst.next().unwrap().as_str();
|
||||||
|
let mut params: Vec<InstructionOpcodeParam> = Vec::new();
|
||||||
|
while let Some(param) = inst.next() {
|
||||||
|
let mut p: Vec<InstructionOpcodeParam> = param.into_inner().map(parse_param).collect();
|
||||||
|
params.append(&mut p);
|
||||||
|
}
|
||||||
|
Instruction::Opcode(InstructionOpcode {
|
||||||
|
name: name.into(),
|
||||||
|
params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Rule::instruction_type3 => {
|
||||||
|
let mut insts = instruction.into_inner();
|
||||||
|
let lhs = parse_instruction(insts.next().unwrap());
|
||||||
|
let rhs = parse_instruction_list(insts.next().unwrap());
|
||||||
|
Instruction::Compound(Box::new(lhs), rhs)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse a list of instruction
|
||||||
|
pub fn parse_instruction_list(instruction_list: Pair<Rule>) -> Vec<Instruction> {
|
||||||
|
let mut parsed_instructions = Vec::new();
|
||||||
|
for instruction in instruction_list.into_inner() {
|
||||||
|
if instruction.as_rule() == Rule::instruction_type2 {
|
||||||
|
// could be many or 1
|
||||||
|
for inst in instruction.into_inner() {
|
||||||
|
parsed_instructions.push(parse_instruction(inst));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parsed_instructions.push(parse_instruction(instruction));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parsed_instructions;
|
||||||
|
}
|
43
test.zkasm
Normal file
43
test.zkasm
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
CONST %aa = 2**32**8 ; atomic ** atomic
|
||||||
|
CONST %aa = 2**32 ; atomic ** atomic
|
||||||
|
CONST %bb = 2**32-1 ; atomic ** atomic ~ rest
|
||||||
|
CONST %bb = (1+1)**32-1 ; expr ** atomic ~ rest
|
||||||
|
CONST %bb = 2**(31+1)-1 ; atomic ** expr ~ rest
|
||||||
|
CONST %bb = (1+1)**(31+1)-1 ; expr ** expr ~ rest
|
||||||
|
CONST %bb = (1+1)**(-32)-1 ; expr ** expr ~ rest
|
||||||
|
CONST %cc = 2**32-1-1 % 10
|
||||||
|
CONST %dd = 2**(32-1) ; good
|
||||||
|
CONST %ee = (2**32)-1 ; good
|
||||||
|
|
||||||
|
|
||||||
|
CONSTL %P2_C0_EGX = %ECGX & 0xFFFF
|
||||||
|
|
||||||
|
a:
|
||||||
|
-1 => B
|
||||||
|
|
||||||
|
CONST %MAX_CNT_PADDING_PG_LIMIT = (%TOTAL_STEPS_LIMIT / 56)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
; CONSTL %FPEC = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2Fn
|
||||||
|
; CONSTL %FPEC_MINUS_ONE = %FPEC - 1
|
||||||
|
; CONSTL %FNEC_DIV_TWO = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0n
|
||||||
|
; CONSTL %FPEC_C2_256 = 0x1000003D1n
|
||||||
|
; CONSTL %FPEC_NON_SQRT = (1n << 256n) - 1n
|
||||||
|
;
|
||||||
|
; CONSTL %FNEC = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141n
|
||||||
|
; CONSTL %FNEC_MINUS_ONE = %FNEC - 1
|
||||||
|
;
|
||||||
|
; CONSTL %ECGX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798n
|
||||||
|
; CONSTL %ECGY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8n
|
||||||
|
; CONSTL %P2_160 = 2n ** 160n
|
||||||
|
; CONSTL %P2_96 = 2n ** 96n
|
||||||
|
|
||||||
|
/*
|
||||||
|
Run:
|
||||||
|
0 => HASH_LEFT, HASH_RIGHT, OLD_ROOT, NEW_ROOT, VALUE_LOW, VALUE_HIGH, SIBLING_VALUE_HASH, RKEY, SIBLING_RKEY, RKEY_BIT, LEVEL
|
||||||
|
*/
|
||||||
|
|
||||||
|
a:
|
||||||
|
A :MSTORE(SP--)
|
Loading…
Reference in New Issue
Block a user