Skip to content

Latest commit

 

History

History
153 lines (136 loc) · 5.49 KB

README.md

File metadata and controls

153 lines (136 loc) · 5.49 KB

rs9cc

mini C compiler written in Rust. This is my hobby project. I use compilerbook as a reference for this project.

Now this compiler can compile chibicc(historical/old branch) by using self.sh (you have to add some function definition in the self.sh to compile)

Build compiler

$ cargo build --release

Build C source

Currently, only x86_64-linux-gnu is supported.

$ ./target/release/rs9cc /path/to/source.c > a.s
$ cc -no-pie a.s
$ ./a.out

Note: Since preprocessor is not currently implemented, you may have to do the prototype declarations yourself.

int printf(char *p, ...);

int main() {
    printf("hello world %d", 1);
}

Test

Unit test

$ cargo test

Integrated test

docker is required.

C script test

$ ./runner.sh test

shell script test

$ ./runner.sh test_sh

Implemented

  • Four arithmetic operations (+, -, *, /)
  • unray(+, -)
  • comparison(>, >=, <, <=, ==, !=)
  • local variable
  • return statement
  • control statement(if, else, for, while)
  • block statement({...})
  • function call
  • function definition
  • array
  • global variable
  • pointer and String literal
  • comment
  • struct, enum
  • bit op (!,~,|,&,^)
  • goto,switch,continue,break
  • extern
  • lvar,gvar initializers
  • va_start
  • static local variable
  • static function, global variable

etc

Reference

EBNF

program                 = (function | declaration ("=" gvar-initializer)? ";" | func-prototype )*
type-specifier          = builtin-type | struct-dec | typedef-name | enum-specifier"
builtin-type            = "void" 
                        | "_Bool"
                        | "char" 
                        | "short" | "short" "int" | "int" "short" 
                        | "int" 
                        | "long" | "int" "long" | "long" "int" 
declarator              = "*"* ("(" declarator ")" | ident) type-suffix
abstract-declarator     = "*"* ("(" declarator ")")? type-suffix
type-suffix             = ("[" const-expr? "]" type-suffix)?
type-name               = type-specifier abstract-declarator type-suffix
struct-dec              = "struct" ident? ("{" declaration ";" "}")?
enum-specifier          = enum ident? "{" enum-list? "}"
                        | enum ident
enum-list               = enum-elem ("," enum-elem)* ","?
enum-elem               = ident ("=" const-expr)?
declaration             = type-specifier declarator type-suffix
                        | type-specifier  
initialize              = "{" (expr ("," expr)*)? "}" 
                        | expr 
func-prototype          = type-specifier declarator "(" params? ")" 
function                = func-prototype "{" stmt* "}"
params                  = declaration ("," declaration)* ("," "...")? | "void" 
stmt                    = expr ";"
                        | "return" expr? ";"
                        | "if" "(" expr ")" stmt
                        | "while" "(" expr ")" stmt
                        | "do" stmt "while" "(" expr ")" ";"
                        | "for" "(" stmt? ";" expr? ";" expr? ")" stmt
                        | "{" stmt* "}"
                        | declaration ("=" lvar-initializer)? ";"
                        | "break" ";" 
                        | "continue" ";"
                        | "goto" ident ";"
                        | ident ":" stmt
                        | "switch" "("expr")" stmt
                        | "case" const-expr ":" stmt
                        | "default" ":" stmt
lvar-initializer        = assign
                        | "{" lvar-initializer ("," lvar-initializer)* ","? "}"
expr                    = assign ("," assign)*
assign                  = conditional (assign-op assign)?
assign-op               = "=" | "+=" | "-=" | "*=" | "/=" | "<<=" | ">>=" | "&=" | "|=" | "^="
conditional             = logor ("?" expr ":" conditional)?
logor                   = logand ("||" logand)*
logand                  = bitor ("&&" bitor)*
bitor                   = bitxor ("|" bitxor)*
bitxor                  = bitand ("^" bitand)*
bitand                  = equality ("&" equality)*
equality                = relational ("==" relational | "!=" relational)*
relational              = shift ("<" shift | "<=" | ">" shift | ">=" shift)*
shift                   = add ("<<" add | ">>" add)*
add                     = mul ("+" mul | "-" mul)*
mul                     = cast ("*" cast | "/" cast)*
cast                    = "(" type-name ")" cast | unary
unary                   = ("+" | "-" | "*" | "&" | "!" | "~")? cast
                        | ("++" | "--") unary
                        | postfix
postfix                 = compound-literal
                        | primary ("[" expr "]" | "." ident | "->" ident | "++" | "--")*
compound-literal        = "(" type-name ")" "{" (gvar-initializer | lvar-initializer) "}"
stmt-expr               = "(" "{" stmt stmt* "}" ")"
primary                 = num 
                        | ident (func-args)? 
                        | "(" expr ")"
                        | str
                        | char
                        | "(" "{" stmt-expr-tail
                        | "sizeof" unary
                        | "sizeof "(" type-name ")"
func-args               = "(" (assign ("," assign)*)? ")"