ccarp 0.1.2

(trans)Compile C And Rust Partially
Documentation
keyword = @{ ("auto" | "break" | "case" | "char" | "const" | "continue" | "default" | "do" | "double" | "else" | "enum" | "extern" | "float" | "for" | "goto" | "if" | "inline" | "int" | "long" | "register" | "restrict" | "return" | "short" | "signed" | "sizeof" | "static" | "struct" | "switch" | "typedef" | "union" | "unsigned" | "void" | "volatile" | "while" | "_Bool" | "_Complex" | "_Imaginary") ~ !ASCII_ALPHANUMERIC }


nondigit = @{ 'a'..'z' | 'A'..'Z' |  "_" }
digit = @{ '0'..'9' }

ident = @{ !digit ~ (nondigit | digit)+ }


long_long_suffix = @{ "ll" | "LL" }

long_suffix = @{ ^"l" }

unsigned_suffix = @{ ^"u" }

int_suffix = @{ unsigned_suffix ~ (long_long_suffix | long_suffix)? | (long_long_suffix | long_suffix) ~ unsigned_suffix? }

hexadec_digit = @{ digit | 'a'..'f' | 'A'..'F' }

octal_digit = @{ '0'..'7' }

nonzero_digit = @{ '1'..'9' }

hexadec_prefix = @{ "0x" | "0X" }

hexadec_lit = @{ hexadec_prefix ~ hexadec_digit+ }

octal_lit = @{ "0" ~ octal_digit* }

dec_lit = @{ nonzero_digit ~ digit* }

int = @{ hexadec_lit ~ int_suffix? | octal_lit ~ int_suffix? | dec_lit ~ int_suffix? }


float_suffix = @{ "f" | "l" | "F" | "L" }

hexadec_digit_seq = @{ hexadec_digit+ }

digit_seq = @{ digit+ }

sign = @{ "+" | "-" }

bin_exp_part = @{ ^"p" ~ sign? ~ digit_seq }

hexadec_frac_lit = @{ hexadec_digit_seq? ~ "." ~ hexadec_digit_seq | hexadec_digit_seq ~ "." }

exp_part = @{ ^"e" ~ sign? ~ digit_seq }

frac_lit = @{ digit_seq? ~ "." ~ digit_seq  | digit_seq ~ "." }

hexadec_float_lit = @{ hexadec_prefix ~ (hexadec_frac_lit | hexadec_digit_seq) ~ bin_exp_part ~ float_suffix? }

dec_float_lit = @{ frac_lit ~ exp_part? ~ float_suffix? | digit_seq ~ exp_part ~ float_suffix? }

float = @{ hexadec_float_lit | dec_float_lit }


hexadec_esc_seq = @{ "\\x" ~ hexadec_digit+ }

octal_esc_seq = @{ "\\" ~ octal_digit{1,3} }

simple_esc_seq = @{ "\\'" |  "\\\"" |  "\\?" | "\\\\" | "\\a" | "\\b" | "\\f" | "\\n" | "\\r" | "\\t" | "\\v" }

esc_seq = @{ simple_esc_seq | octal_esc_seq | hexadec_esc_seq }

c_char = @{ !("'" | "\\" | NEWLINE) ~ ANY | esc_seq }

char = @{ "L"? ~ "'" ~ c_char+ ~ "'" }


s_char = @{ !("\"" | "\\" | NEWLINE) ~ ANY | esc_seq }

string = @{ "L"? ~ "\"" ~ s_char+ ~ "\"" }


lit = { float | int | char | string }



