├── test ├── valid │ ├── cpp │ │ ├── header1.h │ │ ├── header2.h │ │ ├── header3.h │ │ ├── header5.h │ │ ├── header4.h │ │ ├── header │ │ │ └── header_1.h │ │ ├── tri_2.c │ │ ├── tri_1.c │ │ ├── macro_object_2.c │ │ ├── redefined.c │ │ ├── trash.c │ │ ├── macro_func.c │ │ ├── macro_object.c │ │ ├── header1.c │ │ ├── tri_3.c │ │ └── comment_1.c │ ├── no_newlines.c │ ├── missing_return.c │ ├── neg.c │ ├── add.c │ ├── bitwise.c │ ├── div.c │ ├── mult.c │ ├── not_five.c │ ├── not_zero.c │ ├── return_0.c │ ├── return_2.c │ ├── sub.c │ ├── and_false.c │ ├── and_true.c │ ├── bitwise_zero.c │ ├── eq_false.c │ ├── eq_true.c │ ├── ge_false.c │ ├── ge_true.c │ ├── gt_false.c │ ├── gt_true.c │ ├── le_false.c │ ├── le_true.c │ ├── lt_false.c │ ├── lt_true.c │ ├── multi_digit.c │ ├── ne_false.c │ ├── ne_true.c │ ├── nested_ops.c │ ├── nested_ops_2.c │ ├── or_false.c │ ├── or_true.c │ ├── spaces.c │ ├── sub_neg.c │ ├── unop_add.c │ ├── parens.c │ ├── unop_parens.c │ ├── associativity.c │ ├── associativity_2.c │ ├── precedence.c │ ├── precedence_2.c │ ├── precedence_3.c │ ├── precedence_4.c │ ├── refer.c │ ├── associativity_4.c │ ├── initialize.c │ ├── no_initialize.c │ ├── unused_exp.c │ ├── associativity_5.c │ ├── global.c │ ├── decl_1.c │ ├── ternary.c │ ├── assign.c │ ├── assign_val.c │ ├── return_in_while.c │ ├── associativity_3.c │ ├── multiple_global.c │ ├── newlines.c │ ├── assign_ternary.c │ ├── multiple_vars.c │ ├── no_arg.c │ ├── multi_return.c │ ├── complicated_exp.c │ ├── declare_block.c │ ├── exp_return_val.c │ ├── new_precedence.c │ ├── nested_scope_2.c │ ├── single_arg.c │ ├── else.c │ ├── if_not_taken.c │ ├── if_taken.c │ ├── rename_function_param.c │ ├── for.c │ ├── multiple_ternary.c │ ├── rh_assignment.c │ ├── declare_late.c │ ├── do_while.c │ ├── fun_shadowed_by_variable.c │ ├── nested_ternary_2.c │ ├── ternary_short_circuit.c │ ├── ternary_short_circuit_2.c │ ├── for_decl.c │ ├── multi_arg.c │ ├── variable_as_arg.c │ ├── while_single_statement.c │ ├── consecutive_blocks.c │ ├── declare_after_block.c │ ├── empty_expression.c │ ├── nested_ternary.c │ ├── global_not_initialized.c │ ├── continue.c │ ├── nested_scope.c │ ├── expression_args.c │ ├── if_nested.c │ ├── if_nested_2.c │ ├── global_shadowed.c │ ├── if_nested_3.c │ ├── if_nested_4.c │ ├── for_empty.c │ ├── break.c │ ├── multi_nesting.c │ ├── fun_in_expr.c │ ├── while_multi_statement.c │ ├── if_nested_5.c │ ├── consecutive_declarations.c │ ├── nested_while.c │ ├── fib.c │ ├── for_nested_scope.c │ ├── for_variable_shadow.c │ ├── multiple_if.c │ ├── continue_empty_post.c │ ├── global_array_1.c │ ├── nested_if.c │ ├── nested_for.c │ ├── mutual_recursion.c │ ├── fun.c │ ├── nested_break_3.c │ ├── nested_while_2.c │ ├── nested_break_2.c │ ├── nested_break.c │ ├── nested_while_3.c │ ├── global_array_2.c │ ├── multi_arg_1.c │ ├── multi_arg_2.c │ ├── combine_2.c │ ├── combine.c │ ├── bubble_sort.c │ ├── global_array_3.c │ ├── combine_3.c │ ├── parser │ │ └── generic_1.c │ └── combine_4.c └── invalid │ ├── no_brace.c │ ├── missing_paren.c │ ├── no_semicolon.c │ └── wrong_case.c ├── .gitignore ├── bors.toml ├── src ├── lib.rs ├── main.rs ├── sema.rs ├── ast.rs ├── symtable.rs ├── cpp.rs └── lexer.rs ├── sample_code ├── simple_print.c ├── hello_crust.c ├── input_data_array.c ├── bubble_sort.c └── input_data_sort.c ├── Cargo.toml ├── benches ├── bench_cpp.rs ├── bench_lexer.rs └── bench_parser.rs ├── .travis.yml ├── test.sh ├── test_dev.sh ├── README.md ├── LICENSE └── Cargo.lock /test/valid/cpp/header1.h: -------------------------------------------------------------------------------- 1 | int a = 1; 2 | -------------------------------------------------------------------------------- /test/valid/cpp/header2.h: -------------------------------------------------------------------------------- 1 | int b = 2; 2 | -------------------------------------------------------------------------------- /test/valid/cpp/header3.h: -------------------------------------------------------------------------------- 1 | int c = 3; 2 | -------------------------------------------------------------------------------- /test/valid/cpp/header5.h: -------------------------------------------------------------------------------- 1 | int e = 10; 2 | -------------------------------------------------------------------------------- /test/valid/no_newlines.c: -------------------------------------------------------------------------------- 1 | int main(){return 0;} -------------------------------------------------------------------------------- /test/valid/missing_return.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | 3 | } -------------------------------------------------------------------------------- /test/valid/neg.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return -5; 3 | } -------------------------------------------------------------------------------- /test/invalid/no_brace.c: -------------------------------------------------------------------------------- 1 | int main { 2 | return 0; 3 | -------------------------------------------------------------------------------- /test/valid/add.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 + 2; 3 | } -------------------------------------------------------------------------------- /test/valid/bitwise.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return !12; 3 | } -------------------------------------------------------------------------------- /test/valid/div.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 4 / 2; 3 | } -------------------------------------------------------------------------------- /test/valid/mult.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 2 * 3; 3 | } -------------------------------------------------------------------------------- /test/valid/not_five.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return !5; 3 | } -------------------------------------------------------------------------------- /test/valid/not_zero.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return !0; 3 | } -------------------------------------------------------------------------------- /test/valid/return_0.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0; 3 | } -------------------------------------------------------------------------------- /test/valid/return_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 2; 3 | } -------------------------------------------------------------------------------- /test/valid/sub.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 - 2; 3 | } -------------------------------------------------------------------------------- /test/invalid/missing_paren.c: -------------------------------------------------------------------------------- 1 | int main( { 2 | return 0; 3 | } -------------------------------------------------------------------------------- /test/invalid/no_semicolon.c: -------------------------------------------------------------------------------- 1 | int main { 2 | return 0 3 | } -------------------------------------------------------------------------------- /test/invalid/wrong_case.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | RETURN 0; 3 | } -------------------------------------------------------------------------------- /test/valid/and_false.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 && 0; 3 | } -------------------------------------------------------------------------------- /test/valid/and_true.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 && -1; 3 | } -------------------------------------------------------------------------------- /test/valid/bitwise_zero.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return ~0; 3 | } -------------------------------------------------------------------------------- /test/valid/eq_false.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 == 2; 3 | } -------------------------------------------------------------------------------- /test/valid/eq_true.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 == 1; 3 | } -------------------------------------------------------------------------------- /test/valid/ge_false.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 >= 2; 3 | } -------------------------------------------------------------------------------- /test/valid/ge_true.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 >= 1; 3 | } -------------------------------------------------------------------------------- /test/valid/gt_false.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 > 2; 3 | } -------------------------------------------------------------------------------- /test/valid/gt_true.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 > 0; 3 | } -------------------------------------------------------------------------------- /test/valid/le_false.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 <= -1; 3 | } -------------------------------------------------------------------------------- /test/valid/le_true.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0 <= 2; 3 | } -------------------------------------------------------------------------------- /test/valid/lt_false.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 2 < 1; 3 | } -------------------------------------------------------------------------------- /test/valid/lt_true.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 < 2; 3 | } -------------------------------------------------------------------------------- /test/valid/multi_digit.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 100; 3 | } -------------------------------------------------------------------------------- /test/valid/ne_false.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0 != 0; 3 | } -------------------------------------------------------------------------------- /test/valid/ne_true.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return -1 != -2; 3 | } -------------------------------------------------------------------------------- /test/valid/nested_ops.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return !-3; 3 | } -------------------------------------------------------------------------------- /test/valid/nested_ops_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return -~0; 3 | } -------------------------------------------------------------------------------- /test/valid/or_false.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0 || 0; 3 | } -------------------------------------------------------------------------------- /test/valid/or_true.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 || 0; 3 | } -------------------------------------------------------------------------------- /test/valid/spaces.c: -------------------------------------------------------------------------------- 1 | int main ( ) { return 0 ; } -------------------------------------------------------------------------------- /test/valid/sub_neg.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 2- -1; 3 | } -------------------------------------------------------------------------------- /test/valid/unop_add.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return ~2 + 3; 3 | } -------------------------------------------------------------------------------- /test/valid/cpp/header4.h: -------------------------------------------------------------------------------- 1 | int d = 4; 2 | #include "header5.h" 3 | -------------------------------------------------------------------------------- /test/valid/parens.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 2 * (3 + 4); 3 | } -------------------------------------------------------------------------------- /test/valid/unop_parens.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return ~(1 + 1); 3 | } -------------------------------------------------------------------------------- /test/valid/associativity.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 - 2 - 3; 3 | } -------------------------------------------------------------------------------- /test/valid/associativity_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 6 / 3 / 2; 3 | } -------------------------------------------------------------------------------- /test/valid/precedence.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 || 0 && 2; 3 | } -------------------------------------------------------------------------------- /test/valid/precedence_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return (1 || 0) && 0; 3 | } -------------------------------------------------------------------------------- /test/valid/precedence_3.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 2 == 2 > 0; 3 | } -------------------------------------------------------------------------------- /test/valid/precedence_4.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 2 == 2 || 0; 3 | } -------------------------------------------------------------------------------- /test/valid/refer.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 2; 3 | return a; 4 | } -------------------------------------------------------------------------------- /test/valid/associativity_4.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 * 2 * 3 * 4; 3 | } 4 | -------------------------------------------------------------------------------- /test/valid/initialize.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 2; 3 | return 0; 4 | } -------------------------------------------------------------------------------- /test/valid/no_initialize.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a; 3 | return 0; 4 | } -------------------------------------------------------------------------------- /test/valid/unused_exp.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | 2 + 2; 3 | return 0; 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | gen/ 4 | *.s 5 | a.out 6 | b.out 7 | .vscode -------------------------------------------------------------------------------- /bors.toml: -------------------------------------------------------------------------------- 1 | status = [ 2 | "continuous-integration/travis-ci/push", 3 | ] 4 | -------------------------------------------------------------------------------- /test/valid/associativity_5.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 6 / 5 / 4/ 3/2/1; 3 | } 4 | -------------------------------------------------------------------------------- /test/valid/global.c: -------------------------------------------------------------------------------- 1 | int foo = 4; 2 | 3 | int main() { 4 | return foo + 3; 5 | } -------------------------------------------------------------------------------- /test/valid/cpp/header/header_1.h: -------------------------------------------------------------------------------- 1 | int f = 100; 2 | #define NAME "test" 3 | #define NUM 6 -------------------------------------------------------------------------------- /test/valid/cpp/tri_2.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | printf( "What?\?!\n" ); 3 | } 4 | -------------------------------------------------------------------------------- /test/valid/decl_1.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1; 3 | int b; 4 | return 10; 5 | } 6 | -------------------------------------------------------------------------------- /test/valid/ternary.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | return a > -1 ? 4 : 5; 4 | } -------------------------------------------------------------------------------- /test/valid/cpp/tri_1.c: -------------------------------------------------------------------------------- 1 | 2 | int main(void) ??< 3 | printf("what??!\n"); 4 | ??> 5 | -------------------------------------------------------------------------------- /test/valid/assign.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a; 3 | a = 2 * 4; 4 | return a; 5 | } 6 | -------------------------------------------------------------------------------- /test/valid/assign_val.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a; 3 | int b = a = 0; 4 | return b; 5 | } -------------------------------------------------------------------------------- /test/valid/return_in_while.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | while (1) { 3 | return 2; 4 | } 5 | } -------------------------------------------------------------------------------- /test/valid/associativity_3.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10; 3 | } 4 | -------------------------------------------------------------------------------- /test/valid/multiple_global.c: -------------------------------------------------------------------------------- 1 | int a = 3; 2 | int b = 4; 3 | 4 | int main() { 5 | return a * b; 6 | } -------------------------------------------------------------------------------- /test/valid/newlines.c: -------------------------------------------------------------------------------- 1 | 2 | int 3 | main 4 | ( 5 | ) 6 | { 7 | return 8 | 0 9 | ; 10 | } -------------------------------------------------------------------------------- /test/valid/assign_ternary.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | a = 1 ? 2 : 3; 4 | return a; 5 | } -------------------------------------------------------------------------------- /test/valid/multiple_vars.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1; 3 | int b = 2; 4 | return a + b; 5 | } -------------------------------------------------------------------------------- /test/valid/no_arg.c: -------------------------------------------------------------------------------- 1 | int three(){ 2 | return 3; 3 | } 4 | 5 | int main() { 6 | return three(); 7 | } -------------------------------------------------------------------------------- /test/valid/multi_return.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 10; 3 | return 5; 4 | return 10; 5 | return 11; 6 | } 7 | -------------------------------------------------------------------------------- /test/valid/complicated_exp.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return (1 + 3 * 4 / 4 - 5 * 10 + 100) * 10 / 10 - 1; 3 | } 4 | -------------------------------------------------------------------------------- /test/valid/declare_block.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | if (5) { 3 | int i = 0; 4 | return i; 5 | } 6 | } -------------------------------------------------------------------------------- /test/valid/exp_return_val.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a; 3 | int b; 4 | a = b = 4; 5 | return a - b; 6 | } -------------------------------------------------------------------------------- /test/valid/new_precedence.c: -------------------------------------------------------------------------------- 1 | int three() { 2 | return 3; 3 | } 4 | 5 | int main() { 6 | return !three(); 7 | } -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod ast; 2 | pub mod cpp; 3 | pub mod lexer; 4 | pub mod parser; 5 | pub mod sema; 6 | pub mod symtable; 7 | -------------------------------------------------------------------------------- /test/valid/nested_scope_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1; {int a = 2; {int a = 3; {int a = 4;}}} 3 | return a; 4 | } 5 | -------------------------------------------------------------------------------- /test/valid/single_arg.c: -------------------------------------------------------------------------------- 1 | int twice(int x){ 2 | return 2 * x; 3 | } 4 | 5 | int main() { 6 | return twice(3); 7 | } -------------------------------------------------------------------------------- /test/valid/else.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | if (a) 4 | return 1; 5 | else 6 | return 2; 7 | } -------------------------------------------------------------------------------- /test/valid/if_not_taken.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 0; 4 | if (a) 5 | b = 1; 6 | return b; 7 | } -------------------------------------------------------------------------------- /test/valid/if_taken.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1; 3 | int b = 0; 4 | if (a) 5 | b = 1; 6 | return b; 7 | } -------------------------------------------------------------------------------- /test/valid/rename_function_param.c: -------------------------------------------------------------------------------- 1 | int foo(int a){ 2 | return a + 1; 3 | } 4 | int main(){ 5 | return foo(3); 6 | } 7 | 8 | -------------------------------------------------------------------------------- /test/valid/for.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | 4 | for (a = 0; a < 3; a = a + 1) 5 | a = a * 2; 6 | return a; 7 | } -------------------------------------------------------------------------------- /test/valid/multiple_ternary.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1 > 2 ? 3 : 4; 3 | int b = 1 > 2 ? 5 : 6; 4 | return a + b; 5 | } 6 | -------------------------------------------------------------------------------- /test/valid/rh_assignment.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int flag = 1; 3 | int a = 0; 4 | flag ? a = 1 : (a = 0); 5 | return a; 6 | } -------------------------------------------------------------------------------- /test/valid/declare_late.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 2; 3 | { 4 | a = 3; 5 | int a = 0; 6 | } 7 | return a; 8 | } -------------------------------------------------------------------------------- /test/valid/do_while.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1; 3 | do { 4 | a = a * 2; 5 | } while(a < 11); 6 | 7 | return a; 8 | } -------------------------------------------------------------------------------- /test/valid/fun_shadowed_by_variable.c: -------------------------------------------------------------------------------- 1 | int foo() { 2 | return 3; 3 | } 4 | 5 | int main() { 6 | int foo = 5; 7 | return foo; 8 | } -------------------------------------------------------------------------------- /test/valid/nested_ternary_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1 ? 2 ? 3 : 4 : 5; 3 | int b = 0 ? 2 ? 3 : 4 : 5; 4 | return a * b; 5 | } -------------------------------------------------------------------------------- /test/valid/ternary_short_circuit.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1; 3 | int b = 0; 4 | a ? (b = 1) : (b = 2); 5 | return b; 6 | } -------------------------------------------------------------------------------- /test/valid/ternary_short_circuit_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 0; 4 | a ? (b = 1) : (b = 2); 5 | return b; 6 | } -------------------------------------------------------------------------------- /test/valid/for_decl.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | 4 | for (int i = 0; i < 3; i = i + 1) 5 | a = a + 1; 6 | return a; 7 | } -------------------------------------------------------------------------------- /test/valid/multi_arg.c: -------------------------------------------------------------------------------- 1 | int sub(int x, int y, int z) { 2 | return x - y - z; 3 | } 4 | 5 | int main() { 6 | return sub(10, 4, 2); 7 | } 8 | -------------------------------------------------------------------------------- /test/valid/variable_as_arg.c: -------------------------------------------------------------------------------- 1 | int foo(int x) { 2 | return x + 1; 3 | } 4 | 5 | int main() { 6 | int a = 1; 7 | return foo(a); 8 | } 9 | -------------------------------------------------------------------------------- /test/valid/while_single_statement.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | 4 | while (a < 5) 5 | a = a + 2; 6 | 7 | return a; 8 | } -------------------------------------------------------------------------------- /test/valid/consecutive_blocks.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1; 3 | { 4 | int a = 2; 5 | } 6 | { 7 | return a; 8 | } 9 | } -------------------------------------------------------------------------------- /test/valid/declare_after_block.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i = 0; 3 | { 4 | int a = 2; 5 | } 6 | int b = 3; 7 | return b; 8 | } -------------------------------------------------------------------------------- /test/valid/empty_expression.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i = 3; 3 | ; 4 | for (int i = 0; i < 10; i = i + 1) 5 | ; 6 | return i; 7 | } -------------------------------------------------------------------------------- /test/valid/nested_ternary.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1; 3 | int b = 2; 4 | int flag = 0; 5 | 6 | return a > b ? 5 : flag ? 6 : 7; 7 | } -------------------------------------------------------------------------------- /test/valid/cpp/macro_object_2.c: -------------------------------------------------------------------------------- 1 | #define A 1 + 2 2 | #define B A + 3 3 | #define C B + 4 4 | #define D C + 5 5 | 6 | int main(void) { 7 | return D; 8 | } 9 | -------------------------------------------------------------------------------- /test/valid/global_not_initialized.c: -------------------------------------------------------------------------------- 1 | int foo; 2 | 3 | int main() { 4 | for (int i = 0; i < 3; i = i + 1) 5 | foo = foo + 1; 6 | return foo; 7 | } -------------------------------------------------------------------------------- /test/valid/continue.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int sum = 0; 3 | for (int i = 0; i < 10; i = i + 1) { 4 | sum = sum + i; 5 | } 6 | return sum; 7 | } 8 | -------------------------------------------------------------------------------- /test/valid/nested_scope.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 2; 3 | int b = 3; 4 | { 5 | int a = 1; 6 | b = b + a; 7 | } 8 | return b; 9 | } -------------------------------------------------------------------------------- /test/valid/expression_args.c: -------------------------------------------------------------------------------- 1 | int add(int a, int b) { 2 | return a + b; 3 | } 4 | 5 | int main() { 6 | int sum = add(1 + 2, 4); 7 | return sum + sum; 8 | } 9 | -------------------------------------------------------------------------------- /test/valid/if_nested.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1; 3 | int b = 0; 4 | if (a) 5 | b = 1; 6 | else if (b) 7 | b = 2; 8 | return b; 9 | } -------------------------------------------------------------------------------- /test/valid/if_nested_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 1; 4 | if (a) 5 | b = 1; 6 | else if (b) 7 | b = 2; 8 | return b; 9 | } -------------------------------------------------------------------------------- /test/valid/cpp/redefined.c: -------------------------------------------------------------------------------- 1 | #include "header/header_1.h" 2 | 3 | int main(void) { 4 | printf("%d\n", NUM); 5 | #define NUM 7 6 | printf("%d\n", NUM); 7 | return NUM; 8 | } 9 | -------------------------------------------------------------------------------- /test/valid/global_shadowed.c: -------------------------------------------------------------------------------- 1 | int a = 3; 2 | 3 | int main() { 4 | int ret = 0; 5 | if (a) { 6 | int a = 0; 7 | ret = 4; 8 | } 9 | return ret; 10 | } -------------------------------------------------------------------------------- /sample_code/simple_print.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | for (int i = 0; i < 10; i = i + 1) { 3 | printf("hello world\n"); 4 | } 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /test/valid/if_nested_3.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | if (1) 4 | if (2) 5 | a = 3; 6 | else 7 | a = 4; 8 | 9 | return a; 10 | } -------------------------------------------------------------------------------- /test/valid/if_nested_4.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | if (1) 4 | if (0) 5 | a = 3; 6 | else 7 | a = 4; 8 | 9 | return a; 10 | } -------------------------------------------------------------------------------- /test/valid/for_empty.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 2; 3 | for (; ; ) { 4 | a = a + 1; 5 | if (a > 3) 6 | break; 7 | } 8 | 9 | return a; 10 | } 11 | -------------------------------------------------------------------------------- /sample_code/hello_crust.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | printf("Hello, CRUST!\n"); 3 | printf("This is a simple sample code that can be compiled by crust.\n"); 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /test/valid/cpp/trash.c: -------------------------------------------------------------------------------- 1 | int a = 1; 2 | int b = 2; 3 | int c = 3; 4 | int d = 4; 5 | #include "header5.h" 6 | 7 | int main(void) { 8 | printf("%d %d %d %d", a, b, c, d); 9 | } 10 | -------------------------------------------------------------------------------- /test/valid/break.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int sum = 0; 3 | for (int i = 0; i < 10; i = i + 1) { 4 | sum = sum + i; 5 | if (sum > 10) 6 | break; 7 | } 8 | return sum; 9 | } -------------------------------------------------------------------------------- /test/valid/multi_nesting.c: -------------------------------------------------------------------------------- 1 | int main(){ 2 | int a = 2; 3 | if (a < 3) { 4 | { 5 | int a = 3; 6 | return a; 7 | } 8 | return a; 9 | } 10 | } -------------------------------------------------------------------------------- /test/valid/cpp/macro_func.c: -------------------------------------------------------------------------------- 1 | #define S_U_M_0(a, b) a+b 2 | 3 | 4 | int main(void) { 5 | printf("%d\n", S_U_M_0(1,2)); 6 | printf("%d\n", S_U_M_0(2,3)); 7 | 8 | return S_U_M_0(1,2); 9 | } 10 | -------------------------------------------------------------------------------- /test/valid/fun_in_expr.c: -------------------------------------------------------------------------------- 1 | int sum(int a, int b) { 2 | return a + b; 3 | } 4 | 5 | int main() { 6 | int a = sum(1, 2) /2; 7 | int b = 2*sum(3, 4) + sum(1, 2); 8 | return b - a; 9 | } 10 | -------------------------------------------------------------------------------- /test/valid/while_multi_statement.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 1; 4 | 5 | while (a < 5) { 6 | a = a + 2; 7 | b = b * a; 8 | } 9 | 10 | return a; 11 | } -------------------------------------------------------------------------------- /test/valid/if_nested_5.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | if (0) 4 | if (0) 5 | a = 3; 6 | else 7 | a = 4; 8 | else 9 | a = 1; 10 | 11 | return a; 12 | } -------------------------------------------------------------------------------- /test/valid/consecutive_declarations.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | { 4 | int b = 1; 5 | a = b; 6 | } 7 | { 8 | int b = 2; 9 | a = a + b; 10 | } 11 | return a; 12 | } -------------------------------------------------------------------------------- /test/valid/nested_while.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1; 3 | 4 | while (a < 100) { 5 | int b = 1; 6 | while (b < 10) 7 | b = b*2; 8 | a = a + b; 9 | } 10 | 11 | return a; 12 | } 13 | -------------------------------------------------------------------------------- /test/valid/cpp/macro_object.c: -------------------------------------------------------------------------------- 1 | #define a 1 2 | #define PI 3.1415926 3 | #define EXIT_SUCCESS 1 4 | #define AA TMP 5 | #define TMP return EXIT_SUCCESS; 6 | 7 | int main(void) { 8 | // AA should turn into return 1; 9 | AA 10 | } 11 | 12 | -------------------------------------------------------------------------------- /test/valid/fib.c: -------------------------------------------------------------------------------- 1 | int fib(int n) { 2 | if (n == 0 || n == 1) { 3 | return n; 4 | } else { 5 | return fib(n - 1) + fib(n - 2); 6 | } 7 | } 8 | 9 | int main() { 10 | int n = 5; 11 | return fib(n); 12 | } -------------------------------------------------------------------------------- /test/valid/cpp/header1.c: -------------------------------------------------------------------------------- 1 | #include "header1.h" 2 | #include "header2.h" 3 | #include "header3.h" 4 | #include "header4.h" 5 | #include "header/header_1.h" 6 | int main(void) { 7 | printf("%s %d %d %d %d %d %d\n", NAME, a, b, c, d, e, f); 8 | } 9 | -------------------------------------------------------------------------------- /test/valid/for_nested_scope.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i = 0; 3 | int j = 0; 4 | 5 | for (int i = 100; i > 0; i = i - 1) { 6 | int i = 0; 7 | int j = j * 2 + i; 8 | } 9 | 10 | int k = 3; 11 | 12 | return j + k; 13 | } -------------------------------------------------------------------------------- /test/valid/for_variable_shadow.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i = 0; 3 | int j = 0; 4 | for (i = 0; i < 10; i = i + 1) { 5 | int k = i; 6 | for (int i = k; i < 10; i = i + 1) 7 | j = j + 1; 8 | } 9 | return j + i; 10 | } -------------------------------------------------------------------------------- /test/valid/multiple_if.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | int b = 0; 4 | 5 | if (a) 6 | a = 2; 7 | else 8 | a = 3; 9 | 10 | if (b) 11 | b = 4; 12 | else 13 | b = 5; 14 | 15 | return a + b; 16 | } -------------------------------------------------------------------------------- /test/valid/continue_empty_post.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int sum = 0; 3 | for (int i = 0; i < 10;) { 4 | i = i + 1; 5 | if (i == 0 || i == 2 || i == 4 || i == 6 || i == 8) 6 | continue; 7 | sum = sum + i; 8 | } 9 | return sum; 10 | } 11 | -------------------------------------------------------------------------------- /test/valid/global_array_1.c: -------------------------------------------------------------------------------- 1 | 2 | int a[100]; 3 | 4 | int main() { 5 | for (int i = 0; i < 100; i = i + 1) { 6 | for (int j = 0; j < 100; j = j + 1) { 7 | a[i] = a[i] + j; 8 | } 9 | } 10 | return a[10]; 11 | } 12 | -------------------------------------------------------------------------------- /test/valid/nested_if.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 0; 3 | if (a) { 4 | int b = 2; 5 | return b; 6 | } else { 7 | int c = 3; 8 | if (a < c) { 9 | return 4; 10 | } else { 11 | return 5; 12 | } 13 | } 14 | return a; 15 | } -------------------------------------------------------------------------------- /test/valid/nested_for.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int ans = 0; 3 | int ansa = 0; 4 | for (int i = 0; i < 2; i = i + 1) { 5 | ans = ans + 1; 6 | for (int j = 0; j < 10; j = j + 1) { 7 | ansa = ansa + 1; 8 | } 9 | } 10 | return ansa; 11 | } 12 | -------------------------------------------------------------------------------- /test/valid/mutual_recursion.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return foo(5); 3 | } 4 | 5 | int foo(int a) { 6 | if (a <= 0) { 7 | return a; 8 | } 9 | 10 | return a + bar(a - 1); 11 | } 12 | 13 | int bar(int b) { 14 | if (b <= 0) { 15 | return b; 16 | } 17 | 18 | return b + bar(b / 2); 19 | } 20 | -------------------------------------------------------------------------------- /test/valid/fun.c: -------------------------------------------------------------------------------- 1 | void a123(int* p) { 2 | *p=1; 3 | } 4 | 5 | int _123(int *p, int q) { 6 | return *p+q; 7 | } 8 | 9 | int _SUM_(int p, int q) { 10 | return p+q; 11 | } 12 | 13 | int main() { 14 | int r = 0; 15 | a123(&r); 16 | r=_123(&r,1); 17 | r=_SUM_(r,2); 18 | printf("%d\n", r); 19 | return r; 20 | } -------------------------------------------------------------------------------- /test/valid/nested_break_3.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int ans = 0; 3 | for (int i = 0; i < 10; i = i + 1) 4 | for (int j = 0; j < 10; j = j + 1) 5 | if (i == 0 || i == 2 || i == 4 || i == 6 || i == 8) 6 | break; 7 | else 8 | ans = ans + i; 9 | return ans; 10 | } 11 | -------------------------------------------------------------------------------- /test/valid/nested_while_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a = 1; 3 | int b = 1; 4 | int ans = 0; 5 | while (a < 10) { 6 | while (b < 10) { 7 | b = b + 1; 8 | ans = ans + 1; 9 | } 10 | a = a + 1; 11 | } 12 | return ans; 13 | } 14 | -------------------------------------------------------------------------------- /test/valid/nested_break_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int ans = 0; 3 | for (int i = 0; i < 10; i = i + 1) 4 | for (int j = 0; j < 10; j = j + 1) { 5 | if (i == 0 || i == 2 || i == 4 || i == 6 || i == 8) 6 | break; 7 | else 8 | ans = ans + i; 9 | } 10 | return ans; 11 | } 12 | -------------------------------------------------------------------------------- /test/valid/nested_break.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int ans = 0; 3 | for (int i = 0; i < 10; i = i + 1) { 4 | for (int j = 0; j < 10; j = j + 1) { 5 | if (i == 0 || i == 2 || i == 4 || i == 6 || i == 8) 6 | break; 7 | else 8 | ans = ans + i; 9 | } 10 | } 11 | return ans; 12 | } 13 | -------------------------------------------------------------------------------- /test/valid/cpp/tri_3.c: -------------------------------------------------------------------------------- 1 | 2 | int a??(100??); 3 | 4 | int main(void) ??< 5 | for (int i = 0; i < 100; i++) ??< 6 | a??(i??) = ??-i ??! 1 ^ 100; 7 | ??> 8 | int b = 10; 9 | for (int i = 0; i < 100; i++) ??< 10 | printf("%d ", a??(i??)); 11 | ??> 12 | printf("??/n"); 13 | printf("%d", b); 14 | return 0; 15 | ??> 16 | -------------------------------------------------------------------------------- /test/valid/nested_while_3.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int ans = 0; 3 | int a = 0; 4 | int b = 0; 5 | int c = 0; 6 | while (a < 4) { 7 | a = a + 1; 8 | while (b < 10) { 9 | b = b + 1; 10 | while (c < 100) { 11 | ans = ans + 1; 12 | c = c + 1; 13 | } 14 | } 15 | } 16 | return ans; 17 | } 18 | -------------------------------------------------------------------------------- /sample_code/input_data_array.c: -------------------------------------------------------------------------------- 1 | int a[100]; 2 | int main(void) { 3 | int n = 10; 4 | printf("Input array len: "); 5 | scanf("%lld", &n); 6 | printf("Now input %d numbers:\n", n); 7 | for (int i = 0; i < n; i = i + 1) { 8 | scanf("%d", &a[i]); 9 | } 10 | printf("Your input array:\n"); 11 | for (int i = 0; i < n; i = i + 1) { 12 | printf("%d ", a[i]); 13 | } 14 | printf("\n"); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /test/valid/cpp/comment_1.c: -------------------------------------------------------------------------------- 1 | int a[100]; 2 | int b[100][100][100]; 3 | int c[100]; 4 | int main() { 5 | a[0] = 1; 6 | a[1] = 2; 7 | a[3] = a[0] + a[1]; 8 | // adfsaf \ 9 | dafdaffafsaf\ 10 | adsfafafas\ 11 | 12 | /* this is a comment for the preprocessor to handle */ 13 | /* 14 | try multiline 15 | */ 16 | // /* try some thing 17 | /* 18 | printf("%d\ n", a[0]); 19 | // */ 20 | 21 | printf("%d\n", a[1]); 22 | printf("%d\n", a[2]); 23 | } 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "crust" 3 | version = "0.1.0" 4 | authors = ["onehrxn "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | lazy_static = "1.4.0" 9 | clap = "2.33.0" 10 | regex = "1.3.5" 11 | log = "0.4" 12 | simple_logger = "1.4.0" 13 | loggerv = "0.7" 14 | 15 | [features] 16 | debug = [] 17 | ast = [] 18 | source = [] 19 | token = [] 20 | as = [] 21 | 22 | [dev-dependencies] 23 | criterion = "0.2" 24 | 25 | [[bench]] 26 | name = "bench_lexer" 27 | harness = false 28 | [[bench]] 29 | name = "bench_cpp" 30 | harness = false 31 | [[bench]] 32 | name = "bench_parser" 33 | harness = false 34 | -------------------------------------------------------------------------------- /test/valid/global_array_2.c: -------------------------------------------------------------------------------- 1 | int a[1000]; 2 | int b[1000]; 3 | 4 | int COMPILER_OK = 0; 5 | int COMPILER_ERROR = 1; 6 | int main() { 7 | for (int i = 0; i < 100; i = i + 1) { 8 | a[i] = i; 9 | } 10 | for (int i = 0; i < 100; i = i + 1) { 11 | b[i] = 99 - i; 12 | } 13 | int sum_a = 0; 14 | int sum_b = 0; 15 | for (int i = 0; i < 100; i = i + 1) { 16 | sum_a = sum_a + a[i]; 17 | } 18 | for (int i = 0; i < 100; i = i + 1) { 19 | sum_b = sum_b + b[i]; 20 | } 21 | 22 | if (sum_a == sum_b) return COMPILER_OK; 23 | else return COMPILER_ERROR; 24 | } 25 | -------------------------------------------------------------------------------- /test/valid/multi_arg_1.c: -------------------------------------------------------------------------------- 1 | int foo( 2 | int a, 3 | int b, 4 | int c, 5 | int d, 6 | int e, 7 | int f, 8 | int g, 9 | int h, 10 | int i, 11 | int j, 12 | int k, 13 | int l, 14 | int m, 15 | int n, 16 | int o, 17 | int p, 18 | int q, 19 | int r, 20 | int s, 21 | int t, 22 | int u, 23 | int v, 24 | int w, 25 | int x, 26 | int y, 27 | int z) { 28 | return a+b+c+d+e+f+g; 29 | } 30 | 31 | int main() { 32 | return foo(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25); 33 | } 34 | -------------------------------------------------------------------------------- /test/valid/multi_arg_2.c: -------------------------------------------------------------------------------- 1 | int foo( 2 | int a, 3 | int b, 4 | int c, 5 | int d, 6 | int e, 7 | int f, 8 | int g, 9 | int h, 10 | int i, 11 | int j, 12 | int k, 13 | int l, 14 | int m, 15 | int n, 16 | int o, 17 | int p, 18 | int q, 19 | int r, 20 | int s, 21 | int t, 22 | int u, 23 | int v, 24 | int w, 25 | int x, 26 | int y, 27 | int z) { 28 | return h+e+l+l+o+c+r+u+s+t; 29 | } 30 | 31 | int main() { 32 | return foo(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25); 33 | } 34 | -------------------------------------------------------------------------------- /test/valid/combine_2.c: -------------------------------------------------------------------------------- 1 | int fib(int a) {if (a == 0 || a == 1) {return a;} else {return fib(a - 1) + fib(a - 2);}} 2 | int max(int a, int b) {return a > b ? a : b;} 3 | int min(int a, int b) {return a < b ? a : b;} 4 | int sum(int a, int b) {return a + b;} 5 | int mul(int a, int b) {return a * b;} 6 | int div(int a, int b) {return a / b;} 7 | 8 | int EXIT_SUCCESS = 0; 9 | int EXIT_FAILURE = 1; 10 | 11 | int main() { 12 | int a = 2; 13 | int b = 3; 14 | int n = 10; 15 | 16 | if (fib(n) != 55) return EXIT_FAILURE; 17 | 18 | if (min(a, b) != 2) return EXIT_FAILURE; 19 | 20 | if (max(a, b) != 3) return EXIT_FAILURE; 21 | 22 | if (sum(a, b) != 5) return EXIT_FAILURE; 23 | 24 | if (mul(a, b) != 6) return EXIT_FAILURE; 25 | 26 | if (div(a, b) != 0) return EXIT_FAILURE; 27 | 28 | return EXIT_SUCCESS; 29 | } 30 | -------------------------------------------------------------------------------- /test/valid/combine.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int ans = 0; 3 | for (int i = 0; i < 10; i = i + 1) { 4 | for (int j = 0; j < 10; j = j + 1) { 5 | ans = ans + 1; 6 | } 7 | } 8 | while (1) { 9 | ans = ans + 1; 10 | if (ans > 120) break; 11 | } 12 | do { 13 | ans = ans + 2; 14 | } while (ans > 160); 15 | 16 | int b = ans + 1; 17 | int c = b + 1; 18 | int d = b + c - ans; 19 | int a = ans * 2; 20 | a = ans - 1; 21 | for (int i = 0; i < 10; i = i + 1) 22 | a = a + 1; 23 | a = -a; 24 | a = -a; 25 | a = a / 2; 26 | a = a * 3; 27 | 28 | if (a == 197) { 29 | return 10 + a; 30 | } else 31 | return 0 + a; 32 | } 33 | -------------------------------------------------------------------------------- /test/valid/bubble_sort.c: -------------------------------------------------------------------------------- 1 | int a[100]; 2 | 3 | int EXIT_FAILURE = 1; 4 | int EXIT_SUCCESS = 0; 5 | 6 | int main() { 7 | int tmp; 8 | 9 | for (int i = 0; i < 100; i = i + 1) { 10 | a[i] = 99 - i; 11 | } 12 | 13 | for (int i = 0; i < 100; i = i + 1) { 14 | if (a[i] != 99 - i) return EXIT_FAILURE; 15 | } 16 | int len = 100; 17 | for (int i = 0; i < len - 1; i = i + 1) { 18 | for (int j = 0; j < len - 1 - i; j = j + 1) 19 | if (a[j] > a[j + 1]) { 20 | tmp = a[j]; 21 | a[j] = a[j + 1]; 22 | a[j + 1] = tmp; 23 | } 24 | } 25 | 26 | for (int i = 0; i < 100; i = i + 1) { 27 | if (a[i] != i) return EXIT_FAILURE; 28 | } 29 | 30 | return a[10]; 31 | } 32 | -------------------------------------------------------------------------------- /sample_code/bubble_sort.c: -------------------------------------------------------------------------------- 1 | int a[15]; 2 | 3 | int main(void) { 4 | int tmp; 5 | 6 | for (int i = 0; i < 15; i = i + 1) { 7 | a[i] = 15 - i; 8 | } 9 | 10 | printf("Before bubble sort:\n"); 11 | for (int i = 0; i < 15; i = i + 1) { 12 | printf("%d ", a[i]); 13 | } 14 | printf("\n"); 15 | 16 | int len = 15; 17 | for (int i = 0; i < len - 1; i = i + 1) { 18 | for (int j = 0; j < len - 1 - i; j = j + 1) 19 | if (a[j] > a[j + 1]) { 20 | tmp = a[j]; 21 | a[j] = a[j + 1]; 22 | a[j + 1] = tmp; 23 | } 24 | } 25 | 26 | printf("After bubble sort:\n"); 27 | for (int i = 0; i < 15; i = i + 1) { 28 | printf("%d ", a[i]); 29 | } 30 | printf("\n"); 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /sample_code/input_data_sort.c: -------------------------------------------------------------------------------- 1 | int array[100]; 2 | 3 | int main(void) { 4 | int len; 5 | scanf("%d", &len); 6 | 7 | for (int i = 0; i < len; i = i + 1) { 8 | scanf("%d", &array[i]); 9 | } 10 | 11 | printf("your input array:\n"); 12 | for (int i = 0; i < len; i = i + 1) { 13 | printf("%d ", array[i]); 14 | } 15 | printf("\n"); 16 | 17 | int tmp; 18 | for (int i = 0; i < len - 1; i = i + 1) { 19 | for (int j = 0; j < len - 1 - i; j = j + 1) 20 | if (array[j] > array[j + 1]) { 21 | tmp = array[j]; 22 | array[j] = array[j + 1]; 23 | array[j + 1] = tmp; 24 | } 25 | } 26 | 27 | printf("After sort:\n"); 28 | for (int i = 0; i < len; i = i + 1) { 29 | printf("%d ", array[i]); 30 | } 31 | printf("\n"); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /test/valid/global_array_3.c: -------------------------------------------------------------------------------- 1 | int a[100]; 2 | int b[100]; 3 | 4 | int main() { 5 | for (int i = 0; i < 100; i = i + 1) { 6 | a[i] = 1; 7 | b[i] = 0; 8 | } 9 | 10 | for (int i = 0; i < 100; i = i + 1) { 11 | if (a[i] != 1) return 1; 12 | } 13 | 14 | for (int i = 0; i < 100; i = i + 1) { 15 | if (b[i] != 0) return 1; 16 | } 17 | 18 | int tmp = 10; 19 | for (int i = 0; i < 100; i = i + 1) { 20 | tmp = a[i]; 21 | a[i] = b[i]; 22 | b[i] = tmp; 23 | } 24 | 25 | for (int i = 0; i < 100; i = i + 1) { 26 | if (a[i] != 0) return 1; 27 | } 28 | for (int i = 0; i < 100; i = i + 1) { 29 | if (b[i] != 1) return 1; 30 | } 31 | 32 | for (int i = 0; i < 100; i = i + 1) { 33 | a[i] = b[i]; 34 | } 35 | 36 | for (int i = 0; i < 100; i = i + 1) { 37 | if (a[i] != 1) return 1; 38 | } 39 | for (int i = 0; i < 100; i = i + 1) { 40 | if (b[i] != 1) return 1; 41 | } 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /benches/bench_cpp.rs: -------------------------------------------------------------------------------- 1 | extern crate crust; 2 | #[macro_use] 3 | extern crate criterion; 4 | 5 | use criterion::black_box; 6 | use criterion::Criterion; 7 | 8 | use crust::cpp; 9 | use std::{error, fs, path::PathBuf}; 10 | 11 | fn criterion_benchmark(c: &mut Criterion) -> Result<(), Box> { 12 | // TODO: change this to iter through every c file under "test/valid/cpp" 13 | let input_files = &[ 14 | "test/valid/cpp/macro_object.c", 15 | "test/valid/cpp/macro_object_2.c", 16 | "test/valid/cpp/trash.c", 17 | "test/valid/cpp/header1.c", 18 | "test/valid/cpp/comment_1.c", 19 | "test/valid/cpp/tri_1.c", 20 | "test/valid/cpp/tri_2.c", 21 | "test/valid/cpp/tri_3.c", 22 | ]; 23 | for input_file in input_files.iter() { 24 | c.bench_function(&format!("cpp {}", input_file), move |b| { 25 | b.iter(|| { 26 | cpp::cpp_driver( 27 | black_box(fs::read_to_string(input_file).unwrap()), 28 | PathBuf::from(input_file), 29 | ) 30 | }) 31 | }); 32 | } 33 | return Ok(()); 34 | } 35 | 36 | criterion_group!(benches, criterion_benchmark); 37 | criterion_main!(benches); 38 | -------------------------------------------------------------------------------- /test/valid/combine_3.c: -------------------------------------------------------------------------------- 1 | int fib(int a) {if (a == 0 || a == 1) {return a;} else {return fib(a - 1) + fib(a - 2);}} 2 | int max(int a, int b) {return a > b ? a : b;} 3 | int min(int a, int b) {return a < b ? a : b;} 4 | int sum(int a, int b) {return a + b;} 5 | int mul(int a, int b) {return a * b;} 6 | int div(int a, int b) {return a / b;} 7 | 8 | int EXIT_SUCCESS = 0; 9 | int EXIT_FAILURE = 1; 10 | 11 | int arr[30]; 12 | 13 | int main() { 14 | int a = 2; 15 | int b = 3; 16 | int n = 10; 17 | 18 | for (int i = 0; i < 30; i = i + 1) { 19 | if (i == 0 || i == 1) arr[i] = i; 20 | else arr[i] = arr[i-1] + arr[i-2]; 21 | } 22 | 23 | for (int i = 0; i < 30; i = i + 1) { 24 | if (arr[i] != fib(i)) return EXIT_FAILURE; 25 | } 26 | 27 | if (fib(n) != 55) return EXIT_FAILURE; 28 | 29 | if (min(a, b) != 2) return EXIT_FAILURE; 30 | 31 | if (max(a, b) != 3) return EXIT_FAILURE; 32 | 33 | if (sum(a, b) != 5) return EXIT_FAILURE; 34 | 35 | if (mul(a, b) != 6) return EXIT_FAILURE; 36 | 37 | if (div(a, b) != 0) return EXIT_FAILURE; 38 | 39 | return EXIT_SUCCESS; 40 | } 41 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | sudo: required 3 | rust: 4 | - stable 5 | - beta 6 | - nightly 7 | 8 | branches: 9 | only: 10 | # This is where pull requests from "bors r+" are built. 11 | - staging 12 | # This is where pull requests from "bors try" are built. 13 | - trying 14 | # Uncomment this to enable building pull requests. 15 | - master 16 | 17 | notifications: 18 | webhooks: 19 | urls: 20 | - https://webhooks.gitter.im/e/7635afc956f0e96a3b5a 21 | on_success: change # options: [always|never|change] default: always 22 | on_failure: always # options: [always|never|change] default: always 23 | on_start: never # options: [always|never|change] default: always 24 | 25 | matrix: 26 | allow_failures: 27 | - rust: nightly 28 | include: 29 | # works on Precise and Trusty 30 | - os: linux 31 | addons: 32 | apt: 33 | sources: 34 | - ubuntu-toolchain-r-test 35 | packages: 36 | - g++-7 37 | env: 38 | - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" 39 | 40 | before_script: 41 | - "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | sudo bash" 42 | 43 | script: 44 | - eval "${MATRIX_EVAL}" 45 | - mkdir gen/ 46 | - bash test_dev.sh 47 | 48 | cache: cargo 49 | -------------------------------------------------------------------------------- /test/valid/parser/generic_1.c: -------------------------------------------------------------------------------- 1 | const int a = 0; 2 | 3 | struct a { 4 | int a; 5 | }; 6 | 7 | struct b { 8 | int a; 9 | }; 10 | 11 | int a_f() 12 | { 13 | return 20; 14 | } 15 | 16 | int b_f() 17 | { 18 | return 10; 19 | } 20 | 21 | int foo(int i) 22 | { 23 | return i; 24 | } 25 | 26 | 27 | int main() 28 | { 29 | int i = 0; 30 | signed long int l = 2; 31 | struct b titi; 32 | const int * const ptr; 33 | const char *ti; 34 | 35 | i = _Generic(a, int: a_f, const int: b_f)(); 36 | printf("%d\n", i); 37 | i = _Generic(a, int: a_f() / 2, const int: b_f() / 2); 38 | printf("%d\n", i); 39 | i = _Generic(ptr, int *:1, int * const:2, default:20); 40 | printf("%d\n", i); 41 | i = _Generic(titi, struct a:1, struct b:2, default:20); 42 | printf("%d\n", i); 43 | i = _Generic(a, char:1, int[4]:2, default:5); 44 | printf("%d\n", i); 45 | i = _Generic(17, int :1, int **:2); 46 | printf("%d\n", i); 47 | i = _Generic(17, int :1, long :2, long long : 3); 48 | printf("%d\n", i); 49 | i = _Generic("17, io", char *: 3, const char *: 1); 50 | printf("%d\n", i); 51 | i = _Generic(ti, const unsigned char *:1, const char *:4, char *:3, 52 | const signed char *:2); 53 | printf("%d\n", i); 54 | printf("%s\n", _Generic(i + 2, long: "long", int: "int", 55 | long long: "long long")); 56 | i = _Generic(l, long: 1, int: 2); 57 | printf("%d\n", i); 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # build the project 3 | cargo build 4 | rm -r gen/ 5 | mkdir -p gen/test/valid 6 | 7 | # now just test whether the number returned was right 8 | RED='\033[0;31m' 9 | BLUE='\033[0;34m' 10 | NC='\033[0m' 11 | inc=0 12 | test_fun() { 13 | $1.crust 14 | a=$? 15 | $1.gcc 16 | b=$? 17 | inc=$(($inc+1)) 18 | echo "TEST $inc: [$1] -> crustRet: $a gccRet: $b" 19 | if [ "$a" -eq "$b" ]; then 20 | echo -e "[${BLUE}Passed${NC}]" 21 | else 22 | echo -e "[${RED}Error${NC}]" 23 | exit 1 24 | fi 25 | } 26 | 27 | crust_compile() { 28 | echo "crust compile $1.c -> $2.s" && ./target/debug/crust -o $2.s $1.c 29 | } 30 | 31 | gcc_compile() { 32 | echo "gcc compile $2.s -> $2.crust" 33 | gcc -o $2.crust $2.s 34 | echo "gcc compile $1.c -> $2.gcc" 35 | gcc -std=c99 -o $2.gcc $1.c 36 | } 37 | srcdir=test/valid 38 | echo -e "[${BLUE}crust compile all the test file now, generated file should be in CRUST_HOME/gen/test/valid/${NC}]" 39 | for f in $srcdir/*.c 40 | do 41 | file=${f%.*} 42 | crust_compile $file ./gen/$file 43 | done 44 | echo -e "[${BLUE}Now gcc compile the assembly code and prepare for test${NC}]" 45 | for f in $srcdir/*.c 46 | do 47 | file=${f%.*} 48 | gcc_compile $file ./gen/$file 49 | done 50 | echo -e "[${BLUE}test begins${NC}]" 51 | for f in gen/test/valid/*.crust 52 | do 53 | exec=${f%.*} 54 | test_fun $exec 55 | done 56 | 57 | echo -e "Passed ${BLUE}All${NC} tests :)" 58 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod ast; 2 | mod cpp; 3 | mod lexer; 4 | mod parser; 5 | mod sema; 6 | mod symtable; 7 | 8 | use clap::{App, Arg}; 9 | use log::{trace, info}; 10 | use std::{fs, error, path::Path}; 11 | 12 | fn main() -> Result<(), Box> { 13 | let args = App::new("Crust") 14 | .version("0.1.0") 15 | .about("Crust is a C Compiler Powered by Rust") 16 | .arg( 17 | Arg::with_name("files") 18 | .required(true) 19 | .multiple(true) 20 | .help("Input files"), 21 | ) 22 | .arg( 23 | Arg::with_name("v") 24 | .short("v") 25 | .multiple(true) 26 | .help("Sets the level of verbosity"), 27 | ) 28 | .get_matches(); 29 | 30 | loggerv::Logger::new() 31 | .verbosity(args.occurrences_of("v")) 32 | .level(false) 33 | .colors(true) 34 | .level(true) 35 | .init() 36 | .unwrap(); 37 | 38 | let files: Vec<_> = args.values_of("files").unwrap().collect(); 39 | 40 | for file in files { 41 | info!("Compiling: {}", file); 42 | let path = Path::new(file); 43 | let file_contents = fs::read_to_string(path)?; 44 | 45 | // 1. Preprocessing 46 | let contents_after_cpp = cpp::cpp_driver(file_contents, path.to_path_buf())?; 47 | trace!("File content after replacing PreProcessors: {:?}", contents_after_cpp); 48 | 49 | // 2. lexing 50 | let tokens = lexer::lex(&contents_after_cpp)?; 51 | trace!("Tokens: {:?}", &tokens); 52 | 53 | 54 | // 3. parsing 55 | let root_node = parser::parser_driver(&tokens, &file)?; 56 | trace!( 57 | "Source AST:{}", 58 | parser::parser_pretty_printer(&root_node, 0) 59 | ); 60 | } 61 | 62 | Ok(()) 63 | } 64 | -------------------------------------------------------------------------------- /test/valid/combine_4.c: -------------------------------------------------------------------------------- 1 | int fib(int a) {if (a == 0 || a == 1) {return a;} else {return fib(a - 1) + fib(a - 2);}} 2 | int max(int a, int b) {return a > b ? a : b;} 3 | int min(int a, int b) {return a < b ? a : b;} 4 | int sum(int a, int b) {return a + b;} 5 | int mul(int a, int b) {return a * b;} 6 | int div(int a, int b) {return a / b;} 7 | 8 | int EXIT_SUCCESS = 0; 9 | int EXIT_FAILURE = 1; 10 | 11 | int arr[100]; 12 | 13 | int main() { 14 | int a = 2; 15 | int b = 3; 16 | int n = 10; 17 | int len = 100; 18 | 19 | for (int i = 0; i < 30; i = i + 1) { 20 | if (i == 0 || i == 1) arr[i] = i; 21 | else arr[i] = arr[i-1] + arr[i-2]; 22 | } 23 | 24 | for (int i = 0; i < 30; i = i + 1) { 25 | if (arr[i] != fib(i)) return EXIT_FAILURE; 26 | } 27 | 28 | for (int i = 0; i < len; i = i + 1) { 29 | arr[i] = len - 1 - i; 30 | } 31 | 32 | for (int i = 0; i < len; i = i + 1) { 33 | if (arr[i] != len - 1 - i) return EXIT_FAILURE; 34 | } 35 | 36 | int tmp = 0; 37 | for (int i = 0; i < len - 1; i = i + 1) { 38 | for (int j = 0; j < len - 1 - i; j = j + 1) 39 | if (arr[j] > arr[j + 1]) { 40 | tmp = arr[j]; 41 | arr[j] = arr[j + 1]; 42 | arr[j + 1] = tmp; 43 | } 44 | } 45 | 46 | for (int i = 0; i < 100; i = i + 1) { 47 | if (arr[i] != i) return EXIT_FAILURE; 48 | } 49 | 50 | 51 | if (fib(n) != 55) return EXIT_FAILURE; 52 | 53 | if (min(a, b) != 2) return EXIT_FAILURE; 54 | 55 | if (max(a, b) != 3) return EXIT_FAILURE; 56 | 57 | if (sum(a, b) != 5) return EXIT_FAILURE; 58 | 59 | if (mul(a, b) != 6) return EXIT_FAILURE; 60 | 61 | if (div(a, b) != 0) return EXIT_FAILURE; 62 | 63 | return arr[len-1]; 64 | } 65 | -------------------------------------------------------------------------------- /test_dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # build the project 3 | 4 | ## PS. Now this test do not generate any file. 5 | ## keep the -o file_name just for satisfy the command line option requirement 6 | 7 | cargo build 8 | 9 | RED='\033[0;31m' 10 | BLUE='\033[0;34m' 11 | NC='\033[0m' 12 | inc=0 13 | 14 | crust_compile() { 15 | echo "TEST $inc: parse [$1]" 16 | echo "crust parse $1.c -> ast" && ./target/debug/crust $1.c 17 | } 18 | 19 | echo -e "[${BLUE}test begins${NC}]" 20 | echo -e "${BLUE}crust now only try to parse those files${NC}" 21 | 22 | srcdir=test/valid 23 | for f in $srcdir/*.c 24 | do 25 | inc=$(($inc+1)) 26 | file=${f%.*} 27 | crust_compile $file ./gen/$file 28 | if [ "$?" -ne 0 ]; then 29 | echo -e "[${RED}Error${NC}]" 30 | exit 1 31 | else 32 | echo -e "[${BLUE}parse ok${NC}]" 33 | fi 34 | done 35 | 36 | srcdir=sample_code 37 | for f in $srcdir/*.c 38 | do 39 | inc=$(($inc+1)) 40 | file=${f%.*} 41 | crust_compile $file ./gen/$file 42 | if [ "$?" -ne 0 ]; then 43 | echo -e "[${RED}Error${NC}]" 44 | exit 1 45 | else 46 | echo -e "[${BLUE}parse ok${NC}]" 47 | fi 48 | done 49 | 50 | # should cause error in parser 51 | srcdir=test/invalid 52 | for f in $srcdir/*.c 53 | do 54 | inc=$(($inc+1)) 55 | file=${f%.*} 56 | crust_compile $file ./gen/$file 57 | if [ "$?" -ne 1 ]; then 58 | echo -e "[${RED}Error${NC}]" 59 | exit 1 60 | else 61 | echo -e "[${BLUE}parse ok${NC}]" 62 | fi 63 | done 64 | 65 | # should cause no error 66 | srcdir=test/valid/parser 67 | for f in $srcdir/*.c 68 | do 69 | inc=$(($inc+1)) 70 | file=${f%.*} 71 | crust_compile $file ./gen/$file 72 | if [ "$?" -ne 0 ]; then 73 | echo -e "[${RED}Error${NC}]" 74 | exit 1 75 | else 76 | echo -e "[${BLUE}parse ok${NC}]" 77 | fi 78 | done 79 | 80 | # test for preprocessor 81 | srcdir=test/valid/cpp 82 | for f in $srcdir/*.c 83 | do 84 | inc=$(($inc+1)) 85 | file=${f%.*} 86 | crust_compile $file ./gen/$file 87 | if [ "$?" -ne 0 ]; then 88 | echo -e "[${RED}Error${NC}]" 89 | exit 1 90 | else 91 | echo -e "[${BLUE}parse ok${NC}]" 92 | fi 93 | done 94 | 95 | echo -e "Now the parser can parse them all" 96 | -------------------------------------------------------------------------------- /src/sema.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Haoran Wang 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // ------------------------------------------------------------------------ 15 | //! sema.rs : semantis checker for crust compiler tool-chain 16 | //! 17 | //! # rules 18 | //! 19 | //! * type should match when assign 20 | //! * different type should invoke implicit cast 21 | //! * declare before use 22 | //! * argument type should match when calling a function 23 | // ------------------------------------------------------------------------ 24 | use crate::ast::ParseNode; 25 | use crate::lexer; 26 | use crate::symtable; 27 | 28 | pub fn judge_cast( 29 | _to_type: &symtable::TypeExpression, 30 | _from_type: &symtable::TypeExpression, 31 | ) -> bool { 32 | // TODO: should finish a judge function: 33 | // judge whether can we use type_name to cast the cast_expression 34 | // most situations should raise error, like we can not write (struct) int, etc.. 35 | // now just return true 36 | 37 | return true; 38 | } 39 | 40 | pub fn judge_combine_type( 41 | _l_type: &symtable::TypeExpression, 42 | r_type: &symtable::TypeExpression, 43 | _op: &lexer::TokType, 44 | ) -> (bool, symtable::TypeExpression) { 45 | // TODO: now just return true and the r_type 46 | // need to judge whether we can combine two types and return the new type. 47 | 48 | return (true, r_type.clone()); 49 | } 50 | 51 | pub fn judge_type_same( 52 | _l_type: &symtable::TypeExpression, 53 | _r_type: &symtable::TypeExpression, 54 | ) -> bool { 55 | // TODO: now just return true 56 | 57 | return true; 58 | } 59 | 60 | pub fn implicit_type_cast( 61 | l_type: &symtable::TypeExpression, 62 | _r_type: &symtable::TypeExpression, 63 | ) -> Result { 64 | // TODO: implicit convert r_type to l_type, if able then return TypeExpression, 65 | // else return Err. Now just simply return l_type. 66 | 67 | return Ok(l_type.clone()); 68 | } 69 | 70 | /// Semantics analysis driver 71 | /// # Args: 72 | /// * `ParseNode` : root of the parse tree 73 | /// * `c_src_name`: input file name 74 | /// 75 | /// # Return 76 | /// * Ok -> Ok(()) 77 | /// * Err -> Err(msg) 78 | #[allow(dead_code)] 79 | pub fn sema_driver(_tree: &ParseNode, _c_src_name: &str) -> Result<(), String> { 80 | return Ok(()); 81 | } 82 | -------------------------------------------------------------------------------- /src/ast.rs: -------------------------------------------------------------------------------- 1 | use crate::lexer; 2 | use crate::symtable::TypeExpression; 3 | // ---------------------------------------------------------------------------------------- 4 | #[allow(dead_code)] 5 | #[derive(PartialEq, Clone, Debug)] 6 | pub enum NodeType { 7 | BinaryExpression(lexer::TokType), 8 | PrimaryExpression, 9 | Constant(ConstantType), 10 | EnumerationConstant(String), 11 | Identifier(String), 12 | STRING(String), 13 | GenericSelection, 14 | GenericAssociation, 15 | GenericAssocList, 16 | PostfixExpression, 17 | PostfixExpressionPost(lexer::TokType), 18 | ArgumentExpressionList, 19 | UnaryExpression(Option), 20 | UnaryOperator(lexer::TokType), 21 | CastExpression, 22 | MultiplicativeExpression, 23 | AdditiveExpression, 24 | ShiftExpression, 25 | RelationalExpression, 26 | EqualityExpression, 27 | AndExpression, 28 | ExclusiveOrExpression, 29 | InclusiveOrExpression, 30 | LogicalAndExpression, 31 | LogicalOrExpression, 32 | ConditionalExpression, 33 | AssignmentExpression, 34 | AssignmentOperator(lexer::TokType), 35 | Expression, 36 | ConstantExpression, 37 | Declaration, 38 | DeclarationSpecifiers, 39 | InitDeclaratorList, 40 | InitDeclarator, 41 | StorageClassSpecifier(lexer::TokType), 42 | TypeSpecifier(Option), 43 | StructOrUnionSpecifier, 44 | StructOrUnion(lexer::TokType), 45 | StructDeclarationList, 46 | StructDeclaration, 47 | SpecifierQualifier, 48 | StructDeclaratorList, 49 | StructDeclarator, 50 | EnumSpecifier(Option), // Option 51 | EnumeratorList, 52 | Enumerator, 53 | AtomicTypeSpecifier, 54 | TypeQualifier(lexer::TokType), 55 | FunctionSpecifier(lexer::TokType), 56 | AlignmentSpecifier, 57 | Declarator, 58 | DirectDeclarator, 59 | DirectDeclaratorPostList, 60 | DirectDeclaratorPost(lexer::TokType), 61 | Pointer, // one node represents one `*` 62 | TypeQualifierList, 63 | ParameterDeclaration, 64 | ParameterTypeList(bool), // true: has ..., var_arg_list 65 | ParameterList, 66 | IdentifierList, 67 | TypeName, 68 | AbstractDeclarator, 69 | InitializerList, 70 | DirectAbstractDeclarator, 71 | DirectAbstractDeclaratorBlock(lexer::TokType), 72 | Initializer, 73 | Designation, 74 | DesignatorList, 75 | Designator, 76 | StaticAssertDeclaration, 77 | Statement, 78 | LabeledStatement(String), // string: label 79 | CompoundStatement, 80 | BlockItemList, 81 | BlockItem, 82 | ExpressionStatement, 83 | SelectionStatement(lexer::TokType), // if, switch 84 | IterationStatement(lexer::TokType), 85 | JumpStatement(String, Option), // String: goto, continue, ... Option : label 86 | TranslationUnit, 87 | ExternalDeclaration, 88 | FunctionDefinition, 89 | DeclarationList, 90 | } 91 | #[derive(PartialEq, Clone, Debug)] 92 | pub enum ConstantType { 93 | I64(i64), 94 | F64(f64), 95 | String(String), 96 | } 97 | 98 | #[derive(PartialEq, Clone, Debug)] 99 | pub struct ParseNode { 100 | pub child: Vec, 101 | pub entry: NodeType, 102 | pub type_exp: TypeExpression, 103 | } 104 | 105 | impl ParseNode { 106 | pub fn new(s: NodeType) -> ParseNode { 107 | ParseNode { 108 | child: Vec::new(), 109 | entry: s, 110 | type_exp: TypeExpression::new(), 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CRUST 2 | [![Build Status](https://travis-ci.com/onehr/crust.svg?branch=master)](https://travis-ci.com/onehr/crust) 3 | [![Gitter](https://badges.gitter.im/crust-dev/community.svg)](https://gitter.im/crust-dev/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 4 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fonehr%2Fcrust.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fonehr%2Fcrust?ref=badge_shield) 5 | [![](https://tokei.rs/b1/github/onehr/crust)](https://github.com/onehr/crust) 6 | ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/onehr/crust.svg?style=plastic) 7 | ![GitHub](https://img.shields.io/github/license/onehr/crust.svg) 8 | 9 | A simple C compiler written in the Rust-lang. (early development stage, started at Mar 30, 2019) 10 | 11 | **(PS. this is the development branch, 12 | if you want to see how to write a simple c compiler in rust, you should check 13 | [branch toy](https://github.com/onehr/crust/tree/toy), 14 | which contains a simple c compiler written in rust without extra libs, 15 | it can read simple c source code and produce x86-64 assembly code).** 16 | 17 | ## Project Goal 18 | Should follow the C11 Standard and generate binary code from C source code. 19 | 20 | This compiler is in the very early development stage, 21 | the plan is to continue developing it until it can compile real-world applications. 22 | 23 | If you are interested in `crust` and want to contribute, feel free to join the Gitter chat room, 24 | we have already got some contributors now who are interested in building this project. 25 | 26 | ## Milestone 0.1 Goal 27 | 1. Finish the preprocessor. 28 | 2. Support all C11 grammar rules. 29 | 3. replace gcc with it's own assembler to generate binary code 30 | 4. Stabilize the interfaces among different layers. 31 | 5. With some possible optimizations. 32 | 33 | ## Track of current progress 34 | - Preprocessor (working on) 35 | - [X] support `#include "local-header"`, nested-include is supported (need to add more features) 36 | - [X] Trigraph translation 37 | - [X] comment support `/**/ and //` 38 | - [X] line concatenation with ` \ ` 39 | - [X] object-like macro expansion 40 | - [X] function-like macro expansion 41 | - [ ] should support all directives (ifdef, elif, endif, ...) 42 | - Lexer (working on) 43 | - [X] lex all c11 keywords 44 | - [ ] the floating point number and number with postfix should be supported later. 45 | * Parser (almost done, need to be carefully tested) 46 | - [X] support c11 standard and generate ast tree 47 | - [ ] better ast printer 48 | - [ ] should be able handle typedef 49 | - [ ] add more tests for parser 50 | * Semantics Analyzer (working on) 51 | - [X] Type system 52 | - [ ] Type checker 53 | * Benchmark (working on) 54 | - [X] Use [Criterion.rs](https://github.com/bheisler/criterion.rs#quickstart) to do benchmarks. 55 | - [ ] Generate more informations from benchmarking. 56 | * IR generator (TODO) 57 | * Optimizer (TODO) 58 | * Assembly code generator (TODO) 59 | * Code clean up 60 | - [ ] Remove `#[allow(dead_code)]` 61 | 62 | ## Requirements 63 | 64 | You need a valid rust environment, Cargo. 65 | 66 | ## Build 67 | (PS. Now the crust can only preprocess, lex, and parse the source code, the generator was disabled now). 68 | ```bash 69 | $ cargo build # use this command to build the project 70 | ``` 71 | run 72 | ```shell 73 | $ cargo run [FLAGS] ... 74 | ``` 75 | 76 | ## Running Tests 77 | 78 | Run: 79 | ```bash 80 | $ ./test_dev.sh 81 | ``` 82 | 83 | ## Benchmark 84 | (PS. This is pretty time consuming, 85 | cause benchmark will do lots of iterations to test different layers' performance. 86 | 87 | Might take 20 to 30 minutes until it is finished. 88 | ) 89 | Run: 90 | ```bash 91 | $ cargo bench 92 | ``` 93 | 94 | After it is finished, 95 | you can open `target/criterion/report/index.html` in your web browser to see the details of performance. 96 | 97 | ## License 98 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fonehr%2Fcrust.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fonehr%2Fcrust?ref=badge_large) 99 | -------------------------------------------------------------------------------- /benches/bench_lexer.rs: -------------------------------------------------------------------------------- 1 | extern crate crust; 2 | #[macro_use] 3 | extern crate criterion; 4 | 5 | use criterion::black_box; 6 | use criterion::Criterion; 7 | 8 | use crust::lexer; 9 | use std::{error, fs}; 10 | 11 | fn criterion_benchmark(c: &mut Criterion) -> Result<(), Box> { 12 | let input_files = &[ 13 | "test/valid/nested_scope_2.c", 14 | "test/valid/consecutive_declarations.c", 15 | "test/valid/return_0.c", 16 | "test/valid/continue_empty_post.c", 17 | "test/valid/for_nested_scope.c", 18 | "test/valid/nested_break_3.c", 19 | "test/valid/multiple_vars.c", 20 | "test/valid/sub.c", 21 | "test/valid/mult.c", 22 | "test/valid/ternary.c", 23 | "test/valid/if_nested.c", 24 | "test/valid/multi_arg_2.c", 25 | "test/valid/combine_4.c", 26 | "test/valid/declare_late.c", 27 | "test/valid/continue.c", 28 | "test/valid/nested_scope.c", 29 | "test/valid/combine.c", 30 | "test/valid/else.c", 31 | "test/valid/while_single_statement.c", 32 | "test/valid/associativity_3.c", 33 | "test/valid/gt_true.c", 34 | "test/valid/combine_3.c", 35 | "test/valid/assign_ternary.c", 36 | "test/valid/fun_shadowed_by_variable.c", 37 | "test/valid/for_variable_shadow.c", 38 | "test/valid/new_precedence.c", 39 | "test/valid/variable_as_arg.c", 40 | "test/valid/nested_break_2.c", 41 | "test/valid/no_initialize.c", 42 | "test/valid/le_true.c", 43 | "test/valid/decl_1.c", 44 | "test/valid/multi_nesting.c", 45 | "test/valid/multiple_if.c", 46 | "test/valid/declare_after_block.c", 47 | "test/valid/nested_ops_2.c", 48 | "test/valid/global_shadowed.c", 49 | "test/valid/nested_if.c", 50 | "test/valid/global_array_3.c", 51 | "test/valid/multiple_ternary.c", 52 | "test/valid/nested_while.c", 53 | "test/valid/combine_2.c", 54 | "test/valid/lt_true.c", 55 | "test/valid/and_false.c", 56 | "test/valid/return_in_while.c", 57 | "test/valid/precedence_3.c", 58 | "test/valid/nested_while_2.c", 59 | "test/valid/gt_false.c", 60 | "test/valid/if_nested_2.c", 61 | "test/valid/for.c", 62 | "test/valid/nested_break.c", 63 | "test/valid/refer.c", 64 | "test/valid/assign.c", 65 | "test/valid/if_not_taken.c", 66 | "test/valid/associativity_5.c", 67 | "test/valid/fib.c", 68 | "test/valid/multi_return.c", 69 | "test/valid/global_array_2.c", 70 | "test/valid/single_arg.c", 71 | "test/valid/ternary_short_circuit.c", 72 | "test/valid/initialize.c", 73 | "test/valid/bitwise_zero.c", 74 | "test/valid/nested_for.c", 75 | "test/valid/ge_true.c", 76 | "test/valid/expression_args.c", 77 | "test/valid/neg.c", 78 | "test/valid/unop_parens.c", 79 | "test/valid/add.c", 80 | "test/valid/lt_false.c", 81 | "test/valid/not_five.c", 82 | "test/valid/multi_digit.c", 83 | "test/valid/if_nested_5.c", 84 | "test/valid/assign_val.c", 85 | "test/valid/nested_while_3.c", 86 | "test/valid/multi_arg.c", 87 | "test/valid/multi_arg_1.c", 88 | "test/valid/or_false.c", 89 | "test/valid/multiple_global.c", 90 | "test/valid/for_empty.c", 91 | "test/valid/no_newlines.c", 92 | "test/valid/nested_ternary_2.c", 93 | "test/valid/exp_return_val.c", 94 | "test/valid/eq_true.c", 95 | "test/valid/associativity_4.c", 96 | "test/valid/missing_return.c", 97 | "test/valid/complicated_exp.c", 98 | "test/valid/not_zero.c", 99 | "test/valid/rh_assignment.c", 100 | "test/valid/newlines.c", 101 | "test/valid/unop_add.c", 102 | "test/valid/ge_false.c", 103 | "test/valid/sub_neg.c", 104 | "test/valid/global_array_1.c", 105 | "test/valid/ne_false.c", 106 | "test/valid/for_decl.c", 107 | "test/valid/no_arg.c", 108 | "test/valid/nested_ternary.c", 109 | "test/valid/ternary_short_circuit_2.c", 110 | "test/valid/associativity.c", 111 | "test/valid/precedence_2.c", 112 | "test/valid/empty_expression.c", 113 | "test/valid/rename_function_param.c", 114 | "test/valid/div.c", 115 | "test/valid/precedence_4.c", 116 | "test/valid/global.c", 117 | "test/valid/bitwise.c", 118 | "test/valid/nested_ops.c", 119 | "test/valid/unused_exp.c", 120 | "test/valid/if_taken.c", 121 | "test/valid/mutual_recursion.c", 122 | "test/valid/fun_in_expr.c", 123 | "test/valid/ne_true.c", 124 | "test/valid/associativity_2.c", 125 | "test/valid/if_nested_4.c", 126 | "test/valid/global_not_initialized.c", 127 | "test/valid/consecutive_blocks.c", 128 | "test/valid/precedence.c", 129 | "test/valid/le_false.c", 130 | "test/valid/while_multi_statement.c", 131 | "test/valid/spaces.c", 132 | "test/valid/declare_block.c", 133 | "test/valid/break.c", 134 | "test/valid/bubble_sort.c", 135 | "test/valid/and_true.c", 136 | "test/valid/or_true.c", 137 | "test/valid/do_while.c", 138 | "test/valid/return_2.c", 139 | "test/valid/parens.c", 140 | "test/valid/if_nested_3.c", 141 | "test/valid/eq_false.c", 142 | ]; 143 | for input_file in input_files.iter() { 144 | c.bench_function(&format!("lex {}", input_file), move |b| { 145 | b.iter(|| lexer::lex(black_box(&fs::read_to_string(input_file).unwrap()))) 146 | }); 147 | } 148 | return Ok(()); 149 | } 150 | 151 | criterion_group!(benches, criterion_benchmark); 152 | criterion_main!(benches); 153 | -------------------------------------------------------------------------------- /benches/bench_parser.rs: -------------------------------------------------------------------------------- 1 | extern crate crust; 2 | #[macro_use] 3 | extern crate criterion; 4 | 5 | use criterion::black_box; 6 | use criterion::Criterion; 7 | 8 | use crust::{cpp, lexer, parser}; 9 | use std::{error, fs, path::PathBuf}; 10 | 11 | fn criterion_benchmark(c: &mut Criterion) -> Result<(), Box> { 12 | let input_files = &[ 13 | "test/valid/nested_scope_2.c", 14 | "test/valid/consecutive_declarations.c", 15 | "test/valid/return_0.c", 16 | "test/valid/continue_empty_post.c", 17 | "test/valid/for_nested_scope.c", 18 | "test/valid/nested_break_3.c", 19 | "test/valid/multiple_vars.c", 20 | "test/valid/sub.c", 21 | "test/valid/mult.c", 22 | "test/valid/ternary.c", 23 | "test/valid/if_nested.c", 24 | "test/valid/multi_arg_2.c", 25 | "test/valid/combine_4.c", 26 | "test/valid/declare_late.c", 27 | "test/valid/continue.c", 28 | "test/valid/nested_scope.c", 29 | "test/valid/combine.c", 30 | "test/valid/else.c", 31 | "test/valid/while_single_statement.c", 32 | "test/valid/associativity_3.c", 33 | "test/valid/gt_true.c", 34 | "test/valid/combine_3.c", 35 | "test/valid/assign_ternary.c", 36 | "test/valid/fun_shadowed_by_variable.c", 37 | "test/valid/for_variable_shadow.c", 38 | "test/valid/new_precedence.c", 39 | "test/valid/variable_as_arg.c", 40 | "test/valid/nested_break_2.c", 41 | "test/valid/no_initialize.c", 42 | "test/valid/le_true.c", 43 | "test/valid/decl_1.c", 44 | "test/valid/multi_nesting.c", 45 | "test/valid/multiple_if.c", 46 | "test/valid/declare_after_block.c", 47 | "test/valid/nested_ops_2.c", 48 | "test/valid/global_shadowed.c", 49 | "test/valid/nested_if.c", 50 | "test/valid/global_array_3.c", 51 | "test/valid/multiple_ternary.c", 52 | "test/valid/nested_while.c", 53 | "test/valid/combine_2.c", 54 | "test/valid/lt_true.c", 55 | "test/valid/and_false.c", 56 | "test/valid/return_in_while.c", 57 | "test/valid/precedence_3.c", 58 | "test/valid/nested_while_2.c", 59 | "test/valid/gt_false.c", 60 | "test/valid/if_nested_2.c", 61 | "test/valid/for.c", 62 | "test/valid/nested_break.c", 63 | "test/valid/refer.c", 64 | "test/valid/assign.c", 65 | "test/valid/if_not_taken.c", 66 | "test/valid/associativity_5.c", 67 | "test/valid/fib.c", 68 | "test/valid/multi_return.c", 69 | "test/valid/global_array_2.c", 70 | "test/valid/single_arg.c", 71 | "test/valid/ternary_short_circuit.c", 72 | "test/valid/initialize.c", 73 | "test/valid/bitwise_zero.c", 74 | "test/valid/nested_for.c", 75 | "test/valid/ge_true.c", 76 | "test/valid/expression_args.c", 77 | "test/valid/neg.c", 78 | "test/valid/unop_parens.c", 79 | "test/valid/add.c", 80 | "test/valid/lt_false.c", 81 | "test/valid/not_five.c", 82 | "test/valid/multi_digit.c", 83 | "test/valid/if_nested_5.c", 84 | "test/valid/assign_val.c", 85 | "test/valid/nested_while_3.c", 86 | "test/valid/multi_arg.c", 87 | "test/valid/multi_arg_1.c", 88 | "test/valid/or_false.c", 89 | "test/valid/multiple_global.c", 90 | "test/valid/for_empty.c", 91 | "test/valid/no_newlines.c", 92 | "test/valid/nested_ternary_2.c", 93 | "test/valid/exp_return_val.c", 94 | "test/valid/eq_true.c", 95 | "test/valid/associativity_4.c", 96 | "test/valid/missing_return.c", 97 | "test/valid/complicated_exp.c", 98 | "test/valid/not_zero.c", 99 | "test/valid/rh_assignment.c", 100 | "test/valid/newlines.c", 101 | "test/valid/unop_add.c", 102 | "test/valid/ge_false.c", 103 | "test/valid/sub_neg.c", 104 | "test/valid/global_array_1.c", 105 | "test/valid/ne_false.c", 106 | "test/valid/for_decl.c", 107 | "test/valid/no_arg.c", 108 | "test/valid/nested_ternary.c", 109 | "test/valid/ternary_short_circuit_2.c", 110 | "test/valid/associativity.c", 111 | "test/valid/precedence_2.c", 112 | "test/valid/empty_expression.c", 113 | "test/valid/rename_function_param.c", 114 | "test/valid/div.c", 115 | "test/valid/precedence_4.c", 116 | "test/valid/global.c", 117 | "test/valid/bitwise.c", 118 | "test/valid/nested_ops.c", 119 | "test/valid/unused_exp.c", 120 | "test/valid/if_taken.c", 121 | "test/valid/mutual_recursion.c", 122 | "test/valid/fun_in_expr.c", 123 | "test/valid/ne_true.c", 124 | "test/valid/associativity_2.c", 125 | "test/valid/if_nested_4.c", 126 | "test/valid/global_not_initialized.c", 127 | "test/valid/consecutive_blocks.c", 128 | "test/valid/precedence.c", 129 | "test/valid/le_false.c", 130 | "test/valid/while_multi_statement.c", 131 | "test/valid/spaces.c", 132 | "test/valid/declare_block.c", 133 | "test/valid/break.c", 134 | "test/valid/bubble_sort.c", 135 | "test/valid/and_true.c", 136 | "test/valid/or_true.c", 137 | "test/valid/do_while.c", 138 | "test/valid/return_2.c", 139 | "test/valid/parens.c", 140 | "test/valid/if_nested_3.c", 141 | "test/valid/eq_false.c", 142 | ]; 143 | for input_file in input_files.iter() { 144 | let input_file_contents = fs::read_to_string(input_file.clone())?; 145 | // 1. Preprocessing 146 | let contents_after_cpp = 147 | cpp::cpp_driver(input_file_contents, PathBuf::from(input_file.clone()))?; 148 | // 2. lexing 149 | let tokens = lexer::lex(&contents_after_cpp)?; 150 | let name = input_file.clone(); 151 | 152 | c.bench_function(&format!("parse {}", input_file), move |b| { 153 | b.iter(|| parser::parser_driver(black_box(&tokens), &name)) 154 | }); 155 | } 156 | return Ok(()); 157 | } 158 | 159 | criterion_group!(benches, criterion_benchmark); 160 | criterion_main!(benches); 161 | -------------------------------------------------------------------------------- /src/symtable.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Haoran Wang 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // ------------------------------------------------------------------------ 15 | // symtable.rs: symbol table for identifiers. 16 | // ------------------------------------------------------------------------ 17 | 18 | const _X86_64_CHAR_BYTES: u64 = 1; 19 | const _X86_64_SHORT_BYTES: u64 = 2; 20 | const _X86_64_INT_BYTES: u64 = 4; 21 | const _X86_64_LONG_BYTES: u64 = 8; 22 | 23 | const _NUM_REG: usize = 16; 24 | 25 | const _B64_REG_NAMES: [&str; _NUM_REG] = [ 26 | "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp", "r8", "r9", "r10", "r11", "r12", "r13", 27 | "r14", "r15", 28 | ]; 29 | const _B32_REG_NAMES: [&str; _NUM_REG] = [ 30 | "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp", "r8d", "r9d", "r10d", "r11d", "r12d", 31 | "r13d", "r14d", "r15d", 32 | ]; 33 | const _B16_REG_NAMES: [&str; _NUM_REG] = [ 34 | "ax", "bx", "cx", "dx", "si", "di", "bp", "sp", "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", 35 | "r14w", "r15w", 36 | ]; 37 | const _B8_REG_NAMES: [&str; _NUM_REG] = [ 38 | "al", "bl", "cl", "dl", "sil", "dil", "bpl", "spl", "r8b", "r9b", "r10b", "r11b", "r12b", 39 | "r13b", "r14b", "r15b", 40 | ]; 41 | 42 | #[derive(PartialEq, Clone, Debug)] 43 | pub struct SymbolRecord { 44 | pub name: String, 45 | pub attr: SymbolAttr, 46 | } 47 | 48 | #[allow(dead_code)] 49 | impl SymbolRecord { 50 | pub fn new(s: String, a: SymbolAttr) -> SymbolRecord { 51 | SymbolRecord { 52 | name: s.clone(), 53 | attr: a, 54 | } 55 | } 56 | } 57 | 58 | #[derive(PartialEq, Clone, Debug)] 59 | pub enum BaseType { 60 | Void, 61 | VoidPointer, 62 | Char, 63 | Short, 64 | Int, 65 | Long, 66 | Float, 67 | Double, 68 | Signed, 69 | Unsigned, 70 | SizeT, 71 | Bool, 72 | Complex, 73 | Imaginary, 74 | Pointer, 75 | Function, 76 | Array(usize), // len 77 | Struct, 78 | Union, 79 | Identifier(String), 80 | VaList, 81 | 82 | Noreturn, 83 | Inline, 84 | 85 | Const, 86 | Restrict, 87 | Volatile, 88 | Atomic, 89 | 90 | Static, 91 | ThreadLocal, 92 | Extern, 93 | Register, 94 | Auto, 95 | 96 | NoneExpression, // error if assign this 97 | } 98 | 99 | /// struct: TypeExpressionTree 100 | /// 101 | /// # Note: 102 | /// 103 | /// In semantics analysis, the semantics checker should build a TypeExpressionTree. 104 | /// to make type checking 105 | #[derive(PartialEq, Clone, Debug)] 106 | pub struct TypeExpression { 107 | // XXX: cause every node can contains a type that need to combine several kind of 108 | // base type, like *var -> *(void *), string literal -> arr + char 109 | pub val: Vec, 110 | pub child: Vec, 111 | } 112 | 113 | impl TypeExpression { 114 | pub fn new() -> TypeExpression { 115 | TypeExpression { 116 | // should occur when we don't know now what is its type. It may need to 117 | // but should be judged by it's parent. 118 | val: Vec::new(), 119 | child: Vec::new(), 120 | } 121 | } 122 | pub fn new_val(s: BaseType) -> TypeExpression { 123 | let mut v: Vec = Vec::new(); 124 | v.push(s); 125 | TypeExpression { 126 | val: v, 127 | child: Vec::new(), 128 | } 129 | } 130 | 131 | pub fn print(&self) -> String { 132 | let mut format_str = String::new(); 133 | if self.val.is_empty() { 134 | if self.child.is_empty() { 135 | return format_str; 136 | } 137 | for it in self.child.iter() { 138 | format_str.push_str(&(*it).print()); 139 | } 140 | } else { 141 | format_str.push_str(&format!(" {:?} ", self.val)); 142 | if self.child.is_empty() { 143 | return format_str; 144 | } 145 | for it in self.child.iter() { 146 | format_str.push_str("{"); 147 | format_str.push_str(&(*it).print()); 148 | format_str.push_str("}"); 149 | } 150 | } 151 | 152 | format_str 153 | } 154 | } 155 | 156 | #[allow(dead_code)] 157 | #[derive(PartialEq, Clone, Debug)] 158 | pub enum StorageClass { 159 | Local, 160 | Static, 161 | Global, 162 | } 163 | 164 | #[derive(PartialEq, Clone, Debug)] 165 | pub struct SymbolAttr { 166 | volatile: bool, // Asynchronously accessed. 167 | size: u64, // size in bytes. 168 | boundary: u64, // alignment in bytes. 169 | base_type: TypeExpression, // base type in source language. 170 | n_elements: u64, // number of elements. 171 | register: bool, // whether the value is in register. 172 | reg: u64, // index of the name of register which contains the value. 173 | base_reg: u64, // index of the name of register used to calculate the symbol's address. 174 | storage_class: StorageClass, // `local`, `static`, `global` 175 | fn_parameter: bool, // true: a function parameter 176 | // loc: SourceLoc// TODO: add source code location 177 | } 178 | 179 | #[allow(dead_code)] 180 | impl SymbolAttr { 181 | pub fn new() -> SymbolAttr { 182 | SymbolAttr { 183 | volatile: false, 184 | size: _X86_64_INT_BYTES, 185 | boundary: _X86_64_INT_BYTES, 186 | base_type: TypeExpression::new_val(BaseType::Int), 187 | n_elements: 1, 188 | register: false, 189 | reg: 0, 190 | base_reg: 0, 191 | storage_class: StorageClass::Local, 192 | fn_parameter: false, 193 | } 194 | } 195 | pub fn _set_volatile(&mut self, val: bool) { 196 | self.volatile = val; 197 | } 198 | pub fn _set_size(&mut self, val: u64) { 199 | self.size = val; 200 | } 201 | pub fn _set_boundary(&mut self, val: u64) { 202 | self.boundary = val; 203 | } 204 | pub fn _set_base_type(&mut self, val: TypeExpression) { 205 | self.base_type = val.clone(); 206 | } 207 | pub fn _set_n_elements(&mut self, val: u64) { 208 | self.n_elements = val; 209 | } 210 | pub fn _set_register(&mut self, val: bool) { 211 | self.register = val; 212 | } 213 | pub fn _set_reg(&mut self, idx: u64) { 214 | self.reg = idx; 215 | } 216 | pub fn _set_base_reg(&mut self, idx: u64) { 217 | self.base_reg = idx; 218 | } 219 | pub fn _set_storage_class(&mut self, class: StorageClass) { 220 | self.storage_class = class; 221 | } 222 | pub fn _set_fn_parameter(&mut self, val: bool) { 223 | self.fn_parameter = val; 224 | } 225 | 226 | pub fn _get_volatile(&self) -> bool { 227 | self.volatile 228 | } 229 | pub fn _get_size(&self) -> u64 { 230 | self.size 231 | } 232 | pub fn _get_boundary(&self) -> u64 { 233 | self.boundary 234 | } 235 | pub fn _get_base_type(&self) -> TypeExpression { 236 | self.base_type.clone() 237 | } 238 | pub fn _get_n_elements(&self) -> u64 { 239 | self.n_elements 240 | } 241 | pub fn _get_register(&self) -> bool { 242 | self.register 243 | } 244 | pub fn _get_reg(&self) -> u64 { 245 | self.reg 246 | } 247 | pub fn _get_basereg(&self) -> u64 { 248 | self.base_reg 249 | } 250 | pub fn _get_storage_class(&self) -> StorageClass { 251 | self.storage_class.clone() 252 | } 253 | pub fn _get_fn_parameter(&self) -> bool { 254 | self.fn_parameter 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/cpp.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Haoran Wang 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // ----------------------------------------------------------------------------- 16 | // cpp.rs: Simple c preprocessor 17 | // ----------------------------------------------------------------------------- 18 | 19 | use lazy_static::lazy_static; 20 | use log::{debug, error}; 21 | use regex::Regex; 22 | use std::collections::HashMap; 23 | use std::path::PathBuf; 24 | use std::sync::Mutex; 25 | use std::{error, fs, path::Path}; 26 | 27 | #[derive(Debug)] 28 | struct Macro { 29 | replacement: String, 30 | params: Vec, 31 | } 32 | lazy_static! { 33 | static ref MACROS: Mutex> = { 34 | let m = HashMap::new(); 35 | Mutex::new(m) 36 | }; 37 | } 38 | 39 | fn trigraph_processor(input: String) -> Result { 40 | // Trigraph: ??( ??) ??< ??> ??= ??/ ??' ??! ??- 41 | // Replacement: [ ] { } # \ ^ | ~ 42 | let mut res = "".to_string(); 43 | 44 | let mut idx = 0; 45 | while idx < input.len() { 46 | if idx > input.len() - 3 { 47 | res.push(char::from(input.as_bytes()[idx])); 48 | idx = idx + 1; 49 | continue; 50 | } 51 | let mut combine = String::new(); 52 | combine.push(char::from(input.as_bytes()[idx])); 53 | combine.push(char::from(input.as_bytes()[idx + 1])); 54 | combine.push(char::from(input.as_bytes()[idx + 2])); 55 | match combine.as_ref() { 56 | "??(" => { 57 | res.push('['); 58 | idx += 3; 59 | } 60 | "??)" => { 61 | res.push(']'); 62 | idx += 3; 63 | } 64 | "??<" => { 65 | res.push('{'); 66 | idx += 3; 67 | } 68 | "??>" => { 69 | res.push('}'); 70 | idx += 3; 71 | } 72 | "??=" => { 73 | res.push('#'); 74 | idx += 3; 75 | } 76 | "??/" => { 77 | res.push('\\'); 78 | idx += 3; 79 | } 80 | "??'" => { 81 | res.push('^'); 82 | idx += 3; 83 | } 84 | "??!" => { 85 | res.push('|'); 86 | idx += 3; 87 | } 88 | "??-" => { 89 | res.push('~'); 90 | idx += 3; 91 | } 92 | _ => { 93 | res.push(char::from(input.as_bytes()[idx])); 94 | idx += 1; 95 | } 96 | } 97 | } 98 | return Ok(res); 99 | } 100 | 101 | fn line_concat(input: String) -> Result { 102 | let mut res = String::new(); 103 | let mut it = input.chars().peekable(); 104 | while let Some(&c) = it.peek() { 105 | if c == '\\' { 106 | it.next(); 107 | if let Some(&nc) = it.peek() { 108 | match nc { 109 | '\n' => { 110 | // remove this `\` and `\n` 111 | // so nothing here, just skip 112 | } 113 | _ => { 114 | res.push(c); 115 | res.push(nc); 116 | } 117 | } 118 | } else { 119 | // no other characters, at the end of file 120 | // Should give warning, but continue compile. 121 | // cause crust now has no warning option, so just remove this `\` 122 | break; 123 | } 124 | } else { 125 | res.push(c); 126 | } 127 | it.next(); 128 | } 129 | 130 | return Ok(res); 131 | } 132 | 133 | fn remove_comment(input: String) -> Result { 134 | fn in_comment(single: bool, multi: bool) -> bool { 135 | return single || multi; 136 | } 137 | let mut res = String::new(); 138 | 139 | let mut idx = 0; 140 | let mut single_line_in_comment = false; 141 | let mut multi_line_in_comment = false; 142 | while idx < input.len() { 143 | if idx == input.len() - 1 { 144 | if single_line_in_comment || multi_line_in_comment { 145 | // skip 146 | break; 147 | } else { 148 | res.push(char::from(input.as_bytes()[idx])); 149 | break; 150 | } 151 | } 152 | let b1 = char::from(input.as_bytes()[idx]); 153 | let b2 = char::from(input.as_bytes()[idx + 1]); 154 | 155 | let mut combine = String::new(); 156 | combine.push(b1); 157 | combine.push(b2); 158 | match combine.as_ref() { 159 | "//" => { 160 | if !in_comment(single_line_in_comment, multi_line_in_comment) { 161 | single_line_in_comment = true; 162 | } 163 | idx = idx + 2; 164 | } 165 | "/*" => { 166 | if !in_comment(single_line_in_comment, multi_line_in_comment) { 167 | multi_line_in_comment = true; 168 | } 169 | idx = idx + 2; 170 | } 171 | "*/" => { 172 | if multi_line_in_comment { 173 | multi_line_in_comment = false; 174 | idx = idx + 2; 175 | } else { 176 | res.push(b1); 177 | idx = idx + 1; 178 | } 179 | } 180 | _ => { 181 | if b1 == '\n' && single_line_in_comment { 182 | single_line_in_comment = false; 183 | idx = idx + 1; 184 | } else { 185 | if in_comment(single_line_in_comment, multi_line_in_comment) { 186 | idx = idx + 1; 187 | } else { 188 | res.push(b1); 189 | idx = idx + 1; 190 | } 191 | } 192 | } 193 | } 194 | } 195 | return Ok(res); 196 | } 197 | 198 | fn include_headers(input: String, parent: Option<&Path>) -> Result> { 199 | // TODO: now only support "header.h", system header file not supported now 200 | // should add system header support when the macro expension was finished and 201 | // other directives are supported. 202 | fn include_file_path(relational_name: &str) -> Result<&Path, String> { 203 | if char::from(relational_name.as_bytes()[0]) == '<' { 204 | return Err("Crust do not support system header now".to_string()); 205 | } 206 | let name = Path::new(&relational_name[1..(relational_name.len() - 1)]); 207 | return Ok(name); 208 | } 209 | 210 | let mut res = String::new(); 211 | 212 | for line in input.lines() { 213 | if line.is_empty() { 214 | // empty line 215 | res.push_str("\n"); 216 | continue; 217 | } 218 | match char::from(line.trim_start().as_bytes()[0]) { 219 | '#' => { 220 | let a: Vec<&str> = line.split_whitespace().collect(); 221 | let directive = *a.get(0).unwrap(); 222 | match directive { 223 | "#include" => { 224 | let file_name = include_file_path(*a.get(1).unwrap())?; 225 | let full_relational_path = file_name; 226 | 227 | match parent { 228 | None => { 229 | let header_contents = fs::read_to_string(full_relational_path)?; 230 | res.push_str(include_headers(header_contents, None)?.as_ref()); 231 | } 232 | Some(p_dir) => { 233 | let full_relational_path = p_dir.join(file_name); 234 | let header_contents = fs::read_to_string(full_relational_path)?; 235 | res.push_str(include_headers(header_contents, parent)?.as_ref()); 236 | } 237 | } 238 | } 239 | _ => { 240 | // just leave other directives to be handled by the directive_handler 241 | res.push_str(line); 242 | res.push_str("\n"); 243 | } 244 | } 245 | } 246 | _ => { 247 | res.push_str(line); 248 | res.push_str("\n"); 249 | } 250 | } 251 | } 252 | 253 | return Ok(res); 254 | } 255 | 256 | fn replace(input: String) -> String { 257 | // This is a function, which replace the string if contains defined identifier. 258 | let mut it = input.chars().peekable(); 259 | let mut res = String::new(); 260 | while let Some(&c) = it.peek() { 261 | match c { 262 | 'a'..='z' | 'A'..='Z' | '_' => { 263 | it.next(); 264 | let mut id = String::new(); 265 | id.push(c); 266 | while let Some(&tmp) = it.peek() { 267 | match tmp { 268 | 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => { 269 | id.push(tmp); 270 | it.next(); 271 | } 272 | _ => { 273 | break; 274 | } 275 | } 276 | } 277 | let mut get_val = String::new(); 278 | match MACROS.lock().unwrap().get(&id) { 279 | Some(s) => { 280 | // XXX: I use this method to get rid of deadlock. 281 | // cause call replace function in this scope will cause the 282 | // child function to lock the MACROS, which is locked here. 283 | 284 | let mut replacement = s.replacement.clone(); 285 | if !s.params.is_empty() { 286 | let re_args: Regex = 287 | Regex::new(&format!(r"{}\(([^)]+)\)", id)).unwrap(); 288 | 289 | if re_args.is_match(&input) { 290 | let caps = re_args.captures(&input).unwrap(); 291 | let matched = caps[0].to_string(); 292 | let all_args = caps[1].to_string(); 293 | let args: Vec<&str> = all_args.split(",").collect(); 294 | if args.len() != s.params.len() { 295 | error!("Not matched with macro arguments{:?}", id); 296 | } 297 | 298 | for (i, p) in s.params.iter().enumerate() { 299 | replacement = replacement.replace(p, args[i]); 300 | } 301 | 302 | // Skip matched text 303 | for _ in 0..matched.len() - id.len() { 304 | it.next(); 305 | } 306 | } else { 307 | error!("Unable to find macro's parameter, {:?}", id); 308 | } 309 | } 310 | get_val.push_str(&replacement); 311 | } 312 | None => { 313 | res.push_str(&id); 314 | } 315 | } 316 | // after the lock was released, can lock in child replace function 317 | res.push_str(&replace(get_val)); 318 | } 319 | _ => { 320 | res.push(c); 321 | it.next(); 322 | } 323 | } 324 | } 325 | return res; 326 | } 327 | 328 | fn directive_handler(input: String) -> Result> { 329 | // TODO: now only support #define directive 330 | let mut res = String::new(); 331 | 332 | let mut lines = input.lines(); 333 | loop { 334 | let iter = lines.next(); 335 | match iter { 336 | Some(line) => { 337 | if line.trim_start().is_empty() { 338 | // empty line 339 | res.push_str("\n"); 340 | continue; 341 | } 342 | match char::from(line.trim_start().as_bytes()[0]) { 343 | '#' => { 344 | lazy_static! { 345 | static ref RE_MACRO: Regex = Regex::new( 346 | r"^[ \t]*#define[ \t]+([A-Za-z0-9_]+)(\(.*\))?[ \t]*((?:.*\\\r?\n)*.*)" 347 | ) 348 | .unwrap(); 349 | } 350 | if RE_MACRO.is_match(line) { 351 | let caps = RE_MACRO.captures(line).unwrap(); 352 | let name = caps[1].to_string(); 353 | let params = caps 354 | .get(2) 355 | .map_or("", |m| m.as_str()) 356 | .to_string() 357 | .replace(&['(', ')', ' ', '\t'][..], ""); 358 | let replacement = caps[3].to_string(); 359 | 360 | let mut param_list = Vec::new(); 361 | for t in params.split(",") { 362 | if !t.is_empty() { 363 | param_list.push(t.to_string()); 364 | } 365 | } 366 | 367 | let m = Macro { 368 | replacement: replacement, 369 | params: param_list, 370 | }; 371 | debug!("Macro detected: name:{:?} => {:?}", name, m); 372 | 373 | MACROS.lock().unwrap().insert(name, m); 374 | } 375 | } 376 | _ => { 377 | // not directive starting sentence, so replace the token if it's defined before. 378 | // check every identifier name 379 | res.push_str(&replace(line.to_string())); 380 | res.push('\n'); 381 | } 382 | } 383 | } 384 | None => break, 385 | } 386 | } 387 | return Ok(res); 388 | } 389 | 390 | pub fn cpp_driver(input: String, path: PathBuf) -> Result> { 391 | let parent = path.parent(); 392 | // include the header files in the source file 393 | let after_cpp_str = include_headers(input, parent)?; 394 | // first translate trigraph into chars 395 | let after_cpp_str = trigraph_processor(after_cpp_str)?; 396 | // concatenate lines 397 | let after_cpp_str = line_concat(after_cpp_str)?; 398 | // remove comment 399 | let after_cpp_str = remove_comment(after_cpp_str)?; 400 | // directives handler 401 | let after_cpp_str = directive_handler(after_cpp_str)?; 402 | 403 | Ok(after_cpp_str) 404 | } 405 | -------------------------------------------------------------------------------- /src/lexer.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Haoran Wang 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // ------------------------------------------------------------------------ 15 | // lexer.rs: lexer for c11 tokens. 16 | // some situations should be added later. 17 | // ------------------------------------------------------------------------ 18 | // TODO: 1. add token information for error message. 19 | // 2. seperate each TokType to their type, now just a global type TokType. 20 | // 3. add some check in lexer for enum and typedef. 21 | // 4. add floating point number support. 22 | // 5. number with postfix. 23 | 24 | #[allow(dead_code)] 25 | #[derive(PartialEq, Clone, Debug)] 26 | pub enum TokType { 27 | LBrace, // { 28 | RBrace, // } 29 | LParen, // ( 30 | RParen, // ) 31 | LBracket, // [ 32 | RBracket, // ] 33 | Semicolon, // ; 34 | Assign, // = 35 | Lt, // < 36 | Gt, // > 37 | Minus, // - 38 | Tilde, // ~ 39 | Exclamation, // ! 40 | Plus, // + 41 | Multi, // * 42 | Splash, // / 43 | Colon, // : 44 | QuestionMark, // ? 45 | Comma, // , 46 | Dot, // . 47 | SingleAnd, // & 48 | InclusiveOr, // | 49 | ExclusiveOr, // ^ 50 | Mod, // % 51 | IDENTIFIER(String), 52 | IConstant(i64), 53 | FConstant(f64), 54 | StringLiteral(String, String), 55 | FuncName, // __func__ 56 | SIZEOF, // sizeof 57 | PtrOp, // -> 58 | IncOp, // ++ 59 | DecOp, // -- 60 | LeftOp, // << 61 | RightOp, // >> 62 | LeOp, // <= 63 | GeOp, // >= 64 | EqOp, // == 65 | NeOp, // != 66 | AndOp, // && 67 | OrOp, // || 68 | MulAssign, // *= 69 | DivAssign, // /= 70 | ModAssign, // %= 71 | AddAssign, // += 72 | SubAssign, // -= 73 | LeftAssign, // <<= 74 | RightAssign, // >>= 75 | AndAssign, // &= 76 | XorAssign, // ^= 77 | OrAssign, // |= 78 | // TODO: this should be done when we found this is a typedef name, 79 | // typedef LL int, then LL is typedef_name 80 | TypedefName, 81 | ELLIPSIS, // ... 82 | EnumerationConstant(String), // TODO: add check 83 | TYPEDEF, 84 | EXTERN, 85 | STATIC, 86 | AUTO, 87 | REGISTER, 88 | INLINE, 89 | CONST, 90 | RESTRICT, 91 | VOLATILE, 92 | BOOL, 93 | CHAR, 94 | SHORT, 95 | INT, 96 | LONG, 97 | SIGNED, 98 | UNSIGNED, 99 | FLOAT, 100 | DOUBLE, 101 | VOID, 102 | COMPLEX, 103 | IMAGINARY, 104 | STRUCT, 105 | UNION, 106 | ENUM, 107 | CASE, 108 | DEFAULT, 109 | IF, 110 | ELSE, 111 | SWITCH, 112 | WHILE, 113 | DO, 114 | FOR, 115 | GOTO, 116 | CONTINUE, 117 | BREAK, 118 | RETURN, 119 | ALIGNAS, 120 | ALIGNOF, 121 | ATOMIC, 122 | GENERIC, 123 | NORETURN, 124 | StaticAssert, 125 | ThreadLocal, 126 | } 127 | 128 | use std::sync::atomic; 129 | 130 | static LABEL_COUNTER: atomic::AtomicUsize = atomic::AtomicUsize::new(0); 131 | fn gen_string_tag() -> String { 132 | let label_counter = LABEL_COUNTER.fetch_add(1, atomic::Ordering::SeqCst); 133 | let label = format!(".LSTR{}", label_counter); 134 | 135 | label 136 | } 137 | 138 | pub fn lex(input: &str) -> Result, String> { 139 | let mut result = Vec::new(); 140 | 141 | let mut it = input.chars().peekable(); 142 | 143 | while let Some(&c) = it.peek() { 144 | match c { 145 | '"' => { 146 | it.next(); 147 | let mut s = "".to_string(); 148 | loop { 149 | let &c = it.peek().unwrap(); 150 | if c == '"' { 151 | break; 152 | } 153 | s.push(c); 154 | it.next(); 155 | } 156 | result.push(TokType::StringLiteral(s, gen_string_tag())); 157 | it.next(); 158 | } 159 | '\'' => { 160 | // try parse a char 161 | it.next(); // skip ' 162 | let &c = it.peek().unwrap(); 163 | if c == '\'' { 164 | return Err(format!("Error: empty character constant")); 165 | } 166 | if c == '\\' { 167 | it.next(); 168 | let &c = it.peek().unwrap(); 169 | match c { 170 | 'a' => { 171 | result.push(TokType::IConstant(0x07)); 172 | } // Alert (Beep, Bell) (added in C89) 173 | 'b' => { 174 | result.push(TokType::IConstant(0x08)); 175 | } // Backspace 176 | 'e' => { 177 | result.push(TokType::IConstant(0x1B)); 178 | } // escape character 179 | 'f' => { 180 | result.push(TokType::IConstant(0x0C)); 181 | } // Formfeed Page Break 182 | 'n' => { 183 | result.push(TokType::IConstant(0x0A)); 184 | } // Newline (Line Feed) 185 | 'r' => { 186 | result.push(TokType::IConstant(0x0D)); 187 | } // Carriage Return 188 | 't' => { 189 | result.push(TokType::IConstant(0x09)); 190 | } // Horizontal Tab 191 | 'v' => { 192 | result.push(TokType::IConstant(0x0B)); 193 | } // Vertical Tab 194 | '\\' => { 195 | result.push(TokType::IConstant(0x5C)); 196 | } // Backslash 197 | '\'' => { 198 | result.push(TokType::IConstant(0x27)); 199 | } // Apostrophe or single quotation mark 200 | '\"' => { 201 | result.push(TokType::IConstant(0x22)); 202 | } // Double quotation mark 203 | '?' => { 204 | result.push(TokType::IConstant(0x3F)); 205 | } // question mark 206 | _ => { 207 | return Err(format!("unrecongnized character")); 208 | } 209 | } 210 | it.next(); 211 | if it.peek().unwrap() != &'\'' { 212 | return Err(format!("Error: unmatched '")); 213 | } 214 | it.next(); 215 | } else { 216 | result.push(TokType::IConstant(c as i64)); 217 | it.next(); // skip char 218 | it.next(); // skip ' 219 | } 220 | } 221 | '0'..='9' => { 222 | it.next(); 223 | let mut number = c 224 | .to_string() 225 | .parse::() 226 | .expect("The caller should have passed a digit."); 227 | 228 | while let Some(Ok(digit)) = it.peek().map(|c| c.to_string().parse::()) { 229 | number = number * 10 + digit; 230 | it.next(); 231 | } 232 | result.push(TokType::IConstant(number)); 233 | } 234 | 'a'..='z' | 'A'..='Z' | '_' => { 235 | it.next(); 236 | let mut s = String::new(); 237 | s.push(c); 238 | while let Some(&tmp) = it.peek() { 239 | match tmp { 240 | 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => { 241 | s.push(tmp); 242 | it.next(); 243 | } 244 | _ => { 245 | break; 246 | } 247 | } 248 | } 249 | match s.as_ref() { 250 | "auto" => result.push(TokType::AUTO), 251 | "break" => result.push(TokType::BREAK), 252 | "case" => result.push(TokType::CASE), 253 | "char" => result.push(TokType::CHAR), 254 | "const" => result.push(TokType::CONST), 255 | "continue" => result.push(TokType::CONTINUE), 256 | "default" => result.push(TokType::DEFAULT), 257 | "do" => result.push(TokType::DO), 258 | "double" => result.push(TokType::DOUBLE), 259 | "else" => result.push(TokType::ELSE), 260 | "enum" => result.push(TokType::ENUM), 261 | "extern" => result.push(TokType::EXTERN), 262 | "float" => result.push(TokType::FLOAT), 263 | "for" => result.push(TokType::FOR), 264 | "goto" => result.push(TokType::GOTO), 265 | "if" => result.push(TokType::IF), 266 | "inline" => result.push(TokType::INLINE), 267 | "int" => result.push(TokType::INT), 268 | "long" => result.push(TokType::LONG), 269 | "register" => result.push(TokType::REGISTER), 270 | "restrict" => result.push(TokType::RESTRICT), 271 | "return" => result.push(TokType::RETURN), 272 | "short" => result.push(TokType::SHORT), 273 | "signed" => result.push(TokType::SIGNED), 274 | "sizeof" => result.push(TokType::SIZEOF), 275 | "static" => result.push(TokType::STATIC), 276 | "struct" => result.push(TokType::STRUCT), 277 | "switch" => result.push(TokType::SWITCH), 278 | "typedef" => result.push(TokType::TYPEDEF), 279 | "union" => result.push(TokType::UNION), 280 | "unsigned" => result.push(TokType::UNSIGNED), 281 | "void" => result.push(TokType::VOID), 282 | "volatile" => result.push(TokType::VOLATILE), 283 | "while" => result.push(TokType::WHILE), 284 | "_Alignas" => result.push(TokType::ALIGNAS), 285 | "_Alignof" => result.push(TokType::ALIGNOF), 286 | "_Atomic" => result.push(TokType::ATOMIC), 287 | "_Bool" => result.push(TokType::BOOL), 288 | "_Complex" => result.push(TokType::COMPLEX), 289 | "_Generic" => result.push(TokType::GENERIC), 290 | "_Imaginary" => result.push(TokType::IMAGINARY), 291 | "_Noreturn" => result.push(TokType::NORETURN), 292 | "_Static_assert" => result.push(TokType::StaticAssert), 293 | "_Thread_local" => result.push(TokType::ThreadLocal), 294 | "__func__" => result.push(TokType::FuncName), 295 | _ => result.push(TokType::IDENTIFIER(s)), 296 | } 297 | } 298 | '(' => { 299 | result.push(TokType::LParen); 300 | it.next(); 301 | } 302 | ')' => { 303 | result.push(TokType::RParen); 304 | it.next(); 305 | } 306 | '{' => { 307 | result.push(TokType::LBrace); 308 | it.next(); 309 | } 310 | '}' => { 311 | result.push(TokType::RBrace); 312 | it.next(); 313 | } 314 | '[' => { 315 | result.push(TokType::LBracket); 316 | it.next(); 317 | } 318 | ']' => { 319 | result.push(TokType::RBracket); 320 | it.next(); 321 | } 322 | ';' => { 323 | result.push(TokType::Semicolon); 324 | it.next(); 325 | } 326 | '=' => { 327 | it.next(); 328 | match it.peek() { 329 | Some(tmp) => match tmp { 330 | '=' => { 331 | result.push(TokType::EqOp); 332 | it.next(); 333 | } 334 | _ => { 335 | result.push(TokType::Assign); 336 | } 337 | }, 338 | _ => return Err(format!("Can not peek next char")), 339 | } 340 | } 341 | '<' => { 342 | it.next(); 343 | match it.peek() { 344 | Some(tmp) => match tmp { 345 | '=' => { 346 | it.next(); 347 | result.push(TokType::LeOp); 348 | it.next(); 349 | } 350 | '<' => { 351 | it.next(); 352 | match it.peek() { 353 | Some(tmp) => match tmp { 354 | '=' => { 355 | it.next(); 356 | result.push(TokType::LeftAssign); // <<= 357 | it.next(); 358 | } 359 | _ => { 360 | result.push(TokType::LeftOp); 361 | it.next(); 362 | } 363 | }, 364 | _ => { 365 | result.push(TokType::LeftOp); 366 | } 367 | } 368 | } 369 | _ => { 370 | result.push(TokType::Lt); 371 | } 372 | }, 373 | _ => { 374 | result.push(TokType::Lt); 375 | } 376 | } 377 | } 378 | '>' => { 379 | it.next(); 380 | match it.peek() { 381 | Some(tmp) => match tmp { 382 | '=' => { 383 | result.push(TokType::GeOp); 384 | it.next(); 385 | } 386 | '>' => { 387 | it.next(); 388 | match it.peek() { 389 | Some(tmp) => match tmp { 390 | '=' => { 391 | result.push(TokType::RightAssign); 392 | it.next(); 393 | } 394 | _ => { 395 | result.push(TokType::RightOp); 396 | } 397 | }, 398 | _ => { 399 | result.push(TokType::RightOp); 400 | } 401 | } 402 | } 403 | _ => { 404 | result.push(TokType::Gt); 405 | } 406 | }, 407 | _ => { 408 | result.push(TokType::Gt); 409 | } 410 | } 411 | } 412 | '-' => { 413 | it.next(); 414 | match it.peek() { 415 | Some(tmp) => match tmp { 416 | '-' => { 417 | result.push(TokType::DecOp); 418 | it.next(); 419 | } 420 | '=' => { 421 | result.push(TokType::SubAssign); 422 | it.next(); 423 | } 424 | '>' => { 425 | result.push(TokType::PtrOp); 426 | it.next(); 427 | } 428 | _ => { 429 | result.push(TokType::Minus); 430 | } 431 | }, 432 | _ => { 433 | result.push(TokType::Minus); 434 | } 435 | } 436 | } 437 | '~' => { 438 | result.push(TokType::Tilde); 439 | it.next(); 440 | } 441 | '!' => { 442 | it.next(); 443 | match it.peek() { 444 | Some(tmp) => match tmp { 445 | '=' => { 446 | result.push(TokType::NeOp); 447 | it.next(); 448 | } 449 | _ => { 450 | result.push(TokType::Exclamation); 451 | } 452 | }, 453 | _ => return Err(format!("Can not peek next char")), 454 | } 455 | } 456 | '+' => { 457 | it.next(); 458 | match it.peek().unwrap() { 459 | '+' => { 460 | result.push(TokType::IncOp); 461 | it.next(); 462 | } 463 | '=' => { 464 | result.push(TokType::AddAssign); 465 | it.next(); 466 | } 467 | _ => { 468 | result.push(TokType::Plus); 469 | } 470 | } 471 | } 472 | '*' => { 473 | it.next(); 474 | match it.peek() { 475 | Some(tmp) => match tmp { 476 | '=' => { 477 | result.push(TokType::MulAssign); 478 | it.next(); 479 | } 480 | _ => { 481 | result.push(TokType::Multi); 482 | } 483 | }, 484 | _ => { 485 | result.push(TokType::Multi); 486 | } 487 | } 488 | } 489 | '%' => { 490 | it.next(); 491 | match it.peek() { 492 | Some(tmp) => match tmp { 493 | '=' => { 494 | result.push(TokType::ModAssign); 495 | it.next(); 496 | } 497 | _ => { 498 | result.push(TokType::Mod); 499 | } 500 | }, 501 | _ => { 502 | result.push(TokType::Mod); 503 | } 504 | } 505 | } 506 | '/' => { 507 | it.next(); 508 | match it.peek() { 509 | Some(tmp) => match tmp { 510 | '=' => { 511 | result.push(TokType::DivAssign); 512 | it.next(); 513 | } 514 | _ => { 515 | result.push(TokType::Splash); 516 | } 517 | }, 518 | _ => { 519 | result.push(TokType::Splash); 520 | } 521 | } 522 | } 523 | '&' => { 524 | it.next(); 525 | match it.peek() { 526 | Some(tmp) => match tmp { 527 | '&' => { 528 | result.push(TokType::AndOp); 529 | it.next(); 530 | } 531 | '=' => { 532 | result.push(TokType::AndAssign); 533 | it.next(); 534 | } 535 | _ => { 536 | // & operator to get the address of a variable 537 | result.push(TokType::SingleAnd); 538 | } 539 | }, 540 | _ => { 541 | result.push(TokType::SingleAnd); 542 | } 543 | } 544 | } 545 | '|' => { 546 | it.next(); 547 | match it.peek() { 548 | Some(tmp) => match tmp { 549 | '|' => { 550 | result.push(TokType::OrOp); 551 | it.next(); 552 | } 553 | '=' => { 554 | result.push(TokType::OrAssign); 555 | it.next(); 556 | } 557 | _ => { 558 | // now don't support bitwise or, so just return Err 559 | result.push(TokType::InclusiveOr); 560 | } 561 | }, 562 | _ => { 563 | result.push(TokType::InclusiveOr); 564 | } 565 | } 566 | } 567 | '^' => { 568 | it.next(); 569 | match it.peek() { 570 | Some(tmp) => match tmp { 571 | '=' => { 572 | result.push(TokType::XorAssign); 573 | it.next(); 574 | } 575 | _ => { 576 | result.push(TokType::ExclusiveOr); 577 | } 578 | }, 579 | _ => { 580 | result.push(TokType::ExclusiveOr); 581 | } 582 | } 583 | } 584 | '?' => { 585 | result.push(TokType::QuestionMark); 586 | it.next(); 587 | } 588 | ':' => { 589 | result.push(TokType::Colon); 590 | it.next(); 591 | } 592 | ',' => { 593 | result.push(TokType::Comma); 594 | it.next(); 595 | } 596 | ' ' | '\n' | '\t' | '\r' | '#' => { 597 | // skip 598 | it.next(); 599 | } 600 | _ => { 601 | return Err(format!("unexpected character {}", c)); 602 | } 603 | } 604 | } 605 | Ok(result) 606 | } 607 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aho-corasick" 5 | version = "0.7.10" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "ansi_term" 13 | version = "0.11.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | dependencies = [ 16 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 17 | ] 18 | 19 | [[package]] 20 | name = "ansi_term" 21 | version = "0.12.1" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | dependencies = [ 24 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 25 | ] 26 | 27 | [[package]] 28 | name = "arrayvec" 29 | version = "0.4.10" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | dependencies = [ 32 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 33 | ] 34 | 35 | [[package]] 36 | name = "atty" 37 | version = "0.2.14" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | dependencies = [ 40 | "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 41 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", 42 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 43 | ] 44 | 45 | [[package]] 46 | name = "autocfg" 47 | version = "1.0.0" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | 50 | [[package]] 51 | name = "bitflags" 52 | version = "1.0.4" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | 55 | [[package]] 56 | name = "byteorder" 57 | version = "1.3.1" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | 60 | [[package]] 61 | name = "cast" 62 | version = "0.2.2" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | 65 | [[package]] 66 | name = "cfg-if" 67 | version = "0.1.7" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | 70 | [[package]] 71 | name = "chrono" 72 | version = "0.4.11" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | dependencies = [ 75 | "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", 76 | "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 77 | "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", 78 | ] 79 | 80 | [[package]] 81 | name = "clap" 82 | version = "2.33.0" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | dependencies = [ 85 | "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 86 | "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", 87 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 88 | "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 89 | "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 90 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 91 | "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 92 | ] 93 | 94 | [[package]] 95 | name = "cloudabi" 96 | version = "0.0.3" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | dependencies = [ 99 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 100 | ] 101 | 102 | [[package]] 103 | name = "colored" 104 | version = "1.9.3" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | dependencies = [ 107 | "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", 108 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 109 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 110 | ] 111 | 112 | [[package]] 113 | name = "criterion" 114 | version = "0.2.11" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | dependencies = [ 117 | "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", 118 | "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 119 | "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", 120 | "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 121 | "csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", 122 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 123 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 124 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", 125 | "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 126 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 127 | "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 128 | "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 129 | "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 130 | "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 131 | "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", 132 | "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", 133 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 134 | "tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 135 | "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 136 | ] 137 | 138 | [[package]] 139 | name = "criterion-plot" 140 | version = "0.3.1" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | dependencies = [ 143 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 144 | "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 145 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 146 | ] 147 | 148 | [[package]] 149 | name = "crossbeam-deque" 150 | version = "0.2.0" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | dependencies = [ 153 | "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 154 | "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 155 | ] 156 | 157 | [[package]] 158 | name = "crossbeam-epoch" 159 | version = "0.3.1" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | dependencies = [ 162 | "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", 163 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 164 | "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 165 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 166 | "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 167 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 168 | "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 169 | ] 170 | 171 | [[package]] 172 | name = "crossbeam-utils" 173 | version = "0.2.2" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | dependencies = [ 176 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 177 | ] 178 | 179 | [[package]] 180 | name = "crust" 181 | version = "0.1.0" 182 | dependencies = [ 183 | "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", 184 | "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 185 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 186 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 187 | "loggerv 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 188 | "regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 189 | "simple_logger 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", 190 | ] 191 | 192 | [[package]] 193 | name = "csv" 194 | version = "1.0.7" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | dependencies = [ 197 | "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 198 | "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 199 | "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 200 | "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", 201 | ] 202 | 203 | [[package]] 204 | name = "csv-core" 205 | version = "0.1.5" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | dependencies = [ 208 | "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 209 | ] 210 | 211 | [[package]] 212 | name = "either" 213 | version = "1.5.2" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | 216 | [[package]] 217 | name = "fuchsia-cprng" 218 | version = "0.1.1" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | 221 | [[package]] 222 | name = "hermit-abi" 223 | version = "0.1.8" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | dependencies = [ 226 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", 227 | ] 228 | 229 | [[package]] 230 | name = "itertools" 231 | version = "0.8.0" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | dependencies = [ 234 | "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 235 | ] 236 | 237 | [[package]] 238 | name = "itoa" 239 | version = "0.4.3" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | 242 | [[package]] 243 | name = "lazy_static" 244 | version = "1.4.0" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | 247 | [[package]] 248 | name = "libc" 249 | version = "0.2.51" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | 252 | [[package]] 253 | name = "log" 254 | version = "0.4.8" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | dependencies = [ 257 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 258 | ] 259 | 260 | [[package]] 261 | name = "loggerv" 262 | version = "0.7.2" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | dependencies = [ 265 | "ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", 266 | "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", 267 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 268 | ] 269 | 270 | [[package]] 271 | name = "memchr" 272 | version = "2.3.3" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | dependencies = [ 275 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", 276 | ] 277 | 278 | [[package]] 279 | name = "memoffset" 280 | version = "0.2.1" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | 283 | [[package]] 284 | name = "nodrop" 285 | version = "0.1.13" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | 288 | [[package]] 289 | name = "num-integer" 290 | version = "0.1.42" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | dependencies = [ 293 | "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 294 | "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 295 | ] 296 | 297 | [[package]] 298 | name = "num-traits" 299 | version = "0.2.11" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | dependencies = [ 302 | "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 303 | ] 304 | 305 | [[package]] 306 | name = "num_cpus" 307 | version = "1.10.0" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | dependencies = [ 310 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", 311 | ] 312 | 313 | [[package]] 314 | name = "proc-macro2" 315 | version = "0.4.27" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | dependencies = [ 318 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 319 | ] 320 | 321 | [[package]] 322 | name = "quote" 323 | version = "0.6.11" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | dependencies = [ 326 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 327 | ] 328 | 329 | [[package]] 330 | name = "rand_core" 331 | version = "0.3.1" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | dependencies = [ 334 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 335 | ] 336 | 337 | [[package]] 338 | name = "rand_core" 339 | version = "0.4.0" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | 342 | [[package]] 343 | name = "rand_os" 344 | version = "0.1.3" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | dependencies = [ 347 | "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 348 | "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 349 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", 350 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 351 | "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 352 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 353 | ] 354 | 355 | [[package]] 356 | name = "rand_xoshiro" 357 | version = "0.1.0" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | dependencies = [ 360 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 361 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 362 | ] 363 | 364 | [[package]] 365 | name = "rayon" 366 | version = "1.0.3" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | dependencies = [ 369 | "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 370 | "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 371 | "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 372 | ] 373 | 374 | [[package]] 375 | name = "rayon-core" 376 | version = "1.4.1" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | dependencies = [ 379 | "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 380 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 381 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", 382 | "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 383 | ] 384 | 385 | [[package]] 386 | name = "rdrand" 387 | version = "0.4.0" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | dependencies = [ 390 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 391 | ] 392 | 393 | [[package]] 394 | name = "redox_syscall" 395 | version = "0.1.54" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | 398 | [[package]] 399 | name = "regex" 400 | version = "1.3.5" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | dependencies = [ 403 | "aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", 404 | "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 405 | "regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", 406 | "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 407 | ] 408 | 409 | [[package]] 410 | name = "regex-syntax" 411 | version = "0.6.17" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | 414 | [[package]] 415 | name = "ryu" 416 | version = "0.2.7" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | 419 | [[package]] 420 | name = "same-file" 421 | version = "1.0.4" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | dependencies = [ 424 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 425 | ] 426 | 427 | [[package]] 428 | name = "scopeguard" 429 | version = "0.3.3" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | 432 | [[package]] 433 | name = "serde" 434 | version = "1.0.90" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | 437 | [[package]] 438 | name = "serde_derive" 439 | version = "1.0.90" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | dependencies = [ 442 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 443 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 444 | "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", 445 | ] 446 | 447 | [[package]] 448 | name = "serde_json" 449 | version = "1.0.39" 450 | source = "registry+https://github.com/rust-lang/crates.io-index" 451 | dependencies = [ 452 | "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 453 | "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 454 | "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", 455 | ] 456 | 457 | [[package]] 458 | name = "simple_logger" 459 | version = "1.6.0" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | dependencies = [ 462 | "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", 463 | "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", 464 | "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", 465 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 466 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 467 | ] 468 | 469 | [[package]] 470 | name = "strsim" 471 | version = "0.8.0" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | 474 | [[package]] 475 | name = "syn" 476 | version = "0.15.30" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | dependencies = [ 479 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 480 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 481 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 482 | ] 483 | 484 | [[package]] 485 | name = "textwrap" 486 | version = "0.11.0" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | dependencies = [ 489 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 490 | ] 491 | 492 | [[package]] 493 | name = "thread_local" 494 | version = "1.0.1" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | dependencies = [ 497 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 498 | ] 499 | 500 | [[package]] 501 | name = "time" 502 | version = "0.1.42" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | dependencies = [ 505 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", 506 | "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", 507 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 508 | ] 509 | 510 | [[package]] 511 | name = "tinytemplate" 512 | version = "1.0.1" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | dependencies = [ 515 | "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", 516 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 517 | ] 518 | 519 | [[package]] 520 | name = "unicode-width" 521 | version = "0.1.5" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | 524 | [[package]] 525 | name = "unicode-xid" 526 | version = "0.1.0" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | 529 | [[package]] 530 | name = "vec_map" 531 | version = "0.8.1" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | 534 | [[package]] 535 | name = "walkdir" 536 | version = "2.2.7" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | dependencies = [ 539 | "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 540 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 541 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 542 | ] 543 | 544 | [[package]] 545 | name = "winapi" 546 | version = "0.3.7" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | dependencies = [ 549 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 550 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 551 | ] 552 | 553 | [[package]] 554 | name = "winapi-i686-pc-windows-gnu" 555 | version = "0.4.0" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | 558 | [[package]] 559 | name = "winapi-util" 560 | version = "0.1.2" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | dependencies = [ 563 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 564 | ] 565 | 566 | [[package]] 567 | name = "winapi-x86_64-pc-windows-gnu" 568 | version = "0.4.0" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | 571 | [metadata] 572 | "checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" 573 | "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 574 | "checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 575 | "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" 576 | "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 577 | "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 578 | "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 579 | "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" 580 | "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" 581 | "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" 582 | "checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" 583 | "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" 584 | "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 585 | "checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" 586 | "checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" 587 | "checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" 588 | "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" 589 | "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" 590 | "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" 591 | "checksum csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9044e25afb0924b5a5fc5511689b0918629e85d68ea591e5e87fbf1e85ea1b3b" 592 | "checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" 593 | "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" 594 | "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 595 | "checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" 596 | "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" 597 | "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" 598 | "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 599 | "checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" 600 | "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 601 | "checksum loggerv 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "60d8de15ae71e760bce7f05447f85f73624fe0d3b1e4c5a63ba5d4cb0748d374" 602 | "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" 603 | "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" 604 | "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 605 | "checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" 606 | "checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" 607 | "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" 608 | "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" 609 | "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" 610 | "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 611 | "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" 612 | "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" 613 | "checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" 614 | "checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" 615 | "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" 616 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 617 | "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" 618 | "checksum regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8900ebc1363efa7ea1c399ccc32daed870b4002651e0bed86e72d501ebbe0048" 619 | "checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" 620 | "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" 621 | "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" 622 | "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 623 | "checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4" 624 | "checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79" 625 | "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" 626 | "checksum simple_logger 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fea0c4611f32f4c2bac73754f22dca1f57e6c1945e0590dae4e5f2a077b92367" 627 | "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 628 | "checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2" 629 | "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 630 | "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" 631 | "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 632 | "checksum tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7655088894274afb52b807bd3c87072daa1fedd155068b8705cabfd628956115" 633 | "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" 634 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 635 | "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 636 | "checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" 637 | "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" 638 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 639 | "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" 640 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 641 | --------------------------------------------------------------------------------