pseudocode 0.1.3

AP CSP Pseudocode interpreter (rough cut)
Documentation
WHITESPACE = _{ " " }

identifier = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* }

int   =  { ('0'..'9')+  }

number = @{
    int ~ ("." ~ int?)?
}

plus  = { "+" }
minus = { "-" }
neq = { "≠" }
eq = { "=" }
gt = { ">" }
lt = { "<" }
gte = { "≥" }
lte = { "≤" }
modop = { "MOD" }
not = { "NOT" }
mult = { "*" }
div = { "/" }
assign = { "🠐" }
lparen = _{ "(" }
rparen = _{ ")" }
boolean = { "true" | "false" }
exp   = { ^"e" ~ (plus | minus)? ~ int }

string = ${ "\"" ~ inner ~ "\"" }
inner = @{ char* }
char = {
    !("\"" | "\\") ~ ANY
        | "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t")
        | "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4})
}

nl = _{ "\n"+ }

program = _{ SOI ~ nl? ~ (instruction ~ nl)* ~ instruction? ~ EOI }

instruction = _{
    selection_block |
    iteration_block |
    procedure_def |
    display |
    assignment |
    expression
}

// returns a value
value = {
    prefix_op? ~ number |
    string |
    prefix_op? ~ boolean |
    prefix_op? ~ procedure_call |
    prefix_op? ~ identifier |
    prefix_op? ~ lparen ~ expression ~ rparen
}

operator = { (neq|eq|gt|lt|gte|lte|mult|div|plus|minus|modop) }

expression = { value ~ (operator ~ value)* }
prefix_op = { minus | not }
term = _{  value | lparen ~ expression ~ rparen }

display = { "DISPLAY" ~ lparen ~ expression ~ rparen }
assignment = { identifier ~ assign ~ expression }

procedure_call = { identifier ~ lparen ~ arglist? ~ rparen }
arglist = {
    (expression ~ ("," ~ expression)*)
}

selection_block = {
    if_else_expr |
    if_expr
}

if_expr = { "IF" ~ expression ~ block }
if_else_expr =  { "IF" ~ expression ~ block ~ "ELSE" ~ block }

block = {
    "{" ~ nl ~ (block_instruction ~ nl )* ~ "}"
}

block_instruction = {
    selection_block |
    iteration_block |
    display |
    assignment
}

proc_instruction = {
    selection_block |
    iteration_block |
    return_statement |
    display |
    assignment
}

return_statement = {
    "RETURN" ~ expression
}

iteration_block = {
    repeat_until |
    repeat_times |
    for_each
}

repeat_until = { "REPEAT" ~ "UNTIL" ~ expression ~ block }
repeat_times = { "REPEAT" ~ expression ~ "TIMES" ~ block }
for_each = { "FOR" ~ "EACH" ~ identifier ~ "IN" ~ expression ~ block }

procedure_def = {
    "PROCEDURE" ~ identifier ~ lparen ~ paramlist ~ rparen ~ procedure_block
}

procedure_block = {
    "{" ~ nl ~ (proc_instruction ~ nl )* ~ "}"
}


paramlist = {
    (identifier ~ ("," ~ identifier)*)
}