├── .gitignore ├── .gitmodules ├── .travis.yml ├── Cargo.lock ├── Cargo.toml ├── README.md ├── fuzz ├── .gitignore ├── Cargo.lock ├── Cargo.toml └── fuzz_targets │ └── parse.rs ├── parser-c-macro ├── Cargo.lock ├── Cargo.toml └── src │ └── lib.rs ├── parser-c-tests ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── gcc_expect_fail.txt ├── lib.rs ├── smoke │ ├── fibonacci.c │ └── tree_traversal.c └── tests │ ├── eval_smoke.rs │ ├── gcc_dg.rs │ ├── simple.rs │ ├── simple_file.c │ └── simple_file.rs ├── reference ├── .travis.yml ├── AUTHORS ├── AUTHORS.c2hs ├── ChangeLog ├── LICENSE ├── MAINTAINANCE ├── README ├── Setup.hs ├── docs │ ├── Cee.txt │ ├── GettingStarted.txt │ ├── ProjectStatus.txt │ ├── Start.txt │ └── semantics │ │ ├── ExternalDefinitions.txt │ │ ├── Glossary.txt │ │ └── NameSpaces.txt ├── examples │ ├── BasicUsage.hs │ ├── ComputeSize.hs │ ├── DumpAst.hs │ ├── LICENSE │ ├── Makefile │ ├── ParseAndPrint.hs │ ├── ScanFile.hs │ ├── SearchDef.hs │ ├── TypeCheck.hs │ ├── compute_size.c │ ├── example.c │ ├── language-c-examples.cabal │ └── sourceview │ │ ├── GenericTree.hs │ │ ├── README │ │ ├── SourceBrowser.hs │ │ └── SourceView.hs ├── language-c.cabal ├── scripts │ ├── GenerateKeywords.hs │ ├── move_module │ ├── regression_test │ └── tokenlist.txt ├── src │ ├── Language │ │ ├── C.hs │ │ └── C │ │ │ ├── Analysis.hs │ │ │ ├── Analysis │ │ │ ├── AstAnalysis.hs │ │ │ ├── AstAnalysis.hs-boot │ │ │ ├── Builtins.hs │ │ │ ├── ConstEval.hs │ │ │ ├── Debug.hs │ │ │ ├── DeclAnalysis.hs │ │ │ ├── DefTable.hs │ │ │ ├── Export.hs │ │ │ ├── NameSpaceMap.hs │ │ │ ├── SemError.hs │ │ │ ├── SemRep.hs │ │ │ ├── TravMonad.hs │ │ │ ├── TypeCheck.hs │ │ │ ├── TypeConversions.hs │ │ │ └── TypeUtils.hs │ │ │ ├── Data.hs │ │ │ ├── Data │ │ │ ├── Error.hs │ │ │ ├── Ident.hs │ │ │ ├── InputStream.hs │ │ │ ├── Name.hs │ │ │ ├── Node.hs │ │ │ ├── Position.hs │ │ │ └── RList.hs │ │ │ ├── Parser.hs │ │ │ ├── Parser │ │ │ ├── Builtin.hs │ │ │ ├── Lexer.hs │ │ │ ├── Lexer.x │ │ │ ├── Parser.hs │ │ │ ├── Parser.y │ │ │ ├── ParserMonad.hs │ │ │ └── Tokens.hs │ │ │ ├── Pretty.hs │ │ │ ├── Syntax.hs │ │ │ ├── Syntax │ │ │ ├── AST.hs │ │ │ ├── Constants.hs │ │ │ ├── Ops.hs │ │ │ └── Utils.hs │ │ │ └── System │ │ │ ├── GCC.hs │ │ │ └── Preprocess.hs │ ├── README │ ├── derive.sh │ └── derive │ │ ├── Data │ │ └── Derive │ │ │ ├── Annotated.hs │ │ │ └── CNode.hs │ │ ├── Derive.hs │ │ ├── DeriveTest.hs │ │ ├── DeriveTest.hs.expect │ │ ├── DeriveTest2.hs │ │ ├── Makefile │ │ └── derive-2.4.2.patch └── test │ ├── LICENSE │ ├── Makefile │ ├── README │ ├── bin │ ├── cc-wrapper │ ├── clear_test_suite │ ├── compile_log.sh │ ├── mkdist.sh │ ├── run-test │ ├── set_test_suite │ ├── setup │ └── setup_test_suite │ ├── config.mk │ ├── harness │ ├── Makefile │ ├── README │ ├── analysis_enum │ │ ├── Makefile │ │ ├── enum.c │ │ └── enum.expect │ ├── analysis_ext_decls │ │ ├── Makefile │ │ ├── globreg.c │ │ ├── globreg.expect │ │ ├── ident_kinds.c │ │ ├── ident_kinds.expect │ │ ├── tentative.c │ │ └── tentative.expect │ ├── analysis_local_decls │ │ ├── Makefile │ │ ├── error_extern_init.c │ │ ├── error_extern_no_linkage_1.c │ │ ├── error_extern_no_linkage_2.c │ │ ├── error_inner_scope_duple_def.c │ │ ├── other.c │ │ ├── scopes.c │ │ └── static_extern.c │ ├── analysis_type_check │ │ ├── Makefile │ │ ├── bad_args.c │ │ ├── bad_bug29.c │ │ ├── bad_bug29.c.expect │ │ ├── bad_sinit1.c │ │ ├── good_anonunion.c │ │ ├── good_anonunion.c.expect │ │ ├── good_bug29.c │ │ ├── good_bug29.c.expect │ │ ├── good_bug29_2.c │ │ ├── good_bug29_2.c.expect │ │ ├── good_return.c │ │ ├── good_return.c.expect │ │ ├── good_sinit.c │ │ ├── good_sinit.c.expect │ │ ├── good_sinit2.c │ │ └── good_sinit2.c.expect │ ├── attributes │ │ ├── Makefile │ │ ├── deprecated-2.c │ │ ├── deprecated-3.c │ │ ├── deprecated-bitfield-init.c │ │ ├── deprecated.c │ │ ├── fun_decl.c │ │ └── osx-1.c │ ├── bug20130805_nopos │ │ ├── Makefile │ │ ├── Test.hs │ │ ├── test.c │ │ └── test.expect │ ├── bug20160302_int128 │ │ ├── Makefile │ │ ├── test.c │ │ ├── test.expect │ │ ├── test_ty.c │ │ └── test_ty.expect │ ├── bug20160314_noreturn │ │ ├── Makefile │ │ ├── test.c │ │ ├── test.expect │ │ ├── test_pp.expect │ │ └── test_ty.expect │ ├── bug20160729_C_include_stack │ │ ├── Makefile │ │ ├── a.h │ │ ├── b.h │ │ ├── c.h │ │ ├── test.c │ │ ├── test.expect │ │ └── test.i │ ├── bug20160911_builtin_bswap │ │ ├── Makefile │ │ ├── test.c │ │ └── test.expect │ ├── bug21_sem_typedef │ │ ├── Makefile │ │ ├── typedef.c │ │ └── typedef.expect │ ├── bug22_file_permission_cpp │ │ ├── Makefile │ │ ├── Test.hs │ │ └── input.c │ ├── bug30_preserve_int_repr │ │ ├── Makefile │ │ ├── test.c │ │ └── test.expect │ ├── bug31_pp_if_else │ │ ├── Makefile │ │ ├── Test.hs │ │ └── test.expect │ ├── bug5_dos_newline │ │ ├── Makefile │ │ └── min.i │ ├── bugn6_empty_file │ │ ├── Makefile │ │ ├── Test.hs │ │ ├── test.c │ │ └── test.expect │ ├── builtins │ │ ├── Makefile │ │ ├── test.c │ │ ├── test.expect │ │ └── test_ty.expect │ ├── expect_error │ ├── parse_dg │ │ ├── Makefile │ │ ├── expect_fail.txt │ │ ├── expect_parse.txt │ │ ├── expect_parse_only.txt │ │ ├── expect_roundtrip.txt │ │ ├── gcc_dg_pre.tar.bz2 │ │ └── memory_usage_parse.ref │ └── run-harness.hs │ ├── language-c-test.cabal │ ├── res │ └── style.css │ ├── src │ ├── CEquiv.hs │ ├── CParse.hs │ ├── CRoundTrip.hs │ ├── CTest.hs │ ├── CheckGccArgs.hs │ ├── Language │ │ └── C │ │ │ └── Test │ │ │ ├── Environment.hs │ │ │ ├── Framework.hs │ │ │ ├── GenericAST.hs │ │ │ ├── Measures.hs │ │ │ ├── ParseTests.hs │ │ │ └── TestMonad.hs │ ├── RenderTests.hs │ └── ReportFatal.hs │ └── suite │ ├── README │ ├── bugs │ ├── additional_builtins.c │ ├── assignment_prec_1.c │ ├── assignment_prec_2.c │ ├── ast_empty_struct.c │ ├── attr.c │ ├── builtin_typedefs.c │ ├── concat.c │ ├── decl_attr.c │ ├── elseif11K.c │ ├── empty.c │ ├── empty_enum.c │ ├── float_non_compile.c │ ├── gen_lex_stress.rb │ ├── gnu_complex.c │ ├── hex_float_1.c │ ├── hex_float_2.c │ ├── ifpp.c │ ├── int_non_compile.c │ ├── local_labels.c │ ├── member_ident.c │ ├── offset_of.c │ ├── pp_address_of_label.c │ ├── pp_align_of.c │ ├── pp_assign_prec.c │ ├── pp_case_range.c │ ├── pp_compound_lit.c │ ├── pp_decrement.c │ ├── pp_old_style_decl.c │ ├── qualifier_pretty.c │ ├── restrict.c │ └── struct_attr.c │ ├── classify-dg.sh │ ├── compile-lib.template │ ├── configuration │ ├── decls │ └── attr.c │ ├── dg-ignore.txt │ ├── preprocess-dg.sh │ ├── run-bugs.sh │ ├── run-dg-list.sh │ ├── run-dg.sh │ ├── run-smoke.sh │ ├── run-suite.sh │ └── smoke │ ├── elsif.c │ ├── test.c │ ├── test1.c │ ├── test_attr.non_equiv_1.c │ ├── test_attr.non_equiv_2.c │ └── test_non_parse.c ├── regen.sh ├── src ├── analysis │ ├── ast_analysis.rs │ ├── builtins.rs │ ├── const_eval.rs │ ├── debug.rs │ ├── decl_analysis.rs │ ├── def_table.rs │ ├── export.rs │ ├── mod.rs │ ├── name_space_map.rs │ ├── sem_error.rs │ ├── sem_rep.rs │ ├── trav_monad.rs │ ├── type_check.rs │ ├── type_conversions.rs │ └── type_utils.rs ├── bin │ ├── lex.rs │ ├── parse.rs │ └── pretty.rs ├── data │ ├── error.rs │ ├── ident.rs │ ├── input_stream.rs │ ├── mod.rs │ ├── name.rs │ ├── node.rs │ └── position.rs ├── lib.rs ├── parser │ ├── Lexer.x │ ├── Parser.y │ ├── builtin.rs │ ├── lexer.rs │ ├── mod.rs │ ├── parser.rs │ └── tokens.rs ├── pretty.rs ├── syntax │ ├── ast.rs │ ├── constants.rs │ ├── mod.rs │ ├── ops.rs │ └── utils.rs └── system │ ├── gcc.rs │ ├── mod.rs │ └── preprocess.rs └── test.sh /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .vscode 3 | .stack-work 4 | reference/stack.yaml 5 | parser-c-tests/gcc_pre 6 | callgrind.out.* 7 | dist/ 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/alex-rust"] 2 | path = deps/alex-rust 3 | url = https://github.com/birkenfeld/alex-rust 4 | [submodule "deps/happy-rust"] 5 | path = deps/happy-rust 6 | url = https://github.com/birkenfeld/happy-rust 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - nightly 4 | 5 | script: 6 | - ./test.sh 7 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parser-c" 3 | version = "0.3.0" 4 | authors = [ 5 | "Tim Ryan ", 6 | "Georg Brandl ", 7 | ] 8 | description = "Rust module for parsing C code." 9 | repository = "http://github.com/tcr/parser-c" 10 | homepage = "http://github.com/tcr/parser-c" 11 | license = "MIT" 12 | 13 | [workspace] 14 | members = ["parser-c-macro", "parser-c-tests"] 15 | 16 | [dependencies] 17 | tempdir = "0.3.5" 18 | bitflags = "1.0.1" 19 | either = "1.5.0" 20 | parser-c-macro = { path = "parser-c-macro", version = "0.3" } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # parser-c 2 | 3 | [![Gitter](https://img.shields.io/gitter/room/tcr/parser-c.svg)](http://gitter.im/parser-c/Lobby) [![https://img.shields.io/crates/v/parser-c.svg](https://img.shields.io/crates/v/parser-c.svg)](http://crates.io/crates/parser-c/) 4 | 5 | Rust module for parsing C code. Port of Haskell's [language-c](https://github.com/visq/language-c), semi-automatically translated using [Corollary](https://github.com/tcr/corrode-but-in-rust). 6 | 7 | **This port is a work in progress.** A lot of work remains to parse anything but very simple C files; while most source code has been translated from Haskell, errors in translation prevent it from matching language-c's functionality yet. Here are the next steps for achieving parity, in order: 8 | 9 | 1. Building up an equivalent test bed to language-c's, then automatically cross-check 10 | 1. Fix errors in the ported code to support those test cases 11 | 1. Converting portions of the code into Rust idioms without breaking tests 12 | 1. Figure out a porting story for the alex/happy generated parser output 13 | 14 | `parser-c` requires nightly (for now). See `tests/` for some working examples, or try this example: 15 | 16 | ```rust 17 | extern crate parser_c; 18 | 19 | use parser_c::parse; 20 | 21 | const INPUT: &'static str = r#" 22 | 23 | int main() { 24 | printf("hello world!\n"); 25 | return 0; 26 | } 27 | 28 | "#; 29 | 30 | fn main() { 31 | match parse(INPUT, "simple.c") { 32 | Err(err) => { 33 | panic!("error: {}", err); 34 | } 35 | Ok(ast) => { 36 | println!("success: {:#?}", ast); 37 | } 38 | } 39 | } 40 | ``` 41 | 42 | Result is: 43 | 44 | ``` 45 | success: Right( 46 | CTranslationUnit( 47 | [ 48 | CFDefExt( 49 | CFunctionDef( 50 | [ 51 | CTypeSpec( 52 | CIntType( 53 | .. 54 | ) 55 | ) 56 | ], 57 | CDeclarator( 58 | Some( 59 | Ident( 60 | "main", 61 | 124382170, 62 | .. 63 | ) 64 | ), 65 | ... 66 | ``` 67 | 68 | ## Development 69 | 70 | Clone this crate: 71 | 72 | ``` 73 | git clone https://github.com/tcr/parser-c --init --recursive 74 | ``` 75 | 76 | Hacking on the lexer and parser requires to build and run the Haskell 77 | dependencies using: 78 | 79 | ``` 80 | ./regen.sh 81 | ``` 82 | 83 | The test suite is being ported at the moment. It is in a separate crate, 84 | because it requires a build script with prerequisites, so to run it, use 85 | this script: 86 | 87 | ``` 88 | ./test.sh 89 | ``` 90 | 91 | ## License 92 | 93 | MIT 94 | -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | target 3 | corpus 4 | artifacts 5 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "parser-c-fuzz" 4 | version = "0.0.1" 5 | authors = ["Automatically generated"] 6 | publish = false 7 | 8 | [package.metadata] 9 | cargo-fuzz = true 10 | 11 | [dependencies.parser-c] 12 | path = ".." 13 | [dependencies.libfuzzer-sys] 14 | git = "https://github.com/rust-fuzz/libfuzzer-sys.git" 15 | [dependencies.arbitrary] 16 | version = "0.1" 17 | 18 | # Prevent this from interfering with workspaces 19 | [workspace] 20 | members = ["."] 21 | 22 | [profile.dev] 23 | opt-level = 3 24 | 25 | [[bin]] 26 | name = "parse" 27 | path = "fuzz_targets/parse.rs" 28 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/parse.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #[macro_use] extern crate libfuzzer_sys; 3 | extern crate parser_c; 4 | 5 | use std::str; 6 | 7 | fuzz_target!(|data: &[u8]| { 8 | if let Ok(data) = str::from_utf8(&data) { 9 | let _ = parser_c::parse(&data, "input"); 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /parser-c-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parser-c-macro" 3 | version = "0.3.0" 4 | authors = ["Tim Ryan "] 5 | description = "Helper macros for parser-c" 6 | license = "MIT OR Apache-2.0" 7 | 8 | [lib] 9 | proc-macro = true 10 | 11 | [dependencies] 12 | syn = { version = "0.10.5", features = [ "full" ] } 13 | quote = "0.3.10" 14 | regex = "0.2.2" 15 | -------------------------------------------------------------------------------- /parser-c-tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parser-c-tests" 3 | version = "0.3.0" 4 | authors = [ 5 | "Tim Ryan ", 6 | "Georg Brandl ", 7 | ] 8 | description = "Test suite for parser-c." 9 | license = "MIT" 10 | workspace = ".." 11 | 12 | 13 | [lib] 14 | path = "lib.rs" 15 | 16 | [dependencies] 17 | parser-c = { path = ".." } 18 | walkdir = "1" 19 | -------------------------------------------------------------------------------- /parser-c-tests/build.rs: -------------------------------------------------------------------------------- 1 | //! Generate individual test cases for all files in the gcc_pre directory. 2 | 3 | use std::collections::HashSet; 4 | use std::env; 5 | use std::fs::{File, read_dir}; 6 | use std::io::{BufRead, BufReader, Write}; 7 | use std::path::Path; 8 | 9 | fn read_set(name: &str) -> HashSet { 10 | let file = File::open(format!("./gcc_expect_{}.txt", name)).unwrap(); 11 | let mut set = HashSet::new(); 12 | for line in BufReader::new(file).lines() { 13 | let line = line.unwrap(); 14 | set.insert(line); 15 | } 16 | set 17 | } 18 | 19 | fn main() { 20 | let mut test_files = read_dir("./gcc_pre") 21 | .expect("Could not find gcc-dg tests (unpack into parser-c-tests/gcc_pre)") 22 | .filter_map(|v| v.ok()) 23 | .collect::>(); 24 | test_files.sort_by_key(|d| d.path()); 25 | 26 | let fail_list = read_set("fail"); 27 | 28 | let out_path = Path::new(&env::var("OUT_DIR").unwrap()).join("gcc_dg_tests.rs"); 29 | let mut out = File::create(out_path).unwrap(); 30 | 31 | for entry in test_files { 32 | let file_str = entry.file_name(); 33 | let file_str = file_str.to_string_lossy(); 34 | if !file_str.ends_with(".i") { 35 | continue; 36 | } 37 | 38 | // custom skips 39 | 40 | // stack overflows 41 | if file_str == "inline-24.i" { continue; } 42 | if file_str == "20020425-1.i" { continue; } 43 | // invalid (256-bit) integer literal 44 | if file_str == "unnamed-1.i" { continue; } 45 | if file_str == "ms_unnamed-1.i" { continue; } 46 | // strange Unicode pragma 47 | if file_str == "pragma-darwin-2.i" { continue; } 48 | 49 | let test_name = file_str.trim_right_matches(".i").replace(&['-', '.', '+'][..], "__"); 50 | let should_fail = fail_list.contains(&*file_str); 51 | 52 | write!(out, "\ 53 | #[test] 54 | #[allow(non_snake_case)] 55 | fn gcc_dg_{}() {{ 56 | check_gcc_dg_file({:?}, {}); 57 | }} 58 | 59 | ", test_name, file_str, should_fail).unwrap(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /parser-c-tests/lib.rs: -------------------------------------------------------------------------------- 1 | //! Test crate for parser-c. 2 | //! 3 | //! This is a separate crate because we want to build some binaries, 4 | //! and also generate test cases using a build script. 5 | 6 | extern crate parser_c; 7 | -------------------------------------------------------------------------------- /parser-c-tests/smoke/fibonacci.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int n, first = 0, second = 1, next, c; 4 | 5 | printf("Enter the number of terms\n"); 6 | scanf("%d",&n); 7 | 8 | printf("First %d terms of Fibonacci series are :-\n",n); 9 | 10 | for ( c = 0 ; c < n ; c++ ) 11 | { 12 | if ( c <= 1 ) 13 | next = c; 14 | else 15 | { 16 | next = first + second; 17 | first = second; 18 | second = next; 19 | } 20 | printf("%d\n",next); 21 | } 22 | 23 | return 0; 24 | } -------------------------------------------------------------------------------- /parser-c-tests/smoke/tree_traversal.c: -------------------------------------------------------------------------------- 1 | struct node 2 | { 3 | int a; 4 | struct node *left; 5 | struct node *right; 6 | }; 7 | 8 | void generate(struct node **, int); 9 | int search(struct node *, int); 10 | void delete(struct node **); 11 | 12 | int main() 13 | { 14 | struct node *head = NULL; 15 | int choice = 0, num, flag = 0, key; 16 | 17 | do 18 | { 19 | printf("\nEnter your choice:\n1. Insert\n2. Search\n3. Exit\nChoice: "); 20 | scanf("%d", &choice); 21 | switch(choice) 22 | { 23 | case 1: 24 | printf("Enter element to insert: "); 25 | scanf("%d", &num); 26 | generate(&head, num); 27 | break; 28 | case 2: 29 | printf("Enter key to search: "); 30 | scanf("%d", &key); 31 | flag = search(head, key); 32 | if (flag) 33 | { 34 | printf("Key found in tree\n"); 35 | } 36 | else 37 | { 38 | printf("Key not found\n"); 39 | } 40 | break; 41 | case 3: 42 | delete(&head); 43 | printf("Memory Cleared\nPROGRAM TERMINATED\n"); 44 | break; 45 | default: printf("Not a valid input, try again\n"); 46 | } 47 | } while (choice != 3); 48 | return 0; 49 | } 50 | 51 | void generate(struct node **head, int num) 52 | { 53 | struct node *temp = *head, *prev = *head; 54 | 55 | if (*head == NULL) 56 | { 57 | *head = (struct node *)malloc(sizeof(struct node)); 58 | (*head)->a = num; 59 | (*head)->left = (*head)->right = NULL; 60 | } 61 | else 62 | { 63 | while (temp != NULL) 64 | { 65 | if (num > temp->a) 66 | { 67 | prev = temp; 68 | temp = temp->right; 69 | } 70 | else 71 | { 72 | prev = temp; 73 | temp = temp->left; 74 | } 75 | } 76 | temp = (struct node *)malloc(sizeof(struct node)); 77 | temp->a = num; 78 | if (num >= prev->a) 79 | { 80 | prev->right = temp; 81 | } 82 | else 83 | { 84 | prev->left = temp; 85 | } 86 | } 87 | } 88 | 89 | int search(struct node *head, int key) 90 | { 91 | while (head != NULL) 92 | { 93 | if (key > head->a) 94 | { 95 | head = head->right; 96 | } 97 | else if (key < head->a) 98 | { 99 | head = head->left; 100 | } 101 | else 102 | { 103 | return 1; 104 | } 105 | } 106 | return 0; 107 | } 108 | 109 | void delete(struct node **head) 110 | { 111 | if (*head != NULL) 112 | { 113 | if ((*head)->left) 114 | { 115 | delete(&(*head)->left); 116 | } 117 | if ((*head)->right) 118 | { 119 | delete(&(*head)->right); 120 | } 121 | free(*head); 122 | } 123 | } -------------------------------------------------------------------------------- /parser-c-tests/tests/eval_smoke.rs: -------------------------------------------------------------------------------- 1 | extern crate parser_c; 2 | extern crate walkdir; 3 | 4 | use std::fs::read_to_string; 5 | use parser_c::parse_str; 6 | use walkdir::WalkDir; 7 | 8 | #[test] 9 | fn eval_smoke() { 10 | for item in WalkDir::new("smoke") { 11 | if let Ok(entry) = item { 12 | if entry.path().extension().map_or(false, |v| v == "c") { 13 | let input = read_to_string(entry.path()).unwrap(); 14 | match parse_str(&input, &entry.path().display().to_string()) { 15 | Err(err) => { 16 | panic!("error: {}", err); 17 | } 18 | Ok(_) => { 19 | println!("smoke test passed: {}", entry.path().display()); 20 | } 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /parser-c-tests/tests/gcc_dg.rs: -------------------------------------------------------------------------------- 1 | extern crate parser_c; 2 | 3 | use std::any::Any; 4 | use std::path::Path; 5 | use std::fs::read_to_string; 6 | 7 | use parser_c::{parse_str, parse_file_pre}; 8 | use parser_c::pretty::pretty_to_string; 9 | use parser_c::syntax::ast::{Equiv, Traverse, CStat, CCompound, CBlockStmt}; 10 | 11 | /// Replace single-statement CCompound statements by the single statement. 12 | fn normalize(node: &mut Any) { 13 | if let Some(stat) = node.downcast_mut::() { 14 | let mut new_stat = None; 15 | if let CCompound(ref labels, ref mut stmts, _) = *stat { 16 | if labels.is_empty() && stmts.len() == 1 { 17 | if let CBlockStmt(_) = stmts[0] { 18 | let stmtitem = stmts.pop().unwrap(); 19 | if let CBlockStmt(stmt) = stmtitem { 20 | new_stat = Some(stmt); 21 | } 22 | } 23 | } 24 | } 25 | if let Some(new_stat) = new_stat { 26 | *stat = new_stat; 27 | } 28 | } 29 | } 30 | 31 | fn check_gcc_dg_file(file_str: &str, should_fail: bool) { 32 | let path = Path::new("./gcc_pre").join(file_str); 33 | let mut ast = match parse_file_pre(&path) { 34 | Ok(mut ast) => if !should_fail { 35 | ast 36 | } else { 37 | panic!("*** Parse unexpectedly successful"); 38 | }, 39 | Err(e) => if should_fail { 40 | return; 41 | } else { 42 | panic!("*** Parse fail: {}", e); 43 | } 44 | }; 45 | let pretty = pretty_to_string(&ast); 46 | let mut ast2 = match parse_str(&pretty, file_str) { 47 | Ok(mut ast) => ast, 48 | Err(e) => { 49 | let s = read_to_string(&path).unwrap(); 50 | println!("--- Original source:"); 51 | println!("{}", s); 52 | println!("--- Pretty-printed source:"); 53 | println!("{}", pretty); 54 | println!("---"); 55 | panic!("*** Parse pretty-printed source fail: {}", e); 56 | } 57 | }; 58 | ast.traverse(&normalize); 59 | ast2.traverse(&normalize); 60 | if !ast.equiv(&ast2) { 61 | let s = read_to_string(&path).unwrap(); 62 | println!("--- Original source:"); 63 | println!("{}", s); 64 | println!("--- Pretty-print of original AST:"); 65 | println!("{}", pretty_to_string(&ast)); 66 | println!("--- Pretty-print of reparsed AST:"); 67 | println!("{}", pretty_to_string(&ast2)); 68 | println!("---"); 69 | println!("*** Parsed ASTs are not equivalent"); 70 | } 71 | } 72 | 73 | include!(concat!(env!("OUT_DIR"), "/gcc_dg_tests.rs")); 74 | -------------------------------------------------------------------------------- /parser-c-tests/tests/simple.rs: -------------------------------------------------------------------------------- 1 | extern crate parser_c; 2 | 3 | use parser_c::parse_str; 4 | 5 | const INPUT: &'static str = r#" 6 | 7 | int main() { 8 | printf("hello world!\n"); 9 | return 0; 10 | } 11 | 12 | "#; 13 | 14 | #[test] 15 | fn simple() { 16 | match parse_str(INPUT, "simple.c") { 17 | Err(err) => { 18 | panic!("error: {:?}", err); 19 | } 20 | Ok(ast) => { 21 | println!("success: {:?}", ast); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /parser-c-tests/tests/simple_file.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | printf("hello world!\n"); 3 | return 0; 4 | } 5 | -------------------------------------------------------------------------------- /parser-c-tests/tests/simple_file.rs: -------------------------------------------------------------------------------- 1 | extern crate parser_c; 2 | 3 | use parser_c::parse_file_pre; 4 | 5 | #[test] 6 | fn simple_file() { 7 | let input_file = "./tests/simple_file.c"; 8 | let todo = parse_file_pre(input_file); 9 | 10 | println!("OUT {:#?}", todo); 11 | } 12 | -------------------------------------------------------------------------------- /reference/AUTHORS: -------------------------------------------------------------------------------- 1 | Benedikt Huber 2 | Manuel M T Chakravarty 3 | Duncan Coutts 4 | Bertram Felgenhauer 5 | 6 | with code contributions and patches from 7 | 8 | Iavor Diatchki 9 | Kevin Charter 10 | Aleksey Kliger 11 | 12 | This project originated from the C parser component of c2hs, 13 | for many additional contributors see AUTHORS.c2hs. 14 | 15 | Special thanks for their great support, comments and suggestions to: 16 | 17 | Duncan Coutts 18 | Iavor Diatchki 19 | Don Steward 20 | -------------------------------------------------------------------------------- /reference/AUTHORS.c2hs: -------------------------------------------------------------------------------- 1 | Manuel M T Chakravarty 2 | Duncan Coutts 3 | 4 | with contributions from (alphabetical order) 5 | 6 | Bertram Felgenhauer 7 | Ian Lynagh 8 | André Pang 9 | Jens-Ulrik Petersen 10 | Armin Sander 11 | Sean Seefried 12 | Udo Stenzel 13 | Axel Simon 14 | Michael Weber 15 | 16 | Thanks for comments and suggestions to 17 | 18 | Roman Leshchinskiy 19 | Jan Kort 20 | Seth Kurtzberg 21 | Simon Marlow 22 | Matthias Neubauer 23 | Sven Panne 24 | Simon L. Peyton Jones 25 | Volker Wysk 26 | -------------------------------------------------------------------------------- /reference/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 1999-2008 Manuel M T Chakravarty 2 | Duncan Coutts 3 | Benedikt Huber 4 | Portions Copyright (c) 1989, 1990 James A. Roskind 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 3. Neither the name of the author nor the names of his contributors 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /reference/MAINTAINANCE: -------------------------------------------------------------------------------- 1 | # Maintainance Release Procedure 2 | 3 | # bump version and update dependencies if necessary 4 | emacs language-c.cabal 5 | darcs record 6 | 7 | # apply patches 8 | darcs am *.patch 9 | 10 | # add minimal test for new functionality 11 | # (edit test/harness) 12 | 13 | # haskell updates 14 | # (update GHC to stable release) 15 | cabal update 16 | cabal install -p --upgrade-dependencies --only-dependencies 17 | 18 | # build & harness test 19 | cabal configure -fallWarnings --enable-tests 20 | cabal build 21 | cabal test 22 | 23 | # regression test 24 | DEFAULT_BROWSER=firefox bash scripts/regression_test 25 | 26 | # tag 27 | darcs tag language-c-0.5.0 28 | 29 | # upload to code.haskell.org 30 | darcs push 31 | 32 | # update github mirror (darcs-2-git) 33 | cd ../language-c-darcs2git 34 | darcs-2-git ../language-c 35 | cd ../language-c-github 36 | git checkout darcs2git 37 | git pull ../language-c-darcs2git 38 | git checkout master 39 | git merge darcs2git 40 | 41 | # upload to hackage (using website) 42 | -------------------------------------------------------------------------------- /reference/README: -------------------------------------------------------------------------------- 1 | = Language.C = 2 | 3 | Language.C is a parser and pretty-printer framework for C11 and the extensions of gcc. 4 | 5 | See http://visq.github.io/language-c/ 6 | 7 | == Build and Install == 8 | 9 | cabal install 10 | 11 | -- or -- 12 | 13 | runhaskell Setup.hs configure FLAGS 14 | runhaskell Setup.hs build 15 | runhaskell Setup.hs install 16 | 17 | Provide the set of flags passing 18 | --flags="" 19 | to configure. 20 | 21 | == Compatibility == 22 | 23 | Tested with GHC 7.8, 7.10, 8.0 and 8.2. 24 | It is recommended to use the most recent platform release: http://hackage.haskell.org/platform/. 25 | 26 | == C Language Compatibility == 27 | 28 | Currently unsupported C11 constructs: 29 | - static assertion 6.7.10 (_Static_assert) 30 | - generic selection 6.5.1.1 (_Generic) 31 | - _Atomic, _Alignas, _Thread_local 32 | - Universal character names 33 | 34 | Currently unsupported GNU C extensions: 35 | - __auto_type 36 | - __builtin_offsetof 37 | char a[__builtin_offsetof (struct S, sa->f) 38 | - _Decimal32 39 | - Extended assembler 40 | __asm__ __volatile__ ("" : : : ); 41 | __asm__ goto ("" : : : : label); 42 | 43 | == Sources == 44 | 45 | see src/README 46 | 47 | == Examples == 48 | 49 | A couple of small examples are available in /examples 50 | 51 | == Testing == 52 | 53 | A couple of regression tests can be run via 54 | > cd test/harness; make 55 | 56 | For more tests, see test/README. 57 | -------------------------------------------------------------------------------- /reference/Setup.hs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env runhaskell 2 | 3 | import Distribution.Simple 4 | 5 | main = defaultMain 6 | -------------------------------------------------------------------------------- /reference/docs/ProjectStatus.txt: -------------------------------------------------------------------------------- 1 | = Project Status = 2 | 3 | == Parser and Pretty-Printer == 4 | 5 | The core parser / pretty-printer components are more or less complete (see [wiki:Cee C language support]). 6 | 7 | == Preprocessor == 8 | 9 | === Done === 10 | * Provide a module for calling an external preprocessor 11 | * Support for using GCC as preprocessor 12 | 13 | == Analysis == 14 | 15 | === Done (0.3) === 16 | * Framework for name analysis 17 | * File-scope analysis 18 | * Declaration analysis 19 | 20 | === Planned === 21 | * Type checking expressions 22 | * Constant expression evaluation 23 | * typed representation of attributes 24 | * Normalized representation of initializers 25 | * Support for analyzing function bodies 26 | * Normalizing expressions and statements 27 | 28 | == Other Features under consideration == 29 | 30 | * Exposing more parsers ({{{parseExpr}}},{{{parseStmt}}}) 31 | * Quasiquoting (problem with typedefs) 32 | * Code generation combinators 33 | * Recording comments 34 | * Code transformations (deferred) -------------------------------------------------------------------------------- /reference/docs/Start.txt: -------------------------------------------------------------------------------- 1 | '''currently under construction''' 2 | = Language.C - A C99 library for haskell = 3 | 4 | The Language.C project aims to be a stable and compliant C99 library for [http://www.haskell.org haskell]. 5 | 6 | As for now, it features a complete, reasonably well tested parser and pretty printer for all of C99 and a large set of GNU extensions ([wiki:Cee C language support]). 7 | 8 | Eventually, we also want to provide a complete analysis framework for C. 9 | 10 | == Good news, everybody == 11 | 12 | * 2008/08/12: Released 0.3 13 | 14 | == Download == 15 | 16 | * darcs get [http://code.haskell.org/language-c] 17 | * (soon also via hackage / cabal-install) 18 | 19 | == Documentation == 20 | 21 | * [wiki:GettingStarted Getting Started] 22 | * [http://code.haskell.org/~bhuber/docs/language-c-latest/ API docs] 23 | * [wiki:ProjectPlan project status and further directions] 24 | 25 | == Feedback == 26 | 27 | * Please submit bug reports and feature request using the [http://www.sivity.net/projects/language.c/report/ bug tracker] 28 | * You may also contact the me at ''benedikt huber gmail com'' 29 | 30 | == License == 31 | 32 | Language.C is released under the BSD-3 license. 33 | 34 | == Acknowledgments == 35 | 36 | Google's [http://code.google.com/soc Summer Of Code] funded Benedikt Huber to work on this project ([wiki:DetailledProposal updated detailed proposal]). 37 | [http://yav.purely-functional.net/ Iavor Diatchki] and [http://www.cse.unsw.edu.au/~dons/ Don Steward] have been the great supervisors and Duncan Coutts provided a lot of valuable suggestions. -------------------------------------------------------------------------------- /reference/docs/semantics/ExternalDefinitions.txt: -------------------------------------------------------------------------------- 1 | = External Definitions = 2 | 3 | This document covers file-scope declarations and definitions of objects and functions. 4 | All file-scope declarations have static storage, see [wiki:Glossary] for explanation of terminology. 5 | We use the following abbreviations: 6 | {{{ 7 | T - type 8 | To - object type 9 | Tf - function type 10 | Tv - void type 11 | }}} 12 | 13 | == Declarations, tentative definitions (C99 6.9.2 / 2) and definitions == 14 | 15 | A declaration introduce a identifier and associates it with a kind and type. 16 | An external definition does the same, but also requests to allocate storage for an object, or generate code for a function. 17 | 18 | A tentative definition will either be interpreted as a external declaration or definition, depending on the file scope context. 19 | A tentative definition is of the form {{{ static? To name; }}}, i.e. an object declaration without initializer. 20 | If the tentative definition is the last tentative definition and there are no external definitions for that object, 21 | then it is an external definition, with an implicit initializer ( {{{ static? To name = (To) 0; }}} ). 22 | Otherwise, it is a declaration. 23 | Tentative definitions with internal linkage may not have incomplete type. 24 | 25 | == Syntactic Forms == 26 | On the top level, the semantics of declarations and definitions is given as follows: 27 | 28 | {{{ 29 | To name; /* tentative _definition_ of an object of type T with external linkage */ 30 | Tf name; /* prototype _declaration_ of a function with external linkage*/ 31 | static To name; /* tentative definition of an object of type T with internal linkage */ 32 | static Tf name; /* prototype _declaration_ of a function with internal linkage */ 33 | extern To name = I; /* _definition_ of an object with external linkage (6.9.2 / 1) */ 34 | extern T name; /* not OBJ_NAME_IN_SCOPE(name): declaration of an object/function with external linkage */ 35 | extern T name; /* OBJ_NAME_IN_SCOPE(name): declaration which refers to the previously declared entity */ 36 | 37 | Tf f { ... } /* definition of a function with either external linkage or with the linkage of previous declaration */ 38 | static Tf f { ... } /* definition of a function with internal linkage */ 39 | extern Tf f { ... } /* definition of a function with either external linkage or with the linkage of previous declaration */ 40 | 41 | /* ERROR */ (register|auto) T name; 42 | }}} 43 | 44 | == Constraints == 45 | 46 | 1) '''At most one''' ''external definition'' of an identifier with ''internal linkage''. 47 | 48 | 2) '''Exactly one''' ''external definition'' of an idenitifer used 49 | (references in compile-time constants (sizeof) do not count as usage) 50 | 51 | 3) '''Exactly one''' definition of an identifier used in the entire program. 52 | 53 | 4) The declarator of a function definition has to have function type and may not return an array type. 54 | 55 | 5) The only storage specifiers allowed for function definitions are {{{extern}}} or {{{static}}}. 56 | 57 | 6) Parameters may only have the storage specifier {{{register}}}. 58 | -------------------------------------------------------------------------------- /reference/docs/semantics/Glossary.txt: -------------------------------------------------------------------------------- 1 | h1. Glossary (stub) 2 | h2. General 3 | * translation unit - the unit which is translated to an object file, usually a preprocessed C file 4 | * declaration - introduces a name for a object, function or type 5 | * definition - defines an object (which needs to be allocated) or a function (code generation) 6 | * type definition - defines a struct,union or enum type 7 | * typedef - defines an alias for a type 8 | * identifier - (general) name for an composite type, struct/union member, typedef, object, 9 | function, enumerator or label 10 | - (ordinary) name for a typedef, object, enumerator or function (which live in the same namespace) 11 | * tag - name for a struct, union or enum type, sometimes referring to such a type 12 | 13 | h2. Linkage of Declarations / Definitions 14 | 15 | * External linkage: All decls/defs with external linkage in the program denote the same object/function. 16 | This means, they are visible in all translation units. 17 | * Internal linkage: All decls/defs within the translation unit denote the same object/function (static keyword). 18 | * No linkage: The declaration denotes a unique entity (not applicable for external decs/defs). 19 | 20 | -------------------------------------------------------------------------------- /reference/docs/semantics/NameSpaces.txt: -------------------------------------------------------------------------------- 1 | In C, there are 4 categories of identifiers: 2 | * labels 3 | * tag names (@(struct|union|enum) tag-name@), where all tag names live in one namespace 4 | * members of structures and unions 5 | * identifiers, type-names and enumeration constants 6 | 7 | There are 4 kind of scopes: 8 | * file scope: outside of parameter lists and blocks 9 | * function prototype scope 10 | * function scope: labels are visible within the entire function, and declared implicitely 11 | * block scope 12 | 13 | Scoping rules: 14 | * labels have function scope 15 | * all other identifiers have scope determined by the placement of the identifier 16 | * struct/union/enum tags have scopes that begin after their appearance 17 | * all other identifiers scopes begins at the end of the corresponding declarator 18 | * their scope ends at the end of the block / file / prototype if they are in block/file/prototype scope 19 | * inner scope hides (shadows) outer scope 20 | 21 | Linkage rules: 22 | * if an identifier declaration has no linkage, it refers to the unique object declared 23 | * if an identifier decl has internal linkage, it refers to the file-scope object with the given name 24 | * the specifier `static' declares internal linkage 25 | * if an identifier decl has external linkage, it refers to the program scope object with the given name 26 | * the specifier `extern' declares external linkage IF no identifier of the given name is visible 27 | File-scope function declarations have and implicit `extern` specifier, while file-scope objects 28 | have external linkage, unless declared otherwise. 29 | * the specifier `extern' denotes the object with the same name which is visible (if there is one) 30 | * undefined behaviour if identifier appears with both internal and external linkage 31 | 32 | Strategy for declarations/definitions: 33 | * if there is no identifier 34 | * if there is an undefined declaration of the same kind in scope, we define it 35 | * if there is an identifier of different kind in scope, we overwrite it and return the old definition 36 | It is the clients responsibility to check whether the redefinition is ok 37 | * if there is an defined declaration of the same kind in scope, we redefine it and return the old definition 38 | -------------------------------------------------------------------------------- /reference/examples/BasicUsage.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | import Language.C 3 | import Language.C.System.GCC 4 | 5 | main = parseMyFile "test.c" >>= printMyAST 6 | 7 | parseMyFile :: FilePath -> IO CTranslUnit 8 | parseMyFile input_file = 9 | do parse_result <- parseCFile (newGCC "gcc") Nothing [] input_file 10 | case parse_result of 11 | Left parse_err -> error (show parse_err) 12 | Right ast -> return ast 13 | 14 | printMyAST :: CTranslUnit -> IO () 15 | printMyAST ctu = (print . pretty) ctu -------------------------------------------------------------------------------- /reference/examples/DumpAst.hs: -------------------------------------------------------------------------------- 1 | 2 | import System.Environment (getArgs) 3 | import System.Exit (exitWith, ExitCode(ExitFailure)) 4 | import System.IO (hPutStrLn, stderr) 5 | import Control.Monad (when) 6 | import Text.PrettyPrint.HughesPJ (render, text, (<+>), hsep) 7 | 8 | import Language.C (parseCFile) 9 | import Language.C.System.GCC (newGCC) 10 | 11 | usageMsg :: String -> String 12 | usageMsg prg = render $ text "Usage:" <+> text prg <+> hsep (map text ["CPP_OPTIONS","input_file.c"]) 13 | 14 | main :: IO () 15 | main = do 16 | let usageErr = (hPutStrLn stderr (usageMsg "./ParseAndPrint") >> exitWith (ExitFailure 1)) 17 | args <- getArgs 18 | when (length args < 1) usageErr 19 | let (opts,input_file) = (init args, last args) 20 | ast <- errorOnLeftM "Parse Error" $ parseCFile (newGCC "gcc") Nothing opts input_file 21 | putStrLn $ (decorate (shows (fmap (const ShowPlaceholder) ast)) "") 22 | 23 | errorOnLeft :: (Show a) => String -> (Either a b) -> IO b 24 | errorOnLeft msg = either (error . ((msg ++ ": ")++).show) return 25 | 26 | errorOnLeftM :: (Show a) => String -> IO (Either a b) -> IO b 27 | errorOnLeftM msg action = action >>= errorOnLeft msg 28 | 29 | data ShowPlaceholder = ShowPlaceholder 30 | instance Show ShowPlaceholder where 31 | showsPrec _ ShowPlaceholder = showString "_" 32 | 33 | decorate :: ShowS -> ShowS 34 | decorate app = showString "(" . app . showString ")" 35 | 36 | -------------------------------------------------------------------------------- /reference/examples/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 1999-2008 Manuel M T Chakravarty 2 | Duncan Coutts 3 | Benedikt Huber 4 | Portions Copyright (c) 1989, 1990 James A. Roskind 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 3. Neither the name of the author nor the names of his contributors 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /reference/examples/Makefile: -------------------------------------------------------------------------------- 1 | # Build examples 2 | BINARIES=ParseAndPrint ScanFile SearchDef TypeCheck ComputeSize DumpAst 3 | 4 | PROJECT_DIR=.. 5 | BIN_DIR=. 6 | INPLACE_PACKAGE_CONF=$(PROJECT_DIR)/dist/package.conf.inplace 7 | 8 | all: build 9 | build: $(INPLACE_PACKAGE_CONF) 10 | cabal install --package-db $(INPLACE_PACKAGE_CONF) --dependencies-only 11 | cabal configure --package-db $(INPLACE_PACKAGE_CONF) 12 | cabal build 13 | for b in $(BINARIES) ; do cp dist/build/$$b/$$b $(BIN_DIR) ; done 14 | 15 | demo_compute_size: ComputeSize 16 | gcc -DDEBUG compute_size.c -o compute_size.bin && ./compute_size.bin 17 | ./ComputeSize 'comp' compute_size.c | gcc -x c -o compute_size_hs.bin - && \ 18 | ./compute_size_hs.bin 19 | ComputeSize: 20 | echo "Please run make build first" >&2 21 | exit 1 22 | 23 | clean: 24 | rm -f $(addprefix $(BIN_DIR)/, $(BINARIES)) compute_size.bin compute_size_hs.bin 25 | cabal clean 26 | 27 | ../dist/package.conf.inplace: 28 | echo "Please run cd .. && cabal build first" 29 | exit 1 30 | -------------------------------------------------------------------------------- /reference/examples/ParseAndPrint.hs: -------------------------------------------------------------------------------- 1 | -- Minimal example: parse a file, and pretty print it again 2 | module Main where 3 | import System.Environment 4 | import System.Exit 5 | import System.IO 6 | import Control.Monad 7 | import Text.PrettyPrint.HughesPJ 8 | 9 | import Language.C -- simple API 10 | import Language.C.System.GCC -- preprocessor used 11 | 12 | usageMsg :: String -> String 13 | usageMsg prg = render $ 14 | text "Usage:" <+> text prg <+> hsep (map text ["CPP_OPTIONS","input_file.c"]) 15 | 16 | main :: IO () 17 | main = do 18 | let usageErr = (hPutStrLn stderr (usageMsg "./ParseAndPrint") >> exitWith (ExitFailure 1)) 19 | args <- getArgs 20 | when (length args < 1) usageErr 21 | let (opts,input_file) = (init args, last args) 22 | 23 | -- parse 24 | ast <- errorOnLeftM "Parse Error" $ 25 | parseCFile (newGCC "gcc") Nothing opts input_file 26 | -- pretty print 27 | print $ pretty ast 28 | 29 | errorOnLeft :: (Show a) => String -> (Either a b) -> IO b 30 | errorOnLeft msg = either (error . ((msg ++ ": ")++).show) return 31 | errorOnLeftM :: (Show a) => String -> IO (Either a b) -> IO b 32 | errorOnLeftM msg action = action >>= errorOnLeft msg 33 | -------------------------------------------------------------------------------- /reference/examples/ScanFile.hs: -------------------------------------------------------------------------------- 1 | -- Simple example demonstrating the API: parse a file, and print its definition table 2 | module Main where 3 | import System.Environment 4 | import System.FilePath 5 | import System.Exit 6 | import System.IO 7 | import Control.Monad 8 | import Debug.Trace 9 | import Text.PrettyPrint.HughesPJ 10 | import Data.List 11 | 12 | import Language.C -- simple API 13 | import Language.C.Analysis -- analysis API 14 | import Language.C.System.GCC -- preprocessor used 15 | 16 | usageMsg :: String -> String 17 | usageMsg prg = render $ 18 | text "Usage:" <+> text prg <+> hsep (map text ["CPP_OPTIONS","input_file.c","[file-pattern]"]) $+$ 19 | (nest 4 $ 20 | text "Environment Variables" $+$ 21 | (nest 4 $ 22 | hsep [text "TRACE_EVENTS", text "trace definition events as they occur"] 23 | ) 24 | ) 25 | 26 | main :: IO () 27 | main = do 28 | let usageErr = (hPutStrLn stderr (usageMsg "./ScanFile") >> exitWith (ExitFailure 1)) 29 | args <- getArgs 30 | when (length args < 1) usageErr 31 | doTraceDecls <- liftM (("TRACE_EVENTS" `elem`). map fst) getEnvironment 32 | -- get cpp options and input file 33 | let (pat,opts,input_file) = case hasExtension (last args) of 34 | True -> (Nothing,init args,last args) 35 | False -> let (pat',args') = (last args, init args) 36 | in (Just pat',init args',last args') 37 | 38 | -- parse 39 | ast <- errorOnLeftM "Parse Error" $ 40 | parseCFile (newGCC "gcc") Nothing opts input_file 41 | 42 | -- analyze 43 | (globals,warnings) <- errorOnLeft "Semantic Error" $ runTrav_ $ traversal doTraceDecls ast 44 | 45 | -- print 46 | mapM_ (hPutStrLn stderr . show) warnings 47 | print $ pretty $ filterGlobalDecls (maybe False (fileOfInterest pat input_file) . fileOfNode) globals 48 | 49 | where 50 | traversal False ast = analyseAST ast 51 | traversal True ast = withExtDeclHandler (analyseAST ast) $ \ext_decl -> 52 | trace (declTrace ext_decl) (return ()) 53 | 54 | fileOfInterest (Just pat) _ file_name = pat `isInfixOf` file_name 55 | fileOfInterest Nothing input_file file_name = fileOfInterest' (splitExtensions input_file) (splitExtension file_name) 56 | fileOfInterest' (c_base,c_ext) (f_base,f_ext) | takeBaseName c_base /= takeBaseName f_base = False 57 | | f_ext == ".h" && c_ext == ".c" = False 58 | | otherwise = True 59 | 60 | errorOnLeft :: (Show a) => String -> (Either a b) -> IO b 61 | errorOnLeft msg = either (error . ((msg ++ ": ")++).show) return 62 | errorOnLeftM :: (Show a) => String -> IO (Either a b) -> IO b 63 | errorOnLeftM msg action = action >>= errorOnLeft msg 64 | 65 | declTrace :: DeclEvent -> String 66 | declTrace event = render $ case event of 67 | TagEvent tag_def -> (text "Tag:" <+> (pretty tag_def) <+> file tag_def) 68 | DeclEvent ident_decl -> (text "Decl:" <+> (pretty ident_decl) <+> file ident_decl) 69 | ParamEvent pd -> (text "Param:" <+> (pretty pd) <+> file pd) 70 | LocalEvent ident_decl -> (text "Local:" <+> (pretty ident_decl) <+> file ident_decl) 71 | TypeDefEvent tydef -> (text "Typedef:" <+> (pretty tydef) <+> file tydef) 72 | AsmEvent _block -> (text $ "Assembler block") 73 | where 74 | file :: (CNode a) => a -> Doc 75 | file = text . show . posOfNode . nodeInfo 76 | -------------------------------------------------------------------------------- /reference/examples/SearchDef.hs: -------------------------------------------------------------------------------- 1 | -- Simple example demonstrating the syntax - semantic interplay: search and print definitions 2 | module Main where 3 | import System.Environment 4 | import Control.Arrow 5 | import Control.Monad 6 | import Control.Applicative 7 | import qualified Data.Map as Map 8 | 9 | import Language.C -- simple API 10 | import Language.C.Analysis -- analysis API 11 | import Language.C.System.GCC -- preprocessor used 12 | 13 | main :: IO () 14 | main = do 15 | let usage = error "Example Usage: ./ShowDef '((struct|union|enum) tagname|typename|objectname)' -I/usr/include my_file.c" 16 | args <- getArgs 17 | when (length args < 2) usage 18 | 19 | -- get cpp options and input file 20 | let (searchterm:args') = args 21 | let (opts,c_file) = (init &&& last) args' 22 | 23 | -- parse 24 | ast <- parseCFile (newGCC "gcc") Nothing opts c_file 25 | >>= checkResult "[parsing]" 26 | (globals,_warnings) <- (runTrav_ >>> checkResult "[analysis]") $ analyseAST ast 27 | let defId = searchDef globals searchterm 28 | -- traverse the AST and print decls which match 29 | case defId of 30 | Nothing -> print "Not found" 31 | Just def_id -> printDecl def_id ast 32 | where 33 | checkResult :: (Show a) => String -> (Either a b) -> IO b 34 | checkResult label = either (error . (label++) . show) return 35 | 36 | printDecl :: NodeInfo -> CTranslUnit -> IO () 37 | printDecl def_id (CTranslUnit decls _) = 38 | let decls' = filter (maybe False (posFile (posOfNode def_id) ==).fileOfNode) decls in 39 | mapM_ (printIfMatch def_id) (zip decls' (map Just (tail decls') ++ [Nothing])) 40 | printIfMatch def (decl,Just next_decl) | posOfNode def >= posOf decl && 41 | posOfNode def < posOf next_decl = (print . pretty) decl 42 | | otherwise = return () 43 | printIfMatch def (decl, Nothing) | posOfNode def >= posOf decl = (print . pretty) decl 44 | | otherwise = return () 45 | searchDef globs term = 46 | case analyseSearchTerm term of 47 | Left tag -> fmap nodeInfo (Map.lookup tag (gTags globs)) 48 | Right ident -> fmap nodeInfo (Map.lookup ident (gObjs globs)) 49 | <|> fmap nodeInfo (Map.lookup ident (gTypeDefs globs)) 50 | <|> fmap nodeInfo (Map.lookup (NamedRef ident) (gTags globs)) 51 | analyseSearchTerm term = 52 | case words term of 53 | [tag,name] | tag `elem` (words "struct union enum") -> Left $ NamedRef (internalIdent name) 54 | [ident] -> Right (internalIdent ident) 55 | _ -> error "bad search term" 56 | -------------------------------------------------------------------------------- /reference/examples/TypeCheck.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Data.List 4 | import Language.C 5 | import Language.C.Analysis.AstAnalysis 6 | import Language.C.Analysis.TravMonad 7 | import Language.C.System.GCC 8 | import System.Environment 9 | import System.IO 10 | import System.Exit 11 | 12 | processFile :: CLanguage -> [String] -> FilePath -> IO () 13 | processFile lang cppOpts file = 14 | do hPutStr stderr $ file ++ ": " 15 | result <- parseCFile (newGCC "gcc") Nothing cppOpts file 16 | case result of 17 | Left err -> do 18 | hPutStrLn stderr ('\n' : show err) 19 | hPutStrLn stderr "Failed: Parse Error" 20 | exitWith (ExitFailure 1) 21 | Right tu -> case runTrav_ (body tu) of 22 | Left errs -> mapM_ (hPutStrLn stderr) ("Error" : map show errs) 23 | Right (_,errs) -> mapM_ (hPutStrLn stderr) ("Success" : map show errs) 24 | where body tu = do modifyOptions (\opts -> opts { language = lang }) 25 | analyseAST tu 26 | 27 | main :: IO () 28 | main = 29 | do args <- getArgs 30 | let (cppOpts, files) = partition (isPrefixOf "-") args 31 | mapM_ (processFile GNU99 cppOpts) files 32 | -------------------------------------------------------------------------------- /reference/examples/compute_size.c: -------------------------------------------------------------------------------- 1 | #ifdef DEBUG 2 | #include 3 | #endif 4 | typedef _Bool bool; 5 | typedef struct __attribute__((packed)) 6 | { char x; short y; } 7 | T; 8 | typedef struct { bool b1; short b2; bool b3; 9 | bool b4; short b5; bool b6; } 10 | Bools; 11 | union u1 { 12 | T x; 13 | /* packed for struct/union fields: smallest possible alignment, i.e. do not add padding zeros to align the pointer 14 | in an array of u1s */ 15 | __attribute__((packed)) T* y; 16 | Bools z; 17 | }; 18 | 19 | union __attribute__((packed)) 20 | u2 21 | { 22 | T x,*y; Bools z; 23 | }; 24 | 25 | /* this attribute is ignored, because it belongs to x */ 26 | __attribute__((packed)) 27 | union u3 28 | { 29 | T x, *y; Bools z; 30 | } x; 31 | 32 | struct s { 33 | struct k { short b1 : 8, b2: 9, b3: 8, b4 : 7;} x; 34 | union u1 a,*b; 35 | union u2 c_1,c_2; 36 | union u3 d_1,d_2,d_3; 37 | } __attribute__((packed)); 38 | 39 | int main() 40 | { 41 | #ifdef DEBUG 42 | printf("T: %lu\n", sizeof(T)); 43 | printf("Bools: %lu\n", sizeof(Bools)); 44 | printf("struct k: %lu\n", sizeof(struct k)); 45 | printf("struct s: %lu\n", sizeof(struct s)); 46 | printf("union u1: %lu\n", sizeof(union u1)); 47 | printf("union u2: %lu\n", sizeof(union u2)); 48 | printf("union u3: %lu\n", sizeof(union u3)); 49 | #endif 50 | } 51 | -------------------------------------------------------------------------------- /reference/examples/example.c: -------------------------------------------------------------------------------- 1 | #include 2 | /* example.c */ 3 | /* (tentative) definitions */ 4 | static c; extern c; 5 | static int c = 3; 6 | static int c; 7 | /* old style function definition */ 8 | void* match(s_ix, l_ix, pat) 9 | long l_ix; 10 | char unsigned *pat; 11 | { exit(1); } 12 | /* typedefs and structs */ 13 | typedef struct s { struct { char chr; double dbl; } x,*y; } __attribute__((packed)) S; 14 | struct t { int a; }; 15 | S f(); 16 | static g(S a) { return 0; } 17 | int main() { printf("%d",sizeof(DIR)); } -------------------------------------------------------------------------------- /reference/examples/language-c-examples.cabal: -------------------------------------------------------------------------------- 1 | Name: language-c-examples 2 | Version: 0.5.1 3 | Cabal-Version: >= 1.8 4 | Build-Type: Simple 5 | License: BSD3 6 | License-File: LICENSE 7 | Copyright: LICENSE 8 | Author: AUTHORS 9 | Maintainer: benedikt.huber@gmail.com 10 | Stability: experimental 11 | Homepage: http://visq.github.io/language-c/ 12 | Bug-reports: https://github.com/visq/language-c/issues/ 13 | 14 | Synopsis: Examples - Analysis and generation of C code 15 | Description: Language C is a haskell library for the analysis and generation of C code. 16 | Category: Language 17 | 18 | Executable ParseAndPrint 19 | main-is: ParseAndPrint.hs 20 | build-depends: base, filepath, mtl, pretty, language-c 21 | 22 | Executable ScanFile 23 | main-is: ScanFile.hs 24 | build-depends: base, filepath, mtl, pretty, language-c 25 | 26 | Executable SearchDef 27 | main-is: SearchDef.hs 28 | build-depends: base, filepath, mtl, pretty, containers, language-c 29 | 30 | Executable TypeCheck 31 | main-is: TypeCheck.hs 32 | build-depends: base, filepath, mtl, pretty, containers, syb, language-c 33 | 34 | Executable ComputeSize 35 | main-is: ComputeSize.hs 36 | build-depends: base, filepath, mtl, pretty, containers, syb, language-c 37 | 38 | Executable DumpAst 39 | main-is: DumpAst.hs 40 | build-depends: base, filepath, mtl, pretty, language-c 41 | 42 | -------------------------------------------------------------------------------- /reference/examples/sourceview/README: -------------------------------------------------------------------------------- 1 | = Prototype Status = 2 | 3 | needs gtk2hs (tested with 0.9.13) and language-c (>= 0.3.2 from darcs) 4 | > ghc --make -O SourceView.hs 5 | > gcc -E example.c > example.i 6 | > ./SourceView example.i 7 | -------------------------------------------------------------------------------- /reference/examples/sourceview/SourceView.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE PatternSignatures, RankNTypes #-} 2 | -- Example demonstrating how link the AST back to the source code, 3 | -- using a simple heuristic 4 | module Main where 5 | import System.Environment 6 | import System.Exit 7 | import System.IO 8 | import Control.Monad () 9 | import Control.Monad.Error as Err 10 | import Data.List 11 | import Text.PrettyPrint.HughesPJ 12 | import Data.Tree 13 | import Data.Maybe (fromMaybe) 14 | --import Debug.Trace 15 | 16 | 17 | import Language.C -- simple API 18 | import Language.C.Data.Node 19 | import GenericTree 20 | import SourceBrowser 21 | 22 | usageMsg :: String -> String 23 | usageMsg prg = render $ 24 | text "Usage:" <+> text prg <+> hsep (map text ["input_file.i"]) 25 | errorOnLeftM :: (MonadError e m, Err.Error e, Show a) => String -> m (Either a b) -> m b 26 | errorOnLeftM msg action = either (throwError . strMsg . showWith) return =<< action 27 | where showWith s = msg ++ ": " ++ (show s) 28 | 29 | main :: IO () 30 | main = do 31 | let usageErr = (hPutStrLn stderr (usageMsg "./Annotate") >> exitWith (ExitFailure 1)) 32 | -- get command line arguments 33 | args <- getArgs 34 | c_file <- case args of 35 | [a1] -> return a1 36 | _ -> usageErr 37 | -- parse the file 38 | ast <- errorOnLeftM "Parse Error" (parseCFilePre c_file) 39 | -- split the AST by input file 40 | let groups = groupAstBySourceFile ast 41 | -- show the generic tree 42 | putStrLn . drawTree . fmap show . (uncurry treeView) $ last groups 43 | -- run the source view 44 | runGTK (map (uncurry treeView) groups) c_file 45 | 46 | groupAstBySourceFile :: CTranslUnit -> [(FilePath,CTranslUnit)] 47 | groupAstBySourceFile (CTranslUnit decls _) = 48 | map (\decls -> (fileOfNode' (head decls), CTranslUnit decls (topNodePos decls))) . 49 | groupBy (\a b -> (fileOfNode' a) == fileOfNode' b) $ decls 50 | where 51 | fileOfNode' = maybe "" id . fileOfNode 52 | topNodePos decls = 53 | let lastDecl = nodeInfo (last decls) in 54 | mkNodeInfoPosLen (posOf (head decls)) (getLastTokenPos lastDecl) 55 | -------------------------------------------------------------------------------- /reference/scripts/GenerateKeywords.hs: -------------------------------------------------------------------------------- 1 | -- Generate lexer patterns (reimplementation) 2 | -- input := tokenlist 3 | -- tokenlist := tokenspec [,\n] tokenlist | 4 | -- tokenspec := (tletters | tctor tletters+) @__? 5 | -- tctor := ctor | (composite ctor) 6 | import Data.Maybe 7 | import Data.Char 8 | import qualified Data.Text as T 9 | import System.IO 10 | import System.Environment 11 | import Data.List as L 12 | import Data.Ord 13 | 14 | parseInput :: String -> [[String]] 15 | parseInput = map (map T.unpack) . 16 | catMaybes . 17 | map (parseTokenSpec . T.strip) . 18 | T.split (','==) . T.intercalate (T.pack ",") . 19 | T.lines . T.pack 20 | 21 | parseTokenSpec t | T.null t = Nothing 22 | | T.head t == '(' = 23 | let (tokexpr,tokenstr) = T.break (==')') t 24 | in Just $ parseTokenSpec' (T.snoc tokexpr ')') (T.words $ T.tail tokenstr) 25 | | otherwise = 26 | let (tokexpr:tokens) = T.words t 27 | in Just $ parseTokenSpec' tokexpr tokens 28 | 29 | parseTokenSpec' tokexpr tokenlist = 30 | case T.unpack (last (tokexpr:tokenlist)) of 31 | "@__" -> addReservedTokens (parseTokenSpec'' tokexpr (init tokenlist)) 32 | _ -> parseTokenSpec'' tokexpr tokenlist 33 | 34 | parseTokenSpec'' tokexpr [] = [tokexpr, tokexpr] 35 | parseTokenSpec'' tokexpr ts = tokexpr : ts 36 | 37 | addReservedTokens [tokexpr, tok] = tokexpr : [us `T.append` tok, tok, us `T.append` tok `T.append` us ] 38 | where us = T.pack "__" 39 | addReservedTokens list = error $ "addReservedTokens" ++ show list 40 | 41 | expandInput = sortBy (comparing (dropWhile (=='_') . snd)) . concatMap expand 42 | where 43 | expand (t:ts) = [ (t,t') | t' <- ts ] 44 | 45 | genOutput (ttok,tstr) = 46 | "idkwtok " ++ pattern ++ " = tok " ++ (show$length tstr) ++ " " ++ (genTok ttok) 47 | where 48 | genTok ts@('(':_) = ts 49 | genTok (t:ts) = "CTok" ++ (toUpper t : ts) 50 | pattern = "(" ++ L.intercalate " : " (map charPat tstr) ++ " : [])" 51 | charPat c = '\'' : c : '\'' : [] 52 | 53 | run ifile ofile = do 54 | inp <-readFile ifile 55 | let tokens = parseInput inp 56 | withFile ofile WriteMode $ \handle -> do 57 | hPutStrLn handle $ "-- Tokens: " ++ unwords (concatMap tail tokens) 58 | mapM_ (hPutStrLn handle) ((map genOutput . expandInput) tokens) 59 | 60 | main = do 61 | arguments <- getArgs 62 | let (ifile,ofile) = 63 | case arguments of 64 | [a,b]-> (a,b) 65 | _ -> error "Usage: GenerateKeywords.hs tokenlist.txt tokenlist.hs" 66 | run ifile ofile 67 | -------------------------------------------------------------------------------- /reference/scripts/move_module: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Move a module using darcs and rpl, creating a shell script 3 | if [ -e script.sh ]; then 4 | echo "remove script.sh first"; exit 1 5 | fi 6 | SRC=$1 7 | TARGET=$2 8 | shift 2 9 | echo "darcs mv $SRC.hs $TARGET.hs || (echo darcs failed; exit 1)" > script.sh 10 | echo "darcs record ." >> script.sh 11 | for path in $@; do 12 | if [ -d $path ]; then 13 | echo "(cd $path; rpl -x .hs -R ${SRC//\//.} ${TARGET//\//.} *; darcs amend .)" >> script.sh 14 | elif [ -e $path ]; then 15 | echo "(rpl ${SRC//\//.} ${TARGET//\//.} $path; darcs amend $path)" >> script.sh 16 | else 17 | echo "Non existing source file path $path" 18 | rm script.sh 19 | exit 1 20 | fi 21 | done 22 | 23 | -------------------------------------------------------------------------------- /reference/scripts/regression_test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run a regression test before pushing to code.haskell.org 3 | # People don't like code that doesn't compile 4 | 5 | # Configuration 6 | if [ -z "${TMPDIR}" ] ; then 7 | TMPDIR=/tmp 8 | fi 9 | if [ -z "${TESTDIR}" ] ; then 10 | TESTDIR=regression_test 11 | fi 12 | if [ -z "${DEFAULT_BROWSER}" ] ; then 13 | DEFAULT_BROWSER=firefox 14 | fi 15 | if [ -e ".git" ] ; then 16 | HAS_GIT=1 17 | elif [ -e "_darcs" ] ; then 18 | HAS_DARCS=1 19 | else 20 | echo "Please run this script from the language-c repository (darcs or git)" >&2 21 | exit 1 22 | fi 23 | 24 | # messages 25 | function die() { 26 | echo "*** Regression test failed: $1 ***" 1>&2; exit 1 27 | } 28 | function warning() { 29 | echo "[WARNING] $1" 1>&2 30 | } 31 | 32 | # preparation 33 | if [ ! -d "$TMPDIR" ] ; then 34 | die "TMPDIR ('$TMPDIR') directory does not exist " \ 35 | "(absolute path to a directory for temporary files)" 36 | fi 37 | 38 | if [ ! -d "$TESTDIR" ] ; then 39 | warning "'$TESTDIR' directory does not exist " \ 40 | "(needs to be a checkout of your local HEAD)" 41 | savedir="$(pwd)" 42 | mkdir -p $(dirname "${TESTDIR}") 43 | pushd $(dirname "${TESTDIR}") 44 | if [ $HAS_GIT -eq 1 ] ; then 45 | git clone "${savedir}" $(basename "${TESTDIR}") || die "Failed to clone local git repo" 46 | else 47 | darcs clone "${savedir}" $(basename "${TESTDIR}") || die "Failed to clone local darcs repo" 48 | fi 49 | popd 50 | fi 51 | 52 | # update 53 | cd "${TESTDIR}" 54 | if [ $HAS_GIT -eq 1 ] ; then 55 | git pull origin master || die "git pull (from local HEAD) failed" 56 | else 57 | darcs pull || die "darcs pull (from local HEAD) failed" 58 | fi 59 | 60 | 61 | # regression test 62 | echo "Building via cabal" 63 | cabal configure || die "cabal configure failed" 64 | cabal build || die "cabal build failed" 65 | cabal haddock || die "cabal haddock failed" 66 | echo "Finished building via cabal" 67 | 68 | cd test 69 | echo "Building test suite" 70 | make || die "make failed in /test" 71 | 72 | (cd harness && make) || die \ 73 | "test harness failed" 74 | 75 | (cd suite && yes | bash run-smoke.sh && yes | bash run-bugs.sh) || die \ 76 | "run-dg.sh failed - make sure there is a symlink or copy " \ 77 | "to the gcc.dg testsuite in $TMPDIR/test/suite" 78 | 79 | ( cd results && ../bin/RenderTests regression *dat) || die "rendering tests failed" 80 | 81 | ${BROWSER:-${DEFAULT_BROWSER}} results/index.html 82 | 83 | exit 0 84 | 85 | -------------------------------------------------------------------------------- /reference/scripts/tokenlist.txt: -------------------------------------------------------------------------------- 1 | alignas _Alignas, alignof _Alignof __alignof alignof __alignof__, asm @__, atomic _Atomic, auto 2 | break, bool _Bool, 3 | case, char, const @__, continue, complex _Complex __complex__ 4 | default, do, double, 5 | else, enum, extern, 6 | float, for, 7 | generic _Generic, goto, 8 | if, inline @__, int, int128 __int128, long, noreturn _Noreturn, 9 | nullable _Nullable __nullable, 10 | nonnull _Nonnull __nonnull, 11 | register, restrict @__, return 12 | short, signed @__, sizeof, static, staticAssert _Static_assert, struct, switch, 13 | typedef, typeof @__, thread __thread _Thread_local 14 | union, unsigned, void, volatile @__, 15 | while, 16 | label __label__ 17 | (CTokGnuC GnuCAttrTok) __attribute __attribute__ 18 | (CTokGnuC GnuCExtTok) __extension__ 19 | (CTokGnuC GnuCComplexReal) __real __real__ 20 | (CTokGnuC GnuCComplexImag) __imag __imag__ 21 | (CTokGnuC GnuCVaArg) __builtin_va_arg 22 | (CTokGnuC GnuCOffsetof) __builtin_offsetof 23 | (CTokGnuC GnuCTyCompat) __builtin_types_compatible_p 24 | -------------------------------------------------------------------------------- /reference/src/Language/C.hs: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- | 3 | -- Module : Language.C 4 | -- Copyright : (c) 2008 Benedikt Huber 5 | -- [1995..2007] 6 | -- Manuel M. T. Chakravarty 7 | -- Duncan Coutts 8 | -- Betram Felgenhauer 9 | -- License : BSD-style 10 | -- Maintainer : benedikt.huber@gmail.com 11 | -- Stability : experimental 12 | -- Portability : ghc 13 | -- 14 | -- Library for analysing and generating C code. 15 | -- 16 | -- See 17 | ----------------------------------------------------------------------------- 18 | module Language.C ( 19 | parseCFile, parseCFilePre, -- maybe change ? 20 | module Language.C.Data, 21 | module Language.C.Syntax, 22 | module Language.C.Pretty, 23 | module Language.C.Parser, 24 | ) 25 | where 26 | import Language.C.Data 27 | import Language.C.Syntax 28 | import Language.C.Pretty 29 | import Language.C.Parser 30 | import Language.C.System.Preprocess 31 | 32 | -- | preprocess (if necessary) and parse a C source file 33 | -- 34 | -- > Synopsis: parseCFile preprocesssor tmp-dir? cpp-opts file 35 | -- > Example: parseCFile (newGCC "gcc") Nothing ["-I/usr/include/gtk-2.0"] my-gtk-exts.c 36 | parseCFile :: (Preprocessor cpp) => cpp -> Maybe FilePath -> [String] -> FilePath -> IO (Either ParseError CTranslUnit) 37 | parseCFile cpp tmp_dir_opt args input_file = do 38 | input_stream <- if not (isPreprocessed input_file) 39 | then let cpp_args = (rawCppArgs args input_file) { cppTmpDir = tmp_dir_opt } 40 | in runPreprocessor cpp cpp_args >>= handleCppError 41 | else readInputStream input_file 42 | return$ parseC input_stream (initPos input_file) 43 | where 44 | handleCppError (Left exitCode) = fail $ "Preprocessor failed with " ++ show exitCode 45 | handleCppError (Right ok) = return ok 46 | 47 | -- | parse an already preprocessed C file 48 | -- 49 | -- > Synopsis: parseCFilePre file.i 50 | parseCFilePre :: FilePath -> IO (Either ParseError CTranslUnit) 51 | parseCFilePre file = do 52 | input_stream <- readInputStream file 53 | return $ parseC input_stream (initPos file) 54 | -------------------------------------------------------------------------------- /reference/src/Language/C/Analysis.hs: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- | 3 | -- Module : Language.C.Analysis 4 | -- Copyright : (c) 2008 Benedikt Huber 5 | -- License : BSD-style 6 | -- Maintainer : benedikt.huber@gmail.com 7 | -- Stability : alpha 8 | -- Portability : ghc 9 | -- 10 | -- Analysis of the AST. 11 | -- 12 | -- Currently, we provide a monad for analysis and analyze declarations and types. 13 | -- Especially note that there is no direct support for analyzing function bodies and 14 | -- constant expressions. 15 | -- 16 | -- /NOTE/ This is an experimental interface, and therefore the API will change in the 17 | -- future. 18 | -- 19 | -- DONE: 20 | -- 21 | -- * Name analysis framework 22 | -- 23 | -- * File-scope analysis 24 | -- 25 | -- * Declaration analysis 26 | -- 27 | -- TODO: 28 | -- 29 | -- * Type checking expressions 30 | -- 31 | -- * Constant expression evaluation (CEE) 32 | -- 33 | -- * Typed representation of attributes (depends on CEE) 34 | -- 35 | -- * Normalized representation of initializers 36 | -- 37 | -- * Support for analyzing function bodies (depends on CEE) 38 | -- 39 | -- * Normalizing expressions and statements 40 | -- 41 | -- * Formal rules how to link back to the AST using NodeInfo fields 42 | -- 43 | -- * Typed assembler representation 44 | 45 | ----------------------------------------------------------------------------- 46 | module Language.C.Analysis ( 47 | -- * Semantic representation 48 | module Language.C.Analysis.SemRep, 49 | -- * Error datatypes for the analysis 50 | module Language.C.Analysis.SemError, 51 | -- * Traversal monad 52 | module Language.C.Analysis.TravMonad, 53 | -- * Top level analysis 54 | module Language.C.Analysis.AstAnalysis, 55 | -- * Analyzing declarations 56 | module Language.C.Analysis.DeclAnalysis, 57 | -- * Debug print 58 | module Language.C.Analysis.Debug, 59 | ) 60 | where 61 | import Language.C.Analysis.SemError 62 | import Language.C.Analysis.SemRep 63 | 64 | import Language.C.Analysis.TravMonad 65 | 66 | import Language.C.Analysis.AstAnalysis 67 | import Language.C.Analysis.DeclAnalysis 68 | 69 | import Language.C.Analysis.Debug 70 | -------------------------------------------------------------------------------- /reference/src/Language/C/Analysis/AstAnalysis.hs-boot: -------------------------------------------------------------------------------- 1 | module Language.C.Analysis.AstAnalysis where 2 | 3 | import Language.C.Analysis.SemRep 4 | import Language.C.Analysis.TravMonad 5 | import Language.C.Syntax.AST 6 | 7 | data StmtCtx = FunCtx VarDecl 8 | | LoopCtx 9 | | SwitchCtx 10 | 11 | data ExprSide = LValue | RValue 12 | 13 | tExpr :: MonadTrav m => [StmtCtx] -> ExprSide -> CExpr -> m Type 14 | -------------------------------------------------------------------------------- /reference/src/Language/C/Analysis/TypeConversions.hs: -------------------------------------------------------------------------------- 1 | module Language.C.Analysis.TypeConversions ( 2 | arithmeticConversion, 3 | floatConversion, 4 | intConversion 5 | ) where 6 | 7 | import Language.C.Analysis.SemRep 8 | 9 | -- | For an arithmetic operator, if the arguments are of the given 10 | -- types, return the type of the full expression. 11 | arithmeticConversion :: TypeName -> TypeName -> Maybe TypeName 12 | -- XXX: I'm assuming that double `op` complex float = complex 13 | -- double. The standard seems somewhat unclear on whether this is 14 | -- really the case. 15 | arithmeticConversion (TyComplex t1) (TyComplex t2) = 16 | Just $ TyComplex $ floatConversion t1 t2 17 | arithmeticConversion (TyComplex t1) (TyFloating t2) = 18 | Just $ TyComplex $ floatConversion t1 t2 19 | arithmeticConversion (TyFloating t1) (TyComplex t2) = 20 | Just $ TyComplex $ floatConversion t1 t2 21 | arithmeticConversion t1@(TyComplex _) (TyIntegral _) = Just t1 22 | arithmeticConversion (TyIntegral _) t2@(TyComplex _) = Just t2 23 | arithmeticConversion (TyFloating t1) (TyFloating t2) = 24 | Just $ TyFloating $ floatConversion t1 t2 25 | arithmeticConversion t1@(TyFloating _) (TyIntegral _) = Just t1 26 | arithmeticConversion (TyIntegral _) t2@(TyFloating _) = Just t2 27 | arithmeticConversion (TyIntegral t1) (TyIntegral t2) = 28 | Just $ TyIntegral $ intConversion t1 t2 29 | arithmeticConversion (TyEnum _) (TyEnum _) = Just $ TyIntegral TyInt 30 | arithmeticConversion (TyEnum _) t2 = Just t2 31 | arithmeticConversion t1 (TyEnum _) = Just t1 32 | arithmeticConversion _ _ = Nothing 33 | 34 | floatConversion :: FloatType -> FloatType -> FloatType 35 | floatConversion = max 36 | 37 | intConversion :: IntType -> IntType -> IntType 38 | intConversion t1 t2 = max TyInt (max t1 t2) 39 | 40 | -------------------------------------------------------------------------------- /reference/src/Language/C/Data.hs: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- | 3 | -- Module : Language.C.Data 4 | -- Copyright : (c) 2008 Benedikt Huber 5 | -- License : BSD-style 6 | -- Maintainer : benedikt.huber@gmail.com 7 | -- Stability : experimental 8 | -- Portability : ghc 9 | -- 10 | -- Common data types for Language.C: Identifiers, unique names, source code locations, 11 | -- ast node attributes and extensible errors. 12 | ----------------------------------------------------------------------------- 13 | module Language.C.Data ( 14 | -- * Input stream 15 | module Language.C.Data.InputStream, 16 | -- * Identifiers 17 | SUERef(..), isAnonymousRef, sueRefToString, 18 | Ident,mkIdent, identToString, internalIdent, isInternalIdent, builtinIdent, 19 | -- * Unqiue names 20 | Name(..),newNameSupply, 21 | -- * Source code positions 22 | Position(..),posFile,posParent, 23 | Pos(..), 24 | initPos, nopos,builtinPos,internalPos, 25 | isSourcePos,isBuiltinPos,isInternalPos, 26 | -- * Syntax tree nodes 27 | NodeInfo(..),CNode(..), 28 | fileOfNode,posOfNode,nameOfNode, 29 | undefNode,mkNodeInfoOnlyPos,mkNodeInfo, 30 | internalNode, -- DEPRECATED 31 | -- * Extensible errors 32 | module Language.C.Data.Error 33 | ) 34 | where 35 | import Language.C.Data.InputStream 36 | import Language.C.Data.Ident 37 | import Language.C.Data.Name 38 | import Language.C.Data.Position 39 | import Language.C.Data.Error 40 | import Language.C.Data.Node 41 | -------------------------------------------------------------------------------- /reference/src/Language/C/Data/InputStream.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP, BangPatterns #-} 2 | {-# OPTIONS -Wall #-} 3 | ----------------------------------------------------------------------------- 4 | -- | 5 | -- Module : Language.C.Data.InputStream 6 | -- Copyright : (c) 2008,2011 Benedikt Huber 7 | -- License : BSD-style 8 | -- Maintainer : benedikt.huber@gmail.com 9 | -- Stability : experimental 10 | -- Portability : ghc 11 | -- 12 | -- Compile time input abstraction for the parser, relying on ByteString. 13 | -- The String interface only supports Latin-1 since alex-3, as alex now requires 14 | -- byte based access to the input stream. 15 | ------------------------------------------------------------------------------- 16 | module Language.C.Data.InputStream ( 17 | InputStream, readInputStream,inputStreamToString,inputStreamFromString, 18 | takeByte, takeChar, inputStreamEmpty, takeChars, 19 | countLines, 20 | ) 21 | where 22 | 23 | import Data.Word 24 | 25 | #ifndef NO_BYTESTRING 26 | import Data.ByteString (ByteString) 27 | import qualified Data.ByteString as BSW 28 | import qualified Data.ByteString.Char8 as BSC 29 | #else 30 | import qualified Data.Char as Char 31 | #endif 32 | 33 | -- Generic InputStream stuff 34 | 35 | -- | read a file into an 'InputStream' 36 | readInputStream :: FilePath -> IO InputStream 37 | 38 | -- | convert 'InputStream' to 'String' 39 | inputStreamToString :: InputStream -> String 40 | {-# INLINE inputStreamToString #-} 41 | 42 | -- | convert a 'String' to an 'InputStream' 43 | inputStreamFromString :: String -> InputStream 44 | 45 | -- | @(b,is') = takeByte is@ reads and removes 46 | -- the first byte @b@ from the 'InputStream' @is@ 47 | takeByte :: InputStream -> (Word8, InputStream) 48 | {-# INLINE takeByte #-} 49 | 50 | -- | @(c,is') = takeChar is@ reads and removes 51 | -- the first character @c@ from the 'InputStream' @is@ 52 | takeChar :: InputStream -> (Char, InputStream) 53 | {-# INLINE takeChar #-} 54 | 55 | -- | return @True@ if the given input stream is empty 56 | inputStreamEmpty :: InputStream -> Bool 57 | {-# INLINE inputStreamEmpty #-} 58 | 59 | -- | @str = takeChars n is@ returns the first @n@ characters 60 | -- of the given input stream, without removing them 61 | takeChars :: Int -> InputStream -> [Char] 62 | {-# INLINE takeChars #-} 63 | 64 | -- | @countLines@ returns the number of text lines in the 65 | -- given 'InputStream' 66 | countLines :: InputStream -> Int 67 | 68 | #ifndef NO_BYTESTRING 69 | 70 | type InputStream = ByteString 71 | takeByte bs = BSW.head bs `seq` (BSW.head bs, BSW.tail bs) 72 | takeChar bs = BSC.head bs `seq` (BSC.head bs, BSC.tail bs) 73 | inputStreamEmpty = BSW.null 74 | #ifndef __HADDOCK__ 75 | takeChars !n bstr = BSC.unpack $ BSC.take n bstr --leaks 76 | #endif 77 | readInputStream = BSW.readFile 78 | 79 | inputStreamToString = BSC.unpack 80 | inputStreamFromString = BSC.pack 81 | countLines = length . BSC.lines 82 | 83 | 84 | #else 85 | 86 | type InputStream = String 87 | takeByte bs 88 | | Char.isLatin1 c = let b = fromIntegral (Char.ord c) in b `seq` (b, tail bs) 89 | | otherwise = error "takeByte: not a latin-1 character" 90 | where c = head bs 91 | takeChar bs = (head bs, tail bs) 92 | inputStreamEmpty = null 93 | takeChars n str = take n str 94 | readInputStream = readFile 95 | inputStreamToString = id 96 | inputStreamFromString = id 97 | countLines = length . lines 98 | #endif 99 | 100 | -------------------------------------------------------------------------------- /reference/src/Language/C/Data/Name.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveDataTypeable #-} 2 | ----------------------------------------------------------------------------- 3 | -- | 4 | -- Module : Language.C.Data.Name 5 | -- Copyright : (c) 2008 Benedikt Huber 6 | -- License : BSD-style 7 | -- Maintainer : benedikt.huber@gmail.com 8 | -- Stability : experimental 9 | -- Portability : ghc 10 | -- 11 | -- Unique Names with fast equality (newtype 'Int') 12 | module Language.C.Data.Name ( 13 | Name(..),newNameSupply, namesStartingFrom 14 | ) where 15 | import Data.Ix 16 | import Data.Generics 17 | 18 | -- | Name is a unique identifier 19 | newtype Name = Name { nameId :: Int } deriving (Show, Read, Eq, Ord, Ix, Data, Typeable) 20 | 21 | instance Enum Name where 22 | toEnum = Name 23 | fromEnum (Name n) = n 24 | 25 | -- | return an infinite stream of 'Name's starting with @nameId@ 0 26 | newNameSupply :: [Name] 27 | newNameSupply = namesStartingFrom 0 28 | 29 | -- | get the infinite stream of unique names starting from the given integer 30 | namesStartingFrom :: Int -> [Name] 31 | namesStartingFrom k = [Name k..] 32 | -------------------------------------------------------------------------------- /reference/src/Language/C/Data/RList.hs: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- | 3 | -- Module : Language.C.Data.RList 4 | -- Copyright : (c) [2007..2008] Duncan Coutts, Benedikt Huber 5 | -- License : BSD-style 6 | -- Maintainer : benedikt.huber@gmail.com 7 | -- Stability : experimental 8 | -- Portability : ghc 9 | -- 10 | -- Due to the way the grammar is constructed we very often have to build lists 11 | -- in reverse. To make sure we do this consistently and correctly we have a 12 | -- newtype to wrap the reversed style of list: 13 | ----------------------------------------------------------------------------- 14 | module Language.C.Data.RList ( 15 | RList,Reversed(..), 16 | empty,singleton,snoc,rappend,appendr,rappendr,rmap,reverse, 17 | viewr, 18 | ) 19 | where 20 | import Prelude hiding (reverse) 21 | import qualified Data.List as List 22 | 23 | newtype Reversed a = Reversed a 24 | type RList a = Reversed [a] 25 | empty :: Reversed [a] 26 | empty = Reversed [] 27 | 28 | singleton :: a -> Reversed [a] 29 | singleton x = Reversed [x] 30 | 31 | snoc :: Reversed [a] -> a -> Reversed [a] 32 | snoc (Reversed xs) x = Reversed (x : xs) 33 | infixl 5 `snoc` 34 | 35 | rappend :: Reversed [a] -> [a] -> Reversed [a] 36 | rappend (Reversed xs) ys = Reversed (List.reverse ys ++ xs) 37 | 38 | appendr :: [a] -> Reversed [a] -> Reversed [a] 39 | appendr xs (Reversed ys) = Reversed (ys ++ List.reverse xs) 40 | 41 | rappendr :: Reversed [a] -> Reversed [a] -> Reversed [a] 42 | rappendr (Reversed xs) (Reversed ys) = Reversed (ys ++ xs) 43 | 44 | rmap :: (a -> b) -> Reversed [a] -> Reversed [b] 45 | rmap f (Reversed xs) = Reversed (map f xs) 46 | 47 | reverse :: Reversed [a] -> [a] 48 | reverse (Reversed xs) = List.reverse xs 49 | 50 | viewr :: Reversed [a] -> (Reversed [a] , a) 51 | viewr (Reversed []) = error "viewr: empty RList" 52 | viewr (Reversed (x:xs)) = (Reversed xs, x) 53 | -------------------------------------------------------------------------------- /reference/src/Language/C/Parser.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS #-} 2 | ----------------------------------------------------------------------------- 3 | -- | 4 | -- Module : Language.C.Parser 5 | -- Copyright : (c) 2008 Benedikt Huber 6 | -- License : BSD-style 7 | -- Maintainer : benedikt.huber@gmail.com 8 | -- Stability : experimental 9 | -- Portability : ghc 10 | -- 11 | -- Language.C parser 12 | ----------------------------------------------------------------------------- 13 | module Language.C.Parser ( 14 | -- * Simple API 15 | parseC, 16 | -- * Parser Monad 17 | P,execParser,execParser_,builtinTypeNames, 18 | -- * Exposed Parsers 19 | translUnitP, extDeclP, statementP, expressionP, 20 | -- * Parser Monad 21 | ParseError(..) 22 | ) 23 | where 24 | import Language.C.Parser.Parser (parseC,translUnitP, extDeclP, statementP, expressionP) 25 | import Language.C.Parser.ParserMonad (execParser, ParseError(..),P) 26 | import Language.C.Parser.Builtin (builtinTypeNames) 27 | 28 | import Language.C.Data 29 | 30 | -- | run the given parser using a new name supply and builtin typedefs 31 | -- see 'execParser' 32 | -- 33 | -- Synopsis: @runParser parser inputStream initialPos@ 34 | execParser_ :: P a -> InputStream -> Position -> Either ParseError a 35 | execParser_ parser input pos = 36 | fmap fst $ execParser parser input pos builtinTypeNames newNameSupply 37 | -------------------------------------------------------------------------------- /reference/src/Language/C/Parser/Builtin.hs: -------------------------------------------------------------------------------- 1 | -- | 2 | -- Module : Language.C.Parser.Builtin 3 | -- Copyright : (c) 2001 Manuel M. T. Chakravarty 4 | -- License : BSD-style 5 | -- Maintainer : benedikt.huber@gmail.com 6 | -- Portability : portable 7 | -- 8 | -- This module provides information about builtin entities. 9 | -- 10 | -- Currently, only builtin type names are supported. The only builtin type 11 | -- name is `__builtin_va_list', which is a builtin of GNU C. 12 | -- 13 | module Language.C.Parser.Builtin ( 14 | builtinTypeNames 15 | ) where 16 | import Language.C.Data.Ident (Ident, builtinIdent) 17 | 18 | -- predefined type names 19 | -- 20 | builtinTypeNames :: [Ident] 21 | builtinTypeNames = [builtinIdent "__builtin_va_list"] 22 | -------------------------------------------------------------------------------- /reference/src/Language/C/Syntax.hs: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- | 3 | -- Module : Language.C.Syntax 4 | -- Copyright : (c) 2008 Benedikt Huber 5 | -- License : BSD-style 6 | -- Maintainer : benedikt.huber@gmail.com 7 | -- Stability : experimental 8 | -- Portability : ghc 9 | -- 10 | -- Syntax of C files: The abstract syntax tree and constants. 11 | ----------------------------------------------------------------------------- 12 | module Language.C.Syntax ( 13 | -- * Constants 14 | module Language.C.Syntax.Constants, 15 | -- * Syntax tree 16 | module Language.C.Syntax.AST, 17 | ) 18 | where 19 | import Language.C.Syntax.AST 20 | import Language.C.Syntax.Constants 21 | -------------------------------------------------------------------------------- /reference/src/Language/C/Syntax/Utils.hs: -------------------------------------------------------------------------------- 1 | module Language.C.Syntax.Utils ( 2 | -- * Generic operations 3 | getSubStmts, 4 | mapSubStmts, 5 | mapBlockItemStmts, 6 | -- * Concrete operations 7 | getLabels 8 | ) where 9 | 10 | import Data.List 11 | import Language.C.Data.Ident 12 | import Language.C.Syntax.AST 13 | 14 | -- XXX: This is should be generalized !!! 15 | -- Data.Generics sounds attractive, but we really need to control the evaluation order 16 | -- XXX: Expression statements (which are somewhat problematic anyway), aren't handled yet 17 | getSubStmts :: CStat -> [CStat] 18 | getSubStmts (CLabel _ s _ _) = [s] 19 | getSubStmts (CCase _ s _) = [s] 20 | getSubStmts (CCases _ _ s _) = [s] 21 | getSubStmts (CDefault s _) = [s] 22 | getSubStmts (CExpr _ _) = [] 23 | getSubStmts (CCompound _ body _) = concatMap compoundSubStmts body 24 | getSubStmts (CIf _ sthen selse _) = maybe [sthen] (\s -> [sthen,s]) selse 25 | getSubStmts (CSwitch _ s _) = [s] 26 | getSubStmts (CWhile _ s _ _) = [s] 27 | getSubStmts (CFor _ _ _ s _) = [s] 28 | getSubStmts (CGoto _ _) = [] 29 | getSubStmts (CGotoPtr _ _) = [] 30 | getSubStmts (CCont _) = [] 31 | getSubStmts (CBreak _) = [] 32 | getSubStmts (CReturn _ _) = [] 33 | getSubStmts (CAsm _ _) = [] 34 | 35 | mapSubStmts :: (CStat -> Bool) -> (CStat -> CStat) -> CStat -> CStat 36 | mapSubStmts stop _ s | stop s = s 37 | mapSubStmts stop f (CLabel i s attrs ni) = 38 | f (CLabel i (mapSubStmts stop f s) attrs ni) 39 | mapSubStmts stop f (CCase e s ni) = 40 | f (CCase e (mapSubStmts stop f s) ni) 41 | mapSubStmts stop f (CCases e1 e2 s ni) = 42 | f (CCases e1 e2 (mapSubStmts stop f s) ni) 43 | mapSubStmts stop f (CDefault s ni) = 44 | f (CDefault (mapSubStmts stop f s) ni) 45 | mapSubStmts stop f (CCompound ls body ni) = 46 | f (CCompound ls (map (mapBlockItemStmts stop f) body) ni) 47 | mapSubStmts stop f (CIf e sthen selse ni) = 48 | f (CIf e 49 | (mapSubStmts stop f sthen) 50 | (fmap (mapSubStmts stop f) selse) 51 | ni) 52 | mapSubStmts stop f (CSwitch e s ni) = 53 | f (CSwitch e (mapSubStmts stop f s) ni) 54 | mapSubStmts stop f (CWhile e s isdo ni) = 55 | f (CWhile e (mapSubStmts stop f s) isdo ni) 56 | mapSubStmts stop f (CFor i t a s ni) = 57 | f (CFor i t a (mapSubStmts stop f s) ni) 58 | mapSubStmts _ f s = f s 59 | 60 | mapBlockItemStmts :: (CStat -> Bool) 61 | -> (CStat -> CStat) 62 | -> CBlockItem 63 | -> CBlockItem 64 | mapBlockItemStmts stop f (CBlockStmt s) = CBlockStmt (mapSubStmts stop f s) 65 | mapBlockItemStmts _ _ bi = bi 66 | 67 | compoundSubStmts :: CBlockItem -> [CStat] 68 | compoundSubStmts (CBlockStmt s) = [s] 69 | compoundSubStmts (CBlockDecl _) = [] 70 | compoundSubStmts (CNestedFunDef _) = [] 71 | 72 | getLabels :: CStat -> [Ident] 73 | getLabels (CLabel l s _ _) = l : getLabels s 74 | getLabels (CCompound ls body _) = 75 | concatMap (concatMap getLabels . compoundSubStmts) body \\ ls 76 | getLabels stmt = concatMap getLabels (getSubStmts stmt) 77 | -------------------------------------------------------------------------------- /reference/src/README: -------------------------------------------------------------------------------- 1 | = Language.C sources = 2 | The sources are located in /src. 3 | 4 | The Language.C source tree is structured as follows: 5 | - Language 6 | - C ... C facade imports 7 | - C.Data ... common datatypes, such as identifiers, unique names etc. 8 | - C.Syntax ... The AST 9 | - C.Pretty ... Pretty printing C code 10 | - C.InputStream ... Input stream abstraction 11 | - C.Parser ... C parser and pretty printer 12 | - C.System ... Executing preprocessors and compilers 13 | - C.Analysis ... Analysis of C source files (alpha) 14 | 15 | -------------------------------------------------------------------------------- /reference/src/derive.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o errexit 3 | DERIVE=./derive/Derive 4 | DERIVE_PATCH_VERSION=2.4.2 5 | if ghc-pkg find-module Data.DeriveMain | grep -q '^[ ]*derive-'; then 6 | (cd derive && make) 7 | fi 8 | if [ ! -e ${DERIVE} ] ; then 9 | echo "Warning: Could not find ${DERIVE}, and derive >= 2.5 is not installed">&2 10 | echo "Please install derive 2.5.* (tested with 2.5.23)" >&2 11 | exit 1 12 | fi 13 | TARGETS="Language/C/Syntax/AST.hs Language/C/Analysis/SemRep.hs" 14 | for T in ${TARGETS} ; do 15 | echo "Appending derived instances to ${T}" 16 | $DERIVE -a "${T}" 17 | done 18 | -------------------------------------------------------------------------------- /reference/src/derive/Derive.hs: -------------------------------------------------------------------------------- 1 | import Data.DeriveMain 2 | import Data.Derive.All 3 | import Data.Derive.Annotated 4 | import Data.Derive.CNode 5 | 6 | main = deriveMain $ [makeAnnotated,makeCNode] ++ derivations 7 | -------------------------------------------------------------------------------- /reference/src/derive/DeriveTest.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveDataTypeable #-} 2 | 3 | module DeriveTest where 4 | import Language.C.Data.Node 5 | import Language.C.Data.Position 6 | import Data.Data 7 | data ExplicitNodeInfo = ExplicitNodeInfo1 NodeInfo Int 8 | | ExplicitNodeInfo2 Int NodeInfo 9 | | ExplicitNodeInfo3 Int NodeInfo Int 10 | deriving (Data,Typeable {-! ,CNode !-}) 11 | data OneArgNodeInfo = ExplicitNodeInfo4 Int NodeInfo 12 | | Delegator ExplicitNodeInfo 13 | deriving (Data,Typeable {-! ,CNode !-}) 14 | data PolyVarNodeInfo a = PolyCon2 Int Int a 15 | | PolyCon1 Int a 16 | | PolyCon0 a 17 | | PolyDelegator OneArgNodeInfo 18 | deriving (Data,Typeable {-! ,CNode !-}) 19 | 20 | -- -- Should fail 21 | -- data PolyVarNodeInfo a b = PolyCon2 Int Int a 22 | -- | PolyCon1 a b 23 | -- deriving (Data,Typeable {-! CNode !-}) 24 | -- 25 | 26 | 27 | -- GENERATED START 28 | 29 | instance CNode ExplicitNodeInfo where 30 | nodeInfo (ExplicitNodeInfo1 n _) = n 31 | nodeInfo (ExplicitNodeInfo2 _ n) = n 32 | nodeInfo (ExplicitNodeInfo3 _ n _) = n 33 | instance Pos ExplicitNodeInfo where 34 | posOf x = posOf (nodeInfo x) 35 | 36 | instance CNode OneArgNodeInfo where 37 | nodeInfo (ExplicitNodeInfo4 _ n) = n 38 | nodeInfo (Delegator d) = nodeInfo d 39 | instance Pos OneArgNodeInfo where 40 | posOf x = posOf (nodeInfo x) 41 | 42 | instance CNode t1 => CNode (PolyVarNodeInfo t1) where 43 | nodeInfo (PolyCon2 _ _ n) = nodeInfo n 44 | nodeInfo (PolyCon1 _ n) = nodeInfo n 45 | nodeInfo (PolyCon0 d) = nodeInfo d 46 | nodeInfo (PolyDelegator d) = nodeInfo d 47 | instance CNode t1 => Pos (PolyVarNodeInfo t1) where 48 | posOf x = posOf (nodeInfo x) 49 | -- GENERATED STOP 50 | -------------------------------------------------------------------------------- /reference/src/derive/DeriveTest.hs.expect: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveDataTypeable #-} 2 | 3 | module DeriveTest where 4 | import Language.C.Data.Node 5 | import Language.C.Data.Position 6 | import Data.Data 7 | data ExplicitNodeInfo = ExplicitNodeInfo1 NodeInfo Int 8 | | ExplicitNodeInfo2 Int NodeInfo 9 | | ExplicitNodeInfo3 Int NodeInfo Int 10 | deriving (Data,Typeable {-! ,CNode !-}) 11 | data OneArgNodeInfo = ExplicitNodeInfo4 Int NodeInfo 12 | | Delegator ExplicitNodeInfo 13 | deriving (Data,Typeable {-! ,CNode !-}) 14 | data PolyVarNodeInfo a = PolyCon2 Int Int a 15 | | PolyCon1 Int a 16 | | PolyCon0 a 17 | | PolyDelegator OneArgNodeInfo 18 | deriving (Data,Typeable {-! ,CNode !-}) 19 | 20 | -- -- Should fail 21 | -- data PolyVarNodeInfo a b = PolyCon2 Int Int a 22 | -- | PolyCon1 a b 23 | -- deriving (Data,Typeable {-! CNode !-}) 24 | -- 25 | 26 | 27 | -- GENERATED START 28 | 29 | instance CNode ExplicitNodeInfo where 30 | nodeInfo (ExplicitNodeInfo1 n _) = n 31 | nodeInfo (ExplicitNodeInfo2 _ n) = n 32 | nodeInfo (ExplicitNodeInfo3 _ n _) = n 33 | instance Pos ExplicitNodeInfo where 34 | posOf x = posOf (nodeInfo x) 35 | 36 | instance CNode OneArgNodeInfo where 37 | nodeInfo (ExplicitNodeInfo4 _ n) = n 38 | nodeInfo (Delegator d) = nodeInfo d 39 | instance Pos OneArgNodeInfo where 40 | posOf x = posOf (nodeInfo x) 41 | 42 | instance CNode t1 => CNode (PolyVarNodeInfo t1) where 43 | nodeInfo (PolyCon2 _ _ n) = nodeInfo n 44 | nodeInfo (PolyCon1 _ n) = nodeInfo n 45 | nodeInfo (PolyCon0 d) = nodeInfo d 46 | nodeInfo (PolyDelegator d) = nodeInfo d 47 | instance CNode t1 => Pos (PolyVarNodeInfo t1) where 48 | posOf x = posOf (nodeInfo x) 49 | -- GENERATED STOP 50 | -------------------------------------------------------------------------------- /reference/src/derive/DeriveTest2.hs: -------------------------------------------------------------------------------- 1 | -- For all type variables a, we require (CNode a) 2 | 3 | -- If we have a data constructor 4 | -- X a_1 .. a_n, and exactly one a_k is a Language.C.Data.NodeInfo, then return that a_k 5 | data Test1 = X Int NodeInfo | Y NodeInfo String | Z Int NodeInfo Integer deriving (Show {-! ,CNode !-}) 6 | 7 | -- If we have a data constructor 8 | -- X a, then return nodeInfo a 9 | data Test2 = U Test1 | V Test1 deriving (Show {-! ,CNode !-}) 10 | 11 | -- If we have a data constructor 12 | -- X a_1 .. a_n, and exactly one a_k is a polymorphic variable, then return (nodeInfo a_k) 13 | data Test3 a = A a Test1 | B Test2 a | C (Test3 a) a (Test3 a) | D (Test4 a) a deriving (Show {-! ,Functor,Annotated,CNode !-}) 14 | data Test4 a = Test4 NodeInfo (Test3 a) deriving (Show {-! ,Functor, CNode !-}) 15 | -------------------------------------------------------------------------------- /reference/src/derive/Makefile: -------------------------------------------------------------------------------- 1 | GHC=ghc 2 | GHC_FLAGS=-O 3 | DERIVE_TARGET=Derive 4 | .PHONY: all clean 5 | all: $(DERIVE_TARGET) 6 | $(DERIVE_TARGET): | objdir 7 | $(GHC) $(GHC_FLAGS) --make -outputdir objdir -o $(DERIVE_TARGET) $(DERIVE_TARGET).hs 8 | objdir: 9 | mkdir -p $@ 10 | test: $(DERIVE_TARGET) 11 | ./$(DERIVE_TARGET) -a DeriveTest.hs 12 | diff DeriveTest.hs.expect DeriveTest.hs 13 | clean: 14 | rm -f $(DERIVE_TARGET) 15 | rm -rf objdir 16 | -------------------------------------------------------------------------------- /reference/test/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 1999-2008 Manuel M T Chakravarty 2 | Duncan Coutts 3 | Benedikt Huber 4 | Portions Copyright (c) 1989, 1990 James A. Roskind 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 3. Neither the name of the author nor the names of his contributors 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /reference/test/Makefile: -------------------------------------------------------------------------------- 1 | # Build test binaries 2 | BINARIES=CTest CParse CRoundTrip CEquiv RenderTests ReportFatal CheckGccArgs 3 | 4 | PROJECT_DIR=.. 5 | BIN_DIR=bin 6 | INPLACE_PACKAGE_CONF=$(PROJECT_DIR)/dist/package.conf.inplace 7 | 8 | all: $(INPLACE_PACKAGE_CONF) 9 | cabal configure --package-db $(INPLACE_PACKAGE_CONF) 10 | cabal build 11 | for b in $(BINARIES) ; do cp dist/build/$$b/$$b $(BIN_DIR) ; done 12 | 13 | clean: 14 | rm -f $(addprefix $(BIN_DIR)/, $(BINARIES)) 15 | cabal clean 16 | make -C harness clean 17 | 18 | ../dist/package.conf.inplace: 19 | echo "Please run cd .. && cabal build first" 20 | exit 1 21 | -------------------------------------------------------------------------------- /reference/test/README: -------------------------------------------------------------------------------- 1 | = Test Framework = 2 | 3 | == Build == 4 | 5 | > make 6 | 7 | == Running roundtrip tests == 8 | 9 | > cd suite 10 | > cp compile-lib.template run-my-lib.sh 11 | 12 | Now edit run-my-lib.sh and change the test specific names (my-lib*). 13 | Then either change the make target, or customize the build script. 14 | 15 | == Rendering test results == 16 | 17 | In the default configuration: 18 | 19 | > cd results 20 | > ../bin/RenderTests parser-version list-of-test-files 21 | 22 | for example 23 | 24 | > ../bin/RenderTests parser-0.2 smoke.dat glib.dat gtk2.dat 25 | 26 | The result overview can be found in index.html. 27 | 28 | == Running custom tests == 29 | 30 | Look at suite/run-smoke.sh 31 | 32 | * First the general setup: 33 | 34 | > #!/bin/sh 35 | > source ./configuration 36 | > source $CTEST_BINDIR/setup_test_suite my-custom-test-suite 37 | > # export CTEST_DEBUG=1 # Set if you want a lot of debug messages 38 | 39 | * Run custom tests 40 | 41 | > export CTEST_DRIVER= 42 | > export CTEST_= 43 | > sh run-test test-args 44 | 45 | for example 46 | 47 | > export CTEST_DRIVER=CEquiv 48 | > export CTEST_NON_EQUIV=1 49 | > sh run-test my-file-1.c my-file-2.c 50 | 51 | Currently, the test drivers CParse, CRoundTrip and CEquiv are implemented. 52 | Execute them without arguments (in bin/) to get help. 53 | -------------------------------------------------------------------------------- /reference/test/bin/cc-wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Parse the given files, acting as if it was a C-compiler 3 | 4 | # Run the roundtrip test 5 | if [ -z $CTEST_DRIVER ] ; then 6 | export CTEST_DRIVER=CRoundTrip 7 | fi 8 | 9 | # Run test 10 | $CTEST_BINDIR/CheckGccArgs $@ 11 | if [ $? -eq 0 ]; then 12 | sh $CTEST_BINDIR/run-test $@ 13 | # Invoke gcc 14 | gcc "$@" 15 | else 16 | gcc "$@" 17 | fi 18 | 19 | -------------------------------------------------------------------------------- /reference/test/bin/clear_test_suite: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Remove the result files of a test suite 3 | # Arguments: 4 | # $1 .. the name of the test suite to clear 5 | # Environment: 6 | # CTEST_BINDIR ... the directory containing the test executables (including this file) 7 | # CTEST_RESULTDIR ... the directory to write report files and logs 8 | # Calls: 9 | # die() 10 | if [ ! -e $CTEST_BINDIR/setup ]; then echo "Missing environment variable \$CTEST_BINDIR or missing file $CTEST_BINDIR/setup"; exit 1; fi 11 | if [ -z $TEST_SETUP ]; then source $CTEST_BINDIR/setup; fi 12 | L_TEST=$1 13 | if [ -z $L_TEST ]; then die "Usage: ./clear_test_suite test_name"; fi 14 | 15 | L_TEST_TMPDIR=$CTEST_RESULTDIR/$L_TEST/ 16 | L_TEST_REPORT_FILE=$CTEST_RESULTDIR/$L_TEST.dat 17 | L_TEST_LOGFILE=$L_TEST_TMPDIR/parse.log 18 | 19 | # rm is somewhat dangerous, therefore we are careful here 20 | 21 | # Create temporary directory for tests 22 | mkdir -p "$L_TEST_TMPDIR" || die "Failed to create directory $L_TEST_TMPDIR" 23 | 24 | # Remove the old report file (with interactive query) 25 | if [ -e "$L_TEST_REPORT_FILE" ]; then 26 | rm -i "$L_TEST_REPORT_FILE"; 27 | fi 28 | 29 | # Ensure the tmp directory is present 30 | if [ ! -d $L_TEST_TMPDIR ]; then 31 | die "No a valid directory : $L_TEST_TMPDIR"; 32 | 33 | # If there is a parse.log file in the temporary directory, remove its contents 34 | elif [ -e "$L_TEST_TMPDIR"/parse.log ]; then 35 | (cd "$L_TEST_TMPDIR" && ls | xargs rm) 36 | fi 37 | -------------------------------------------------------------------------------- /reference/test/bin/compile_log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -z "${BINDIR}" ] ; then 3 | echo "$0: BINDIR not set. Exit." >&2 4 | exit 1 5 | fi 6 | if [ -z "${1}" ] ; then 7 | echo "$0: Exactly one argument is required, but none was provided. Exit." >&2 8 | exit 1 9 | fi 10 | 11 | # replace position information 12 | REPLACE1='$_ = $_.gsub(/[\w_-]+\.c:[\d:]*/,"@POS")' 13 | REPLACE2='$_ = $_.gsub(/:[\d:]*/,"@POS")' 14 | gcc -fsyntax-only $1.c 2>&1 1>/dev/null | ruby -pe "${REPLACE1}" | grep '@POS' > $1.log 15 | $BINDIR/CTest $1.c | gcc -x c -fsyntax-only - 2>&1 1>/dev/null | ruby -pe "${REPLACE2}" | grep '@POS' > $1_test.log 16 | diff -u $1.log $1_test.log 17 | -------------------------------------------------------------------------------- /reference/test/bin/mkdist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # compress the files of the test results 3 | TAG=$1 4 | if [ -z $TAG ]; then 5 | echo "Usage: $0 tag test1.dat ..." 6 | exit 1 7 | fi 8 | shift 9 | # Bash parameter expansion: ${@/%/suffix} -> append suffix to every positional parameter 10 | tar -czf language-c-reports_$TAG.tgz index.html ${@/.dat/.html} ${@/.dat//} res 11 | ls -lh language-c-reports_$TAG.tgz -------------------------------------------------------------------------------- /reference/test/bin/run-test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # See http://wooledge.org:8000/BashFAQ for advanced bash tricks. 3 | # TODO: This depends on bash's PIPESTATUS and perl 4 | if [ ! -e $CTEST_BINDIR/setup ]; then echo "Missing environment variable \$CTEST_BINDIR or missing file $CTEST_BINDIR/setup"; exit 1; fi 5 | if [ -z $TEST_SETUP ]; then source $CTEST_BINDIR/setup; fi 6 | 7 | doalarm() { perl -e 'alarm shift; exec @ARGV' "$@"; } 8 | 9 | # Runs the test $CTEST_DRIVER 10 | if [ -z $CTEST_BINDIR ]; then die "Missing environment variable \$CTEST_BINDIR"; fi 11 | if [ -z $CTEST_TMPDIR ]; then die "Missing environment variable \$CTEST_TMPDIR"; fi 12 | if [ -z $CTEST_DRIVER ]; then die "Missing environment variable \$CTEST_DRIVER"; fi 13 | if [ -z $CTEST_REPORT_FILE ]; then die "Missing environment variable \$CTEST_REPORT_FILE"; fi 14 | 15 | # Temporary file to collect stderr output 16 | TMPFILE=`mktemp $CTEST_TMPDIR/cc-wrapper.XXXXXX` || exit 1 17 | 18 | if [ -z $CTEST_MAX_MEM ]; then 19 | CTEST_MAX_MEM=64M 20 | fi 21 | # Run the test (max 30 seconds), teeing output to TMPFILE 22 | doalarm 30 $CTEST_BINDIR/$CTEST_DRIVER +RTS -M$CTEST_MAX_MEM -RTS $@ 2>&1 | tee $TMPFILE 23 | 24 | # If return status of test driver isn't 0, we have a fatal error and report it. 25 | if [ $PIPESTATUS -ne 0 ]; then 26 | if [ -n $CTEST_DEBUG ]; then 27 | echo '[DEBUG]: Fatal Error (Caught)' 2>&1 28 | fi 29 | $CTEST_BINDIR/ReportFatal $CTEST_REPORT_FILE $@ < $TMPFILE 30 | fi 31 | 32 | # Remove the temporary file 33 | rm $TMPFILE -------------------------------------------------------------------------------- /reference/test/bin/set_test_suite: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Set the environment variables for testing to one test suite 3 | # Arguments: 4 | # $1 .. the name of the test suite 5 | # Environment: 6 | # CTEST_BINDIR ... the directory containing the test executables (including this file) 7 | # CTEST_RESULTDIR ... the directory to write report files and logs 8 | # Calls: 9 | # die() 10 | if [ ! -e $CTEST_BINDIR/setup ]; then echo "Missing environment variable \$CTEST_BINDIR or missing file $CTEST_BINDIR/setup"; exit 1; fi 11 | if [ -z $TEST_SETUP ]; then source $CTEST_BINDIR/setup; fi 12 | if [ -z $1 ]; then die "Usage: ./set_test_suite test"; fi 13 | 14 | export TESTNAME=$1 15 | export CTEST_TMPDIR=$CTEST_RESULTDIR/$TESTNAME/ 16 | if [ ! -e $CTEST_TMPDIR ]; then 17 | mkdir $CTEST_TMPDIR || die "Failed to create result directory $CTEST_TMPDIR" ; 18 | elif [ ! -d $CTEST_TMPDIR ]; then 19 | die "Result directory $CTEST_TMPDIR is not a directory" 20 | fi 21 | export CTEST_REPORT_FILE=$CTEST_RESULTDIR/$TESTNAME.dat 22 | export CTEST_LOGFILE=$CTEST_TMPDIR/parse.log 23 | -------------------------------------------------------------------------------- /reference/test/bin/setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Setup test environment 3 | # Arguments: 4 | # Environment: 5 | # CTEST_BINDIR ... the directory containing the test executables (including this file) 6 | # CTEST_RESULTDIR ... the directory to write report files and logs 7 | # Calls: 8 | 9 | # Setup 10 | function die() { 11 | echo $1 1>&2 12 | exit 1 13 | } 14 | 15 | if [ ! -d $CTEST_BINDIR ]; then die "Missing environment variable \$CTEST_BINDIR"; fi 16 | if [ -z $CTEST_RESULTDIR ] ; then die "Missing environment variable \$CTEST_RESULTDIR"; fi 17 | if [ ! -d $CTEST_RESULTDIR ]; then 18 | mkdir "${CTEST_RESULTDIR}" 19 | fi 20 | export PATH=$CTEST_BINDIR:$PATH 21 | TEST_SETUP=1 22 | -------------------------------------------------------------------------------- /reference/test/bin/setup_test_suite: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Setup test suite (clear and set) 3 | # Arguments: 4 | # $1 .. the name of the test suite 5 | # Environment: 6 | # CTEST_BINDIR ... the directory containing the test executables (including this file) 7 | # CTEST_RESULTDIR ... the directory to write report files and logs 8 | if [ ! -e $CTEST_BINDIR/setup ]; then echo "Missing environment variable \$CTEST_BINDIR or missing file $CTEST_BINDIR/setup"; exit 1; fi 9 | if [ -z $TEST_SETUP ]; then source $CTEST_BINDIR/setup; fi 10 | source $CTEST_BINDIR/clear_test_suite $1 11 | source $CTEST_BINDIR/set_test_suite $1 -------------------------------------------------------------------------------- /reference/test/config.mk: -------------------------------------------------------------------------------- 1 | # Configuration for test builds 2 | 3 | ifndef HC 4 | HC=ghc 5 | endif 6 | 7 | ifndef OPT 8 | OPT = -O -rtsopts 9 | endif 10 | HFLAGS = $(OPT) 11 | ifdef PROFILE 12 | HFLAGS += -prof -auto-all 13 | SUFFIX="_p" 14 | ifdef BUILD_DIR 15 | BUILD_DIR=$(BUILD_DIR)$(SUFFIX) 16 | endif 17 | endif 18 | 19 | ifdef BUILD_DIR 20 | HFLAGS+=-hidir $(BUILD_DIR) -odir $(BUILD_DIR) 21 | endif 22 | 23 | INPLACE_PACKAGE_CONF=$(PROJECT_DIR)/dist/package.conf.inplace 24 | 25 | VERSION?=$(shell cat $(PROJECT_DIR)/language-c.cabal | grep '^Version:' | sed -E 's/[ \t]+/ /g' | cut -sd' ' -f2) 26 | 27 | HFLAGS += -package-db $(INPLACE_PACKAGE_CONF) -package language-c-$(VERSION) 28 | 29 | 30 | -------------------------------------------------------------------------------- /reference/test/harness/Makefile: -------------------------------------------------------------------------------- 1 | TESTS=analysis_enum \ 2 | analysis_ext_decls \ 3 | analysis_local_decls \ 4 | analysis_type_check attributes \ 5 | builtins \ 6 | bug5_dos_newline bugn6_empty_file bug21_sem_typedef \ 7 | bug22_file_permission_cpp bug30_preserve_int_repr bug31_pp_if_else \ 8 | bug20130805_nopos \ 9 | bug20160302_int128 \ 10 | bug20160314_noreturn \ 11 | bug20160729_C_include_stack \ 12 | bug20160911_builtin_bswap \ 13 | parse_dg 14 | 15 | #bug20140111_utf8 16 | all: tests 17 | tests: $(TESTS:=.runtest) 18 | prepare: make_examples make_test 19 | make_examples: build_lib 20 | make -C ../../examples 21 | build_lib: 22 | cd ../.. && cabal build 23 | make_test: build_lib 24 | make -C ../ 25 | clean: $(TESTS:=.runclean) 26 | make -C ../../examples clean 27 | %.runtest: | prepare 28 | make -C $* clean all 29 | %.runclean: 30 | make -C $* clean 31 | 32 | -------------------------------------------------------------------------------- /reference/test/harness/README: -------------------------------------------------------------------------------- 1 | == Description == 2 | 3 | while `suite' is intended to execute long test runs on existing libraries, 4 | `harness' consists of crafted tests documenting bugs and problems. 5 | 6 | == Execute == 7 | 8 | Make sure to first run make in the parent directory 'language-c/test' ! 9 | 10 | > (cd ..; make) 11 | > make 12 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_enum/Makefile: -------------------------------------------------------------------------------- 1 | SCANFILE=../../../examples/ScanFile 2 | all: 3 | $(SCANFILE) enum.c > enum.out 4 | diff -u enum.expect enum.out 5 | clean: 6 | rm -f *.out 7 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_enum/enum.c: -------------------------------------------------------------------------------- 1 | int printf(const char * restrict format, ...); 2 | #define DBG(fmt,val) (printf(#val ": " fmt "\n",val)) 3 | enum a { e0, e1, e2, e3 }; 4 | enum b { e4 = e3 + 1, e5, e9 = e3*3, e10 }; 5 | enum c { e20 = 20, e15 = 15, e16, e17, emm = -2, em, e0a }; 6 | int main() { 7 | DBG("%d",e0); 8 | DBG("%d",e1); 9 | DBG("%d",e2); 10 | DBG("%d",e3); 11 | DBG("%d",e4); 12 | DBG("%d",e5); 13 | DBG("%d",e9); 14 | DBG("%d",e10); 15 | DBG("%d",e20); 16 | DBG("%d",e15); 17 | DBG("%d",e16); 18 | DBG("%d",e17); 19 | DBG("%d",emm); 20 | DBG("%d",em); 21 | DBG("%d",e0a); 22 | } 23 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_enum/enum.expect: -------------------------------------------------------------------------------- 1 | Global Declarations 2 | enumerators 3 | e0 ~> e0 = 0 4 | e1 ~> e1 = 1 5 | e2 ~> e2 = 2 6 | e3 ~> e3 = 3 7 | e4 ~> e4 = e3 + 1 8 | e5 ~> e5 = e3 + 1 + 1 9 | e9 ~> e9 = e3 * 3 10 | em ~> em = -2 + 1 11 | e10 ~> e10 = e3 * 3 + 1 12 | e20 ~> e20 = 20 13 | e15 ~> e15 = 15 14 | e16 ~> e16 = 15 + 1 15 | e17 ~> e17 = 15 + 2 16 | e0a ~> e0a = -2 + 2 17 | emm ~> emm = -2 18 | declarations 19 | printf ~> declaration printf | function/external | int (const char * __restrict format, ...) 20 | objects 21 | functions 22 | main ~> function main | function/external | int () 23 | tags a ~> enum a {e0 = 0; e1 = 1; e2 = 2; e3 = 3;} 24 | b ~> enum b {e4 = e3 + 1; e5 = e3 + 1 + 1; e9 = e3 * 3; e10 = e3 * 3 + 1;} 25 | c ~> enum c {e20 = 20; e15 = 15; e16 = 15 + 1; e17 = 15 + 2; emm = -2; em = -2 + 1; e0a = -2 + 2;} 26 | typeDefs 27 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_ext_decls/Makefile: -------------------------------------------------------------------------------- 1 | SCANFILE=../../../examples/ScanFile 2 | all: 3 | $(SCANFILE) ident_kinds.c > ident_kinds.out 4 | diff -u ident_kinds.expect ident_kinds.out 5 | $(SCANFILE) tentative.c > tentative.out 6 | diff -u tentative.expect tentative.out 7 | $(SCANFILE) globreg.c > globreg.out 8 | diff -u globreg.expect globreg.out 9 | clean: 10 | rm -rf *.out 11 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_ext_decls/globreg.c: -------------------------------------------------------------------------------- 1 | register int x __asm__("esp"); 2 | void f() { 3 | } 4 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_ext_decls/globreg.expect: -------------------------------------------------------------------------------- 1 | Global Declarations 2 | enumerators 3 | declarations 4 | x ~> declaration x (asmname "esp") | static/internal | int 5 | objects 6 | functions 7 | f ~> function f | function/external | void () 8 | tags 9 | typeDefs 10 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_ext_decls/ident_kinds.c: -------------------------------------------------------------------------------- 1 | enum { e1 = 4 } xe1; 2 | typedef enum E2 { e2 = e1, e3 } ENUM2; 3 | extern int a; /* obj decl, static external */ 4 | static long long b; /* obj tentative def, static internal */ 5 | long c = 4; /* obj def, static external */ 6 | static int f1(); /* fun decl f1?, static internal */ 7 | extern int f1(void) { return 0; } /* fun def f1(), static internal !! */ 8 | extern int f2(void); /* fun decl f2(), static external */ 9 | static int g(char**); /* fun decl (static) */ 10 | int g(char** a) { return 0; } /* fun def, static internal !! */ 11 | int export() { return f1()+b+f2()+g(0); } /* fun def, external */ -------------------------------------------------------------------------------- /reference/test/harness/analysis_ext_decls/ident_kinds.expect: -------------------------------------------------------------------------------- 1 | Global Declarations 2 | enumerators 3 | e1 ~> e1 = 4 4 | e2 ~> e2 = e1 5 | e3 ~> e3 = e1 + 1 6 | declarations 7 | a ~> declaration a | static/external | int 8 | f2 ~> declaration f2 | function/external | int () 9 | objects b ~> object b | static/internal | long long 10 | c ~> object c | static/external | long = 4 11 | xe1 ~> object xe1 | static/external | enum $3 12 | functions 13 | g ~> function g | function/internal | int (char * * a) 14 | f1 ~> function f1 | function/internal | int () 15 | export ~> function export | function/external | int () 16 | tags $3 ~> enum $3 {e1 = 4;} 17 | E2 ~> enum E2 {e2 = e1; e3 = e1 + 1;} 18 | typeDefs 19 | ENUM2 ~> typedef ENUM2 as enum E2 20 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_ext_decls/tentative.c: -------------------------------------------------------------------------------- 1 | int x = 2; /* def */ 2 | int y; /* tentative, decl */ 3 | static int u; /* tentative, def = 0 */ 4 | static int z; /* tentative , decl */ 5 | int x; /* decl */ 6 | int y; /* tentative, decl */ 7 | static int z = 2; /* def */ 8 | int x; /* decl */ 9 | int y = 3; /* def */ 10 | extern int u; /* decl */ 11 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_ext_decls/tentative.expect: -------------------------------------------------------------------------------- 1 | Global Declarations 2 | enumerators 3 | declarations 4 | objects u ~> object u | static/internal | int 5 | x ~> object x | static/external | int = 2 6 | y ~> object y | static/external | int = 3 7 | z ~> object z | static/internal | int = 2 8 | functions 9 | tags 10 | typeDefs 11 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_local_decls/Makefile: -------------------------------------------------------------------------------- 1 | SCANFILE=../../../examples/ScanFile 2 | PROG_C_1=static_extern.c other.c 3 | PROG_CS=scopes.c 4 | ERROR_CS=error_extern_init.c error_extern_no_linkage_1.c error_extern_no_linkage_2.c error_inner_scope_duple_def.c 5 | 6 | export TRACE_EVENTS=1 7 | 8 | all: test 9 | test: 10 | for f in $(PROG_C_1); do $(SCANFILE) $$f; done 11 | for f in $(PROG_CS); do $(SCANFILE) $$f; done 12 | for f in $(ERROR_CS); do ( $(SCANFILE) $$f; sh ../expect_error $$? "Expecting error when analysing $$f"); done 13 | test-gcc: 14 | gcc -o prog $(PROG_C_1) 15 | gcc -c $(PROG_CS) 16 | for f in $(ERROR_CS); do (gcc -c $$f 2>.log ; sh ../expect_error $$? `cat .log`); done 17 | clean: 18 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_local_decls/error_extern_init.c: -------------------------------------------------------------------------------- 1 | int f(int z) { 2 | /* Both extern keyword and initializer is an error */ 3 | extern int z2 = 3; /* error */ 4 | return z+z2; 5 | } 6 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_local_decls/error_extern_no_linkage_1.c: -------------------------------------------------------------------------------- 1 | int f(int z) { 2 | /* There is no z with internal or external linkage visible, so this is 3 | a new declaration conflicting with the parameter z */ 4 | extern int z; /* error */ 5 | return z+1; 6 | } 7 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_local_decls/error_extern_no_linkage_2.c: -------------------------------------------------------------------------------- 1 | int f(int z) { 2 | static int s; /* no linkage, implicit initializer */ 3 | 4 | /* Error, s has no linkage */ 5 | extern int s; 6 | return z+s; 7 | } 8 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_local_decls/error_inner_scope_duple_def.c: -------------------------------------------------------------------------------- 1 | int f(int x) { 2 | while(x < 3) { 3 | int x; 4 | int x; 5 | } 6 | } -------------------------------------------------------------------------------- /reference/test/harness/analysis_local_decls/other.c: -------------------------------------------------------------------------------- 1 | int u; -------------------------------------------------------------------------------- /reference/test/harness/analysis_local_decls/scopes.c: -------------------------------------------------------------------------------- 1 | int x; /* file scope */ 2 | int f() { /* file scope */ 3 | int x; /* block-1 scope */ 4 | while(x<3) { 5 | double x=4; /* block-2 scope */ 6 | } 7 | } -------------------------------------------------------------------------------- /reference/test/harness/analysis_local_decls/static_extern.c: -------------------------------------------------------------------------------- 1 | int x; /* external linkage, tentative definition */ 2 | static int y; /* internal linkage, tentative definition */ 3 | int f(int z) { 4 | extern int x; /* external linkage, (same object as x:1) */ 5 | extern int y; /* internal linkage (same object as y:2) */ 6 | 7 | /* refers to a global variable in another translation unit */ 8 | extern int u; /* external linkage, declaration */ 9 | /* refers to a global variable defined later in this translation unit*/ 10 | extern int v; /* external linkage, declaration */ 11 | 12 | static int s; /* no linkage, implicit initializer */ 13 | 14 | register int a; 15 | int b; 16 | return x+y+u+v+s; 17 | } 18 | int x = 3; /* external linkage, definition */ 19 | int v; 20 | 21 | int main() { 22 | f(2); 23 | } -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/Makefile: -------------------------------------------------------------------------------- 1 | SCANFILE=../../../examples/ScanFile 2 | CORRECT_CS=good_sinit.c good_sinit2.c good_anonunion.c good_return.c \ 3 | good_bug29.c good_bug29_2.c 4 | ERROR_CS=bad_args.c bad_sinit1.c bad_bug29.c 5 | 6 | export TRACE_EVENTS=1 7 | 8 | all: test 9 | test: 10 | @for f in $(CORRECT_CS); do $(SCANFILE) $$f 2> $$f.out; diff $$f.out $$f.expect; done 11 | @for f in $(ERROR_CS); do ( $(SCANFILE) $$f 2> $$f.out; sh ../expect_error $$? "Expecting error when analysing $$f"); done 12 | test-gcc: 13 | @gcc -c $(CORRECT_CS) 14 | @for f in $(ERROR_CS); do (gcc -c $$f 2>.log ; sh ../expect_error $$? `cat .log`); done 15 | clean: 16 | rm -f *.out *.o 17 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/bad_args.c: -------------------------------------------------------------------------------- 1 | void f(int x) { 2 | } 3 | 4 | void g() { 5 | f(1, 2); 6 | } 7 | 8 | void h() { 9 | f(); 10 | } 11 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/bad_bug29.c: -------------------------------------------------------------------------------- 1 | typedef struct { int x; } foo; 2 | 3 | void f() { 4 | foo *foo; 5 | foo *bar; 6 | } 7 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/bad_bug29.c.expect: -------------------------------------------------------------------------------- 1 | Tag: struct $6 {x :: int;} ("bad_bug29.c": line 1) 2 | Typedef: typedef foo as struct $6 ("bad_bug29.c": line 1) 3 | Decl: declaration f | function/external | void () ("bad_bug29.c": line 3) 4 | Local: object foo | auto | foo * ("bad_bug29.c": line 4) 5 | ScanFile: Semantic Error: [bad_bug29.c:5: (column 10) [ERROR] >>> error 6 | not found: bar 7 | ] 8 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/bad_sinit1.c: -------------------------------------------------------------------------------- 1 | typedef struct _s { 2 | int x; 3 | int y; 4 | } s; 5 | 6 | s s1 = { .y = 2, 1 }; 7 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/good_anonunion.c: -------------------------------------------------------------------------------- 1 | typedef struct foo { 2 | int x; 3 | union { 4 | int y; 5 | int z; 6 | }; 7 | } s; 8 | 9 | int f(s *ps) { 10 | return ps->y; 11 | } 12 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/good_anonunion.c.expect: -------------------------------------------------------------------------------- 1 | Tag: union $14 {y :: int; z :: int;} ("good_anonunion.c": line 3) 2 | Tag: struct foo {x :: int; :: union $14;} ("good_anonunion.c": line 1) 3 | Typedef: typedef s as struct foo ("good_anonunion.c": line 1) 4 | Decl: declaration f | function/external | int (s * ps) ("good_anonunion.c": line 9) 5 | Param: auto ps :: s * ("good_anonunion.c": line 9) 6 | Decl: function f | function/external | int (s * ps) ("good_anonunion.c": line 9) 7 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/good_bug29.c: -------------------------------------------------------------------------------- 1 | typedef struct { int x; } foo; 2 | 3 | void f() { 4 | foo *foo, *bar; 5 | } 6 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/good_bug29.c.expect: -------------------------------------------------------------------------------- 1 | Tag: struct $6 {x :: int;} ("good_bug29.c": line 1) 2 | Typedef: typedef foo as struct $6 ("good_bug29.c": line 1) 3 | Decl: declaration f | function/external | void () ("good_bug29.c": line 3) 4 | Local: object foo | auto | foo * ("good_bug29.c": line 4) 5 | Local: object bar | auto | foo * ("good_bug29.c": line 4) 6 | Decl: function f | function/external | void () ("good_bug29.c": line 3) 7 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/good_bug29_2.c: -------------------------------------------------------------------------------- 1 | typedef int ax25_dev; 2 | int f() { 3 | typeof(ax25_dev) *ax25_dev, *ax25_dev_old; 4 | } 5 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/good_bug29_2.c.expect: -------------------------------------------------------------------------------- 1 | Typedef: typedef ax25_dev as int ("good_bug29_2.c": line 1) 2 | Decl: declaration f | function/external | int () ("good_bug29_2.c": line 2) 3 | Local: object ax25_dev | auto | ax25_dev * ("good_bug29_2.c": line 3) 4 | Local: object ax25_dev_old | auto | ax25_dev * ("good_bug29_2.c": line 3) 5 | Decl: function f | function/external | int () ("good_bug29_2.c": line 2) 6 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/good_return.c: -------------------------------------------------------------------------------- 1 | int f(int *x) { 2 | return *x; 3 | } 4 | 5 | int g(const int *x) { 6 | return *x; 7 | } 8 | 9 | int h(int const *x) { 10 | return *x; 11 | } 12 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/good_return.c.expect: -------------------------------------------------------------------------------- 1 | Decl: declaration f | function/external | int (int * x) ("good_return.c": line 1) 2 | Param: auto x :: int * ("good_return.c": line 1) 3 | Decl: function f | function/external | int (int * x) ("good_return.c": line 1) 4 | Decl: declaration g | function/external | int (const int * x) ("good_return.c": line 5) 5 | Param: auto x :: const int * ("good_return.c": line 5) 6 | Decl: function g | function/external | int (const int * x) ("good_return.c": line 5) 7 | Decl: declaration h | function/external | int (const int * x) ("good_return.c": line 9) 8 | Param: auto x :: const int * ("good_return.c": line 9) 9 | Decl: function h | function/external | int (const int * x) ("good_return.c": line 9) 10 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/good_sinit.c: -------------------------------------------------------------------------------- 1 | typedef struct _s { 2 | int x; 3 | int y; 4 | } s; 5 | 6 | s s1 = { 1, 2 }; 7 | s s2 = { .x = 1, .y = 2}; 8 | s s3 = { .y = 1, .x = 2}; 9 | s s4 = { .x = 1, 2}; 10 | s s5 = { 1, .y = 2}; 11 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/good_sinit.c.expect: -------------------------------------------------------------------------------- 1 | Tag: struct _s {x :: int; y :: int;} ("good_sinit.c": line 1) 2 | Typedef: typedef s as struct _s ("good_sinit.c": line 1) 3 | Decl: object s1 | static/external | s = { 1, 2 } ("good_sinit.c": line 6) 4 | Decl: object s2 | static/external | s = { .x = 1, .y = 2 } ("good_sinit.c": line 7) 5 | Decl: object s3 | static/external | s = { .y = 1, .x = 2 } ("good_sinit.c": line 8) 6 | Decl: object s4 | static/external | s = { .x = 1, 2 } ("good_sinit.c": line 9) 7 | Decl: object s5 | static/external | s = { 1, .y = 2 } ("good_sinit.c": line 10) 8 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/good_sinit2.c: -------------------------------------------------------------------------------- 1 | typedef struct _s { 2 | int x; 3 | union { 4 | int y; 5 | int z; 6 | }; 7 | } s; 8 | 9 | s s1 = {1, 2}; 10 | 11 | s s2 = { .x = 1, .y = 2 }; 12 | 13 | s s3 = { .x = 1, .z = 2 }; 14 | -------------------------------------------------------------------------------- /reference/test/harness/analysis_type_check/good_sinit2.c.expect: -------------------------------------------------------------------------------- 1 | Tag: union $14 {y :: int; z :: int;} ("good_sinit2.c": line 3) 2 | Tag: struct _s {x :: int; :: union $14;} ("good_sinit2.c": line 1) 3 | Typedef: typedef s as struct _s ("good_sinit2.c": line 1) 4 | Decl: object s1 | static/external | s = { 1, 2 } ("good_sinit2.c": line 9) 5 | Decl: object s2 | static/external | s = { .x = 1, .y = 2 } ("good_sinit2.c": line 11) 6 | Decl: object s3 | static/external | s = { .x = 1, .z = 2 } ("good_sinit2.c": line 13) 7 | -------------------------------------------------------------------------------- /reference/test/harness/attributes/Makefile: -------------------------------------------------------------------------------- 1 | export BINDIR=../../bin 2 | export NO_SEMANTIC_ANALYSIS=1 3 | export CC_FLAGS=-Wall 4 | TMPDIR:=/tmp/ 5 | export TMPDIR 6 | all: deprecated osx 7 | osx: 8 | $(BINDIR)/CTest osx-1.c 9 | deprecated: 10 | sh $(BINDIR)/compile_log.sh deprecated 11 | sh $(BINDIR)/compile_log.sh deprecated-2 12 | sh $(BINDIR)/compile_log.sh deprecated-3 13 | sh $(BINDIR)/compile_log.sh deprecated-bitfield-init 14 | # $(BINDIR)/compile_log.sh fun_decl # fails 15 | clean: 16 | rm -rf *.log 17 | -------------------------------------------------------------------------------- /reference/test/harness/attributes/deprecated-2.c: -------------------------------------------------------------------------------- 1 | /* Test __attribute__((deprecated)). Test types without names. */ 2 | /* Origin: Joseph Myers */ 3 | /* { dg-do compile } */ 4 | /* { dg-options "" } */ 5 | 6 | struct { int a; } __attribute__((deprecated)) x; /* { dg-warning "type is deprecated" } */ 7 | typeof(x) y; /* { dg-warning "type is deprecated" } */ 8 | -------------------------------------------------------------------------------- /reference/test/harness/attributes/deprecated-3.c: -------------------------------------------------------------------------------- 1 | /* Test __attribute__((deprecated)). Test merging with multiple 2 | declarations. Bug 7425. */ 3 | /* { dg-do compile } */ 4 | /* { dg-options "" } */ 5 | 6 | void func(void); 7 | void func(void) __attribute__((deprecated)); 8 | 9 | void f(void) { 10 | func(); /* { dg-warning "'func' is deprecated" } */ 11 | } 12 | -------------------------------------------------------------------------------- /reference/test/harness/attributes/deprecated-bitfield-init.c: -------------------------------------------------------------------------------- 1 | /* attributes for a declarator have to be placed as follows in conjunction with bitfields or initializers */ 2 | #define DEPR __attribute__((deprecated)) 3 | int a DEPR = 2; 4 | struct x { 5 | int a DEPR; 6 | int b:2 DEPR; 7 | int c:3 DEPR, d:4 DEPR; 8 | int :5 DEPR; /* no sensible attribute for unnamed bitfields */ 9 | }; 10 | int main() { 11 | printf("%d\n",a); 12 | printf("%d %d %d %d"); 13 | } -------------------------------------------------------------------------------- /reference/test/harness/attributes/fun_decl.c: -------------------------------------------------------------------------------- 1 | /* function attributes for old-style function declarations are special 2 | - if we move the attribute to the right of the declarator, we get a syntax error */ 3 | #define DEPR __attribute__((deprecated)) 4 | #define CONST __attribute__((const)) 5 | #define UNUSED __attribute__((unused)) 6 | /* a pointer to a deprecated function returning int - does not work in current gcc ! */ 7 | extern int (DEPR *f_0_a)(int x); 8 | 9 | /* this applies to the function prototype */ 10 | extern int f_0_b(int x) DEPR; 11 | 12 | /* new style */ 13 | static int (CONST f_1)(int x) { return (*f_0_a)(x)+f_0_b(x); } 14 | /* this should be ok, but is a syntax error in current gcc */ 15 | 16 | /* static int f_2(int x) UNUSED { return x; } */ 17 | 18 | /* old-style */ 19 | static int (CONST f_3)(int x) { return x; } 20 | 21 | /* Below: according to the gcc docs, DEPR might belong to f_3 in future implementations, */ 22 | /* but this makes the grammar even more tricky. currently it is a syntax error */ 23 | /* 24 | static int f_4(x) UNUSED 25 | int x; 26 | { 27 | return x; 28 | } 29 | */ 30 | -------------------------------------------------------------------------------- /reference/test/harness/attributes/osx-1.c: -------------------------------------------------------------------------------- 1 | /* Non-Standard attribute syntax used in OS X (no proper support, but should parse) */ 2 | int f1(char ** restrict) __attribute__((availability(macosx,introduced=10.7))); 3 | -------------------------------------------------------------------------------- /reference/test/harness/bug20130805_nopos/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_DIR=../../.. 2 | OPT=-O2 3 | include $(PROJECT_DIR)/test/config.mk 4 | all: 5 | $(HC) $(HFLAGS) Test.hs 6 | ./Test > test.out 7 | diff test.expect test.out 8 | clean: 9 | rm -rf Test.o Test.hi Test test.out 10 | -------------------------------------------------------------------------------- /reference/test/harness/bug20130805_nopos/Test.hs: -------------------------------------------------------------------------------- 1 | -- Bug report: 2 | -- 1. run (parseCFile cfile nopos), on a file with syntax errors 3 | -- 2. error message triggers a bug, because no position information is available 4 | module Main where 5 | import Language.C 6 | import Data.ByteString.Char8 as BS (pack) 7 | 8 | main :: IO () 9 | main = do 10 | let src = BS.pack "int x());" 11 | case parseC src nopos of 12 | Left err -> (length (show err)) `seq` (putStrLn "Expected Parse Error") 13 | Right _ -> putStrLn "Unexpected Parse Success" 14 | let src2 = BS.pack "int x;" 15 | case parseC src2 nopos of 16 | Left _ -> putStrLn "Unexpected Parse Error" 17 | Right ok -> print (prettyUsingInclude ok) -------------------------------------------------------------------------------- /reference/test/harness/bug20130805_nopos/test.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcr/parser-c/1c51c38ffcfda358b9edfd944a4bac7de1ebcf1a/reference/test/harness/bug20130805_nopos/test.c -------------------------------------------------------------------------------- /reference/test/harness/bug20130805_nopos/test.expect: -------------------------------------------------------------------------------- 1 | Expected Parse Error 2 | int x; 3 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160302_int128/Makefile: -------------------------------------------------------------------------------- 1 | PP=../../../examples/ParseAndPrint 2 | TY=../../../examples/TypeCheck 3 | all: parse typecheck 4 | parse: 5 | $(PP) test.c > test.out 6 | diff -u test.expect test.out 7 | typecheck: 8 | $(TY) test_ty.c >test_ty.out 2>&1 || echo "Typecheck failed as expected" 9 | diff -u test_ty.expect test_ty.out 10 | clean: 11 | rm -f *.out 12 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160302_int128/test.c: -------------------------------------------------------------------------------- 1 | /* __int128 feature (gcc extension) */ 2 | /* https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html */ 3 | __int128 y = ((__int128)0x7FFFFFFFFFFFFFFFULL << 32); 4 | unsigned __int128 y2 = ((unsigned __int128)0xFFFFFFFFFFFFFFFFULL << 32); 5 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160302_int128/test.expect: -------------------------------------------------------------------------------- 1 | __int128 y = (__int128) 0x7fffffffffffffffuLL << 32; 2 | unsigned __int128 y2 = (unsigned __int128) 0xffffffffffffffffuLL << 32; 3 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160302_int128/test_ty.c: -------------------------------------------------------------------------------- 1 | /* __int128 feature (gcc extension) */ 2 | /* https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html */ 3 | __int128 y = ((__int128)0x7FFFFFFFFFFFFFFFULL << 32); 4 | unsigned __int128 y2 = ((unsigned __int128)0xFFFFFFFFFFFFFFFFULL << 32); 5 | 6 | /* assignment error */ 7 | struct z a = y2; 8 | 9 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160302_int128/test_ty.expect: -------------------------------------------------------------------------------- 1 | test_ty.c: Error 2 | test_ty.c:7: (column 14) [ERROR] >>> AST invariant violated 3 | incompatible direct types in assignment: struct z, unsigned __int128 4 | 5 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160314_noreturn/Makefile: -------------------------------------------------------------------------------- 1 | PP=../../../examples/ParseAndPrint 2 | TY=../../../examples/TypeCheck 3 | all: test 4 | test: 5 | $(PP) test.c > test_pp.out 2>&1 6 | diff -u test_pp.expect test_pp.out 7 | $(TY) test.c > test_ty.out 2>&1 8 | diff -u test_ty.expect test_ty.out 9 | clean: 10 | rm -f *.out 11 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160314_noreturn/test.c: -------------------------------------------------------------------------------- 1 | /* _Noreturn */ 2 | inline void f(void); 3 | inline void nf(void); 4 | static _Noreturn void nnf(void); 5 | __attribute__((noreturn)) void nnnf(void); 6 | 7 | inline void f(void) 8 | { 9 | } 10 | _Noreturn inline void nf(void) 11 | { 12 | while (1) 13 | { 14 | } 15 | } 16 | static _Noreturn void nnf(void) 17 | { 18 | while (1) 19 | { 20 | } 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160314_noreturn/test.expect: -------------------------------------------------------------------------------- 1 | __int128 y = (__int128) 0x7fffffffffffffffuLL << 32; 2 | unsigned __int128 y2 = (unsigned __int128) 0xffffffffffffffffuLL << 32; 3 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160314_noreturn/test_pp.expect: -------------------------------------------------------------------------------- 1 | inline void f(void); 2 | inline void nf(void); 3 | static _Noreturn void nnf(void); 4 | __attribute__((noreturn)) void nnnf(void); 5 | inline void f(void) 6 | { 7 | } 8 | _Noreturn inline void nf(void) 9 | { 10 | while (1) 11 | { 12 | } 13 | } 14 | static _Noreturn void nnf(void) 15 | { 16 | while (1) 17 | { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160314_noreturn/test_ty.expect: -------------------------------------------------------------------------------- 1 | test.c: Success 2 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160729_C_include_stack/Makefile: -------------------------------------------------------------------------------- 1 | PP=../../../examples/ParseAndPrint 2 | TY=../../../examples/TypeCheck 3 | all: 4 | $(TY) test.i > test.out 2>&1 5 | diff -u test.expect test.out 6 | preprocess: 7 | $(CC) -E test.c > test.i 8 | check_host_cc_build: 9 | $(CC) $(CFLAGS) -o /dev/null test.c 10 | 11 | clean: 12 | rm -f *.out 13 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160729_C_include_stack/a.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | int a1 = 1; 4 | 5 | /* Chain 1: ... - a.h 6 - b.h 5 */ 6 | #include "b.h" 7 | 8 | /* Chain 2: ... - a.h 9 */ 9 | int a2 = 2; 10 | 11 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160729_C_include_stack/b.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /* Chain 1: ... - ... - b.h 5 */ 5 | int b = 3; 6 | 7 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160729_C_include_stack/c.h: -------------------------------------------------------------------------------- 1 | int c = 4; 2 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160729_C_include_stack/test.c: -------------------------------------------------------------------------------- 1 | /* Chain 1: test.c 3 - a.h 6 - b.h 5 */ 2 | /* Chain 2: test.c 3 - a.h 9 */ 3 | #include "a.h" 4 | 5 | #include "b.h" 6 | 7 | int a2 = 7; 8 | 9 | 10 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160729_C_include_stack/test.expect: -------------------------------------------------------------------------------- 1 | test.i: Error 2 | b.h:5: (column 5) [ERROR] >>> b redefined 3 | duplicate definition of b 4 | The previous declaration was here: 5 | ("b.h": line 5, in file included from ("a.h": line 6, in file included from ("test.c": line 3))) 6 | 7 | test.c:7: (column 5) [ERROR] >>> a2 redefined 8 | duplicate definition of a2 9 | The previous declaration was here: 10 | ("a.h": line 9, in file included from ("test.c": line 3)) 11 | 12 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160729_C_include_stack/test.i: -------------------------------------------------------------------------------- 1 | # 1 "test.c" 2 | # 1 "" 3 | # 1 "" 4 | # 31 "" 5 | # 1 "/usr/include/stdc-predef.h" 1 3 4 6 | # 32 "" 2 7 | # 1 "test.c" 3 8 | 9 | 10 | # 1 "a.h" 4 1 11 | 12 | 13 | int a1 = 1; 14 | 15 | 16 | # 1 "b.h" 3 1 17 | 18 | 19 | 20 | 21 | int b = 3; 22 | # 7 "a.h" 3 2 4 23 | 24 | 25 | int a2 = 2; 26 | # 4 "test.c" 2 3 4 27 | 28 | # 1 "b.h" 4 1 3 29 | 30 | 31 | 32 | 33 | int b = 3; 34 | # 6 "test.c" 4 3 2 35 | 36 | int a2 = 7; 37 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160911_builtin_bswap/Makefile: -------------------------------------------------------------------------------- 1 | PP=../../../examples/ParseAndPrint 2 | TY=../../../examples/TypeCheck 3 | all: 4 | $(PP) test.c > test.out 5 | $(TY) test.c >> test.out 6 | diff -u test.expect test.out 7 | check_host_cc_build: 8 | $(CC) $(CFLAGS) -o /dev/null test.c 9 | 10 | clean: 11 | rm -f *.out 12 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160911_builtin_bswap/test.c: -------------------------------------------------------------------------------- 1 | volatile int x, x1, y, y2, z, z1; 2 | 3 | int main(int argc, char **argv) 4 | { 5 | x1 = __builtin_bswap16(x); 6 | y2 = __builtin_bswap32(y); 7 | z1 = __builtin_bswap64(z); 8 | } 9 | -------------------------------------------------------------------------------- /reference/test/harness/bug20160911_builtin_bswap/test.expect: -------------------------------------------------------------------------------- 1 | volatile int x, x1, y, y2, z, z1; 2 | int main(int argc, char * * argv) 3 | { 4 | x1 = __builtin_bswap16(x); 5 | y2 = __builtin_bswap32(y); 6 | z1 = __builtin_bswap64(z); 7 | } 8 | -------------------------------------------------------------------------------- /reference/test/harness/bug21_sem_typedef/Makefile: -------------------------------------------------------------------------------- 1 | MAIN=typedef 2 | SCANFILE=../../../examples/ScanFile 3 | all: 4 | $(SCANFILE) $(MAIN).c > $(MAIN).out 5 | diff -u $(MAIN).expect $(MAIN).out 6 | clean: 7 | rm -f *.out 8 | -------------------------------------------------------------------------------- /reference/test/harness/bug21_sem_typedef/typedef.c: -------------------------------------------------------------------------------- 1 | typedef int nat_int, 2 | *pnat_int, 3 | **ppnat_int; -------------------------------------------------------------------------------- /reference/test/harness/bug21_sem_typedef/typedef.expect: -------------------------------------------------------------------------------- 1 | Global Declarations 2 | enumerators 3 | declarations 4 | objects 5 | functions 6 | tags 7 | typeDefs 8 | nat_int ~> typedef nat_int as int 9 | ppnat_int ~> typedef ppnat_int as int * * 10 | pnat_int ~> typedef pnat_int as int * 11 | -------------------------------------------------------------------------------- /reference/test/harness/bug22_file_permission_cpp/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_DIR=../../.. 2 | OPT=-O2 3 | include $(PROJECT_DIR)/test/config.mk 4 | all: 5 | chmod 444 input.c 6 | $(HC) $(HFLAGS) --make Test.hs 7 | ./Test input.c 8 | clean: 9 | rm -rf Test.o Test.hi Test 10 | -------------------------------------------------------------------------------- /reference/test/harness/bug22_file_permission_cpp/Test.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | import Control.Monad 3 | import System.Environment 4 | import Language.C 5 | import Language.C.System.GCC 6 | main = do 7 | input <- getArgs >>= \args -> 8 | case args of 9 | [f] -> return f 10 | _ -> error "Usage: ./Test.hs c-file" 11 | ast <- parseCFile (newGCC "gcc") Nothing [] input 12 | case ast of 13 | Left err -> error (show err) 14 | Right ast -> print (pretty ast) 15 | -------------------------------------------------------------------------------- /reference/test/harness/bug22_file_permission_cpp/input.c: -------------------------------------------------------------------------------- 1 | /* read-only file permission */ 2 | int test; -------------------------------------------------------------------------------- /reference/test/harness/bug30_preserve_int_repr/Makefile: -------------------------------------------------------------------------------- 1 | PP=../../../examples/ParseAndPrint 2 | all: 3 | $(PP) test.c > test.out 4 | diff -u test.expect test.out 5 | clean: 6 | rm -f test.out -------------------------------------------------------------------------------- /reference/test/harness/bug30_preserve_int_repr/test.c: -------------------------------------------------------------------------------- 1 | int zero = 0, h_1 = 0x0, h_2 = 0x00; 2 | -------------------------------------------------------------------------------- /reference/test/harness/bug30_preserve_int_repr/test.expect: -------------------------------------------------------------------------------- 1 | int zero = 0, h_1 = 0x0, h_2 = 0x0; 2 | -------------------------------------------------------------------------------- /reference/test/harness/bug31_pp_if_else/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_DIR=../../.. 2 | OPT=-O2 3 | include $(PROJECT_DIR)/test/config.mk 4 | all: 5 | $(HC) $(HFLAGS) --make Test.hs 6 | ./Test > test.c 7 | gcc -o test_out test.c 8 | ./test_out > test.out 9 | diff test.expect test.out 10 | clean: 11 | rm -rf Test test.c test_out *.o *.hi *.dyn_hi *.dyn_o *.out 12 | -------------------------------------------------------------------------------- /reference/test/harness/bug31_pp_if_else/Test.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE QuasiQuotes #-} 2 | module Main where 3 | import Control.Monad 4 | import System.Environment 5 | import Language.C 6 | import Language.C.System.GCC 7 | import Text.Printf 8 | import Text.PrettyPrint.HughesPJ 9 | --import Here (here) 10 | main = do 11 | -- this is not the prettiest, but easiest solution 12 | let depth = 2 13 | putStrLn "#include " 14 | print $ pretty $ parseCExtDecl $ show $ 15 | text "int main(int argc, char**argv)" $+$ 16 | (braces $ 17 | stat_embed depth (stat1 depth) $+$ 18 | stat_embed depth (stat2 depth) $+$ 19 | text "return(0);") 20 | 21 | parseCStat :: String -> CStat 22 | parseCStat s = either (error.show) id $ execParser_ statementP (inputStreamFromString s) (initPos "") 23 | parseCExtDecl :: String -> CExtDecl 24 | parseCExtDecl s = either (error.show) id $ execParser_ extDeclP (inputStreamFromString s) (initPos "") 25 | 26 | stat_embed :: Int -> CStat -> Doc 27 | stat_embed k stat = braces $ nest 2 $ 28 | decls $+$ 29 | text "int r = 0;" $+$ 30 | iteropen $+$ 31 | (nest 2 stmt) $+$ 32 | (nest 2 $ text "printf(\"%d\\n\",r);") $+$ 33 | iterclose 34 | where 35 | stmt = pretty stat 36 | decls = vcat $ map (\n -> text "int" <+> text(guardName n) <> semi) [1..k] 37 | iteropen = vcat $ map (\n -> let gn = guardName n in text (printf "for(%s=0;%s<=1;%s++){" gn gn gn)) [1..k] 38 | iterclose = vcat $ replicate k (char '}') 39 | 40 | guardName n = "g_"++show n 41 | setR :: Int -> CStat 42 | setR k = parseCStat $ printf "r = %d;" k 43 | stat1 :: Int -> CStatement NodeInfo 44 | stat1 depth = go depth 45 | where 46 | go depth = 47 | case depth of 48 | n | n <= 1 -> CIf (guard n) (setR 1) (Just$ setR 2) u 49 | | otherwise -> CIf (guard n) (go (n-1)) Nothing u 50 | cexpr = CExpr . Just 51 | vexpr s = CVar (internalIdent s) u 52 | guard n = vexpr (guardName n) 53 | u = undefNode 54 | stat2 :: Int -> CStatement NodeInfo 55 | stat2 depth = CIf (guard depth) (go (depth-1)) (Just$ setR 2) u 56 | where 57 | go n | n == 0 = setR 1 58 | | otherwise = CIf (guard n) (go (n-1)) Nothing u 59 | cexpr = CExpr . Just 60 | vexpr s = CVar (internalIdent s) u 61 | guard n = vexpr (guardName n) 62 | u = undefNode 63 | 64 | -------------------------------------------------------------------------------- /reference/test/harness/bug31_pp_if_else/test.expect: -------------------------------------------------------------------------------- 1 | 0 2 | 2 3 | 2 4 | 1 5 | 2 6 | 2 7 | 2 8 | 1 9 | -------------------------------------------------------------------------------- /reference/test/harness/bug5_dos_newline/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | ../../../examples/ParseAndPrint min.i >/dev/null 3 | clean: 4 | -------------------------------------------------------------------------------- /reference/test/harness/bug5_dos_newline/min.i: -------------------------------------------------------------------------------- 1 | # 1 "foobar.h" 2 | 3 | int main() {} -------------------------------------------------------------------------------- /reference/test/harness/bugn6_empty_file/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_DIR=../../.. 2 | OPT=-O2 3 | include $(PROJECT_DIR)/test/config.mk 4 | all: 5 | $(HC) $(HFLAGS) Test.hs 6 | ./Test > test.out 7 | diff test.expect test.out 8 | clean: 9 | rm -rf Test.o Test.hi Test test.out 10 | -------------------------------------------------------------------------------- /reference/test/harness/bugn6_empty_file/Test.hs: -------------------------------------------------------------------------------- 1 | -- Bug report: 2 | -- 1. Parse empty file. 3 | -- 2. Then try to print filename. 4 | -- 3. Get error. 5 | -- See attachment. 6 | module Main where 7 | import Language.C 8 | import Language.C.System.GCC 9 | 10 | -- Create empty file 'test.c' before 11 | main :: IO () 12 | main = do 13 | Right tu <- parseCFilePre "test.c" 14 | print $ let Just fname = fileOfNode tu in fname -------------------------------------------------------------------------------- /reference/test/harness/bugn6_empty_file/test.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcr/parser-c/1c51c38ffcfda358b9edfd944a4bac7de1ebcf1a/reference/test/harness/bugn6_empty_file/test.c -------------------------------------------------------------------------------- /reference/test/harness/bugn6_empty_file/test.expect: -------------------------------------------------------------------------------- 1 | "test.c" 2 | -------------------------------------------------------------------------------- /reference/test/harness/builtins/Makefile: -------------------------------------------------------------------------------- 1 | PP=../../../examples/ParseAndPrint 2 | TY=../../../examples/TypeCheck 3 | all: parse 4 | # typecheck not fully supported yet 5 | 6 | parse: 7 | $(PP) test.c > test.out 8 | cat test.c | grep -v '^/\*' | grep -v '^$$' > test.expect 9 | diff -u test.expect test.out 10 | typecheck: 11 | $(TY) test.c 2>&1 | tee test_ty.out 12 | diff -u test_ty.expect test_ty.out 13 | clean: 14 | rm -f *.out 15 | -------------------------------------------------------------------------------- /reference/test/harness/builtins/test.c: -------------------------------------------------------------------------------- 1 | /* Builtin regression tests */ 2 | 3 | /* (1) __builtin_convertvector */ 4 | typedef double vector4double __attribute__((__vector_size__(32))); 5 | typedef float vector4float __attribute__((__vector_size__(16))); 6 | typedef short vector4short __attribute__((__vector_size__(8))); 7 | vector4float vf; 8 | vector4short vs; 9 | vector4double vd; 10 | 11 | int test(void) 12 | { 13 | vf = __builtin_convertvector (vs, vector4float); 14 | vd = (vector4double) {(double) vf[0], (double) vf[1], (double) vf[2], (double) vf[3]}; 15 | } 16 | -------------------------------------------------------------------------------- /reference/test/harness/builtins/test.expect: -------------------------------------------------------------------------------- 1 | typedef double vector4double __attribute__((__vector_size__(32))); 2 | typedef float vector4float __attribute__((__vector_size__(16))); 3 | typedef short vector4short __attribute__((__vector_size__(8))); 4 | vector4float vf; 5 | vector4short vs; 6 | vector4double vd; 7 | int test(void) 8 | { 9 | vf = __builtin_convertvector (vs, vector4float); 10 | vd = (vector4double) {(double) vf[0], (double) vf[1], (double) vf[2], (double) vf[3]}; 11 | } 12 | -------------------------------------------------------------------------------- /reference/test/harness/builtins/test_ty.expect: -------------------------------------------------------------------------------- 1 | test.c: Error 2 | test.c:14: (column 10) [ERROR] >>> AST invariant violated 3 | initializer list for type: double 4 | 5 | -------------------------------------------------------------------------------- /reference/test/harness/expect_error: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | CODE=$1 3 | if [ -z "$2" ]; then 4 | MSG="Expected Error" 5 | else 6 | MSG=$2 7 | fi 8 | if [ $CODE -eq 0 ]; then 9 | echo $MSG 1>&2 10 | exit 1 11 | else 12 | exit 0 13 | fi -------------------------------------------------------------------------------- /reference/test/harness/parse_dg/Makefile: -------------------------------------------------------------------------------- 1 | TEST_ARCHIVE=gcc_dg_pre.tar.bz2 2 | TEST_SUITE=gcc_pre 3 | TMP_DIR=gcc_pre_tmp 4 | export CTEST_TMPDIR=$(TMP_DIR) 5 | export CTEST_EXIT_FAILURE=1 6 | 7 | all: expect_parse expect_fail 8 | 9 | full: all expect_roundtrip memory_usage_parse.out memory_usage_roundtrip.out 10 | 11 | # parse tests 12 | EXPECT_PARSE_TARGETS = $(addprefix parse_, $(shell cat expect_parse.txt)) 13 | EXPECT_FAIL_TARGETS = $(addprefix fail_, $(shell cat expect_fail.txt)) 14 | 15 | expect_parse: $(EXPECT_PARSE_TARGETS) 16 | expect_fail: $(EXPECT_FAIL_TARGETS) 17 | 18 | $(EXPECT_PARSE_TARGETS): parse_%: $(TEST_SUITE) 19 | @rm -f $(TMP_DIR)/$@.log 20 | @CTEST_LOGFILE=$(TMP_DIR)/$@.log ../../bin/CParse +RTS -t_stats.log -RTS \ 21 | $(TEST_SUITE)/$(patsubst parse_%,%,$@) \ 22 | || (cat $(TMP_DIR)/$@.log >&2 ; exit 1) 23 | @cat _stats.log >> $(TMP_DIR)/$@.log 24 | 25 | $(EXPECT_FAIL_TARGETS): fail_%: $(TEST_SUITE) 26 | @rm -f $(TMP_DIR)/$@.log 27 | @CTEST_NON_PARSE=1 CTEST_LOGFILE=$(TMP_DIR)/$@.log ../../bin/CParse +RTS -t_stats.log -RTS \ 28 | $(TEST_SUITE)/$(patsubst fail_%,%,$@) \ 29 | || (cat $(TMP_DIR)/$@.log >&2 ; exit 1) 30 | @cat _stats.log >> $(TMP_DIR)/@.log 31 | 32 | 33 | # More tests and stats 34 | 35 | EXPECT_ROUNDTRIP_TARGETS = $(addprefix roundtrip_, $(shell cat expect_roundtrip.txt)) 36 | expect_roundtrip: $(EXPECT_ROUNDTRIP_TARGETS) 37 | 38 | $(EXPECT_ROUNDTRIP_TARGETS): roundtrip_%: $(TEST_SUITE) 39 | @rm -f $(TMP_DIR)/$@.log 40 | @CTEST_LOGFILE=$(TMP_DIR)/$@.log ../../bin/CRoundTrip +RTS -t_stats.log -RTS \ 41 | $(TEST_SUITE)/$(patsubst roundtrip_%,%,$@) \ 42 | || (cat $(TMP_DIR)/$@.log >&2 ; exit 1) 43 | @cat _stats.log >> $(TMP_DIR)/$@.log 44 | 45 | memory_usage_parse.out: $(TEST_SUITE) 46 | time for f in `cat expect_parse.txt` ; do \ 47 | CTEST_TMP_DIR=$(TMP_DIR) ../../bin/CParse +RTS -t -RTS $(TEST_SUITE)/$$f 2>&1 | \ 48 | grep -o [1-9][0-9]*M | sed 's/^/'"$$f"': /' ; \ 49 | done > $@ 50 | 51 | memory_usage_roundtrip.out: $(TEST_SUITE) 52 | time for f in `cat expect_roundtrip.txt` ; do \ 53 | CTEST_TMP_DIR=$(TMP_DIR) ../../bin/CRoundTrip +RTS -t -RTS $(TEST_SUITE)/$$f 2>&1 | \ 54 | grep -o [1-9][0-9]*M | sed 's/^/'"$$f"': /' ; \ 55 | done > $@ 56 | 57 | 58 | $(TEST_SUITE): $(TMP_DIR) 59 | @if [ ! -d $(TEST_SUITE) ] ; then tar xjf $(TEST_ARCHIVE) ; fi 60 | $(TMP_DIR): 61 | @mkdir -p $@ 62 | 63 | clean: 64 | rm -rf $(TEST_SUITE) $(TMP_DIR) _stats.log *.out 65 | 66 | # generating the expect/fail lists 67 | .PHONY: triage_parse triage_roundtrip 68 | triage_parse: 69 | @rm -f expect_fail.txt expect_parse.txt 70 | @touch expect_fail.txt expect_parse.txt 71 | time for f in `ls $(TEST_SUITE) ` ; do ../../bin/CParse +RTS -t -RTS $(TEST_SUITE)/$$f ; if [ $$? -ne 0 ] ; then echo $$f >> expect_fail.txt ; else echo $$f >> expect_parse.txt ; fi ; done 2>triage.log 72 | triage_roundtrip: 73 | @rm -f expect_roundtrip.txt expect_parse_only.txt 74 | @touch expect_roundtrip.txt expect_parse_only.txt 75 | time for f in `cat expect_parse.txt` ; do ../../bin/CRoundTrip +RTS -t -RTS $(TEST_SUITE)/$$f ; if [ $$? -ne 0 ] ; then echo $$f >> expect_parse_only.txt ; else echo $$f >> expect_roundtrip.txt ; fi ; done 2>triage2.log 76 | 77 | -------------------------------------------------------------------------------- /reference/test/harness/parse_dg/gcc_dg_pre.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcr/parser-c/1c51c38ffcfda358b9edfd944a4bac7de1ebcf1a/reference/test/harness/parse_dg/gcc_dg_pre.tar.bz2 -------------------------------------------------------------------------------- /reference/test/harness/run-harness.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Data.List (intercalate) 4 | import System.Exit (ExitCode(..), exitFailure, exitSuccess, exitWith) 5 | import System.Directory (doesDirectoryExist, doesFileExist, getCurrentDirectory, setCurrentDirectory, 6 | getDirectoryContents) 7 | import System.FilePath (()) 8 | import System.Process (readProcessWithExitCode, callProcess) 9 | import System.IO (hPutStrLn, hPrint, stderr) 10 | import Control.Monad (filterM, liftM, when) 11 | 12 | testDirs :: [String] 13 | testDirs = ["test/harness","harness","."] 14 | 15 | getActualTestDirectory :: [String] -> IO FilePath 16 | getActualTestDirectory test_dirs = do 17 | validDirs <- filterM (doesFileExist . ( "run-harness.hs")) test_dirs 18 | case validDirs of 19 | [] -> ioError (userError ("run-harness.hs not found in " ++ intercalate " or " test_dirs)) 20 | (d:_) -> return d 21 | 22 | subdirectoriesOf :: FilePath -> IO [FilePath] 23 | subdirectoriesOf fp = do 24 | entries <- getDirectoryContents fp 25 | filterM (doesDirectoryExist . (fp )) (filter (not . isSpecialDir) entries) 26 | where 27 | isSpecialDir "." = True 28 | isSpecialDir ".." = True 29 | isSpecialDir _ = False 30 | 31 | -- from Control.Monad.Extra 32 | findM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a) 33 | findM _ [] = return Nothing 34 | findM p (x:xs) = do guard <- p x ; if guard then (return $ Just x) else (findM p xs) 35 | 36 | main :: IO ExitCode 37 | main = do 38 | actual_test_dir <- getActualTestDirectory testDirs 39 | has_makefile <- doesFileExist (actual_test_dir "Makefile") 40 | when (not has_makefile) $ do 41 | hPutStrLn stderr "No Makefile found (out of source tree)" 42 | hPutStrLn stderr "Skipping harness test" 43 | exitWith ExitSuccess 44 | tests <- subdirectoriesOf actual_test_dir 45 | cdir <- getCurrentDirectory 46 | hPutStrLn stderr ("Changing to test directory " ++ actual_test_dir ++ " and compiling") 47 | -- build test executables 48 | setCurrentDirectory (cdiractual_test_dir) 49 | callProcess "make" ["prepare"] 50 | -- run harness tests 51 | hasFailure <- findM (liftM (/= ExitSuccess) . runTest . (cdir) . (actual_test_dir)) tests 52 | setCurrentDirectory cdir 53 | case hasFailure of 54 | Nothing -> exitSuccess 55 | Just _failed -> exitFailure 56 | where 57 | runTest :: FilePath -> IO ExitCode 58 | runTest dir = do 59 | setCurrentDirectory dir 60 | (exitCode, _outp, _errp) <- readProcessWithExitCode "make" [] "" 61 | hPutStrLn stderr ("cd " ++ dir ++ " && make: " ++ show exitCode) 62 | when (exitCode /= ExitSuccess) $ do 63 | hPutStrLn stderr "=== Standard Output ===" 64 | hPutStrLn stderr _outp 65 | hPutStrLn stderr "=== Error Output ===" 66 | hPutStrLn stderr _errp 67 | hPutStrLn stderr "=== End of Output ===" 68 | return exitCode 69 | 70 | 71 | -------------------------------------------------------------------------------- /reference/test/language-c-test.cabal: -------------------------------------------------------------------------------- 1 | Name: language-c-test 2 | Version: 0.6.0 3 | Cabal-Version: >= 1.8 4 | Build-Type: Simple 5 | License: BSD3 6 | License-File: LICENSE 7 | Copyright: LICENSE 8 | Author: AUTHORS 9 | Maintainer: benedikt.huber@gmail.com 10 | Stability: experimental 11 | Homepage: http://visq.github.io/language-c/ 12 | Bug-reports: https://github.com/visq/language-c/issues/ 13 | 14 | Synopsis: Test Framework - Analysis and generation of C code 15 | Description: Language C is a haskell library for the analysis and generation of C code. 16 | Category: Language 17 | 18 | Executable CEquiv 19 | main-is: src/CEquiv.hs 20 | build-depends: base, filepath, mtl, pretty, language-c, language-c-test 21 | if impl(ghc >= 8.0) 22 | ghc-options: -rtsopts -Wall -Wno-redundant-constraints 23 | else 24 | ghc-options: -rtsopts -Wall 25 | 26 | Executable CParse 27 | main-is: src/CParse.hs 28 | build-depends: base, filepath, mtl, pretty, language-c, language-c-test 29 | if impl(ghc >= 8.0) 30 | ghc-options: -rtsopts -Wall -Wno-redundant-constraints 31 | else 32 | ghc-options: -rtsopts -Wall 33 | 34 | Executable CTest 35 | main-is: src/CTest.hs 36 | build-depends: base, filepath, mtl, pretty, syb, language-c, language-c-test 37 | if impl(ghc >= 8.0) 38 | ghc-options: -rtsopts -Wall -Wno-redundant-constraints 39 | else 40 | ghc-options: -rtsopts -Wall 41 | 42 | Executable CRoundTrip 43 | main-is: src/CRoundTrip.hs 44 | build-depends: base, filepath, mtl, pretty, language-c, language-c-test 45 | if impl(ghc >= 8.0) 46 | ghc-options: -rtsopts -Wall -Wno-redundant-constraints 47 | else 48 | ghc-options: -rtsopts -Wall 49 | 50 | Executable CheckGccArgs 51 | main-is: src/CheckGccArgs.hs 52 | build-depends: base, filepath, mtl, pretty, language-c, language-c-test 53 | if impl(ghc >= 8.0) 54 | ghc-options: -rtsopts -Wall -Wno-redundant-constraints 55 | else 56 | ghc-options: -rtsopts -Wall 57 | 58 | Executable RenderTests 59 | main-is: src/RenderTests.hs 60 | build-depends: base, filepath, mtl, pretty, containers, directory, xhtml, language-c, language-c-test 61 | if impl(ghc >= 8.0) 62 | ghc-options: -rtsopts -Wall -Wno-redundant-constraints 63 | else 64 | ghc-options: -rtsopts -Wall 65 | 66 | Executable ReportFatal 67 | main-is: src/ReportFatal.hs 68 | build-depends: base, filepath, mtl, pretty, language-c, language-c-test 69 | if impl(ghc >= 8.0) 70 | ghc-options: -rtsopts -Wall -Wno-redundant-constraints 71 | else 72 | ghc-options: -rtsopts -Wall 73 | 74 | Library 75 | Extensions: CPP, DeriveDataTypeable, PatternGuards, BangPatterns, ExistentialQuantification, GeneralizedNewtypeDeriving, ScopedTypeVariables 76 | Build-Depends: base >= 3 && < 5, process, directory, array, containers, pretty, filepath, bytestring >= 0.9.0, syb, mtl, language-c >= 0.5.1 77 | Hs-Source-Dirs: src 78 | if impl(ghc >= 8.0) 79 | ghc-options: -Wall -Wno-redundant-constraints 80 | else 81 | ghc-options: -Wall 82 | Exposed-Modules: 83 | Language.C.Test.Environment 84 | Language.C.Test.Framework 85 | Language.C.Test.GenericAST 86 | Language.C.Test.Measures 87 | Language.C.Test.ParseTests 88 | Language.C.Test.TestMonad 89 | 90 | -- test description 91 | Test-Suite language-c-harness 92 | type: exitcode-stdio-1.0 93 | main-is: harness/run-harness.hs 94 | build-depends: base, language-c, directory, process, filepath, language-c-test -------------------------------------------------------------------------------- /reference/test/res/style.css: -------------------------------------------------------------------------------- 1 | /* Roughly based on the css from the tablesorter JQuery plugin */ 2 | span.time_info { 3 | float: right; 4 | font-size: 88%; 5 | font-family: times; 6 | } 7 | div.errmsg_box { 8 | margin: 5px; 9 | padding: 4px; 10 | font-size: 90%; 11 | border: 1px solid; 12 | } 13 | table { 14 | font-family:arial; 15 | margin:10px 0pt 15px; 16 | font-size: 10pt; 17 | width: 90%; 18 | text-align: left; 19 | padding: 4px; 20 | background-color: #E9E9E9; 21 | } 22 | table.tablesorter thead tr { 23 | font-weight: 400; 24 | font-style: italic; 25 | background-image: url(bg.gif); 26 | background-repeat: no-repeat; 27 | background-position: center right; 28 | cursor: pointer; 29 | } 30 | table a { 31 | color: black; 32 | } 33 | td.last_row { 34 | font-weight: bolder; 35 | } 36 | table tbody tr td.test_ok { 37 | background-color: #2E9910; 38 | } 39 | table tbody tr td.test_fail { 40 | background-color: #CF0700; 41 | } 42 | table tbody tr td.test_fail a { 43 | font-weight: bolder; 44 | } 45 | table tbody tr td.not_avail { 46 | background-color: #949494; 47 | } 48 | table tbody tr td.init_error { 49 | background-color: #EDCD83; 50 | } 51 | table tbody tr td.fatal_error { 52 | background-color: #EDCD83; 53 | } 54 | table tbody tr.odd { 55 | background-color:#F0F0F6; 56 | } 57 | table.tablesorter thead tr .headerSortUp { 58 | background-image: url(asc.gif); 59 | background-repeat: no-repeat; 60 | background-position: center right; 61 | cursor: pointer; 62 | } 63 | table.tablesorter thead tr .headerSortDown { 64 | background-image: url(desc.gif); 65 | background-repeat: no-repeat; 66 | background-position: center right; 67 | cursor: pointer; 68 | } 69 | table.tablesorter thead tr .headerSortDown, table.tablesorter thead tr .headerSortUp { 70 | background-color: #8dbdd8; 71 | } 72 | -------------------------------------------------------------------------------- /reference/test/src/CParse.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS -Wall #-} 2 | ----------------------------------------------------------------------------- 3 | -- | 4 | -- Module : CParse.hs (Executable) 5 | -- Copyright : (c) 2008 Benedikt Huber 6 | -- License : BSD-style 7 | -- Maintainer : benedikt.huber@gmail.com 8 | -- 9 | -- This module is invoked just like gcc. It preprocesses the C source file given in the arguments 10 | -- and parses it. If CTEST_NON_PARSE is set, it is expected that parsing failes, otherwise it expects 11 | -- that parsing succeeds. 12 | -- 13 | -- Tests are logged, and serialized into a result file. 14 | -- If the CParse finishes without runtime error, it always returns ExitSuccess. 15 | -- 16 | -- see 'TestEnvironment'. 17 | ----------------------------------------------------------------------------- 18 | module Main (main) where 19 | import Control.Monad.State 20 | import System.FilePath (takeBaseName) 21 | import Text.PrettyPrint 22 | 23 | import Language.C.Data.Position 24 | import Language.C.Test.Environment 25 | import Language.C.Test.Framework 26 | import Language.C.Test.ParseTests 27 | import Language.C.Test.TestMonad 28 | 29 | nonParseEnvVar :: String 30 | nonParseEnvVar = "CTEST_NON_PARSE" 31 | 32 | main :: IO () 33 | main = defaultMain usage theParseTest 34 | 35 | usage :: Doc 36 | usage = text "./CParse [gcc-opts] file.(c|hc|i)" 37 | $$ nest 4 (text "Test Driver: Parses the given source file") 38 | $$ envHelpDoc [ (nonParseEnvVar, ("expected that the parse fails",Just "False")) ] 39 | 40 | theParseTest :: [String] -> TestMonad () 41 | theParseTest args = 42 | case mungeCcArgs args of 43 | Ignore -> errorOnInit args $ "No C source file found in argument list: `cc " ++ unwords args ++ "'" 44 | Unknown err -> errorOnInit args $ "Could not munge CC args: " ++ err ++ " in `cc "++ unwords args ++ "'" 45 | Groked [origFile] gccArgs -> theParseTest' origFile gccArgs 46 | Groked cFiles _ -> errorOnInit args $ "More than one source file given: " ++ unwords cFiles 47 | 48 | theParseTest' :: FilePath -> [String] -> TestMonad () 49 | theParseTest' origFile gccArgs = do 50 | modify $ setTmpTemplate (takeBaseName origFile) 51 | 52 | expectNonParse <- liftIO$ getEnvFlag nonParseEnvVar 53 | dbgMsg $ "Expecting that the C source file " ++ (if expectNonParse then " doesn't parse" else "parses") ++ ".\n" 54 | 55 | (cFile, preFile) <- runCPP origFile gccArgs 56 | modify $ setTestRunResults (emptyTestResults (takeBaseName origFile) [cFile]) 57 | parseResult <- runParseTest preFile (initPos cFile) 58 | case expectNonParse of 59 | True -> 60 | let parseTest1 = initializeTestResult (parseTestTemplate { testName = "01-fail-parse" }) [origFile] in 61 | addTestM $ 62 | setTestStatus parseTest1 $ 63 | either (\(_,report) -> testOkUntimed (Just report)) -- no timing available 64 | (\_ -> testFailNoReport "parse should fail, but succeeded") parseResult 65 | False -> 66 | let parseTest1 = initializeTestResult (parseTestTemplate { testName = "01-parse" }) [origFile] in 67 | addTestM $ 68 | setTestStatus parseTest1 $ 69 | either (\(errMsg,report) -> testFailWithReport errMsg report) 70 | (\(_,perf) -> testOkNoReport perf) parseResult 71 | -------------------------------------------------------------------------------- /reference/test/src/CheckGccArgs.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS #-} 2 | ----------------------------------------------------------------------------- 3 | -- | 4 | -- Module : CCheckGccArgs 5 | -- Copyright : (c) 2008 Benedikt Huber 6 | -- License : BSD-style 7 | -- Maintainer : benedikt.huber@gmail.com 8 | -- 9 | -- Check if the given gcc args are fine to perform a parse test. 10 | -- Essentially a 'one-liner', used by cc-wrapper. 11 | ----------------------------------------------------------------------------- 12 | module Main (main) 13 | where 14 | import System.Environment 15 | import System.Exit 16 | import Language.C.Test.Environment 17 | 18 | main :: IO () 19 | main = do 20 | args <- getArgs 21 | case mungeCcArgs args of 22 | Ignore -> exitWith (ExitFailure 1) 23 | Unknown _ -> exitWith (ExitFailure 1) 24 | Groked [cfile] _ | cfile == "conftest.c" -> exitWith (ExitFailure 1) -- exclude ./configure stuff 25 | | otherwise -> exitWith ExitSuccess 26 | Groked _ _ -> exitWith (ExitFailure 1) -------------------------------------------------------------------------------- /reference/test/src/ReportFatal.hs: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- | 3 | -- Module : CReportFatal.hs (executable) 4 | -- Copyright : (c) 2008 Benedikt Huber 5 | -- License : BSD-style 6 | -- Maintainer : benedikt.huber@gmail.com 7 | -- 8 | -- Report a fatal error in a test (cannot be done within the test itself, e.g. out-of-memory) 9 | -- Reads the error message from stdin. 10 | ----------------------------------------------------------------------------- 11 | module Main (main) 12 | where 13 | import Language.C.Test.Framework 14 | 15 | import System.Environment (getArgs) 16 | import System.IO (hPutStrLn, stderr) 17 | import System.Exit (exitWith,ExitCode(..)) 18 | 19 | bail :: String -> IO a 20 | bail msg = hPutStrLn stderr msg >> exitWith (ExitFailure 1) >> error "" 21 | usage :: String 22 | usage = "ReportFatal report-file.dat arg_1 [ ... arg_n ] < error-log" 23 | main :: IO () 24 | main = do 25 | arguments <- getArgs 26 | (reportFile,testargs) <- 27 | case arguments of 28 | (rf:args@(_:_)) -> do 29 | return (rf,args) 30 | _ -> bail usage 31 | errMsg <- getContents 32 | appendFile reportFile $ show FatalError { fatalErrMsg = errMsg, runArgs = testargs } ++ "\n" 33 | 34 | -------------------------------------------------------------------------------- /reference/test/suite/README: -------------------------------------------------------------------------------- 1 | # Install gcc.dg test suite 2 | RURL=https://github.com/gcc-mirror/gcc.git 3 | RPATH=gcc/testsuite/gcc.dg 4 | git clone $RURL gcc-mirror 5 | mv gcc-mirror/$RPATH gcc.dg 6 | rm -rf gcc-mirror 7 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/additional_builtins.c: -------------------------------------------------------------------------------- 1 | /* not really bugs, but additional built-in types */ 2 | __float128 x = 0.3; 3 | __float80 y = 0.3; 4 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/assignment_prec_1.c: -------------------------------------------------------------------------------- 1 | void foo() { 2 | /* conditional <-> assignment */ 3 | int x,y; 4 | int u = ( y = 2 ? 3 : 0 ); 5 | int u_ = ( (y = 2) ? 3 : 0 ); 6 | int v = ( y = (2 ? 3 : 0)); 7 | /* no longer supported by gcc 4.5 */ 8 | /* int w = ( (2 ? x : y) = x); // Warning (not really an lvalue) */ 9 | int s = ( 2 ? 3 : (y = x)); 10 | } 11 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/assignment_prec_2.c: -------------------------------------------------------------------------------- 1 | /* Not really a bug (isn't valid C99), but a discrepancy to gcc */ 2 | int bar(int w) { return ( w ? w : w = w); } // not really an lvalue 3 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/ast_empty_struct.c: -------------------------------------------------------------------------------- 1 | /* 20080614: In a definition ... */ 2 | struct c; /* .. is a forward decl. */ 3 | struct c { }; /* .. is an empty struct def. */ 4 | /* They must not be represented using the same AST */ -------------------------------------------------------------------------------- /reference/test/suite/bugs/attr.c: -------------------------------------------------------------------------------- 1 | void foo() __attribute__((noreturn, noreturn)) 2 | __attribute__((noreturn)); 3 | 4 | /* From the gnu examples */ 5 | __attribute__((noreturn)) void 6 | d0 (void), 7 | __attribute__((format(printf, 1, 2))) d1 (const char *, ...), 8 | d2 (void) ; 9 | 10 | /* gcc.dg/attr4 */ 11 | extern __attribute__((format(printf, 1, 2))) void tformatprintf0 (const char *, ...); 12 | extern void __attribute__((format(printf, 1, 2))) tformatprintf1 (const char *, ...); 13 | extern void foo (void), __attribute__((format(printf, 1, 2))) tformatprintf2 (const char *, ...); 14 | extern __attribute__((noreturn)) void bar (void), __attribute__((format(printf, 1, 2))) tformatprintf3 (const char *, ...); 15 | 16 | /* gcc.dg/fundef-attr */ 17 | int (__attribute__((const)) x) (a, b) 18 | int a; 19 | int b; 20 | { 21 | return a + b; 22 | } 23 | typedef void * va_list; 24 | 25 | /* gcc.dg/mult-attr */ 26 | extern __attribute__((__format__(__printf__, 1, 0))) void 27 | my_vprintf_scanf (const char *, va_list, const char *, ...) 28 | __attribute__((__format__(__scanf__, 3, 4))); 29 | extern void (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf2) 30 | (const char *, va_list, const char *, ...) 31 | __attribute__((__format__(__scanf__, 3, 4))); 32 | 33 | extern __attribute__((__format__(__scanf__, 3, 4))) void 34 | (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf3) 35 | (const char *, va_list, const char *, ...); 36 | 37 | /* various other attributes */ 38 | void __attribute__((dj)) foo() { } 39 | typedef enum { a } __attribute__((packed)) t; 40 | unsigned __l __attribute__((__mode__(__SI__))); 41 | double foo_01_12 (void) 42 | { 43 | return (__extension__ ((union { unsigned __l __attribute__((__mode__(__SI__))); float __d; }) { __l: 0x3f800000UL }).__d); 44 | } -------------------------------------------------------------------------------- /reference/test/suite/bugs/builtin_typedefs.c: -------------------------------------------------------------------------------- 1 | /* Pretty printer: correct names for _Bool, _Complex etc. */ 2 | _Bool foo; 3 | _Complex bar; 4 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/decl_attr.c: -------------------------------------------------------------------------------- 1 | #define D __attribute__((deprecated)) 2 | int x_1,x_2 D; 3 | int x_3 D, x_4; 4 | int x_5, D x_6; 5 | int D x_7, x_8; 6 | struct { int a; } D x_9, x_10; 7 | D struct { int a; } x_11, x_12; 8 | struct { int a; } volatile D x_13, x_14; 9 | struct { 10 | int a; 11 | struct { int a_1; } D x_16, x_17; 12 | D struct { int a_2; } x_18, x_19; 13 | struct { int a_3; } const D x_20, x_21; 14 | struct { int a_4; } x_22 D, x_23; 15 | struct { int a_5; } x_24, D x_25; 16 | struct { int a_6; } x_26, x_27 D; 17 | } x_15; 18 | enum E { 19 | ev_0 = 0, 20 | ev_1 D = 1, 21 | ev_2 D D = 2, 22 | ev_3, 23 | ev_4 D, 24 | ev_5 D D 25 | }; 26 | int main() { 27 | /* x_2, x_3, x_6 */ 28 | return x_1+x_2+x_3+x_4+x_5+x_6+x_7+x_8+x_9.a+x_10.a+x_11.a+x_12.a 29 | + x_13.a + x_14.a + x_15.x_16.a_1 + x_15.x_17.a_1 + x_15.x_18.a_2 + x_15.x_19.a_2 + 30 | x_15.x_20.a_3 + x_15.x_21.a_3 + x_15.x_22.a_4 + x_15.x_23.a_4 + x_15.x_24.a_5 + x_15.x_25.a_5 31 | + x_15.x_26.a_6 + x_15.x_27.a_6; // + x_15.x_28.a; 32 | } 33 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/elseif11K.c: -------------------------------------------------------------------------------- 1 | /* PR c/2161: parser stack overflow. */ 2 | /* { dg-do compile } */ 3 | 4 | #define ONE else if (0) { } 5 | #define TEN ONE ONE ONE ONE ONE ONE ONE ONE ONE ONE 6 | #define HUN TEN TEN TEN TEN TEN TEN TEN TEN TEN TEN 7 | #define THOU HUN HUN HUN HUN HUN HUN HUN HUN HUN HUN 8 | 9 | void foo() 10 | { 11 | if (0) { } 12 | /* 11,000 else if's. */ 13 | THOU THOU THOU THOU THOU THOU THOU THOU THOU THOU THOU 14 | } 15 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/empty.c: -------------------------------------------------------------------------------- 1 | /* an empty file */ -------------------------------------------------------------------------------- /reference/test/suite/bugs/empty_enum.c: -------------------------------------------------------------------------------- 1 | /* This also _might_ indicate a principle design bug in the AST : 2 | * The decl `enum empty_enum;` 3 | * and the first parameter of `void foo(enum empty_enum);` have the same AST. 4 | * Not sure yet. 5 | */ 6 | enum empty_enum; 7 | void foo (enum empty_enum); 8 | enum non_empty { E1, E2 = 3 }; 9 | void bar (enum non_empty); 10 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/float_non_compile.c: -------------------------------------------------------------------------------- 1 | double g = 0x00f.e; /* error: hexadecimal constants require an exponent */ 2 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/gen_lex_stress.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | def indent(str,i) 3 | str.split("\n").map { |s| (" "*i) + s }.join("\n") 4 | end 5 | if_stmt=<<-EOF 6 | if (0) 7 | { 8 | ; 9 | } 10 | EOF 11 | 12 | ($stderr.puts "Usage: ./gen_lex_stress.rb number-of-levels" ; exit 1) unless ARGV.first 13 | levels = ARGV.first.to_i 14 | if(levels > 5000) 15 | $stderr.puts "Warning: Creating more than 5000 levels isn't recommended and maybe crash your system" 16 | exit 1 17 | end 18 | preamble=<<-EOF 19 | /* Lexer stress test (#{levels} levels) 20 | * Produces nested if then else, with increasing indentation. 21 | * The lexer shouldn't consume too much memory (try +RTS -32M -RTS) or take too much time 22 | * gcc doesn't have any problems with this one, and only takes ~2.5s for 5K levels (240 Mb) 23 | */ 24 | void foo() 25 | { 26 | EOF 27 | 28 | puts preamble 29 | i=4 30 | 1.upto(levels) do 31 | puts indent(if_stmt,i) 32 | puts indent("else",i) 33 | i+=4 34 | end 35 | puts indent(if_stmt,i) 36 | puts "}" -------------------------------------------------------------------------------- /reference/test/suite/bugs/gnu_complex.c: -------------------------------------------------------------------------------- 1 | __complex__ float c; 2 | int main() { 3 | float i = __imag (c*2); 4 | float r = __real (c-2); 5 | __complex__ double x = 2LLj + 2.0fj; 6 | } -------------------------------------------------------------------------------- /reference/test/suite/bugs/hex_float_1.c: -------------------------------------------------------------------------------- 1 | double f = 0x.aP+0L; 2 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/hex_float_2.c: -------------------------------------------------------------------------------- 1 | long double d = 0x0.0000003ffffffff00000p-16357L; 2 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/ifpp.c: -------------------------------------------------------------------------------- 1 | int f(int d) 2 | { 3 | int i = 0, j, k, l; 4 | if (d%2==0) 5 | if (d%3==0) 6 | i+=2; 7 | else 8 | i+=3; 9 | if (d%2==0) 10 | { 11 | if (d%3==0) 12 | i+=7; 13 | } 14 | else 15 | i+=11; 16 | 17 | l = d; 18 | if (d%2==0) 19 | while (l--) 20 | if (1) 21 | i+=13; 22 | else 23 | i+=17; 24 | l = d; 25 | 26 | if (d%2==0) 27 | { 28 | while (l--) 29 | if (1) 30 | i+=21; 31 | } 32 | else 33 | i+=23; 34 | 35 | if (d==0) 36 | i+=27; 37 | else if (d%2==0) 38 | if (d%3==0) 39 | i+=29; 40 | else if (d%5==0) 41 | if (d%7==0) 42 | i+=31; 43 | else 44 | i+=33; 45 | return i; 46 | } 47 | int main() 48 | { 49 | int i,k=0; 50 | for(i=0;i<255;i++) 51 | { 52 | k+=f(i); 53 | } 54 | printf("Result: %d\n",k); 55 | } -------------------------------------------------------------------------------- /reference/test/suite/bugs/int_non_compile.c: -------------------------------------------------------------------------------- 1 | int i = 192394Ll; /* error: invalid suffix "Ll" on integer constant */ 2 | int j = 192345lll; 3 | int k = 192345ul; 4 | int l = 192345uul; 5 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/local_labels.c: -------------------------------------------------------------------------------- 1 | void foo() { 2 | do { 3 | __label__ go; 4 | { 5 | __label__ foo,bar; 6 | foo: 7 | bar: ; 8 | } 9 | go: ; 10 | foo: ; 11 | } while(0); 12 | } 13 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/member_ident.c: -------------------------------------------------------------------------------- 1 | /* Different kind of identifier */ 2 | typedef int x; // x is now a typedef-ident 3 | struct mystruct { x x; struct mystruct* y; }; // Members 4 | x bar() { 5 | return __builtin_offsetof( struct mystruct, x ) 6 | /* avoid gcc error */ 7 | /* + __builtin_offsetof( struct mystruct, y[0].y[dyn()].x ); */ 8 | + __builtin_offsetof( struct mystruct, y ); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/offset_of.c: -------------------------------------------------------------------------------- 1 | /* x will be a typdef at this point */ 2 | typedef struct point { int x; int y; } x; 3 | int foo() { 4 | struct point y = (struct point) { .x = 2, .y = 3 }; 5 | x z = y; 6 | int x_off = __builtin_offsetof( struct point , x ); 7 | int x_off_2 = __builtin_offsetof( x , x ); 8 | } -------------------------------------------------------------------------------- /reference/test/suite/bugs/pp_address_of_label.c: -------------------------------------------------------------------------------- 1 | int foo() { 2 | int x = 5; 3 | void *p; 4 | c1: 5 | x--; 6 | goto c3; 7 | c2: 8 | x = 4; 9 | goto c4; 10 | c3: 11 | p = (x > 3) ? &&c1 : &&c2; 12 | goto *(p + 1); 13 | c4: 14 | goto c1; 15 | } 16 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/pp_align_of.c: -------------------------------------------------------------------------------- 1 | typedef float v4 __attribute__((vector_size(sizeof(float)*4))); 2 | typedef struct point { int x; int y; } Point; 3 | extern char compile_time_assert[__alignof__(v4) == sizeof(float)*4 ? 1 : -1]; 4 | extern char compile_time_assert[__alignof(v4) == sizeof(float)*4 ? 1 : -1]; 5 | extern char compile_time_assert[__alignof(v4) == sizeof(float)*4 ? 1 : -1]; 6 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/pp_assign_prec.c: -------------------------------------------------------------------------------- 1 | /* Pretty printer: assignment has higher precedence than comma */ 2 | int main() { 3 | int b; 4 | int a = b, c; /* Block Decl int */ 5 | int y = (y,0); /* InitExpr (y,0) */ 6 | int x = ( (y = 3), y - 2); 7 | int z = ( (y ? 2 : 3) , 4 ) ; 8 | int u_ = ( (y = 2) ? 3 : 0 ); 9 | int v = ( y = (2 ? 3 : 0)); 10 | /* no longer supported by gcc */ 11 | /* int w = ( (2 ? x : y) = x); // Warning (not really an lvalue) */ 12 | int s = ( 2 ? 3 : (y = x)); 13 | } 14 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/pp_case_range.c: -------------------------------------------------------------------------------- 1 | enum a { a0, a3 }; 2 | int error(enum a e) 3 | { 4 | switch ( e ) 5 | { 6 | case a0 ... a3: 7 | return 1; 8 | } 9 | } -------------------------------------------------------------------------------- /reference/test/suite/bugs/pp_compound_lit.c: -------------------------------------------------------------------------------- 1 | /* Test compound literals and statement expressions */ 2 | typedef struct point { int x; int y; } Point; 3 | void drawline(Point x, Point y); 4 | void drawline_(Point *x, Point *y); 5 | 6 | /* partial initializer */ 7 | struct s { int a; int b; int c; }; 8 | struct s s6 = { .a = 1 }; 9 | 10 | /* array special form */ 11 | unsigned int a[19] = { 3, 4, 0, 2, 2, [17] = 3, 3 }; 12 | 13 | /* old style */ 14 | union { 15 | double d; 16 | long long l; 17 | } x = { l: 0x7ff8000000000000LL }; 18 | 19 | /* Compound literals */ 20 | int *p = (int []) {2, 4}; 21 | const float* pows = (const float []) {1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}; 22 | int examples() { 23 | int *q = (int [2]) { p[1], p[0] }; 24 | drawline( (struct point){.x=1, .y=1}, (struct point){ .x = 3, .y = 4}); 25 | drawline_( &(struct point){.x=1, .y=1}, &(struct point){.x=1,.y=4}); 26 | 27 | } 28 | /* Statement expressions */ 29 | void gnu() { 30 | int a = 2, b = 3; 31 | int max_a_b = 32 | ({int _a = (a), _b = (b); _a > _b ? _a : _b; }); 33 | int complex_a_b = ({int _c = (a); 34 | while (_c > 0) { _c --; a = a + b; } 35 | a + b + _c; }); 36 | } 37 | void strange() { 38 | char x = ( char ) { 2, } ; /* ok */ 39 | char* y = ( char[3] ) { 'a', x, x = 'b' }; 40 | char z = ({ 'a', x, x = 'b'; }); 41 | } -------------------------------------------------------------------------------- /reference/test/suite/bugs/pp_decrement.c: -------------------------------------------------------------------------------- 1 | void b (int x) { 2 | if (- (-x) - (-x)) 3 | link_error (); 4 | } 5 | void c (int x) { 6 | if (+ (+x) - x) 7 | link_error (); 8 | } 9 | -------------------------------------------------------------------------------- /reference/test/suite/bugs/pp_old_style_decl.c: -------------------------------------------------------------------------------- 1 | /* Note: It is incorrect to drop the identifier list in an old-style function declaration 2 | (it determines the order of the arguments) */ 3 | long 4 | foo1(y,x) 5 | register int x; 6 | register long y; 7 | { 8 | return x-y; 9 | } 10 | 11 | long 12 | foo2(x,y) 13 | register int x; 14 | register long y; 15 | { 16 | return x-y; 17 | } 18 | int main() { 19 | printf("%d // %d\n", foo1(2,3), foo2(2,3)); 20 | } -------------------------------------------------------------------------------- /reference/test/suite/bugs/qualifier_pretty.c: -------------------------------------------------------------------------------- 1 | extern const char *const sys_errlist[]; -------------------------------------------------------------------------------- /reference/test/suite/bugs/restrict.c: -------------------------------------------------------------------------------- 1 | /* 2 | f takes: 3 | an array of restricted pointers to int 4 | an restricted array of restricted pointers to int 5 | */ 6 | void f(int *restrict a[2], int *restrict c[restrict]); -------------------------------------------------------------------------------- /reference/test/suite/bugs/struct_attr.c: -------------------------------------------------------------------------------- 1 | /* Yes ! The first 'bug' I found in CIL :) */ 2 | int x __attribute__((deprecated)); 3 | struct s0 { int x __attribute__((deprecated)); }; 4 | struct s { int x; } __attribute__((packed)) 5 | const __attribute__((deprecated)) S_CONST = { 3 }; 6 | struct t { int x; } f() __attribute__((deprecated)), g(); 7 | struct u1 { int x; } (__attribute__((deprecated)) h)(void); 8 | struct u2 { int y; } i(void) __attribute__((deprecated)); 9 | struct u3 { int y; } j __attribute__((deprecated)); 10 | int main() { f(); g(); return S_CONST.x; } 11 | /* Expected -Wall warnings: S_CONST is deprecated, f() is deprecated */ 12 | -------------------------------------------------------------------------------- /reference/test/suite/classify-dg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source ./configuration 3 | 4 | BASE_DIR=`pwd` 5 | 6 | if [ ! -d gcc_dg ] ; then 7 | if [ -e gcc_dg.tgz ] ; then 8 | echo "Extracting gcc_dg.tgz" 9 | tar xzf ${BASE_DIR}/gcc_dg.tgz 10 | cd gcc_dg 11 | else 12 | echo "gcc_dg / gcc_dg.tgz not found" >&2 13 | exit 1 14 | fi 15 | else 16 | cd gcc_dg 17 | fi 18 | DG_DIR=`pwd` 19 | echo $DG_DIR 20 | 21 | for cf in `find . -name '*.c'`; do 22 | cd $DG_DIR/`dirname $cf` 23 | f=`basename $cf` 24 | echo "Processing $f" 25 | grep -e "^$f" $BASE_DIR/dg-ignore.txt 26 | if [ $? -eq 0 ]; then echo " ... skipped"; continue; fi 27 | 28 | COMPLIANCE= 29 | gcc -c -ansi -pedantic-errors $f 2>/dev/null 30 | if [ $? -eq 0 ] ; then COMPLIANCE=c89; fi 31 | if [ -z $COMPLIANCE ] ; then 32 | gcc -c -std=c99 -pedantic-errors $f 2>/dev/null 33 | if [ $? -eq 0 ] ; then COMPLIANCE=c99; fi 34 | fi 35 | if [ -z $COMPLIANCE ] ; then 36 | gcc -c -std=gnu9x -pedantic-errors $f 2>/dev/null 37 | if [ $? -eq 0 ] ; then COMPLIANCE=gnu99; fi 38 | fi 39 | if [ -z $COMPLIANCE ] ; then 40 | gcc -c -std=c11 -pedantic-errors $f 2>/dev/null 41 | if [ $? -eq 0 ] ; then COMPLIANCE=c11; fi 42 | fi 43 | if [ -z $COMPLIANCE ] ; then 44 | gcc -c -std=gnu11 -pedantic-errors $f 2>/dev/null 45 | if [ $? -eq 0 ] ; then COMPLIANCE=gnu11; fi 46 | fi 47 | if [ -z $COMPLIANCE ] ; then 48 | gcc -c -std=gnu9x $f 2>/dev/null 49 | if [ $? -eq 0 ] ; then COMPLIANCE=incompliant; fi 50 | fi 51 | if [ ! -z $COMPLIANCE ] ; then 52 | echo "[INFO] Classified Test $f as ($COMPLIANCE)" 53 | mkdir -p "$BASE_DIR/gcc-dg-$COMPLIANCE" 54 | cp "$DG_DIR/$cf" "$BASE_DIR/gcc-dg-$COMPLIANCE/./" 55 | fi 56 | done 57 | -------------------------------------------------------------------------------- /reference/test/suite/compile-lib.template: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Template for executing test suites 3 | source ./configuration 4 | 5 | source $CTEST_BINDIR/setup_test_suite my-lib 6 | 7 | export CC=$CTEST_BINDIR/cc-wrapper 8 | cd my-lib-dir 9 | 10 | # Waste of time if run each time 11 | if [ -n $RUN_CONFIGURE ]; then 12 | ./configure 13 | fi 14 | make clean 2> /dev/null 15 | make my-lib-target 16 | -------------------------------------------------------------------------------- /reference/test/suite/configuration: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Common configuration 3 | export CTEST_BINDIR=`pwd`/../bin 4 | export CTEST_RESULTDIR=`pwd`/../results 5 | source $CTEST_BINDIR/setup 6 | -------------------------------------------------------------------------------- /reference/test/suite/dg-ignore.txt: -------------------------------------------------------------------------------- 1 | filename reason 2 | 3 | dollar.c Extended Source Character Set 4 | 5 | digraph1.c Digraphs 6 | digraphs.c Digraphs 7 | paste2.c Digraphs 8 | 9 | lexnum.c Trigraphs 10 | lexstrng.c Trigraphs 11 | pr18502-1.c Trigraphs 12 | trigraphs.c Trigraphs 13 | 14 | escape.c UNC 15 | ucnid-1.c UNC 16 | ucnid-2.c UNC 17 | ucnid-3.c UNC 18 | ucnid-4.c UNC 19 | ucnid-5.c UNC 20 | ucnid-6.c UNC 21 | ucnid-9.c UNC 22 | ucnid-10.c UNC 23 | ucnid-11.c UNC 24 | ucnid-12.c UNC 25 | ucnid-13.c UNC 26 | ucnid-14.c UNC 27 | attr-alias-5.c UNC 28 | 29 | 30 | ia64-float80-1.c float80 builtin 31 | ia64-postinc.c float128 builtin 32 | fp-int-convert-float128 float128 builtin 33 | 34 | c99-float-1.c Preprocessor fails 35 | 36 | cast-lvalue-2.c casting an lvalue 37 | 38 | concat.c 390K input size 39 | concat2.c 390K input size 40 | 41 | anon-struct-6.c qualifier without declaration 42 | anon-struct-7.c qualifier without declaration 43 | anon-struct-8.c qualifier without declaration 44 | declspec-14.c qualifier without declaration 45 | declspec-15.c qualifier without declaration 46 | 47 | c90-init-1.c obsolete use of designated initializer without `=' 48 | init-desig-obs-2.c obsolete use of designated initializer without `=' 49 | init-desig-obs-3.c obsolete use of designated initializer without `=' 50 | 51 | pr69522.c gcc bug (5.3.0 does not termiante) 52 | c90-array-lval.c does not compile 53 | 20100423-2_0.c does not compile 54 | no-asm-4.c -fno-asm not supported, asm always treated as keyword 55 | pr67964.c unsupported __attribute__((const const)) 56 | -------------------------------------------------------------------------------- /reference/test/suite/preprocess-dg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source ./configuration 3 | 4 | if [ -z $2 ] ; then 5 | echo "Usage: $0 gcc_dg gcc_pre" >&2 6 | exit 1 7 | fi 8 | 9 | BASE_DIR=`pwd` 10 | IN_DIR=`pwd`/$1 11 | IN_ARCHIVE=$1.tgz 12 | OUT_DIR=`pwd`/$2 13 | 14 | if [ ! -d "${IN_DIR}" ] ; then 15 | if [ -e "${IN_ARCHIVE}" ] ; then 16 | echo "Extracting ${IN_ARCHIVE}" 17 | tar xzf ${BASE_DIR}/"${IN_ARCHIVE}" 18 | cd gcc_dg 19 | else 20 | echo "${IN_DIR} / ${IN_ARCHIVE} not found" >&2 21 | exit 1 22 | fi 23 | else 24 | if [ ! -e "${OUT_DIR}" ] ; then 25 | mkdir -p ${OUT_DIR} 26 | fi 27 | if [ ! -d "${OUT_DIR}" ] ; then 28 | echo "Not a directory: ${OUT_DIR}" >&2 29 | exit 1 30 | fi 31 | cd "$IN_DIR" 32 | fi 33 | 34 | echo $IN_DIR to $OUT_DIR 35 | 36 | for cf in `find . -name '*.c'`; do 37 | cd $IN_DIR/`dirname $cf` 38 | f=`basename $cf` 39 | echo "Processing $f" 40 | grep -e "^$f" $BASE_DIR/dg-ignore.txt 41 | if [ $? -eq 0 ]; then echo " ... skipped"; continue; fi 42 | gcc -E -std=gnu9x $f -o "$OUT_DIR/${f/.c/.i}" 43 | done 44 | -------------------------------------------------------------------------------- /reference/test/suite/run-bugs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source ./configuration 3 | 4 | source $CTEST_BINDIR/setup_test_suite bugs 5 | 6 | # export CTEST_DEBUG=1 7 | export CTEST_DRIVER=CRoundTrip 8 | 9 | cd bugs 10 | export CTEST_DRIVER=CRoundTrip 11 | # TODO: NonCompile test driver 12 | for f in `ls *.c | grep -v non_compile | grep -v concat | grep -v intconst | grep -v elseif`; do 13 | bash run-test $f 14 | done 15 | export CTEST_DRIVER=CParse 16 | export CTEST_NON_PARSE=1 17 | for f in `ls *.c | grep non_compile`; do 18 | echo "Checking if $f does NOT compile" 19 | bash run-test $f 20 | done 21 | 22 | -------------------------------------------------------------------------------- /reference/test/suite/run-dg-list.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | source ./configuration 3 | 4 | if [ $# -eq 0 ]; then 5 | echo "Usage: run-dg-list.sh dg-test-1.c ..." 6 | exit 1 7 | fi 8 | 9 | TEST_SUITE="gcc-dg-selection" 10 | sh clear_test_suite $TEST_SUITE 11 | source $CTEST_BINDIR/set_test_suite $TEST_SUITE 12 | export CTEST_DRIVER=CRoundTrip 13 | 14 | BASE_DIR=`pwd` 15 | cd gcc.dg 16 | DG_DIR=`pwd` 17 | for cf in $@ ; do 18 | for f in `find . -name $cf | grep -v noncompile`; do 19 | echo "[INFO] Running Test $f" 20 | # grep -e "^$f" $BASE_DIR/dg-ignore.txt 21 | # if [ $? -eq 0 ]; then echo " ... skipped"; continue; fi 22 | # grep -e "__attribute__" $f >/dev/null 23 | # if [ $? -ne 0 ]; then continue; fi 24 | 25 | gcc -I$DG_DIR -I$DG_DIR/cpp -fsyntax-only -std=gnu9x $f 2>/dev/null 26 | if [ $? -eq 0 ] ; then 27 | bash run-test $f 28 | else 29 | echo "[ERROR] Not running Test $f" 30 | gcc -I$DG_DIR -I$DG_DIR/cpp -fsyntax-only -std=gnu9x $f 31 | echo "[EXIT]" 32 | exit 1 33 | fi 34 | done 35 | done 36 | -------------------------------------------------------------------------------- /reference/test/suite/run-dg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | for t in gcc-dg-* ; do 3 | if [ ! -d "${t}" ] ; then 4 | continue 5 | fi 6 | echo "-----------------------" 7 | echo "Running gcc dg suite $t" 8 | echo "-----------------------" 9 | ./run-suite.sh $t `find gcc.dg -name '*.h' | xargs dirname | sort | uniq | sed 's/^/-I..\//'` 10 | done 11 | -------------------------------------------------------------------------------- /reference/test/suite/run-smoke.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source ./configuration 3 | 4 | source $CTEST_BINDIR/setup_test_suite smoke 5 | 6 | # export CTEST_DEBUG=1 7 | 8 | cd smoke 9 | 10 | export CTEST_DRIVER=CParse 11 | # sh run-test doesnotexist.c 12 | export CTEST_NON_PARSE=1 13 | bash run-test test_non_parse.c 14 | export CTEST_NON_PARSE=0 15 | bash run-test test.c 16 | 17 | export CTEST_DRIVER=CRoundTrip 18 | for f in `ls *.c | grep -v non_parse | grep -v equiv`; do bash run-test $f; done; 19 | 20 | export CTEST_DRIVER=CEquiv 21 | export CTEST_NON_EQUIV=1 22 | bash run-test test.c test1.c 23 | bash run-test test_attr.non_equiv_1.c test_attr.non_equiv_2.c 24 | unset CTEST_NON_EQUIV 25 | bash run-test test.c test.c 26 | 27 | cd ../decls 28 | export CTEST_DRIVER=CRoundTrip 29 | for f in `ls *.c | grep -v non_parse | grep -v equiv`; do bash run-test $f; done; 30 | -------------------------------------------------------------------------------- /reference/test/suite/run-suite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source ./configuration 3 | 4 | if [ -z "$1" ] ; then 5 | echo "Usage: ./run-suite.sh .." >&2 6 | exit 1 7 | fi 8 | TEST_SUITE=$1 9 | shift 10 | bash clear_test_suite $TEST_SUITE 11 | source $CTEST_BINDIR/set_test_suite $TEST_SUITE 12 | export CTEST_DRIVER=CRoundTrip 13 | 14 | pushd $TEST_SUITE 15 | for cf in `find . -name '*.c'`; do 16 | echo "[INFO] Running Test $TEST_SUITE::$cf" 17 | bash run-test $@ $cf 18 | done 19 | -------------------------------------------------------------------------------- /reference/test/suite/smoke/elsif.c: -------------------------------------------------------------------------------- 1 | /* #include */ 2 | int printf(const char * restrict format, ...); 3 | 4 | /* Test if-else pretty-printing */ 5 | int main () { 6 | int inp = 0; 7 | 8 | if(inp == 0) inp=1; 9 | else inp=2; 10 | 11 | if(inp == 0) { 12 | inp = 2; 13 | inp = 3; 14 | } 15 | 16 | if(inp == 0) { 17 | inp=1; 18 | } 19 | else inp=2; 20 | 21 | if(0 == inp) { 22 | if(1 == inp) ; 23 | else if(2 == inp) ; 24 | else if(3 == inp) { 25 | if(3 == inp) { 26 | ; 27 | } else if(4 == inp) ; 28 | else ; 29 | } 30 | } 31 | else if (1 == inp) { } 32 | else if (2 == inp) { } 33 | else if (3 == inp) { printf("inp=3\n"); } 34 | else if (4 == inp) { } 35 | else if (5 == inp) { } 36 | else if (6 == inp) { } 37 | } 38 | -------------------------------------------------------------------------------- /reference/test/suite/smoke/test.c: -------------------------------------------------------------------------------- 1 | typedef int bar; 2 | int foo() { 3 | return 2+ (bar) 3.0; 4 | } -------------------------------------------------------------------------------- /reference/test/suite/smoke/test1.c: -------------------------------------------------------------------------------- 1 | typedef int bar; 2 | int foo() { 3 | return 2 * (bar) 3.0; 4 | } -------------------------------------------------------------------------------- /reference/test/suite/smoke/test_attr.non_equiv_1.c: -------------------------------------------------------------------------------- 1 | int my_wait(int *) __asm("_" "wait" "$UNIX2003"); 2 | typedef int bar; 3 | int foo() { 4 | return 2+ (bar) 3.0; 5 | } 6 | -------------------------------------------------------------------------------- /reference/test/suite/smoke/test_attr.non_equiv_2.c: -------------------------------------------------------------------------------- 1 | int my_wait(int *) __asm("_" "wait" "$UNIX2004"); 2 | typedef int bar; 3 | int foo() { 4 | return 2+ (bar) 3.0; 5 | } 6 | -------------------------------------------------------------------------------- /reference/test/suite/smoke/test_non_parse.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return (2,); 3 | } -------------------------------------------------------------------------------- /regen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -x 5 | 6 | if [ "$1" = "-u" ]; then 7 | git submodule update --recursive --remote 8 | fi 9 | 10 | cd deps/happy-rust 11 | if [ ! -f stack.yaml ]; then stack init; fi 12 | stack build 13 | stack exec -- happy ../../src/parser/Parser.y -o ../../src/parser/parser.rs 14 | cd ../.. 15 | 16 | cd deps/alex-rust 17 | if [ ! -f stack.yaml ]; then stack init; fi 18 | stack build 19 | stack exec -- alex ../../src/parser/Lexer.x -o ../../src/parser/lexer.rs 20 | cd ../.. 21 | -------------------------------------------------------------------------------- /src/analysis/debug.rs: -------------------------------------------------------------------------------- 1 | // Original file: "Debug.hs" 2 | // File auto-generated using Corollary. 3 | 4 | #[macro_use] 5 | use corollary_support::*; 6 | 7 | // NOTE: These imports are advisory. You probably need to change them to support Rust. 8 | // use Language::C::Analysis::SemRep; 9 | // use Language::C::Analysis::Export; 10 | // use Language::C::Analysis::DefTable; 11 | // use Language::C::Analysis::NameSpaceMap; 12 | // use Language::C::Data; 13 | // use Language::C::Pretty; 14 | // use Text::PrettyPrint::HughesPJ; 15 | // use Data::Map; 16 | // use Map; 17 | // use Data::Map; 18 | 19 | use analysis::sem_rep::*; 20 | 21 | pub fn prettyAssocs(label: String) -> Doc { 22 | prettyAssocsWith(label, pretty, pretty) 23 | } 24 | 25 | pub fn prettyAssocsWith(label: String, 26 | prettyKey: fn(k) -> Doc, 27 | prettyVal: fn(v) -> Doc, 28 | theMap: Vec<(k, v)>) 29 | -> Doc { 30 | 31 | let prettyEntry = |(k, v)| { 32 | __op_doc_conat(prettyKey(k), 33 | __op_doc_conat(text(" ~> ".to_string()), prettyVal(v))) 34 | }; 35 | 36 | __op_line_something(text(label), nest(8, (vcat(__map!(prettyEntry, theMap))))) 37 | } 38 | 39 | pub fn globalDeclStats(file_filter: fn(FilePath) -> bool, 40 | gmap: GlobalDecls) 41 | -> Vec<(String, isize)> { 42 | 43 | let gmap_q = filterGlobalDecls(filterFile, gmap); 44 | 45 | pub fn filterFile() -> bool { 46 | maybe(true, file_filter, fileOfNode(nodeInfo)) 47 | } 48 | 49 | vec![("Enumeration Constants".to_string(), Map::size(enumerators)), 50 | ("Total Object/Function Declarations".to_string(), Map::size(all_decls)), 51 | ("Object definitions".to_string(), Map::size(objDefs)), 52 | ("Function Definitions".to_string(), Map::size(funDefs)), 53 | ("Tag definitions".to_string(), Map::size(tagDefs)), 54 | ("TypeDefs".to_string(), Map::size(typeDefs))] 55 | } 56 | 57 | pub fn joinComma(input: Vec) -> Doc { 58 | hsep(punctuate(comma, __map!(pretty, input))) 59 | } 60 | 61 | pub fn terminateSemi(input: Vec) -> Doc { 62 | terminateSemi_(__map!(pretty, input)) 63 | } 64 | 65 | pub fn terminateSemi_(input: Vec) -> Doc { 66 | hsep(__map!(|x| __op_ne(semi, x), input)) 67 | } 68 | -------------------------------------------------------------------------------- /src/analysis/mod.rs: -------------------------------------------------------------------------------- 1 | // Original file: "Analysis.hs" 2 | // File auto-generated using Corollary. 3 | 4 | #[macro_use] 5 | use corollary_support::*; 6 | 7 | // NOTE: These imports are advisory. You probably need to change them to support Rust. 8 | // use Language::C::Analysis::SemError; 9 | // use Language::C::Analysis::SemRep; 10 | // use Language::C::Analysis::TravMonad; 11 | // use Language::C::Analysis::AstAnalysis; 12 | // use Language::C::Analysis::DeclAnalysis; 13 | // use Language::C::Analysis::Debug; 14 | 15 | pub mod ast_analysis; 16 | pub mod builtins; 17 | pub mod const_eval; 18 | pub mod debug; 19 | pub mod decl_analysis; 20 | pub mod def_table; 21 | pub mod export; 22 | pub mod name_space_map; 23 | pub mod sem_error; 24 | pub mod sem_rep; 25 | pub mod trav_monad; 26 | pub mod type_check; 27 | pub mod type_conversions; 28 | pub mod type_utils; 29 | -------------------------------------------------------------------------------- /src/analysis/sem_error.rs: -------------------------------------------------------------------------------- 1 | // Original file: "SemError.hs" 2 | // File auto-generated using Corollary. 3 | 4 | #[macro_use] 5 | use corollary_support::*; 6 | 7 | // NOTE: These imports are advisory. You probably need to change them to support Rust. 8 | // use Data::Typeable; 9 | // use Language::C::Analysis::SemRep; 10 | // use Language::C::Data::Error; 11 | // use Language::C::Data::Node; 12 | 13 | use data::node::*; 14 | use analysis::sem_rep::*; 15 | use data::error::*; 16 | 17 | #[derive(Debug)] 18 | pub struct InvalidASTError(pub ErrorInfo); 19 | 20 | 21 | #[derive(Debug)] 22 | pub struct BadSpecifierError(pub ErrorInfo); 23 | 24 | 25 | #[derive(Debug)] 26 | pub struct RedefError(pub ErrorLevel, pub RedefInfo); 27 | 28 | 29 | pub struct RedefInfo(pub String, pub RedefKind, pub NodeInfo, pub NodeInfo); 30 | 31 | 32 | pub enum RedefKind { 33 | DuplicateDef, 34 | DiffKindRedecl, 35 | ShadowedDef, 36 | DisagreeLinkage, 37 | NoLinkageOld, 38 | } 39 | pub use self::RedefKind::*; 40 | 41 | #[derive(Debug)] 42 | pub struct TypeMismatch(pub String, pub (NodeInfo, Type), pub (NodeInfo, Type)); 43 | 44 | 45 | pub fn invalidAST(node_info: NodeInfo, msg: String) -> InvalidASTError { 46 | InvalidAST((mkErrorInfo(LevelError, msg, node_info))) 47 | } 48 | 49 | pub fn badSpecifierError(node_info: NodeInfo, msg: String) -> BadSpecifierError { 50 | BadSpecifierError((mkErrorInfo(LevelError, msg, node_info))) 51 | } 52 | 53 | pub fn typeMismatch() -> TypeMismatch { 54 | TypeMismatch 55 | } 56 | 57 | pub fn typeMismatchInfo(TypeMismatch(reason, (node1, _ty2), _t2): TypeMismatch) -> ErrorInfo { 58 | ErrorInfo(LevelError, (posOfNode(node1)), vec![reason]) 59 | } 60 | 61 | pub fn redefErrLabel(RedefInfo(ident, _, _, _): RedefInfo) -> String { 62 | __op_addadd(ident, " redefined".to_string()) 63 | } 64 | 65 | pub fn redefErrorInfo(lvl: ErrorLevel, info: RedefInfo, __OP__: ErrorInfo) -> ErrorInfo { 66 | ErrorInfo(lvl, 67 | (posOfNode(node)), 68 | (__op_addadd(vec![redefErrReason(info)], prevDeclMsg(old_node)))) 69 | } 70 | 71 | pub fn redefErrReason(_0: RedefInfo) -> String { 72 | match (_0) { 73 | RedefInfo(ident, DuplicateDef, _, _) => { 74 | __op_addadd("duplicate definition of ".to_string(), ident) 75 | } 76 | RedefInfo(ident, ShadowedDef, _, _) => { 77 | __op_addadd("this declaration of ".to_string(), 78 | __op_addadd(ident, " shadows a previous one".to_string())) 79 | } 80 | RedefInfo(ident, DiffKindRedecl, _, _) => { 81 | __op_addadd(ident, 82 | " previously declared as a different kind of symbol".to_string()) 83 | } 84 | RedefInfo(ident, DisagreeLinkage, _, _) => { 85 | __op_addadd(ident, 86 | " previously declared with different linkage".to_string()) 87 | } 88 | RedefInfo(ident, NoLinkageOld, _, _) => { 89 | __op_addadd(ident, " previously declared without linkage".to_string()) 90 | } 91 | } 92 | } 93 | 94 | pub fn prevDeclMsg(old_node: NodeInfo) -> Vec { 95 | vec!["The previous declaration was here: ".to_string(), 96 | show((posOfNode(old_node)))] 97 | } 98 | 99 | pub fn redefinition(lvl: ErrorLevel, 100 | ctx: String, 101 | kind: RedefKind, 102 | new: NodeInfo, 103 | old: NodeInfo) 104 | -> RedefError { 105 | RedefError(lvl, (RedefInfo(ctx, kind, new, old))) 106 | } 107 | -------------------------------------------------------------------------------- /src/analysis/type_conversions.rs: -------------------------------------------------------------------------------- 1 | // Original file: "TypeConversions.hs" 2 | // File auto-generated using Corollary. 3 | 4 | #[macro_use] 5 | use corollary_support::*; 6 | 7 | // NOTE: These imports are advisory. You probably need to change them to support Rust. 8 | // use Language::C::Analysis::SemRep; 9 | 10 | use analysis::sem_rep::*; 11 | 12 | pub fn arithmeticConversion(_0: TypeName, _1: TypeName) -> Option { 13 | match (_0, _1) { 14 | (TyComplex(t1), TyComplex(t2)) => Some(TyComplex(floatConversion(t1, t2))), 15 | (TyComplex(t1), TyFloating(t2)) => Some(TyComplex(floatConversion(t1, t2))), 16 | (TyFloating(t1), TyComplex(t2)) => Some(TyComplex(floatConversion(t1, t2))), 17 | (t1, __OP__, TyComplex(_), TyIntegral(_)) => Some(t1), 18 | (TyIntegral(_), t2, __OP__, TyComplex(_)) => Some(t2), 19 | (TyFloating(t1), TyFloating(t2)) => Some(TyFloating(floatConversion(t1, t2))), 20 | (t1, __OP__, TyFloating(_), TyIntegral(_)) => Some(t1), 21 | (TyIntegral(_), t2, __OP__, TyFloating(_)) => Some(t2), 22 | (TyIntegral(t1), TyIntegral(t2)) => Some(TyIntegral(intConversion(t1, t2))), 23 | (TyEnum(_), TyEnum(_)) => Some(TyIntegral(TyInt)), 24 | (TyEnum(_), t2) => Some(t2), 25 | (t1, TyEnum(_)) => Some(t1), 26 | (_, _) => None, 27 | } 28 | } 29 | 30 | pub fn floatConversion() -> FloatType { 31 | max 32 | } 33 | 34 | pub fn intConversion(t1: IntType, t2: IntType) -> IntType { 35 | max(TyInt, (max(t1, t2))) 36 | } 37 | -------------------------------------------------------------------------------- /src/bin/lex.rs: -------------------------------------------------------------------------------- 1 | extern crate parser_c; 2 | 3 | use std::env; 4 | 5 | use parser_c::parser::exec_parser_simple; 6 | use parser_c::parser::lexer::lex; 7 | use parser_c::data::input_stream::InputStream; 8 | use parser_c::data::position::Position; 9 | use parser_c::parser::tokens::CTokEof; 10 | 11 | fn main() { 12 | let mut args = env::args(); 13 | let input_file = args.nth(1).unwrap(); 14 | let dump = args.nth(0).as_ref().map(|x| &**x) == Some("-d"); 15 | let input_stream = InputStream::from_file(&input_file).unwrap(); 16 | let init_pos = Position::from_file(&input_file); 17 | let res = exec_parser_simple(|p| loop { 18 | let tok = lex(p)?; 19 | if dump { 20 | println!("{:?}", tok); 21 | } 22 | if let CTokEof = tok { 23 | return Ok(()); 24 | } 25 | }, input_stream, init_pos); 26 | if let Err(e) = res { 27 | eprintln!("{}", e); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/bin/parse.rs: -------------------------------------------------------------------------------- 1 | extern crate parser_c; 2 | 3 | use std::env; 4 | 5 | use parser_c::parse_file; 6 | use parser_c::system::gcc; 7 | 8 | fn main() { 9 | let mut args: Vec<_> = env::args().skip(1).collect(); 10 | let mut dump = false; 11 | if let Some("-d") = args.last().map(|v| &**v) { 12 | args.pop(); 13 | dump = true; 14 | } 15 | if let Some(input_file) = args.pop() { 16 | let preprocessor = gcc::GCC::new("gcc"); 17 | match parse_file(preprocessor, None, args, input_file) { 18 | Err(e) => eprintln!("{}", e), 19 | Ok(unit) => if dump { println!("{:?}", unit) }, 20 | } 21 | } else { 22 | eprintln!("usage: parse [CPP_OPT ...] inputfile [-d]"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/bin/pretty.rs: -------------------------------------------------------------------------------- 1 | extern crate parser_c; 2 | 3 | use std::io::{self, BufWriter}; 4 | use std::env; 5 | 6 | use parser_c::parse_file; 7 | use parser_c::system::gcc; 8 | use parser_c::pretty::pretty; 9 | 10 | fn main() { 11 | let mut args: Vec<_> = env::args().skip(1).collect(); 12 | if let Some(input_file) = args.pop() { 13 | let preprocessor = gcc::GCC::new("gcc"); 14 | match parse_file(preprocessor, None, args, input_file) { 15 | Err(e) => eprintln!("{}", e), 16 | Ok(unit) => { 17 | let out = io::stdout(); 18 | let mut writer = BufWriter::new(out); 19 | pretty(&unit, &mut writer); 20 | } 21 | } 22 | } else { 23 | eprintln!("usage: pretty [CPP_OPT ...] inputfile"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/data/ident.rs: -------------------------------------------------------------------------------- 1 | // Original file: "Ident.hs" 2 | // File auto-generated using Corollary. 3 | 4 | use std::fmt; 5 | use std::rc::Rc; 6 | use std::hash::{Hash, Hasher}; 7 | 8 | use data::position::{Position, Pos}; 9 | use data::node::{NodeInfo, CNode}; 10 | use data::name::Name; 11 | 12 | #[derive(Clone, Debug, PartialEq, PartialOrd, Eq)] 13 | pub enum SUERef { 14 | AnonymousRef(Name), 15 | NamedRef(Ident), 16 | } 17 | pub use self::SUERef::*; 18 | 19 | impl SUERef { 20 | pub fn is_anonymous(&self) -> bool { 21 | match *self { 22 | AnonymousRef(_) => true, 23 | _ => false, 24 | } 25 | } 26 | 27 | pub fn as_str(&self) -> &str { 28 | match *self { 29 | AnonymousRef(_) => "".into(), 30 | NamedRef(ref ident) => ident.as_str(), 31 | } 32 | } 33 | } 34 | 35 | #[derive(Debug, PartialOrd, Eq)] 36 | struct RawIdent(pub String, pub NodeInfo); 37 | 38 | // required because we keep Idents in a HashSet and don't want the set to 39 | // consider the NodeInfo part important for comparison 40 | impl Hash for RawIdent { 41 | fn hash(&self, h: &mut H) { 42 | (self.0).hash(h); 43 | } 44 | } 45 | 46 | // the definition of the equality allows identifiers to be equal that are 47 | // defined at different source text positions 48 | impl PartialEq for RawIdent { 49 | fn eq(&self, other: &Self) -> bool { 50 | self.0 == other.0 51 | } 52 | } 53 | 54 | #[derive(Clone, PartialOrd, PartialEq, Eq, Hash)] 55 | pub struct Ident(Rc); 56 | 57 | impl fmt::Debug for Ident { 58 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 59 | write!(f, "Ident({:?}, {:?})", (self.0).0, (self.0).1) 60 | } 61 | } 62 | 63 | // -- identifiers are attributed 64 | impl CNode for Ident { 65 | fn node_info(&self) -> &NodeInfo { 66 | &(self.0).1 67 | } 68 | fn into_node_info(self) -> NodeInfo { 69 | (self.0).1.clone() 70 | } 71 | } 72 | 73 | impl Ident { 74 | pub fn new(pos: Rc, s: String, name: Name) -> Ident { 75 | let len = s.len(); 76 | Ident(Rc::new(RawIdent(s, NodeInfo::new(pos.clone(), pos, len, name)))) 77 | } 78 | 79 | pub fn internal(s: String) -> Ident { 80 | Ident(Rc::new(RawIdent(s, NodeInfo::with_only_pos(Rc::new(Position::internal()))))) 81 | } 82 | 83 | pub fn internal_at(pos: Rc, s: String) -> Ident { 84 | let len = s.len(); 85 | Ident(Rc::new(RawIdent(s, NodeInfo::with_pos_len(pos.clone(), pos, len)))) 86 | } 87 | 88 | pub fn builtin(s: String) -> Ident { 89 | Ident(Rc::new(RawIdent(s, NodeInfo::with_only_pos(Rc::new(Position::builtin()))))) 90 | } 91 | 92 | pub fn is_internal(&self) -> bool { 93 | (self.0).1.pos().is_internal() 94 | } 95 | 96 | pub fn as_str(&self) -> &str { 97 | &(self.0).0 98 | } 99 | 100 | // TODO: should this be a Debug impl? 101 | pub fn dump(&self) -> String { 102 | format!("{:?} at {:?}", (self.0).0, (self.0).1) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/data/input_stream.rs: -------------------------------------------------------------------------------- 1 | // Original file: "InputStream.hs" 2 | // File auto-generated using Corollary. 3 | 4 | use std::str; 5 | use std::char; 6 | use std::fs::File; 7 | use std::io::Read; 8 | use std::path::Path; 9 | 10 | use parser::ParseError; 11 | use data::position::Position; 12 | 13 | #[derive(Debug)] 14 | pub struct InputStream { 15 | src: Vec, 16 | peek_pos: usize, 17 | tok_pos: usize, 18 | } 19 | 20 | impl InputStream { 21 | 22 | pub fn from_file>(p: P) -> Result { 23 | let mut src = vec![]; 24 | File::open(p.as_ref())?.read_to_end(&mut src)?; 25 | Ok(InputStream { src: src, peek_pos: 0, tok_pos: 0 }) 26 | } 27 | 28 | pub fn from_string(src: String) -> InputStream { 29 | InputStream { src: src.into_bytes(), peek_pos: 0, tok_pos: 0 } 30 | } 31 | 32 | pub fn to_string(self) -> String { 33 | String::from_utf8_lossy(&self.src[self.tok_pos..]).into_owned() 34 | } 35 | 36 | pub fn is_done(&self) -> bool { 37 | self.peek_pos == self.src.len() 38 | } 39 | 40 | pub fn peek_byte(&mut self) -> Option { 41 | if self.is_done() { 42 | None 43 | } else { 44 | let byte = self.src[self.peek_pos]; 45 | self.peek_pos += 1; 46 | Some(byte) 47 | } 48 | } 49 | 50 | pub fn last_char(&self) -> Option { 51 | char::decode_utf8(self.src[self.tok_pos..].iter().cloned()).next()?.ok() 52 | } 53 | 54 | pub fn last_string(&self, len: usize) -> &str { 55 | str::from_utf8(&self.src[self.tok_pos - len..self.tok_pos]).unwrap() 56 | } 57 | 58 | pub fn move_token(&mut self, len: usize, pos: &mut Position) { 59 | let tok_str = &self.src[self.tok_pos..self.tok_pos+len]; 60 | for &byte in tok_str { 61 | match byte { 62 | b'\n' => pos.inc_newline(), 63 | // TODO: handle other control chars 64 | b'\r' => pos.inc_offset(1), 65 | // UTF-8 start bytes 66 | 0...127 | 192...255 => pos.inc_chars(1), 67 | // UTF-8 continuation bytes 68 | _ => pos.inc_offset(1), 69 | } 70 | } 71 | self.tok_pos += len; 72 | self.peek_pos = self.tok_pos; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/data/mod.rs: -------------------------------------------------------------------------------- 1 | // Original file: "Data.hs" 2 | // File auto-generated using Corollary. 3 | 4 | pub mod error; 5 | pub mod ident; 6 | pub mod input_stream; 7 | pub mod name; 8 | pub mod node; 9 | pub mod position; 10 | -------------------------------------------------------------------------------- /src/data/name.rs: -------------------------------------------------------------------------------- 1 | // Original file: "Name.hs" 2 | // File auto-generated using Corollary. 3 | 4 | #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] 5 | pub struct Name(usize); 6 | 7 | pub type NameSupply = Box>; 8 | 9 | pub fn new_name_supply() -> NameSupply { 10 | Box::new((0..).map(Name)) 11 | } 12 | -------------------------------------------------------------------------------- /src/data/node.rs: -------------------------------------------------------------------------------- 1 | // Original file: "Node.hs" 2 | // File auto-generated using Corollary. 3 | 4 | use std::fmt; 5 | use std::rc::Rc; 6 | 7 | use data::name::Name; 8 | use data::position::{Pos, Position, PosLength}; 9 | 10 | // a class for convenient access to the attributes of an attributed object 11 | pub trait CNode { 12 | fn node_info(&self) -> &NodeInfo; 13 | fn into_node_info(self) -> NodeInfo; 14 | } 15 | 16 | impl CNode for NodeInfo { 17 | fn node_info(&self) -> &NodeInfo { 18 | self 19 | } 20 | fn into_node_info(self) -> NodeInfo { 21 | self 22 | } 23 | } 24 | 25 | impl CNode for Rc { 26 | fn node_info(&self) -> &NodeInfo { 27 | (**self).node_info() 28 | } 29 | fn into_node_info(self) -> NodeInfo { 30 | (*self).node_info().clone() 31 | } 32 | } 33 | 34 | impl Pos for T { 35 | fn pos(&self) -> Rc { 36 | NodeInfo::pos(self.node_info()) 37 | } 38 | } 39 | 40 | #[derive(Clone, Eq, Ord, PartialEq, PartialOrd, Hash)] 41 | pub enum NodeInfo { 42 | OnlyPos(Rc, Rc, usize), 43 | NodeInfo(Rc, Rc, usize, Name), 44 | } 45 | pub use self::NodeInfo::*; 46 | 47 | // TODO This should be replaced with a better impl 48 | impl fmt::Debug for NodeInfo { 49 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 50 | write!(f, "..") 51 | } 52 | } 53 | 54 | impl NodeInfo { 55 | pub fn internal() -> NodeInfo { 56 | Self::undef() 57 | } 58 | 59 | pub fn undef() -> NodeInfo { 60 | let undef = Rc::new(Position::none()); 61 | OnlyPos(undef.clone(), undef, 0) 62 | } 63 | 64 | pub fn new(pos1: Rc, pos2: Rc, len: usize, name: Name) -> NodeInfo { 65 | NodeInfo(pos1, pos2, len, name) 66 | } 67 | 68 | pub fn with_only_pos(pos: Rc) -> NodeInfo { 69 | OnlyPos(pos, Rc::new(Position::none()), 0) 70 | } 71 | 72 | pub fn with_pos_len(a: Rc, b: Rc, len: usize) -> NodeInfo { 73 | OnlyPos(a, b, len) 74 | } 75 | 76 | pub fn with_pos_name(pos: Rc, name: Name) -> NodeInfo { 77 | NodeInfo(pos, Rc::new(Position::none()), 0, name) 78 | } 79 | 80 | pub fn len(&self) -> Option { 81 | match *self { 82 | NodeInfo(ref first_pos, ref last_pos, last_len, _) | 83 | OnlyPos(ref first_pos, ref last_pos, last_len) => if last_len == 0 { 84 | None 85 | } else { 86 | Some(last_pos.offset().unwrap() + last_len - first_pos.offset().unwrap()) 87 | } 88 | } 89 | } 90 | 91 | pub fn get_last_token_pos(&self) -> PosLength { 92 | match *self { 93 | NodeInfo(_, ref last_pos, last_len, _) | 94 | OnlyPos(_, ref last_pos, last_len) => (last_pos.clone(), last_len), 95 | } 96 | } 97 | 98 | pub fn name(&self) -> Option { 99 | match *self { 100 | OnlyPos(..) => None, 101 | NodeInfo(_, _, _, name) => Some(name), 102 | } 103 | } 104 | 105 | // NOTE: this is not an impl of Pos because that impl is automatic 106 | // for all CNodes and falls back to this inherent method! 107 | 108 | fn pos(&self) -> Rc { 109 | match *self { 110 | NodeInfo(ref pos, ..) | OnlyPos(ref pos, ..) => pos.clone(), 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Very work-in-progress C parser, ported from Haskell's language-c. 2 | //! 3 | //! ```rust,no_run 4 | //! extern crate parser_c; 5 | //! 6 | //! use parser_c::parse_str; 7 | //! 8 | //! const INPUT: &'static str = r#" 9 | //! 10 | //! int main() { 11 | //! printf("hello world!"); 12 | //! return 0; 13 | //! } 14 | //! 15 | //! "#; 16 | //! 17 | //! fn main() { 18 | //! match parse_str(INPUT, "simple.c") { 19 | //! Err(err) => { 20 | //! panic!("error: {}", err); 21 | //! } 22 | //! Ok(ast) => { 23 | //! println!("success: {:?}", ast); 24 | //! } 25 | //! } 26 | //! } 27 | //! ``` 28 | 29 | #![feature(box_syntax, box_patterns, fnbox, vec_remove_item, 30 | slice_patterns, decode_utf8, ascii_ctype, from_ref)] 31 | 32 | extern crate either; 33 | extern crate tempdir; 34 | #[macro_use] extern crate bitflags; 35 | #[macro_use] extern crate parser_c_macro; 36 | 37 | // pub mod analysis; 38 | pub mod data; 39 | pub mod parser; 40 | pub mod system; 41 | pub mod syntax; 42 | pub mod pretty; 43 | 44 | use std::path::{Path, PathBuf}; 45 | 46 | use system::preprocess::{CppArgs, Preprocessor, is_preprocessed, run_preprocessor}; 47 | use syntax::ast::CTranslUnit; 48 | use data::input_stream::InputStream; 49 | use data::position::Position; 50 | use parser::{ParseError, parse}; 51 | 52 | /// Parse a C source file. 53 | /// 54 | /// If the file name does not end in `.i`, use the given preprocessor 55 | /// before parsing. 56 | /// 57 | /// You can select a custom temporary directory if necessary. 58 | pub fn parse_file(cpp: C, tmp_dir: Option, 59 | args: Vec, input_file: P) 60 | -> Result 61 | where C: Preprocessor, P: Into 62 | { 63 | let input_file = input_file.into(); 64 | let pos = Position::from_file(&input_file); 65 | 66 | let input_stream = if !is_preprocessed(&input_file) { 67 | let mut cpp_args = CppArgs::raw(args, input_file); 68 | cpp_args.cpp_tmp_dir = tmp_dir; 69 | run_preprocessor(cpp, cpp_args).map_err(ParseError::input)? 70 | } else { 71 | InputStream::from_file(&input_file)? 72 | }; 73 | 74 | parse(input_stream, pos) 75 | } 76 | 77 | /// Parse an already preprocessed C source file. 78 | pub fn parse_file_pre>(file: P) -> Result { 79 | let input_stream = InputStream::from_file(file.as_ref())?; 80 | parse(input_stream, Position::from_file(file.as_ref())) 81 | } 82 | 83 | /// Basic public API. Accepts C source and a filename. 84 | pub fn parse_str>(input: &str, file: P) -> Result { 85 | // This doesn't represent possible final functionality of the crate, 86 | // but makes it usable at this early stage. 87 | 88 | let input_stream = InputStream::from_string(input.into()); 89 | parse(input_stream, Position::from_file(file.as_ref())) 90 | } 91 | -------------------------------------------------------------------------------- /src/parser/builtin.rs: -------------------------------------------------------------------------------- 1 | // Original file: "Builtin.hs" 2 | // File auto-generated using Corollary. 3 | 4 | use data::ident::Ident; 5 | 6 | pub fn builtin_type_names() -> Vec { 7 | vec![Ident::builtin("__builtin_va_list".into())] 8 | } 9 | -------------------------------------------------------------------------------- /src/syntax/mod.rs: -------------------------------------------------------------------------------- 1 | // Original file: "Syntax.hs" 2 | // File auto-generated using Corollary. 3 | 4 | pub mod ast; 5 | pub mod constants; 6 | pub mod ops; 7 | pub mod utils; 8 | -------------------------------------------------------------------------------- /src/syntax/ops.rs: -------------------------------------------------------------------------------- 1 | // Original file: "Ops.hs" 2 | // File auto-generated using Corollary. 3 | 4 | #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] 5 | pub enum CAssignOp { 6 | CAssignOp, 7 | CMulAssOp, 8 | CDivAssOp, 9 | CRmdAssOp, 10 | CAddAssOp, 11 | CSubAssOp, 12 | CShlAssOp, 13 | CShrAssOp, 14 | CAndAssOp, 15 | CXorAssOp, 16 | COrAssOp, 17 | } 18 | pub use self::CAssignOp::*; 19 | 20 | impl CAssignOp { 21 | pub fn binop(&self) -> Option { 22 | match *self { 23 | CAssignOp => None, 24 | CMulAssOp => Some(CMulOp), 25 | CDivAssOp => Some(CDivOp), 26 | CRmdAssOp => Some(CRmdOp), 27 | CAddAssOp => Some(CAddOp), 28 | CSubAssOp => Some(CSubOp), 29 | CShlAssOp => Some(CShlOp), 30 | CShrAssOp => Some(CShrOp), 31 | CAndAssOp => Some(CAndOp), 32 | CXorAssOp => Some(CXorOp), 33 | COrAssOp => Some(COrOp), 34 | } 35 | } 36 | } 37 | 38 | 39 | #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] 40 | pub enum CBinaryOp { 41 | CMulOp, 42 | CDivOp, 43 | CRmdOp, 44 | CAddOp, 45 | CSubOp, 46 | CShlOp, 47 | CShrOp, 48 | CLeOp, 49 | CGrOp, 50 | CLeqOp, 51 | CGeqOp, 52 | CEqOp, 53 | CNeqOp, 54 | CAndOp, 55 | CXorOp, 56 | COrOp, 57 | CLndOp, 58 | CLorOp, 59 | } 60 | pub use self::CBinaryOp::*; 61 | 62 | impl CBinaryOp { 63 | pub fn is_cmp_op(&self) -> bool { 64 | match *self { 65 | CLeqOp | CGeqOp | CLeOp | CGrOp | CEqOp | CNeqOp => true, 66 | _ => false, 67 | } 68 | } 69 | 70 | pub fn is_ptr_op(&self) -> bool { 71 | match *self { 72 | CAddOp | CSubOp => true, 73 | _ => false, 74 | } 75 | } 76 | 77 | pub fn is_bit_op(&self) -> bool { 78 | match *self { 79 | CShlOp | CShrOp | CAndOp | COrOp | CXorOp => true, 80 | _ => false, 81 | } 82 | } 83 | 84 | pub fn is_logic_op(&self) -> bool { 85 | match *self { 86 | CLndOp | CLorOp => true, 87 | _ => false, 88 | } 89 | } 90 | } 91 | 92 | 93 | #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] 94 | pub enum CUnaryOp { 95 | CPreIncOp, 96 | CPreDecOp, 97 | CPostIncOp, 98 | CPostDecOp, 99 | CAdrOp, 100 | CIndOp, 101 | CPlusOp, 102 | CMinOp, 103 | CCompOp, 104 | CNegOp, 105 | } 106 | pub use self::CUnaryOp::*; 107 | 108 | impl CUnaryOp { 109 | pub fn is_effectful_op(&self) -> bool { 110 | match *self { 111 | CPreIncOp | CPreDecOp | CPostIncOp | CPostDecOp => true, 112 | _ => false, 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/system/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod gcc; 2 | pub mod preprocess; 3 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -x 5 | 6 | cd parser-c-tests 7 | 8 | if [ ! -d gcc_pre ]; then 9 | echo "Unpacking GCC test suite files..." 10 | # TODO: update this location at some point... 11 | tar xjf ../reference/test/harness/parse_dg/gcc_dg_pre.tar.bz2 12 | cp ../reference/test/harness/parse_dg/expect_fail.txt gcc_expect_fail.txt 13 | fi 14 | 15 | # Using release because the gcc_dg tests are too slow in dev mode... 16 | cargo test --release -- "$@" 17 | --------------------------------------------------------------------------------