punct = @{ "[" | "<:" | "]" | ":>" | "(" | ")" | "{" | "<%" | "}" | "%>" | "##" | "%:%:" | "#" | "%:" | "..." | "." | "->" | "++" | "--" | "==" | "=" | "*=" |  "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "/" | "%" | "<<" | ">>" | "<=" | ">=" | "<" | ">" | "!=" | "&&" | "||" | "&" | "*" | "+" | "-" | "~" | "!" | "|" | "^" | "?" | ":" | ";" | "," }

q_char = @{ !("\"" | NEWLINE) ~ ANY }
h_char = @{ !(">" | NEWLINE) ~ ANY }


header_name = @{ "<" ~ h_char* ~ ">" | "\"" ~ q_char* ~ "\""}
include = { "#" ~ "include" ~ header_name }

token = { include | lit | keyword | punct | ident }

tokentree = { WHITESPACE* ~ token* ~ WHITESPACE* }
    tok_ident = { "#i" ~ ident ~ "#i" }
    tok_lit = { "#l" ~ lit ~ "#l" }
    p = _{ "#p" ~ "(" ~ "#p" }
    q = _{ "#p" ~ ")" ~ "#p" }
    s = _{ "#p" ~ ";" ~ "#p" }
    c = _{ "#p" ~ "," ~ "#p" }
    op_br = @{ "#p" ~ ("[" | "<:") ~ "#p" }
    cl_br = @{ "#p" ~ ("]" | ":>") ~ "#p" }
    op_brs = _{ "#p" ~ ("[" | "<:") ~ "#p" }
    cl_brs = _{ "#p" ~ ("]" | ":>") ~ "#p" }
    op_bc = _{ "#p" ~ ("{" | "<%") ~ "#p" }
    cl_bc = _{ "#p" ~ ("}" | "%>") ~ "#p" }


primary_expr = { tok_lit | tok_ident | p ~ expr ~ q}

postfix = { op_brs ~ expr ~ cl_brs | op_parent ~ arg_expr_list? ~ cl_parent | (dot | arrow) ~ tok_ident | inc | dec }
    dot = { "#p" ~ "." ~ "#p" }
    arrow = { "#p" ~ "->" ~ "#p" }
    inc = { "#p" ~ "++" ~ "#p" }
    dec = { "#p" ~ "--" ~ "#p" }
    op_parent = @{ "#p" ~ "(" ~ "#p" }
    cl_parent = @{ "#p" ~ ")" ~ "#p" }

postfix_expr = { primary_expr ~ postfix* | p ~ type_name ~ q ~ op_bc ~ init_list ~ c? ~ cl_bc }

arg_expr_list = { assign_expr ~ (c ~ assign_expr)* }    

unary_expr = { (inc | dec | sizeof) ~ unary_expr | (band | mul | plus | minus | bnot | not) ~ cast_expr | sizeof ~ p ~ type_name ~ q | postfix_expr }
    band = { "#p" ~ "&" ~ "#p" }
    mul  = { "#p" ~ "*" ~ "#p" }
    plus = { "#p" ~ "+" ~ "#p" }
    minus= { "#p" ~ "-" ~ "#p" }
    bnot = { "#p" ~ "~" ~ "#p" }
    not  = { "#p" ~ "!" ~ "#p" }    
    sizeof = { "sizeof" }
    

cast_expr = { p ~ type_name ~ q ~ cast_expr | unary_expr }

mul_expr = { cast_expr ~ ((mul | div | modulo) ~ cast_expr)* }
    div = { "#p" ~ "/" ~ "#p" }
    modulo = { "#p" ~ "%" ~ "#p" }

add_expr = { mul_expr ~ ((plus | minus) ~ mul_expr)* }

shift_expr = { add_expr ~ ((lshift | rshift) ~ add_expr)* }
    lshift = { "#p" ~ "<<" ~ "#p" }
    rshift = { "#p" ~ ">>" ~ "#p" }

rel_expr = { shift_expr ~ ((gt | lt | gte | lte) ~ shift_expr)* }
    gt = { "#p" ~ "<" ~ "#p" }
    lt = { "#p" ~ ">" ~ "#p" }
    gte = { "#p" ~ "<=" ~ "#p" }
    lte = { "#p" ~ ">=" ~ "#p" }

eq_expr = { rel_expr ~ ((eq | neq) ~ rel_expr)* }
    eq = { "#p" ~ "==" ~ "#p" }
    neq = { "#p" ~ "!=" ~ "#p" }

and_expr = { eq_expr ~ ("#p" ~ "&" ~ "#p" ~ eq_expr)* }

xor_expr = { and_expr ~ ("#p" ~ "^" ~ "#p" ~ and_expr)* }

or_expr = { xor_expr ~ ("#p" ~ "|" ~ "#p" ~ xor_expr)* }

log_and_expr = { or_expr ~ ("#p" ~ "&&" ~ "#p" ~ or_expr)* }

log_or_expr = { log_and_expr ~ ("#p" ~ "||" ~ "#p" ~ log_and_expr)* }

cond_expr = { (log_or_expr ~ "#p" ~ "?" ~ "#p" ~ expr ~ "#p" ~ ":" ~ "#p")* ~ log_or_expr }

assign_expr = { unary_expr ~ (assign | mul_assign | div_assign | mod_assign | add_assign | sub_assign | lshift_assign | rshift_assign | and_assign | xor_assign | or_assign) ~ assign_expr | cond_expr }
    assign = { "#p" ~ "=" ~ "#p" }
    mul_assign = { "#p" ~ "*=" ~ "#p" }
    div_assign = { "#p" ~ "/=" ~ "#p" }
    mod_assign = { "#p" ~ "%=" ~ "#p" }
    add_assign = { "#p" ~ "+=" ~ "#p" }
    sub_assign = { "#p" ~ "-=" ~ "#p" }
    lshift_assign = { "#p" ~ "<<=" ~ "#p" }
    rshift_assign = { "#p" ~ ">>=" ~ "#p" }
    and_assign = { "#p" ~ "&=" ~ "#p" }
    xor_assign = { "#p" ~ "^=" ~ "#p" }
    or_assign = { "#p" ~ "|=" ~ "#p" }

const_expr = { cond_expr }

expr = { assign_expr ~ (c ~ assign_expr)* }



decl = { specs ~ init_decl_list? ~ s }

specs = { (storage_spec | type_qual | func_spec)* ~ type_spec ~ (storage_spec | type_spec | type_qual | func_spec)* | (storage_spec | type_qual | func_spec)* ~ typedef_name ~ (storage_spec | type_qual | func_spec)* }

init_decl_list = { init_decl ~ (c ~ init_decl)* }

init_decl = { declarator ~ "#p" ~ "=" ~ "#p" ~ init | declarator }


storage_spec = { "typedef" | "extern" | "static" | "auto" | "register" }

type_spec = { "void" | "char" | "short" | "int" | "long" | "float" | "double" | "signed" | "unsigned" | "_Bool" | "_Complex" | "_Imaginary" | struct_spec | enum_spec }


struct_spec = { struct_union ~ tok_ident? ~ op_bc ~ struct_declaration_list ~ cl_bc | struct_union ~ tok_ident }

struct_union = { "struct" | "union" }

struct_declaration_list = { struct_declaration+ }

struct_declaration = { spec_qual_list ~ struct_declarator_list ~ s }

spec_qual_list = { type_qual* ~ type_spec ~ (type_spec | type_qual)* | type_qual* ~ typedef_name ~ type_qual* }

struct_declarator_list = { struct_declarator ~ (c ~ struct_declarator)* }

struct_declarator = { declarator? ~ "#p" ~ ":" ~ "#p" ~ const_expr | declarator }


enum_spec = { "enum" ~ tok_ident? ~ op_bc ~ enum_list ~ c? ~ cl_bc | "enum" ~ tok_ident }

enum_list = { enumerator ~ (c ~ enumerator)* }

enumerator = { enum_const ~ "#p" ~ "=" ~ "#p" ~ const_expr | enum_const }
    enum_const = { tok_ident }


type_qual = { "const" | "restrict" | "volatile" }

func_spec = { "inline" }
    

declarator = { pointer? ~ direct_declarator }

decl_postfix = { op_br ~ type_qual_list? ~ assign_expr? ~ cl_br | op_br ~ stat ~ type_qual_list? ~ assign_expr ~ cl_br | op_br ~ type_qual_list ~ stat ~ assign_expr ~ cl_br | op_br ~ type_qual_list? ~ mul ~ cl_br | p ~ param_type_list ~ q | p ~ ident_list? ~ q }
    stat = { "static" }

direct_declarator = { (p ~ declarator ~ q | tok_ident) ~ decl_postfix* }

pointer = { (mul ~ type_qual_list?)+ }

type_qual_list = { type_qual+ }


param_type_list = { param_list ~ c ~ tripledot | param_list }
    tripledot = { "#p" ~ "..." ~ "#p" }

param_list = { param_decl ~ (c ~ param_decl)* }

param_decl = { specs ~ declarator | specs ~ abstract_declarator?}

ident_list = { tok_ident ~ (c ~ tok_ident)* }


type_name = { spec_qual_list ~ abstract_declarator? }

abstract_declarator = { pointer? ~ direct_abstract_declarator | pointer }

direct_abstract_declarator_postfix = { op_br ~ assign_expr? ~ cl_br | op_br ~ mul ~ cl_br | p ~ param_type_list? ~ q }

direct_abstract_declarator = { (p ~ abstract_declarator ~ q)? ~ direct_abstract_declarator_postfix+ | p ~ abstract_declarator ~ q }

typedef_name = { tok_ident }


init = { assign_expr | op_bc ~ init_list ~ c? ~ cl_bc }

init_list = { designation? ~ init ~ (c ~ designation? ~ init)* }

designation = { designator_list ~ "#p" ~ "=" ~ "#p" }

designator_list = { designator+ }

designator = { op_brs ~ const_expr ~ cl_brs | "#p" ~ "." ~ "#p" ~ tok_ident }



stmt = { labeled_stmt | compound_stmt | expr_stmt | select_stmt | iter_stmt | jump_stmt }

labeled_stmt = { "case" ~ const_expr ~ "#p" ~ ":" ~ "#p" ~ stmt | "default" ~ "#p" ~ ":" ~ "#p" ~ stmt | tok_ident ~ "#p" ~ ":" ~ "#p" ~ stmt}

compound_stmt = { op_bc ~ block_item_list? ~ cl_bc }

block_item_list = { block_item+ }

block_item = { decl | stmt }

expr_stmt = { expr? ~ s }

select_stmt = { "if" ~ p ~ expr ~ q ~ stmt ~ "else" ~ stmt | "if" ~ p ~ expr ~ q ~ stmt | switch ~ p ~ expr ~ q ~ stmt }
    switch = { "switch" }

iter_stmt = { "while" ~ p ~ expr ~ q ~ stmt | do2 ~ stmt ~ "while" ~ p ~ expr ~ q | "for" ~ p ~ decl ~ expr? ~ s ~ expr? ~ q ~ stmt | "for" ~ p ~ expr? ~ s ~ expr? ~ s ~ expr? ~ q ~ stmt}
    do2 = { "do" }

jump_stmt = { "goto" ~ tok_ident ~ s | cont ~ s | br ~ s | "return" ~ expr? ~ s }
    cont = { "continue" }
    br = { "break" }



trans_unit = { extern_decl+ }

extern_decl = { fn_def | decl }

fn_def = { specs ~ declarator ~ decl_list? ~ compound_stmt }

decl_list = { decl+ }


WHITESPACE = _{ WHITE_SPACE }
COMMENT = _{ "/*" ~ (!"*/" ~ ANY)* ~ "*/" | "//" ~ (!"\n" ~ ANY)* }