├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile ├── README.md ├── grammar.header ├── grammar.rustfmt ├── grammar.rustpeg ├── reftests ├── constant-322.c ├── constant-323.c ├── constant-324.c ├── constant-328.c ├── constant-332.c ├── constant-336.c ├── constant-340.c ├── constant-341.c ├── constant-342.c ├── constant-344.c ├── constant-345.c ├── constant-346.c ├── constant-347.c ├── constant-348.c ├── constant-349.c ├── constant-370.c ├── constant-371.c ├── constant-375.c ├── constant-376.c ├── constant-380.c ├── constant-381.c ├── constant-383.c ├── constant-387.c ├── constant-391.c ├── constant-395.c ├── constant-400.c ├── constant-404.c ├── constant-408.c ├── constant-412.c ├── constant-442.c ├── constant-446.c ├── constant-458.c ├── constant-459.c ├── constant-460.c ├── constant-461.c ├── constant-462.c ├── constant-463.c ├── constant-464.c ├── constant-465.c ├── declaration-1080.c ├── declaration-1443.c ├── declaration-1610.c ├── declaration-1847.c ├── declaration-2243.c ├── declaration-2321.c ├── declaration-2429.c ├── declaration-2477.c ├── declaration-2508.c ├── declaration-2512.c ├── declaration-2594.c ├── declaration-31-field-semicolon.c ├── declaration-31-ty-attr1.c ├── declaration-31-ty-attr2.c ├── declaration-31-ty-attr3.c ├── declaration-659.c ├── declaration-714.c ├── declaration-760.c ├── declaration-837.c ├── declaration-855.c ├── declaration-880.c ├── declaration-983.c ├── declaration-block-2.c ├── declaration-block-3.c ├── declaration-block-4.c ├── declaration-block-5.c ├── declaration-block.c ├── declaration-enum-attr.c ├── declaration-ptr-attr1.c ├── declaration-ptr-attr2.c ├── declaration-ptr-attr3.c ├── declaration-struct.c ├── declaration-typedef.c ├── expression-1295.c ├── expression-1307.c ├── expression-1319.c ├── expression-1338.c ├── expression-1370.c ├── expression-1523.c ├── expression-1595.c ├── expression-2224.c ├── expression-2229.c ├── expression-2234.c ├── expression-2546.c ├── expression-475.c ├── expression-476.c ├── expression-477.c ├── expression-478.c ├── expression-491.c ├── expression-495.c ├── expression-517.c ├── expression-538.c ├── expression-551.c ├── expression-567.c ├── expression-583.c ├── expression-599.c ├── expression-616.c ├── expression-617.c ├── expression-632.c ├── expression-645.c ├── expression-ident-const.c ├── expression-sizeof.c ├── expression-string-1.c ├── expression-string-2.c ├── statement-1408.c ├── statement-1650.c ├── statement-2625.c ├── statement-2669.c ├── statement-case.c ├── statement-case2.c ├── statement-caserange.c ├── statement-caserange2.c ├── statement-caserange3.c ├── statement-caserange4.c ├── statement-caserange5.c ├── statement-default.c ├── statement-label.c ├── translation_unit-1183.c ├── translation_unit-1388.c ├── translation_unit-1692.c ├── translation_unit-1781.c ├── translation_unit-1961.c ├── translation_unit-1993.c ├── translation_unit-2015.c ├── translation_unit-2029.c ├── translation_unit-2045.c ├── translation_unit-2060.c ├── translation_unit-2070.c ├── translation_unit-2086.c ├── translation_unit-2103.c ├── translation_unit-2114.c ├── translation_unit-2129.c ├── translation_unit-2147.c ├── translation_unit-2167.c ├── translation_unit-2190.c ├── translation_unit-2208.c ├── translation_unit-2270.c ├── translation_unit-2300.c ├── translation_unit-2373.c └── translation_unit-31-semicolon.c └── src ├── ast.rs ├── astutil.rs ├── bin ├── dump.rs └── meminfo.rs ├── driver.rs ├── env.rs ├── lib.rs ├── loc.rs ├── parser.rs ├── print.rs ├── span.rs ├── strings.rs ├── tests.rs └── visit.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | pull_request: 4 | schedule: [cron: "40 6 10 1/2 *"] 5 | 6 | name: Tests 7 | 8 | jobs: 9 | test: 10 | name: test 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | rust: 15 | - stable 16 | - nightly 17 | - 1.4.0 18 | steps: 19 | - uses: actions/checkout@v3 20 | - uses: actions-rs/toolchain@v1 21 | with: 22 | profile: minimal 23 | toolchain: ${{ matrix.rust }} 24 | override: true 25 | - uses: actions-rs/cargo@v1 26 | with: 27 | command: test 28 | 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /Cargo.lock 2 | /target/ 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lang-c" 3 | version = "0.15.1" 4 | authors = ["Vickenty Fesunov "] 5 | license = "MIT/Apache-2.0" 6 | description = "Lightweight C parser" 7 | include = [ "/src/**/*.rs", "Cargo.toml", "/LICENSE*", "/README.md" ] 8 | documentation = "https://docs.rs/lang-c" 9 | homepage = "https://github.com/vickenty/lang-c" 10 | repository = "https://github.com/vickenty/lang-c" 11 | keywords = [ "ast", "c", "parser", "c-language" ] 12 | categories = [ "parser-implementations" ] 13 | 14 | [features] 15 | dev-pegviz = [] # tests only: emit extra output for pegviz 16 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all lib 2 | 3 | peg?=rust-peg 4 | 5 | all: src/parser.rs 6 | cargo b --lib --features '$(features)' 7 | cargo t --features '$(features)' 8 | 9 | trace: 10 | rm -f src/parser.rs 11 | make peg=rust-peg-trace features=dev-pegviz 12 | 13 | .INTERMEDIATE: src/parser.rs.raw src/parser.rs.fmt 14 | 15 | src/parser.rs.raw: grammar.rustpeg grammar.rustfmt grammar.header 16 | $(peg) $< > $@ 17 | 18 | src/parser.rs.fmt: src/parser.rs.raw 19 | rustfmt --config-path grammar.rustfmt < $< > $@ 20 | 21 | src/parser.rs: src/parser.rs.fmt 22 | cat grammar.header $< > $@ 23 | 24 | check: 25 | test src/parser.rs -nt grammar.rustpeg 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lang-C 2 | 3 | [![Documentation](https://docs.rs/lang-c/badge.svg)](https://docs.rs/lang-c) 4 | 5 | Ligtweight parser of C language for Rust users. Almost full support for C11 revision of the language. 6 | Several GCC and Clang extensions are also supported as an option. 7 | 8 | ```rust 9 | extern crate lang_c; 10 | use lang_c::driver::{Config, parse}; 11 | 12 | fn main() { 13 | let config = Config::default(); 14 | println!("{:?}", parse(&config, "example.c")); 15 | } 16 | ``` 17 | 18 | # Bugs 19 | 20 | Just open an issue, bug reports and patches are most welcome. 21 | 22 | ## License 23 | 24 | Dual-licenced under Apache 2.0 or MIT licenses (see `LICENSE-APACHE` and `LICENSE-MIT` for legal terms). 25 | 26 | ## Development 27 | 28 | A number of external tools are used during development: 29 | 30 | - GNU make 31 | - rustfmt 32 | - [rust-peg](https://github.com/kevinmehall/rust-peg) 0.5.4 33 | 34 | Parser (`src/parser.rs`) is built from a PEG grammar in `grammar.rustpeg`. It is updated manually and then 35 | committed, not generated on every build, thus no `rust-peg` in the list of dependencies. 36 | 37 | For debugging purposes, it is handy to have a version rust-peg built with tracing enabled. 38 | 39 | A makefile is used to script the development process: 40 | 41 | - `make` update parser, build the library and run the tests; 42 | - `make trace` rebuilds parser using `rust-peg-trace`, which is expected to be a version of `rust-peg` command with `trace` feature enabled 43 | - `make check` can be used as pre-commit git hook to make sure parser is up to date 44 | -------------------------------------------------------------------------------- /grammar.header: -------------------------------------------------------------------------------- 1 | #![cfg_attr(rustfmt, rustfmt_skip)] 2 | #![allow(unknown_lints)] 3 | #![allow(ellipsis_inclusive_range_patterns)] 4 | -------------------------------------------------------------------------------- /grammar.rustfmt: -------------------------------------------------------------------------------- 1 | max_width = 10000 2 | tab_spaces = 4 3 | -------------------------------------------------------------------------------- /reftests/constant-322.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 0 3 | 4 | /*=== 5 | Constant 6 | Integer "0" 7 | IntegerBase Decimal 8 | IntegerSuffix false false 9 | IntegerSize Int 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-323.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 1 3 | 4 | /*=== 5 | Constant 6 | Integer "1" 7 | IntegerBase Decimal 8 | IntegerSuffix false false 9 | IntegerSize Int 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-324.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 1234567890 3 | 4 | /*=== 5 | Constant 6 | Integer "1234567890" 7 | IntegerBase Decimal 8 | IntegerSuffix false false 9 | IntegerSize Int 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-328.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 01234567 3 | 4 | /*=== 5 | Constant 6 | Integer "1234567" 7 | IntegerBase Octal 8 | IntegerSuffix false false 9 | IntegerSize Int 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-332.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 0x1234567890abdefABCDEF 3 | 4 | /*=== 5 | Constant 6 | Integer "1234567890abdefABCDEF" 7 | IntegerBase Hexadecimal 8 | IntegerSuffix false false 9 | IntegerSize Int 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-336.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 0b0001001000110100 3 | 4 | /*=== 5 | Constant 6 | Integer "0001001000110100" 7 | IntegerBase Binary 8 | IntegerSuffix false false 9 | IntegerSize Int 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-340.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 042lu 3 | 4 | /*=== 5 | Constant 6 | Integer "42" 7 | IntegerBase Octal 8 | IntegerSuffix true false 9 | IntegerSize Long 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-341.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 042ul 3 | 4 | /*=== 5 | Constant 6 | Integer "42" 7 | IntegerBase Octal 8 | IntegerSuffix true false 9 | IntegerSize Long 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-342.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 042uL 3 | 4 | /*=== 5 | Constant 6 | Integer "42" 7 | IntegerBase Octal 8 | IntegerSuffix true false 9 | IntegerSize Long 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-344.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 1a 3 | 4 | /*=== 5 | ~ERROR 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-345.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 08 3 | 4 | /*=== 5 | ~ERROR 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-346.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 0xX 3 | 4 | /*=== 5 | ~ERROR 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-347.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 1lul 3 | 4 | /*=== 5 | ~ERROR 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-348.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 2lL 3 | 4 | /*=== 5 | ~ERROR 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-349.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 0b2 3 | 4 | /*=== 5 | ~ERROR 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-370.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 2. 3 | 4 | /*=== 5 | Constant 6 | Float "2." 7 | FloatBase Decimal 8 | FloatSuffix false 9 | FloatFormat Double 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-371.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 2.e2 3 | 4 | /*=== 5 | Constant 6 | Float "2.e2" 7 | FloatBase Decimal 8 | FloatSuffix false 9 | FloatFormat Double 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-375.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | .2 3 | 4 | /*=== 5 | Constant 6 | Float ".2" 7 | FloatBase Decimal 8 | FloatSuffix false 9 | FloatFormat Double 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-376.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | .2e2 3 | 4 | /*=== 5 | Constant 6 | Float ".2e2" 7 | FloatBase Decimal 8 | FloatSuffix false 9 | FloatFormat Double 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-380.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 2.0 3 | 4 | /*=== 5 | Constant 6 | Float "2.0" 7 | FloatBase Decimal 8 | FloatSuffix false 9 | FloatFormat Double 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-381.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 2.0f 3 | 4 | /*=== 5 | Constant 6 | Float "2.0" 7 | FloatBase Decimal 8 | FloatSuffix false 9 | FloatFormat Float 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-383.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 24.01e100 3 | 4 | /*=== 5 | Constant 6 | Float "24.01e100" 7 | FloatBase Decimal 8 | FloatSuffix false 9 | FloatFormat Double 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-387.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 24.01e+100 3 | 4 | /*=== 5 | Constant 6 | Float "24.01e+100" 7 | FloatBase Decimal 8 | FloatSuffix false 9 | FloatFormat Double 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-391.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 24.01e-100 3 | 4 | /*=== 5 | Constant 6 | Float "24.01e-100" 7 | FloatBase Decimal 8 | FloatSuffix false 9 | FloatFormat Double 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-395.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 24.01e100f 3 | 4 | /*=== 5 | Constant 6 | Float "24.01e100" 7 | FloatBase Decimal 8 | FloatSuffix false 9 | FloatFormat Float 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-400.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 0x2Ap19L 3 | 4 | /*=== 5 | Constant 6 | Float "2Ap19" 7 | FloatBase Hexadecimal 8 | FloatSuffix false 9 | FloatFormat LongDouble 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-404.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 0x2A.p19L 3 | 4 | /*=== 5 | Constant 6 | Float "2A.p19" 7 | FloatBase Hexadecimal 8 | FloatSuffix false 9 | FloatFormat LongDouble 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-408.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 0x.DEp19L 3 | 4 | /*=== 5 | Constant 6 | Float ".DEp19" 7 | FloatBase Hexadecimal 8 | FloatSuffix false 9 | FloatFormat LongDouble 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-412.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 0x2A.DEp19L 3 | 4 | /*=== 5 | Constant 6 | Float "2A.DEp19" 7 | FloatBase Hexadecimal 8 | FloatSuffix false 9 | FloatFormat LongDouble 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/constant-442.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 1.0f64 3 | 4 | /*=== 5 | Constant 6 | Float "1.0" 7 | FloatBase Decimal 8 | FloatSuffix false 9 | FloatFormat 10 | TS18661FloatType 64 11 | TS18661FloatFormat BinaryInterchange 12 | ===*/ 13 | -------------------------------------------------------------------------------- /reftests/constant-446.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 0xAp1f16 3 | 4 | /*=== 5 | Constant 6 | Float "Ap1" 7 | FloatBase Hexadecimal 8 | FloatSuffix false 9 | FloatFormat 10 | TS18661FloatType 16 11 | TS18661FloatFormat BinaryInterchange 12 | ===*/ 13 | -------------------------------------------------------------------------------- /reftests/constant-458.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 'a' 3 | 4 | /*=== 5 | Constant Character 'a' 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-459.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | '\n' 3 | 4 | /*=== 5 | Constant Character '\n' 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-460.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | '\\' 3 | 4 | /*=== 5 | Constant Character '\\' 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-461.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | '\'' 3 | 4 | /*=== 5 | Constant Character '\'' 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-462.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | '\1' 3 | 4 | /*=== 5 | Constant Character '\1' 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-463.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | '\02' 3 | 4 | /*=== 5 | Constant Character '\02' 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-464.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | '\027' 3 | 4 | /*=== 5 | Constant Character '\027' 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/constant-465.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | '\xde' 3 | 4 | /*=== 5 | Constant Character '\xde' 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/declaration-1080.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | __attribute__((noreturn)) void d0 (void), 3 | __attribute__((format(printf, 1, 2))) d1 (const char *, ...), 4 | d2 (void); 5 | 6 | /*=== 7 | Declaration 8 | DeclarationSpecifier 9 | Extension 10 | Attribute "noreturn" 11 | DeclarationSpecifier 12 | TypeSpecifier Void 13 | InitDeclarator 14 | Declarator 15 | DeclaratorKind 16 | Identifier "d0" 17 | DerivedDeclarator 18 | FunctionDeclarator 19 | ParameterDeclaration 20 | DeclarationSpecifier 21 | TypeSpecifier Void 22 | Ellipsis None 23 | InitDeclarator 24 | Declarator 25 | DeclaratorKind 26 | Identifier "d1" 27 | DerivedDeclarator 28 | FunctionDeclarator 29 | ParameterDeclaration 30 | DeclarationSpecifier 31 | TypeQualifier Const 32 | DeclarationSpecifier 33 | TypeSpecifier Char 34 | Declarator 35 | DeclaratorKind Abstract 36 | DerivedDeclarator Pointer 37 | Ellipsis Some 38 | Extension 39 | Attribute "format" 40 | Expression 41 | Identifier "printf" 42 | Expression 43 | Constant 44 | Integer "1" 45 | IntegerBase Decimal 46 | IntegerSuffix false false 47 | IntegerSize Int 48 | Expression 49 | Constant 50 | Integer "2" 51 | IntegerBase Decimal 52 | IntegerSuffix false false 53 | IntegerSize Int 54 | InitDeclarator 55 | Declarator 56 | DeclaratorKind 57 | Identifier "d2" 58 | DerivedDeclarator 59 | FunctionDeclarator 60 | ParameterDeclaration 61 | DeclarationSpecifier 62 | TypeSpecifier Void 63 | Ellipsis None 64 | ===*/ 65 | -------------------------------------------------------------------------------- /reftests/declaration-1443.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | union { long double __l; int __i[3]; } __u = { __l: __x }; 3 | 4 | /*=== 5 | Declaration 6 | DeclarationSpecifier 7 | TypeSpecifier 8 | StructType 9 | StructKind Union 10 | StructDeclaration 11 | StructField 12 | SpecifierQualifier 13 | TypeSpecifier Long 14 | SpecifierQualifier 15 | TypeSpecifier Double 16 | StructDeclarator 17 | Declarator 18 | DeclaratorKind 19 | Identifier "__l" 20 | StructDeclaration 21 | StructField 22 | SpecifierQualifier 23 | TypeSpecifier Int 24 | StructDeclarator 25 | Declarator 26 | DeclaratorKind 27 | Identifier "__i" 28 | DerivedDeclarator 29 | ArrayDeclarator 30 | ArraySize VariableExpression 31 | Expression 32 | Constant 33 | Integer "3" 34 | IntegerBase Decimal 35 | IntegerSuffix false false 36 | IntegerSize Int 37 | InitDeclarator 38 | Declarator 39 | DeclaratorKind 40 | Identifier "__u" 41 | Initializer 42 | InitializerListItem 43 | Designator 44 | Identifier "__l" 45 | Initializer 46 | Expression 47 | Identifier "__x" 48 | ===*/ 49 | -------------------------------------------------------------------------------- /reftests/declaration-1610.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | __typeof__(foo(bar, baz)) ook = foo(bar, baz); 3 | 4 | /*=== 5 | Declaration 6 | DeclarationSpecifier 7 | TypeSpecifier 8 | TypeOf 9 | Expression 10 | CallExpression 11 | Expression 12 | Identifier "foo" 13 | Expression 14 | Identifier "bar" 15 | Expression 16 | Identifier "baz" 17 | InitDeclarator 18 | Declarator 19 | DeclaratorKind 20 | Identifier "ook" 21 | Initializer 22 | Expression 23 | CallExpression 24 | Expression 25 | Identifier "foo" 26 | Expression 27 | Identifier "bar" 28 | Expression 29 | Identifier "baz" 30 | ===*/ 31 | -------------------------------------------------------------------------------- /reftests/declaration-1847.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | typedef struct { 3 | long long __max_align_ll __attribute__((__aligned__(__alignof__(long long)))); 4 | long double __max_align_ld __attribute__((__aligned__(__alignof__(long double)))); 5 | } max_align_t; 6 | 7 | /*=== 8 | Declaration 9 | DeclarationSpecifier 10 | StorageClassSpecifier Typedef 11 | DeclarationSpecifier 12 | TypeSpecifier 13 | StructType 14 | StructKind Struct 15 | StructDeclaration 16 | StructField 17 | SpecifierQualifier 18 | TypeSpecifier Long 19 | SpecifierQualifier 20 | TypeSpecifier Long 21 | StructDeclarator 22 | Declarator 23 | DeclaratorKind 24 | Identifier "__max_align_ll" 25 | Extension 26 | Attribute "__aligned__" 27 | Expression 28 | AlignOf 29 | TypeName 30 | SpecifierQualifier 31 | TypeSpecifier Long 32 | SpecifierQualifier 33 | TypeSpecifier Long 34 | StructDeclaration 35 | StructField 36 | SpecifierQualifier 37 | TypeSpecifier Long 38 | SpecifierQualifier 39 | TypeSpecifier Double 40 | StructDeclarator 41 | Declarator 42 | DeclaratorKind 43 | Identifier "__max_align_ld" 44 | Extension 45 | Attribute "__aligned__" 46 | Expression 47 | AlignOf 48 | TypeName 49 | SpecifierQualifier 50 | TypeSpecifier Long 51 | SpecifierQualifier 52 | TypeSpecifier Double 53 | InitDeclarator 54 | Declarator 55 | DeclaratorKind 56 | Identifier "max_align_t" 57 | ===*/ 58 | -------------------------------------------------------------------------------- /reftests/declaration-2243.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | _Float64 foo = 1.5; 3 | 4 | /*=== 5 | Declaration 6 | DeclarationSpecifier 7 | TypeSpecifier 8 | TS18661FloatType 64 9 | TS18661FloatFormat BinaryInterchange 10 | InitDeclarator 11 | Declarator 12 | DeclaratorKind 13 | Identifier "foo" 14 | Initializer 15 | Expression 16 | Constant 17 | Float "1.5" 18 | FloatBase Decimal 19 | FloatSuffix false 20 | FloatFormat Double 21 | ===*/ 22 | -------------------------------------------------------------------------------- /reftests/declaration-2321.c: -------------------------------------------------------------------------------- 1 | // This is the first Clang-specific declaration you'll encounter in macOS 2 | // if you #include . 3 | 4 | #pragma gnu 5 | #pragma clang 6 | int (* _Nullable _close)(void *); 7 | 8 | /*=== 9 | Declaration 10 | DeclarationSpecifier 11 | TypeSpecifier Int 12 | InitDeclarator 13 | Declarator 14 | DeclaratorKind 15 | Declarator 16 | DeclaratorKind 17 | Identifier "_close" 18 | DerivedDeclarator Pointer 19 | PointerQualifier 20 | TypeQualifier Nullable 21 | DerivedDeclarator 22 | FunctionDeclarator 23 | ParameterDeclaration 24 | DeclarationSpecifier 25 | TypeSpecifier Void 26 | Declarator 27 | DeclaratorKind Abstract 28 | DerivedDeclarator Pointer 29 | Ellipsis None 30 | ===*/ 31 | -------------------------------------------------------------------------------- /reftests/declaration-2429.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | #pragma clang 3 | int f __attribute__((availability(p1,introduced=1.2.3))) __attribute__((availability(p2,unavailable,replacement="f2"))); 4 | 5 | /*=== 6 | Declaration 7 | DeclarationSpecifier 8 | TypeSpecifier Int 9 | InitDeclarator 10 | Declarator 11 | DeclaratorKind 12 | Identifier "f" 13 | Extension 14 | AvailabilityAttribute 15 | Extension 16 | AvailabilityAttribute 17 | ===*/ 18 | -------------------------------------------------------------------------------- /reftests/declaration-2477.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | struct foo S; 3 | 4 | /*=== 5 | Declaration 6 | DeclarationSpecifier 7 | TypeSpecifier 8 | StructType 9 | StructKind Struct 10 | Identifier "foo" 11 | InitDeclarator 12 | Declarator 13 | DeclaratorKind 14 | Identifier "S" 15 | ===*/ 16 | -------------------------------------------------------------------------------- /reftests/declaration-2508.c: -------------------------------------------------------------------------------- 1 | struct foo { } S; 2 | 3 | /*=== 4 | ~ERROR 5 | ===*/ 6 | -------------------------------------------------------------------------------- /reftests/declaration-2512.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | struct foo { } S; 3 | 4 | /*=== 5 | Declaration 6 | DeclarationSpecifier 7 | TypeSpecifier 8 | StructType 9 | StructKind Struct 10 | Identifier "foo" 11 | InitDeclarator 12 | Declarator 13 | DeclaratorKind 14 | Identifier "S" 15 | ===*/ 16 | -------------------------------------------------------------------------------- /reftests/declaration-2594.c: -------------------------------------------------------------------------------- 1 | // #23 2 | 3 | typedef const int foo; 4 | 5 | /*=== 6 | Declaration 7 | DeclarationSpecifier 8 | StorageClassSpecifier Typedef 9 | DeclarationSpecifier 10 | TypeQualifier Const 11 | DeclarationSpecifier 12 | TypeSpecifier Int 13 | InitDeclarator 14 | Declarator 15 | DeclaratorKind 16 | Identifier "foo" 17 | ===*/ 18 | -------------------------------------------------------------------------------- /reftests/declaration-31-field-semicolon.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | struct s { 4 | int i;; 5 | }; 6 | 7 | 8 | /*=== 9 | Declaration 10 | DeclarationSpecifier 11 | TypeSpecifier 12 | StructType 13 | StructKind Struct 14 | Identifier "s" 15 | StructDeclaration 16 | StructField 17 | SpecifierQualifier 18 | TypeSpecifier Int 19 | StructDeclarator 20 | Declarator 21 | DeclaratorKind 22 | Identifier "i" 23 | ===*/ 24 | -------------------------------------------------------------------------------- /reftests/declaration-31-ty-attr1.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | // #31 4 | 5 | struct s { 6 | struct t { 7 | int i; 8 | } __attribute((packed)) v; 9 | }; 10 | 11 | /*=== 12 | Declaration 13 | DeclarationSpecifier 14 | TypeSpecifier 15 | StructType 16 | StructKind Struct 17 | Identifier "s" 18 | StructDeclaration 19 | StructField 20 | SpecifierQualifier 21 | TypeSpecifier 22 | StructType 23 | StructKind Struct 24 | Identifier "t" 25 | StructDeclaration 26 | StructField 27 | SpecifierQualifier 28 | TypeSpecifier Int 29 | StructDeclarator 30 | Declarator 31 | DeclaratorKind 32 | Identifier "i" 33 | SpecifierQualifier 34 | Extension 35 | Attribute "packed" 36 | StructDeclarator 37 | Declarator 38 | DeclaratorKind 39 | Identifier "v" 40 | ===*/ 41 | -------------------------------------------------------------------------------- /reftests/declaration-31-ty-attr2.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | struct s { 4 | union { int i; } __attribute__((aligned(8))); 5 | }; 6 | 7 | /*=== 8 | Declaration 9 | DeclarationSpecifier 10 | TypeSpecifier 11 | StructType 12 | StructKind Struct 13 | Identifier "s" 14 | StructDeclaration 15 | StructField 16 | SpecifierQualifier 17 | TypeSpecifier 18 | StructType 19 | StructKind Union 20 | StructDeclaration 21 | StructField 22 | SpecifierQualifier 23 | TypeSpecifier Int 24 | StructDeclarator 25 | Declarator 26 | DeclaratorKind 27 | Identifier "i" 28 | SpecifierQualifier 29 | Extension 30 | Attribute "aligned" 31 | Expression 32 | Constant 33 | Integer "8" 34 | IntegerBase Decimal 35 | IntegerSuffix false false 36 | IntegerSize Int 37 | ===*/ 38 | -------------------------------------------------------------------------------- /reftests/declaration-31-ty-attr3.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | struct s { 4 | int __attribute__((aligned(8))) *i; 5 | }; 6 | 7 | 8 | /*=== 9 | Declaration 10 | DeclarationSpecifier 11 | TypeSpecifier 12 | StructType 13 | StructKind Struct 14 | Identifier "s" 15 | StructDeclaration 16 | StructField 17 | SpecifierQualifier 18 | TypeSpecifier Int 19 | SpecifierQualifier 20 | Extension 21 | Attribute "aligned" 22 | Expression 23 | Constant 24 | Integer "8" 25 | IntegerBase Decimal 26 | IntegerSuffix false false 27 | IntegerSize Int 28 | StructDeclarator 29 | Declarator 30 | DeclaratorKind 31 | Identifier "i" 32 | DerivedDeclarator Pointer 33 | ===*/ 34 | -------------------------------------------------------------------------------- /reftests/declaration-659.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | int typedef * foo, baz[static 10][const *]; 3 | 4 | #pragma is_typename foo 5 | #pragma is_typename baz 6 | /*=== 7 | Declaration 8 | DeclarationSpecifier 9 | TypeSpecifier Int 10 | DeclarationSpecifier 11 | StorageClassSpecifier Typedef 12 | InitDeclarator 13 | Declarator 14 | DeclaratorKind 15 | Identifier "foo" 16 | DerivedDeclarator Pointer 17 | InitDeclarator 18 | Declarator 19 | DeclaratorKind 20 | Identifier "baz" 21 | DerivedDeclarator 22 | ArrayDeclarator 23 | ArraySize StaticExpression 24 | Expression 25 | Constant 26 | Integer "10" 27 | IntegerBase Decimal 28 | IntegerSuffix false false 29 | IntegerSize Int 30 | DerivedDeclarator 31 | ArrayDeclarator 32 | TypeQualifier Const 33 | ArraySize VariableUnknown 34 | ===*/ 35 | -------------------------------------------------------------------------------- /reftests/declaration-714.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | typedef enum { FOO, BAR = 1 } * const foobar; 3 | 4 | #pragma is_typename foobar 5 | /*=== 6 | Declaration 7 | DeclarationSpecifier 8 | StorageClassSpecifier Typedef 9 | DeclarationSpecifier 10 | TypeSpecifier 11 | EnumType 12 | Enumerator 13 | Identifier "FOO" 14 | Enumerator 15 | Identifier "BAR" 16 | Expression 17 | Constant 18 | Integer "1" 19 | IntegerBase Decimal 20 | IntegerSuffix false false 21 | IntegerSize Int 22 | InitDeclarator 23 | Declarator 24 | DeclaratorKind 25 | Identifier "foobar" 26 | DerivedDeclarator Pointer 27 | PointerQualifier 28 | TypeQualifier Const 29 | ===*/ 30 | -------------------------------------------------------------------------------- /reftests/declaration-760.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | struct { int a, b; float c; } S; 3 | 4 | /*=== 5 | Declaration 6 | DeclarationSpecifier 7 | TypeSpecifier 8 | StructType 9 | StructKind Struct 10 | StructDeclaration 11 | StructField 12 | SpecifierQualifier 13 | TypeSpecifier Int 14 | StructDeclarator 15 | Declarator 16 | DeclaratorKind 17 | Identifier "a" 18 | StructDeclarator 19 | Declarator 20 | DeclaratorKind 21 | Identifier "b" 22 | StructDeclaration 23 | StructField 24 | SpecifierQualifier 25 | TypeSpecifier Float 26 | StructDeclarator 27 | Declarator 28 | DeclaratorKind 29 | Identifier "c" 30 | InitDeclarator 31 | Declarator 32 | DeclaratorKind 33 | Identifier "S" 34 | ===*/ 35 | -------------------------------------------------------------------------------- /reftests/declaration-837.c: -------------------------------------------------------------------------------- 1 | int __restrict__; 2 | 3 | /*=== 4 | Declaration 5 | DeclarationSpecifier 6 | TypeSpecifier Int 7 | InitDeclarator 8 | Declarator 9 | DeclaratorKind 10 | Identifier "__restrict__" 11 | ===*/ 12 | -------------------------------------------------------------------------------- /reftests/declaration-855.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | int __restrict__; 3 | 4 | /*=== 5 | Declaration 6 | DeclarationSpecifier 7 | TypeSpecifier Int 8 | DeclarationSpecifier 9 | TypeQualifier Restrict 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/declaration-880.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | #pragma typedef FILE 3 | #pragma typedef size_t 4 | char *fparseln(FILE *, size_t *, size_t *, const char[3], int); 5 | 6 | /*=== 7 | Declaration 8 | DeclarationSpecifier 9 | TypeSpecifier Char 10 | InitDeclarator 11 | Declarator 12 | DeclaratorKind 13 | Identifier "fparseln" 14 | DerivedDeclarator Pointer 15 | DerivedDeclarator 16 | FunctionDeclarator 17 | ParameterDeclaration 18 | DeclarationSpecifier 19 | TypeSpecifier TypedefName 20 | Identifier "FILE" 21 | Declarator 22 | DeclaratorKind Abstract 23 | DerivedDeclarator Pointer 24 | ParameterDeclaration 25 | DeclarationSpecifier 26 | TypeSpecifier TypedefName 27 | Identifier "size_t" 28 | Declarator 29 | DeclaratorKind Abstract 30 | DerivedDeclarator Pointer 31 | ParameterDeclaration 32 | DeclarationSpecifier 33 | TypeSpecifier TypedefName 34 | Identifier "size_t" 35 | Declarator 36 | DeclaratorKind Abstract 37 | DerivedDeclarator Pointer 38 | ParameterDeclaration 39 | DeclarationSpecifier 40 | TypeQualifier Const 41 | DeclarationSpecifier 42 | TypeSpecifier Char 43 | Declarator 44 | DeclaratorKind Abstract 45 | DerivedDeclarator 46 | ArrayDeclarator 47 | ArraySize VariableExpression 48 | Expression 49 | Constant 50 | Integer "3" 51 | IntegerBase Decimal 52 | IntegerSuffix false false 53 | IntegerSize Int 54 | ParameterDeclaration 55 | DeclarationSpecifier 56 | TypeSpecifier Int 57 | Ellipsis None 58 | ===*/ 59 | -------------------------------------------------------------------------------- /reftests/declaration-983.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | #pragma typedef size_t 3 | extern int strerror_r (int __errnum, char *__buf, size_t __buflen) 4 | __asm__ ("" "__xpg_strerror_r") __attribute__ ((__nothrow__ , __leaf__)) 5 | __attribute__ ((__nonnull__ (2))); 6 | 7 | /*=== 8 | Declaration 9 | DeclarationSpecifier 10 | StorageClassSpecifier Extern 11 | DeclarationSpecifier 12 | TypeSpecifier Int 13 | InitDeclarator 14 | Declarator 15 | DeclaratorKind 16 | Identifier "strerror_r" 17 | DerivedDeclarator 18 | FunctionDeclarator 19 | ParameterDeclaration 20 | DeclarationSpecifier 21 | TypeSpecifier Int 22 | Declarator 23 | DeclaratorKind 24 | Identifier "__errnum" 25 | ParameterDeclaration 26 | DeclarationSpecifier 27 | TypeSpecifier Char 28 | Declarator 29 | DeclaratorKind 30 | Identifier "__buf" 31 | DerivedDeclarator Pointer 32 | ParameterDeclaration 33 | DeclarationSpecifier 34 | TypeSpecifier TypedefName 35 | Identifier "size_t" 36 | Declarator 37 | DeclaratorKind 38 | Identifier "__buflen" 39 | Ellipsis None 40 | Extension 41 | StringLiteral ["\"\"", "\"__xpg_strerror_r\""] 42 | Extension 43 | Attribute "__nothrow__" 44 | Extension 45 | Attribute "__leaf__" 46 | Extension 47 | Attribute "__nonnull__" 48 | Expression 49 | Constant 50 | Integer "2" 51 | IntegerBase Decimal 52 | IntegerSuffix false false 53 | IntegerSize Int 54 | ===*/ 55 | -------------------------------------------------------------------------------- /reftests/declaration-block-2.c: -------------------------------------------------------------------------------- 1 | #pragma clang 2 | 3 | void (^ const p)(int); 4 | 5 | /*=== 6 | Declaration 7 | DeclarationSpecifier 8 | TypeSpecifier Void 9 | InitDeclarator 10 | Declarator 11 | DeclaratorKind 12 | Declarator 13 | DeclaratorKind 14 | Identifier "p" 15 | DerivedDeclarator Block 16 | PointerQualifier 17 | TypeQualifier Const 18 | DerivedDeclarator 19 | FunctionDeclarator 20 | ParameterDeclaration 21 | DeclarationSpecifier 22 | TypeSpecifier Int 23 | Ellipsis None 24 | ===*/ 25 | -------------------------------------------------------------------------------- /reftests/declaration-block-3.c: -------------------------------------------------------------------------------- 1 | #pragma clang 2 | #pragma typedef size_t 3 | 4 | void *bsearch_b(const void *__key, const void *__base, size_t __nel, 5 | size_t __width, int (^ _Nonnull __compar)(const void *, const void *) __attribute__((__noescape__))) 6 | __attribute__((availability(macosx,introduced=10.6))); 7 | 8 | /*=== 9 | Declaration 10 | DeclarationSpecifier 11 | TypeSpecifier Void 12 | InitDeclarator 13 | Declarator 14 | DeclaratorKind 15 | Identifier "bsearch_b" 16 | DerivedDeclarator Pointer 17 | DerivedDeclarator 18 | FunctionDeclarator 19 | ParameterDeclaration 20 | DeclarationSpecifier 21 | TypeQualifier Const 22 | DeclarationSpecifier 23 | TypeSpecifier Void 24 | Declarator 25 | DeclaratorKind 26 | Identifier "__key" 27 | DerivedDeclarator Pointer 28 | ParameterDeclaration 29 | DeclarationSpecifier 30 | TypeQualifier Const 31 | DeclarationSpecifier 32 | TypeSpecifier Void 33 | Declarator 34 | DeclaratorKind 35 | Identifier "__base" 36 | DerivedDeclarator Pointer 37 | ParameterDeclaration 38 | DeclarationSpecifier 39 | TypeSpecifier TypedefName 40 | Identifier "size_t" 41 | Declarator 42 | DeclaratorKind 43 | Identifier "__nel" 44 | ParameterDeclaration 45 | DeclarationSpecifier 46 | TypeSpecifier TypedefName 47 | Identifier "size_t" 48 | Declarator 49 | DeclaratorKind 50 | Identifier "__width" 51 | ParameterDeclaration 52 | DeclarationSpecifier 53 | TypeSpecifier Int 54 | Declarator 55 | DeclaratorKind 56 | Declarator 57 | DeclaratorKind 58 | Identifier "__compar" 59 | DerivedDeclarator Block 60 | PointerQualifier 61 | TypeQualifier Nonnull 62 | DerivedDeclarator 63 | FunctionDeclarator 64 | ParameterDeclaration 65 | DeclarationSpecifier 66 | TypeQualifier Const 67 | DeclarationSpecifier 68 | TypeSpecifier Void 69 | Declarator 70 | DeclaratorKind Abstract 71 | DerivedDeclarator Pointer 72 | ParameterDeclaration 73 | DeclarationSpecifier 74 | TypeQualifier Const 75 | DeclarationSpecifier 76 | TypeSpecifier Void 77 | Declarator 78 | DeclaratorKind Abstract 79 | DerivedDeclarator Pointer 80 | Ellipsis None 81 | Extension 82 | Attribute "__noescape__" 83 | Ellipsis None 84 | Extension 85 | AvailabilityAttribute 86 | ===*/ 87 | -------------------------------------------------------------------------------- /reftests/declaration-block-4.c: -------------------------------------------------------------------------------- 1 | int ^none; 2 | 3 | /*=== 4 | ~ERROR 5 | ===*/ 6 | -------------------------------------------------------------------------------- /reftests/declaration-block-5.c: -------------------------------------------------------------------------------- 1 | int (^p)(int); 2 | 3 | /*=== 4 | ~ERROR 5 | ===*/ 6 | -------------------------------------------------------------------------------- /reftests/declaration-block.c: -------------------------------------------------------------------------------- 1 | #pragma clang 2 | 3 | int ^block; 4 | 5 | /*=== 6 | Declaration 7 | DeclarationSpecifier 8 | TypeSpecifier Int 9 | InitDeclarator 10 | Declarator 11 | DeclaratorKind 12 | Identifier "block" 13 | DerivedDeclarator Block 14 | ===*/ 15 | -------------------------------------------------------------------------------- /reftests/declaration-enum-attr.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | enum { 4 | SOME_THING = 0, 5 | OTHER_THING = 1, 6 | OLD_THING __attribute__((deprecated)) = 2, 7 | }; 8 | 9 | /*=== 10 | Declaration 11 | DeclarationSpecifier 12 | TypeSpecifier 13 | EnumType 14 | Enumerator 15 | Identifier "SOME_THING" 16 | Expression 17 | Constant 18 | Integer "0" 19 | IntegerBase Decimal 20 | IntegerSuffix false false 21 | IntegerSize Int 22 | Enumerator 23 | Identifier "OTHER_THING" 24 | Expression 25 | Constant 26 | Integer "1" 27 | IntegerBase Decimal 28 | IntegerSuffix false false 29 | IntegerSize Int 30 | Enumerator 31 | Identifier "OLD_THING" 32 | Expression 33 | Constant 34 | Integer "2" 35 | IntegerBase Decimal 36 | IntegerSuffix false false 37 | IntegerSize Int 38 | Extension 39 | Attribute "deprecated" 40 | ===*/ 41 | -------------------------------------------------------------------------------- /reftests/declaration-ptr-attr1.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | void (****f)(void) __attribute__((noreturn)); 4 | 5 | /*=== 6 | Declaration 7 | DeclarationSpecifier 8 | TypeSpecifier Void 9 | InitDeclarator 10 | Declarator 11 | DeclaratorKind 12 | Declarator 13 | DeclaratorKind 14 | Identifier "f" 15 | DerivedDeclarator Pointer 16 | DerivedDeclarator Pointer 17 | DerivedDeclarator Pointer 18 | DerivedDeclarator Pointer 19 | DerivedDeclarator 20 | FunctionDeclarator 21 | ParameterDeclaration 22 | DeclarationSpecifier 23 | TypeSpecifier Void 24 | Ellipsis None 25 | Extension 26 | Attribute "noreturn" 27 | ===*/ 28 | -------------------------------------------------------------------------------- /reftests/declaration-ptr-attr2.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | void (__attribute__((noreturn)) ****f) (void); 4 | 5 | /*=== 6 | Declaration 7 | DeclarationSpecifier 8 | TypeSpecifier Void 9 | InitDeclarator 10 | Declarator 11 | DeclaratorKind 12 | Declarator 13 | DeclaratorKind 14 | Identifier "f" 15 | DerivedDeclarator Pointer 16 | DerivedDeclarator Pointer 17 | DerivedDeclarator Pointer 18 | DerivedDeclarator Pointer 19 | Extension 20 | Attribute "noreturn" 21 | DerivedDeclarator 22 | FunctionDeclarator 23 | ParameterDeclaration 24 | DeclarationSpecifier 25 | TypeSpecifier Void 26 | Ellipsis None 27 | ===*/ 28 | -------------------------------------------------------------------------------- /reftests/declaration-ptr-attr3.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | char *__attribute__((aligned(8))) *f; 4 | /*=== 5 | Declaration 6 | DeclarationSpecifier 7 | TypeSpecifier Char 8 | InitDeclarator 9 | Declarator 10 | DeclaratorKind 11 | Identifier "f" 12 | DerivedDeclarator Pointer 13 | PointerQualifier 14 | Extension 15 | Attribute "aligned" 16 | Expression 17 | Constant 18 | Integer "8" 19 | IntegerBase Decimal 20 | IntegerSuffix false false 21 | IntegerSize Int 22 | DerivedDeclarator Pointer 23 | ===*/ 24 | -------------------------------------------------------------------------------- /reftests/declaration-struct.c: -------------------------------------------------------------------------------- 1 | struct foo { 2 | int x; 3 | }; 4 | 5 | /*=== 6 | Declaration 7 | DeclarationSpecifier 8 | TypeSpecifier 9 | StructType 10 | StructKind Struct 11 | Identifier "foo" 12 | StructDeclaration 13 | StructField 14 | SpecifierQualifier 15 | TypeSpecifier Int 16 | StructDeclarator 17 | Declarator 18 | DeclaratorKind 19 | Identifier "x" 20 | ===*/ 21 | -------------------------------------------------------------------------------- /reftests/declaration-typedef.c: -------------------------------------------------------------------------------- 1 | typedef struct foo { 2 | int x; 3 | } bar; 4 | 5 | /*=== 6 | Declaration 7 | DeclarationSpecifier 8 | StorageClassSpecifier Typedef 9 | DeclarationSpecifier 10 | TypeSpecifier 11 | StructType 12 | StructKind Struct 13 | Identifier "foo" 14 | StructDeclaration 15 | StructField 16 | SpecifierQualifier 17 | TypeSpecifier Int 18 | StructDeclarator 19 | Declarator 20 | DeclaratorKind 21 | Identifier "x" 22 | InitDeclarator 23 | Declarator 24 | DeclaratorKind 25 | Identifier "bar" 26 | ===*/ 27 | -------------------------------------------------------------------------------- /reftests/expression-1295.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | _Alignof(long long) 3 | 4 | /*=== 5 | Expression 6 | AlignOf 7 | TypeName 8 | SpecifierQualifier 9 | TypeSpecifier Long 10 | SpecifierQualifier 11 | TypeSpecifier Long 12 | ===*/ 13 | -------------------------------------------------------------------------------- /reftests/expression-1307.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | __alignof(long long) 3 | 4 | /*=== 5 | Expression 6 | AlignOf 7 | TypeName 8 | SpecifierQualifier 9 | TypeSpecifier Long 10 | SpecifierQualifier 11 | TypeSpecifier Long 12 | ===*/ 13 | -------------------------------------------------------------------------------- /reftests/expression-1319.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | __alignof__(long long) 3 | 4 | /*=== 5 | Expression 6 | AlignOf 7 | TypeName 8 | SpecifierQualifier 9 | TypeSpecifier Long 10 | SpecifierQualifier 11 | TypeSpecifier Long 12 | ===*/ 13 | -------------------------------------------------------------------------------- /reftests/expression-1338.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | ({ int p = 0; p; }) 3 | 4 | /*=== 5 | Expression 6 | Statement Compound 7 | BlockItem 8 | Declaration 9 | DeclarationSpecifier 10 | TypeSpecifier Int 11 | InitDeclarator 12 | Declarator 13 | DeclaratorKind 14 | Identifier "p" 15 | Initializer 16 | Expression 17 | Constant 18 | Integer "0" 19 | IntegerBase Decimal 20 | IntegerSuffix false false 21 | IntegerSize Int 22 | BlockItem 23 | Statement 24 | Expression 25 | Identifier "p" 26 | ===*/ 27 | -------------------------------------------------------------------------------- /reftests/expression-1370.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | #pragma typedef U64 3 | (U64)foo 4 | 5 | /*=== 6 | Expression 7 | CastExpression 8 | TypeName 9 | SpecifierQualifier 10 | TypeSpecifier TypedefName 11 | Identifier "U64" 12 | Expression 13 | Identifier "foo" 14 | ===*/ 15 | -------------------------------------------------------------------------------- /reftests/expression-1523.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | __builtin_offsetof(struct { struct { int b; } a[2]; }, a->b) 3 | 4 | /*=== 5 | Expression 6 | OffsetOfExpression 7 | TypeName 8 | SpecifierQualifier 9 | TypeSpecifier 10 | StructType 11 | StructKind Struct 12 | StructDeclaration 13 | StructField 14 | SpecifierQualifier 15 | TypeSpecifier 16 | StructType 17 | StructKind Struct 18 | StructDeclaration 19 | StructField 20 | SpecifierQualifier 21 | TypeSpecifier Int 22 | StructDeclarator 23 | Declarator 24 | DeclaratorKind 25 | Identifier "b" 26 | StructDeclarator 27 | Declarator 28 | DeclaratorKind 29 | Identifier "a" 30 | DerivedDeclarator 31 | ArrayDeclarator 32 | ArraySize VariableExpression 33 | Expression 34 | Constant 35 | Integer "2" 36 | IntegerBase Decimal 37 | IntegerSuffix false false 38 | IntegerSize Int 39 | OffsetDesignator 40 | Identifier "a" 41 | OffsetMember IndirectMember 42 | Identifier "b" 43 | ===*/ 44 | -------------------------------------------------------------------------------- /reftests/expression-1595.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | foo(bar, baz) 3 | 4 | /*=== 5 | Expression 6 | CallExpression 7 | Expression 8 | Identifier "foo" 9 | Expression 10 | Identifier "bar" 11 | Expression 12 | Identifier "baz" 13 | ===*/ 14 | -------------------------------------------------------------------------------- /reftests/expression-2224.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | __func__ 3 | 4 | /*=== 5 | Expression 6 | Identifier "__func__" 7 | ===*/ 8 | -------------------------------------------------------------------------------- /reftests/expression-2229.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | __FUNCTION__ 3 | 4 | /*=== 5 | Expression 6 | Identifier "__FUNCTION__" 7 | ===*/ 8 | -------------------------------------------------------------------------------- /reftests/expression-2234.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | __PRETTY_FUNCTION__ 3 | 4 | /*=== 5 | Expression 6 | Identifier "__PRETTY_FUNCTION__" 7 | ===*/ 8 | -------------------------------------------------------------------------------- /reftests/expression-2546.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | (struct test_struct) { 1, .x = 2, 3 } 3 | 4 | /*=== 5 | Expression 6 | CompoundLiteral 7 | TypeName 8 | SpecifierQualifier 9 | TypeSpecifier 10 | StructType 11 | StructKind Struct 12 | Identifier "test_struct" 13 | InitializerListItem 14 | Initializer 15 | Expression 16 | Constant 17 | Integer "1" 18 | IntegerBase Decimal 19 | IntegerSuffix false false 20 | IntegerSize Int 21 | InitializerListItem 22 | Designator 23 | Identifier "x" 24 | Initializer 25 | Expression 26 | Constant 27 | Integer "2" 28 | IntegerBase Decimal 29 | IntegerSuffix false false 30 | IntegerSize Int 31 | InitializerListItem 32 | Initializer 33 | Expression 34 | Constant 35 | Integer "3" 36 | IntegerBase Decimal 37 | IntegerSuffix false false 38 | IntegerSize Int 39 | ===*/ 40 | -------------------------------------------------------------------------------- /reftests/expression-475.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | "foo" 3 | 4 | /*=== 5 | Expression 6 | StringLiteral ["\"foo\""] 7 | ===*/ 8 | -------------------------------------------------------------------------------- /reftests/expression-476.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | "foo\n" 3 | 4 | /*=== 5 | Expression 6 | StringLiteral ["\"foo\\n\""] 7 | ===*/ 8 | -------------------------------------------------------------------------------- /reftests/expression-477.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | "\'\"" 3 | 4 | /*=== 5 | Expression 6 | StringLiteral ["\"\\\'\\\"\""] 7 | ===*/ 8 | -------------------------------------------------------------------------------- /reftests/expression-478.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | "\xaf" 3 | 4 | /*=== 5 | Expression 6 | StringLiteral ["\"\\xaf\""] 7 | ===*/ 8 | -------------------------------------------------------------------------------- /reftests/expression-491.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | a ++ 3 | 4 | /*=== 5 | Expression 6 | UnaryOperatorExpression 7 | Expression 8 | Identifier "a" 9 | UnaryOperator PostIncrement 10 | ===*/ 11 | -------------------------------------------------------------------------------- /reftests/expression-495.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | a.b->c[ d[ e ] ] ++ 3 | 4 | /*=== 5 | Expression 6 | UnaryOperatorExpression 7 | Expression 8 | BinaryOperatorExpression 9 | Expression 10 | MemberExpression 11 | MemberOperator Indirect 12 | Expression 13 | MemberExpression 14 | MemberOperator Direct 15 | Expression 16 | Identifier "a" 17 | Identifier "b" 18 | Identifier "c" 19 | Expression 20 | BinaryOperatorExpression 21 | Expression 22 | Identifier "d" 23 | Expression 24 | Identifier "e" 25 | BinaryOperator Index 26 | BinaryOperator Index 27 | UnaryOperator PostIncrement 28 | ===*/ 29 | -------------------------------------------------------------------------------- /reftests/expression-517.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | a-- * ++b / c 3 | 4 | /*=== 5 | Expression 6 | BinaryOperatorExpression 7 | Expression 8 | BinaryOperatorExpression 9 | Expression 10 | UnaryOperatorExpression 11 | Expression 12 | Identifier "a" 13 | UnaryOperator PostDecrement 14 | Expression 15 | UnaryOperatorExpression 16 | UnaryOperator PreIncrement 17 | Expression 18 | Identifier "b" 19 | BinaryOperator Multiply 20 | Expression 21 | Identifier "c" 22 | BinaryOperator Divide 23 | ===*/ 24 | -------------------------------------------------------------------------------- /reftests/expression-538.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | a && b 3 | 4 | /*=== 5 | Expression 6 | BinaryOperatorExpression 7 | Expression 8 | Identifier "a" 9 | Expression 10 | Identifier "b" 11 | BinaryOperator LogicalAnd 12 | ===*/ 13 | -------------------------------------------------------------------------------- /reftests/expression-551.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | a && b && c 3 | 4 | /*=== 5 | Expression 6 | BinaryOperatorExpression 7 | Expression 8 | BinaryOperatorExpression 9 | Expression 10 | Identifier "a" 11 | Expression 12 | Identifier "b" 13 | BinaryOperator LogicalAnd 14 | Expression 15 | Identifier "c" 16 | BinaryOperator LogicalAnd 17 | ===*/ 18 | -------------------------------------------------------------------------------- /reftests/expression-567.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | a || b || c 3 | 4 | /*=== 5 | Expression 6 | BinaryOperatorExpression 7 | Expression 8 | BinaryOperatorExpression 9 | Expression 10 | Identifier "a" 11 | Expression 12 | Identifier "b" 13 | BinaryOperator LogicalOr 14 | Expression 15 | Identifier "c" 16 | BinaryOperator LogicalOr 17 | ===*/ 18 | -------------------------------------------------------------------------------- /reftests/expression-583.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | a << b << c 3 | 4 | /*=== 5 | Expression 6 | BinaryOperatorExpression 7 | Expression 8 | BinaryOperatorExpression 9 | Expression 10 | Identifier "a" 11 | Expression 12 | Identifier "b" 13 | BinaryOperator ShiftLeft 14 | Expression 15 | Identifier "c" 16 | BinaryOperator ShiftLeft 17 | ===*/ 18 | -------------------------------------------------------------------------------- /reftests/expression-599.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | a >> b >> c 3 | 4 | /*=== 5 | Expression 6 | BinaryOperatorExpression 7 | Expression 8 | BinaryOperatorExpression 9 | Expression 10 | Identifier "a" 11 | Expression 12 | Identifier "b" 13 | BinaryOperator ShiftRight 14 | Expression 15 | Identifier "c" 16 | BinaryOperator ShiftRight 17 | ===*/ 18 | -------------------------------------------------------------------------------- /reftests/expression-616.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | a 3 | 4 | /*=== 5 | Expression 6 | Identifier "a" 7 | ===*/ 8 | -------------------------------------------------------------------------------- /reftests/expression-617.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | a, a, a,a 3 | ,a 4 | 5 | /*=== 6 | Expression 7 | Expression 8 | Identifier "a" 9 | Expression 10 | Identifier "a" 11 | Expression 12 | Identifier "a" 13 | Expression 14 | Identifier "a" 15 | Expression 16 | Identifier "a" 17 | ===*/ 18 | -------------------------------------------------------------------------------- /reftests/expression-632.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | (int) 1 3 | 4 | /*=== 5 | Expression 6 | CastExpression 7 | TypeName 8 | SpecifierQualifier 9 | TypeSpecifier Int 10 | Expression 11 | Constant 12 | Integer "1" 13 | IntegerBase Decimal 14 | IntegerSuffix false false 15 | IntegerSize Int 16 | ===*/ 17 | -------------------------------------------------------------------------------- /reftests/expression-645.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | (foo) 1 3 | 4 | /*=== 5 | ~ERROR 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/expression-ident-const.c: -------------------------------------------------------------------------------- 1 | uident, Uident, Lident, u8ident, 2 | u"str", U"str", L"str", u8"str", 3 | u'chr', U'chr', L'chr' 4 | 5 | /*=== 6 | Expression 7 | Expression 8 | Identifier "uident" 9 | Expression 10 | Identifier "Uident" 11 | Expression 12 | Identifier "Lident" 13 | Expression 14 | Identifier "u8ident" 15 | Expression 16 | StringLiteral ["u\"str\""] 17 | Expression 18 | StringLiteral ["U\"str\""] 19 | Expression 20 | StringLiteral ["L\"str\""] 21 | Expression 22 | StringLiteral ["u8\"str\""] 23 | Expression 24 | Constant Character u'chr' 25 | Expression 26 | Constant Character U'chr' 27 | Expression 28 | Constant Character L'chr' 29 | ===*/ 30 | -------------------------------------------------------------------------------- /reftests/expression-sizeof.c: -------------------------------------------------------------------------------- 1 | #pragma typedef a 2 | sizeof(a) + sizeof b + sizeof(c*10) 3 | /*=== 4 | Expression 5 | BinaryOperatorExpression 6 | Expression 7 | BinaryOperatorExpression 8 | Expression 9 | SizeOfTy 10 | TypeName 11 | SpecifierQualifier 12 | TypeSpecifier TypedefName 13 | Identifier "a" 14 | Expression 15 | SizeOfVal 16 | Expression 17 | Identifier "b" 18 | BinaryOperator Plus 19 | Expression 20 | SizeOfVal 21 | Expression 22 | BinaryOperatorExpression 23 | Expression 24 | Identifier "c" 25 | Expression 26 | Constant 27 | Integer "10" 28 | IntegerBase Decimal 29 | IntegerSuffix false false 30 | IntegerSize Int 31 | BinaryOperator Multiply 32 | BinaryOperator Plus 33 | ===*/ 34 | -------------------------------------------------------------------------------- /reftests/expression-string-1.c: -------------------------------------------------------------------------------- 1 | L".." 2 | /*=== 3 | Expression 4 | StringLiteral ["L\"..\""] 5 | ===*/ 6 | -------------------------------------------------------------------------------- /reftests/expression-string-2.c: -------------------------------------------------------------------------------- 1 | u8".." 2 | /*=== 3 | Expression 4 | StringLiteral ["u8\"..\""] 5 | ===*/ 6 | -------------------------------------------------------------------------------- /reftests/statement-1408.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | __asm ("pmovmskb %1, %0" : "=r" (__m) : "x" (__x)); 3 | 4 | /*=== 5 | Statement 6 | AsmStatement 7 | GnuExtendedAsmStatement 8 | StringLiteral ["\"pmovmskb %1, %0\""] 9 | GnuAsmOperand 10 | StringLiteral ["\"=r\""] 11 | Expression 12 | Identifier "__m" 13 | GnuAsmOperand 14 | StringLiteral ["\"x\""] 15 | Expression 16 | Identifier "__x" 17 | ===*/ 18 | -------------------------------------------------------------------------------- /reftests/statement-1650.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | if (x) do {} while(y); else z(); 3 | 4 | /*=== 5 | Statement 6 | IfStatement 7 | Expression 8 | Identifier "x" 9 | Statement 10 | DoWhileStatement 11 | Statement Compound 12 | Expression 13 | Identifier "y" 14 | Statement 15 | Expression 16 | CallExpression 17 | Expression 18 | Identifier "z" 19 | ===*/ 20 | -------------------------------------------------------------------------------- /reftests/statement-2625.c: -------------------------------------------------------------------------------- 1 | // #27 2 | #pragma gnu 3 | #pragma typedef test_t 4 | return (test_t) { 1, .x = 2, 3 }; 5 | 6 | /*=== 7 | Statement Return 8 | Expression 9 | CompoundLiteral 10 | TypeName 11 | SpecifierQualifier 12 | TypeSpecifier TypedefName 13 | Identifier "test_t" 14 | InitializerListItem 15 | Initializer 16 | Expression 17 | Constant 18 | Integer "1" 19 | IntegerBase Decimal 20 | IntegerSuffix false false 21 | IntegerSize Int 22 | InitializerListItem 23 | Designator 24 | Identifier "x" 25 | Initializer 26 | Expression 27 | Constant 28 | Integer "2" 29 | IntegerBase Decimal 30 | IntegerSuffix false false 31 | IntegerSize Int 32 | InitializerListItem 33 | Initializer 34 | Expression 35 | Constant 36 | Integer "3" 37 | IntegerBase Decimal 38 | IntegerSuffix false false 39 | IntegerSize Int 40 | ===*/ 41 | -------------------------------------------------------------------------------- /reftests/statement-2669.c: -------------------------------------------------------------------------------- 1 | // #27 - make sure expressions starting with a type name in parens still work 2 | #pragma gnu 3 | #pragma typedef test_t 4 | return (test_t) + 1; 5 | 6 | /*=== 7 | Statement Return 8 | Expression 9 | CastExpression 10 | TypeName 11 | SpecifierQualifier 12 | TypeSpecifier TypedefName 13 | Identifier "test_t" 14 | Expression 15 | UnaryOperatorExpression 16 | UnaryOperator Plus 17 | Expression 18 | Constant 19 | Integer "1" 20 | IntegerBase Decimal 21 | IntegerSuffix false false 22 | IntegerSize Int 23 | ===*/ 24 | -------------------------------------------------------------------------------- /reftests/statement-case.c: -------------------------------------------------------------------------------- 1 | case 1: ; 2 | /*=== 3 | Statement 4 | LabeledStatement 5 | Label 6 | Expression 7 | Constant 8 | Integer "1" 9 | IntegerBase Decimal 10 | IntegerSuffix false false 11 | IntegerSize Int 12 | Statement 13 | ===*/ 14 | -------------------------------------------------------------------------------- /reftests/statement-case2.c: -------------------------------------------------------------------------------- 1 | case 1+2: ; 2 | /*=== 3 | Statement 4 | LabeledStatement 5 | Label 6 | Expression 7 | BinaryOperatorExpression 8 | Expression 9 | Constant 10 | Integer "1" 11 | IntegerBase Decimal 12 | IntegerSuffix false false 13 | IntegerSize Int 14 | Expression 15 | Constant 16 | Integer "2" 17 | IntegerBase Decimal 18 | IntegerSuffix false false 19 | IntegerSize Int 20 | BinaryOperator Plus 21 | Statement 22 | ===*/ 23 | -------------------------------------------------------------------------------- /reftests/statement-caserange.c: -------------------------------------------------------------------------------- 1 | case 1 ... 2: ; 2 | /*=== 3 | ~ERROR 4 | ===*/ 5 | -------------------------------------------------------------------------------- /reftests/statement-caserange2.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | case 1 ... 2: ; 3 | /*=== 4 | Statement 5 | LabeledStatement 6 | Label 7 | CaseRange 8 | Expression 9 | Constant 10 | Integer "1" 11 | IntegerBase Decimal 12 | IntegerSuffix false false 13 | IntegerSize Int 14 | Expression 15 | Constant 16 | Integer "2" 17 | IntegerBase Decimal 18 | IntegerSuffix false false 19 | IntegerSize Int 20 | Statement 21 | ===*/ 22 | -------------------------------------------------------------------------------- /reftests/statement-caserange3.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | case 'a'...'z':; 3 | /*=== 4 | Statement 5 | LabeledStatement 6 | Label 7 | CaseRange 8 | Expression 9 | Constant Character 'a' 10 | Expression 11 | Constant Character 'z' 12 | Statement 13 | ===*/ 14 | -------------------------------------------------------------------------------- /reftests/statement-caserange4.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | switch(num) { 3 | for(;;) { 4 | case 1 ... 10: 5 | return; 6 | break; 7 | } 8 | } 9 | /*=== 10 | Statement 11 | SwitchStatement 12 | Expression 13 | Identifier "num" 14 | Statement Compound 15 | BlockItem 16 | Statement 17 | ForStatement 18 | ForInitializer Empty 19 | Statement Compound 20 | BlockItem 21 | Statement 22 | LabeledStatement 23 | Label 24 | CaseRange 25 | Expression 26 | Constant 27 | Integer "1" 28 | IntegerBase Decimal 29 | IntegerSuffix false false 30 | IntegerSize Int 31 | Expression 32 | Constant 33 | Integer "10" 34 | IntegerBase Decimal 35 | IntegerSuffix false false 36 | IntegerSize Int 37 | Statement Return 38 | BlockItem 39 | Statement Break 40 | ===*/ 41 | -------------------------------------------------------------------------------- /reftests/statement-caserange5.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | case 1...3:; 3 | 4 | /*=== 5 | ~ERROR 6 | ===*/ 7 | -------------------------------------------------------------------------------- /reftests/statement-default.c: -------------------------------------------------------------------------------- 1 | default:; 2 | /*=== 3 | Statement 4 | LabeledStatement 5 | Label Default 6 | Statement 7 | ===*/ 8 | -------------------------------------------------------------------------------- /reftests/statement-label.c: -------------------------------------------------------------------------------- 1 | foo: {} 2 | /*=== 3 | Statement 4 | LabeledStatement 5 | Label 6 | Identifier "foo" 7 | Statement Compound 8 | ===*/ 9 | -------------------------------------------------------------------------------- /reftests/translation_unit-1183.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | extern __inline __attribute__ ((__always_inline__)) __attribute__ 3 | ((__artificial__)) __attribute__ ((__warn_unused_result__)) char * 4 | __attribute__ ((__nothrow__ , __leaf__)) realpath (const char *__restrict 5 | __name, char *__restrict __resolved) {} 6 | 7 | /*=== 8 | TranslationUnit 9 | ExternalDeclaration 10 | FunctionDefinition 11 | DeclarationSpecifier 12 | StorageClassSpecifier Extern 13 | DeclarationSpecifier 14 | FunctionSpecifier Inline 15 | DeclarationSpecifier 16 | Extension 17 | Attribute "__always_inline__" 18 | DeclarationSpecifier 19 | Extension 20 | Attribute "__artificial__" 21 | DeclarationSpecifier 22 | Extension 23 | Attribute "__warn_unused_result__" 24 | DeclarationSpecifier 25 | TypeSpecifier Char 26 | Declarator 27 | DeclaratorKind 28 | Identifier "realpath" 29 | DerivedDeclarator Pointer 30 | PointerQualifier 31 | Extension 32 | Attribute "__nothrow__" 33 | Extension 34 | Attribute "__leaf__" 35 | DerivedDeclarator 36 | FunctionDeclarator 37 | ParameterDeclaration 38 | DeclarationSpecifier 39 | TypeQualifier Const 40 | DeclarationSpecifier 41 | TypeSpecifier Char 42 | Declarator 43 | DeclaratorKind 44 | Identifier "__name" 45 | DerivedDeclarator Pointer 46 | PointerQualifier 47 | TypeQualifier Restrict 48 | ParameterDeclaration 49 | DeclarationSpecifier 50 | TypeSpecifier Char 51 | Declarator 52 | DeclaratorKind 53 | Identifier "__resolved" 54 | DerivedDeclarator Pointer 55 | PointerQualifier 56 | TypeQualifier Restrict 57 | Ellipsis None 58 | Statement Compound 59 | ===*/ 60 | -------------------------------------------------------------------------------- /reftests/translation_unit-1388.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | # 1 "" 3 | # 1 "" 4 | # 1 "" 5 | # 31 "" 6 | # 1 "/usr/include/stdc-predef.h" 1 3 4 7 | # 32 "" 2 8 | # 1 "" 9 | 10 | /*=== 11 | TranslationUnit 12 | ===*/ 13 | -------------------------------------------------------------------------------- /reftests/translation_unit-1692.c: -------------------------------------------------------------------------------- 1 | // Check that a typedef that can be mistaken for a K&R-style argument declaration is correctly 2 | // parsed as an external declaration. What went wrong: until we encounter bar, the thing looks like 3 | // a function definition, where the name is followed by a two declarations K&R-style, similar to: 4 | // 5 | // ``` 6 | // int foo(i) 7 | // int i; // <-- __attribute__ and typedef occupy this slot, since both are valid declarations. 8 | // { } 9 | // ``` 10 | 11 | #pragma gnu 12 | 13 | int foo (int) __attribute__ ((__nothrow__)); 14 | typedef int named; 15 | int bar (int f) { } 16 | 17 | 18 | /*=== 19 | TranslationUnit 20 | ExternalDeclaration 21 | Declaration 22 | DeclarationSpecifier 23 | TypeSpecifier Int 24 | InitDeclarator 25 | Declarator 26 | DeclaratorKind 27 | Identifier "foo" 28 | DerivedDeclarator 29 | FunctionDeclarator 30 | ParameterDeclaration 31 | DeclarationSpecifier 32 | TypeSpecifier Int 33 | Ellipsis None 34 | Extension 35 | Attribute "__nothrow__" 36 | ExternalDeclaration 37 | Declaration 38 | DeclarationSpecifier 39 | StorageClassSpecifier Typedef 40 | DeclarationSpecifier 41 | TypeSpecifier Int 42 | InitDeclarator 43 | Declarator 44 | DeclaratorKind 45 | Identifier "named" 46 | ExternalDeclaration 47 | FunctionDefinition 48 | DeclarationSpecifier 49 | TypeSpecifier Int 50 | Declarator 51 | DeclaratorKind 52 | Identifier "bar" 53 | DerivedDeclarator 54 | FunctionDeclarator 55 | ParameterDeclaration 56 | DeclarationSpecifier 57 | TypeSpecifier Int 58 | Declarator 59 | DeclaratorKind 60 | Identifier "f" 61 | Ellipsis None 62 | Statement Compound 63 | ===*/ 64 | -------------------------------------------------------------------------------- /reftests/translation_unit-1781.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | int foo(int a __attribute__((unused)), int b __attribute__((unused))) {} 3 | 4 | /*=== 5 | TranslationUnit 6 | ExternalDeclaration 7 | FunctionDefinition 8 | DeclarationSpecifier 9 | TypeSpecifier Int 10 | Declarator 11 | DeclaratorKind 12 | Identifier "foo" 13 | DerivedDeclarator 14 | FunctionDeclarator 15 | ParameterDeclaration 16 | DeclarationSpecifier 17 | TypeSpecifier Int 18 | Declarator 19 | DeclaratorKind 20 | Identifier "a" 21 | Extension 22 | Attribute "unused" 23 | ParameterDeclaration 24 | DeclarationSpecifier 25 | TypeSpecifier Int 26 | Declarator 27 | DeclaratorKind 28 | Identifier "b" 29 | Extension 30 | Attribute "unused" 31 | Ellipsis None 32 | Statement Compound 33 | ===*/ 34 | -------------------------------------------------------------------------------- /reftests/translation_unit-1961.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | typedef int a; 4 | int foo() { 5 | int a; 6 | } 7 | 8 | /*=== 9 | TranslationUnit 10 | ExternalDeclaration 11 | Declaration 12 | DeclarationSpecifier 13 | StorageClassSpecifier Typedef 14 | DeclarationSpecifier 15 | TypeSpecifier Int 16 | InitDeclarator 17 | Declarator 18 | DeclaratorKind 19 | Identifier "a" 20 | ExternalDeclaration 21 | FunctionDefinition 22 | DeclarationSpecifier 23 | TypeSpecifier Int 24 | Declarator 25 | DeclaratorKind 26 | Identifier "foo" 27 | DerivedDeclarator KRFunction 28 | Statement Compound 29 | BlockItem 30 | Declaration 31 | DeclarationSpecifier 32 | TypeSpecifier Int 33 | InitDeclarator 34 | Declarator 35 | DeclaratorKind 36 | Identifier "a" 37 | ===*/ 38 | -------------------------------------------------------------------------------- /reftests/translation_unit-1993.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | typedef int a; 4 | void foo() { 5 | unsigned int; 6 | const a; 7 | a x; 8 | unsigned a; 9 | a = 1; 10 | } 11 | 12 | /*=== 13 | TranslationUnit 14 | ExternalDeclaration 15 | Declaration 16 | DeclarationSpecifier 17 | StorageClassSpecifier Typedef 18 | DeclarationSpecifier 19 | TypeSpecifier Int 20 | InitDeclarator 21 | Declarator 22 | DeclaratorKind 23 | Identifier "a" 24 | ExternalDeclaration 25 | FunctionDefinition 26 | DeclarationSpecifier 27 | TypeSpecifier Void 28 | Declarator 29 | DeclaratorKind 30 | Identifier "foo" 31 | DerivedDeclarator KRFunction 32 | Statement Compound 33 | BlockItem 34 | Declaration 35 | DeclarationSpecifier 36 | TypeSpecifier Unsigned 37 | DeclarationSpecifier 38 | TypeSpecifier Int 39 | BlockItem 40 | Declaration 41 | DeclarationSpecifier 42 | TypeQualifier Const 43 | DeclarationSpecifier 44 | TypeSpecifier TypedefName 45 | Identifier "a" 46 | BlockItem 47 | Declaration 48 | DeclarationSpecifier 49 | TypeSpecifier TypedefName 50 | Identifier "a" 51 | InitDeclarator 52 | Declarator 53 | DeclaratorKind 54 | Identifier "x" 55 | BlockItem 56 | Declaration 57 | DeclarationSpecifier 58 | TypeSpecifier Unsigned 59 | InitDeclarator 60 | Declarator 61 | DeclaratorKind 62 | Identifier "a" 63 | BlockItem 64 | Statement 65 | Expression 66 | BinaryOperatorExpression 67 | Expression 68 | Identifier "a" 69 | Expression 70 | Constant 71 | Integer "1" 72 | IntegerBase Decimal 73 | IntegerSuffix false false 74 | IntegerSize Int 75 | BinaryOperator Assign 76 | ===*/ 77 | -------------------------------------------------------------------------------- /reftests/translation_unit-2015.c: -------------------------------------------------------------------------------- 1 | // If parameter list treated "a" as a type specifier instead of identifier, this would succeed. 2 | #pragma gnu 3 | 4 | typedef int a; 5 | int foo(int a* b) {} 6 | 7 | /*=== 8 | ~ERROR 9 | ===*/ 10 | -------------------------------------------------------------------------------- /reftests/translation_unit-2029.c: -------------------------------------------------------------------------------- 1 | // If struct field treated "a" as a type specifier instead of identifier, this would succeed. 2 | 3 | #pragma gnu 4 | 5 | typedef int a; 6 | struct a { a a, b; }; 7 | 8 | /*=== 9 | TranslationUnit 10 | ExternalDeclaration 11 | Declaration 12 | DeclarationSpecifier 13 | StorageClassSpecifier Typedef 14 | DeclarationSpecifier 15 | TypeSpecifier Int 16 | InitDeclarator 17 | Declarator 18 | DeclaratorKind 19 | Identifier "a" 20 | ExternalDeclaration 21 | Declaration 22 | DeclarationSpecifier 23 | TypeSpecifier 24 | StructType 25 | StructKind Struct 26 | Identifier "a" 27 | StructDeclaration 28 | StructField 29 | SpecifierQualifier 30 | TypeSpecifier TypedefName 31 | Identifier "a" 32 | StructDeclarator 33 | Declarator 34 | DeclaratorKind 35 | Identifier "a" 36 | StructDeclarator 37 | Declarator 38 | DeclaratorKind 39 | Identifier "b" 40 | ===*/ 41 | -------------------------------------------------------------------------------- /reftests/translation_unit-2045.c: -------------------------------------------------------------------------------- 1 | // Struct fields maintain a separate 2 | 3 | #pragma gnu 4 | 5 | typedef int a; 6 | struct a { a a; a b; }; 7 | 8 | /*=== 9 | TranslationUnit 10 | ExternalDeclaration 11 | Declaration 12 | DeclarationSpecifier 13 | StorageClassSpecifier Typedef 14 | DeclarationSpecifier 15 | TypeSpecifier Int 16 | InitDeclarator 17 | Declarator 18 | DeclaratorKind 19 | Identifier "a" 20 | ExternalDeclaration 21 | Declaration 22 | DeclarationSpecifier 23 | TypeSpecifier 24 | StructType 25 | StructKind Struct 26 | Identifier "a" 27 | StructDeclaration 28 | StructField 29 | SpecifierQualifier 30 | TypeSpecifier TypedefName 31 | Identifier "a" 32 | StructDeclarator 33 | Declarator 34 | DeclaratorKind 35 | Identifier "a" 36 | StructDeclaration 37 | StructField 38 | SpecifierQualifier 39 | TypeSpecifier TypedefName 40 | Identifier "a" 41 | StructDeclarator 42 | Declarator 43 | DeclaratorKind 44 | Identifier "b" 45 | ===*/ 46 | -------------------------------------------------------------------------------- /reftests/translation_unit-2060.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | typedef int a; 4 | void foo() { 5 | a a; 6 | _Atomic (a) b; 7 | } 8 | 9 | /*=== 10 | ~ERROR 11 | ===*/ 12 | -------------------------------------------------------------------------------- /reftests/translation_unit-2070.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | typedef int a; 4 | void foo(int a, _Atomic (a) b) {} 5 | 6 | /*=== 7 | ~ERROR 8 | ===*/ 9 | -------------------------------------------------------------------------------- /reftests/translation_unit-2086.c: -------------------------------------------------------------------------------- 1 | // Technically, "a" is defined as a symbol before the "= .." part of the initializer is parsed. 2 | 3 | #pragma gnu 4 | 5 | typedef int a; 6 | int foo() { 7 | int a = sizeof(_Atomic(a)); 8 | } 9 | 10 | /*=== 11 | ~ERROR 12 | ===*/ 13 | -------------------------------------------------------------------------------- /reftests/translation_unit-2103.c: -------------------------------------------------------------------------------- 1 | // enum {a} defines a new variable "a" into the current scope. So the next _Atomic(a) must fail. 2 | 3 | #pragma gnu 4 | 5 | typedef int a; 6 | int foo() { 7 | int x = (enum {a})1; 8 | _Atomic(a) b; 9 | } 10 | 11 | /*=== 12 | ~ERROR 13 | ===*/ 14 | -------------------------------------------------------------------------------- /reftests/translation_unit-2114.c: -------------------------------------------------------------------------------- 1 | // enum {a} defines a new variable "a" into the current scope immediately after its declaration. 2 | #pragma gnu 3 | 4 | typedef int a; 5 | int foo() { 6 | int x = (enum {a, b = (a)1})1; 7 | } 8 | 9 | /*=== 10 | ~ERROR 11 | ===*/ 12 | -------------------------------------------------------------------------------- /reftests/translation_unit-2129.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | typedef int a; 4 | int foo(a a) {} 5 | int bar(int a); 6 | _Atomic (a) b; 7 | 8 | 9 | /*=== 10 | TranslationUnit 11 | ExternalDeclaration 12 | Declaration 13 | DeclarationSpecifier 14 | StorageClassSpecifier Typedef 15 | DeclarationSpecifier 16 | TypeSpecifier Int 17 | InitDeclarator 18 | Declarator 19 | DeclaratorKind 20 | Identifier "a" 21 | ExternalDeclaration 22 | FunctionDefinition 23 | DeclarationSpecifier 24 | TypeSpecifier Int 25 | Declarator 26 | DeclaratorKind 27 | Identifier "foo" 28 | DerivedDeclarator 29 | FunctionDeclarator 30 | ParameterDeclaration 31 | DeclarationSpecifier 32 | TypeSpecifier TypedefName 33 | Identifier "a" 34 | Declarator 35 | DeclaratorKind 36 | Identifier "a" 37 | Ellipsis None 38 | Statement Compound 39 | ExternalDeclaration 40 | Declaration 41 | DeclarationSpecifier 42 | TypeSpecifier Int 43 | InitDeclarator 44 | Declarator 45 | DeclaratorKind 46 | Identifier "bar" 47 | DerivedDeclarator 48 | FunctionDeclarator 49 | ParameterDeclaration 50 | DeclarationSpecifier 51 | TypeSpecifier Int 52 | Declarator 53 | DeclaratorKind 54 | Identifier "a" 55 | Ellipsis None 56 | ExternalDeclaration 57 | Declaration 58 | DeclarationSpecifier 59 | TypeSpecifier Atomic 60 | TypeName 61 | SpecifierQualifier 62 | TypeSpecifier TypedefName 63 | Identifier "a" 64 | InitDeclarator 65 | Declarator 66 | DeclaratorKind 67 | Identifier "b" 68 | ===*/ 69 | -------------------------------------------------------------------------------- /reftests/translation_unit-2147.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | void foo() { 4 | typedef int a; 5 | { 6 | a a; 7 | } 8 | _Atomic (a) b; 9 | } 10 | 11 | /*=== 12 | TranslationUnit 13 | ExternalDeclaration 14 | FunctionDefinition 15 | DeclarationSpecifier 16 | TypeSpecifier Void 17 | Declarator 18 | DeclaratorKind 19 | Identifier "foo" 20 | DerivedDeclarator KRFunction 21 | Statement Compound 22 | BlockItem 23 | Declaration 24 | DeclarationSpecifier 25 | StorageClassSpecifier Typedef 26 | DeclarationSpecifier 27 | TypeSpecifier Int 28 | InitDeclarator 29 | Declarator 30 | DeclaratorKind 31 | Identifier "a" 32 | BlockItem 33 | Statement Compound 34 | BlockItem 35 | Declaration 36 | DeclarationSpecifier 37 | TypeSpecifier TypedefName 38 | Identifier "a" 39 | InitDeclarator 40 | Declarator 41 | DeclaratorKind 42 | Identifier "a" 43 | BlockItem 44 | Declaration 45 | DeclarationSpecifier 46 | TypeSpecifier Atomic 47 | TypeName 48 | SpecifierQualifier 49 | TypeSpecifier TypedefName 50 | Identifier "a" 51 | InitDeclarator 52 | Declarator 53 | DeclaratorKind 54 | Identifier "b" 55 | ===*/ 56 | -------------------------------------------------------------------------------- /reftests/translation_unit-2167.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | typedef int a; 4 | void foo() { 5 | for (a a;;) 6 | a = a; 7 | while (true) {int a;} 8 | do { int a; } while(true); 9 | _Atomic (a) b; 10 | } 11 | 12 | /*=== 13 | TranslationUnit 14 | ExternalDeclaration 15 | Declaration 16 | DeclarationSpecifier 17 | StorageClassSpecifier Typedef 18 | DeclarationSpecifier 19 | TypeSpecifier Int 20 | InitDeclarator 21 | Declarator 22 | DeclaratorKind 23 | Identifier "a" 24 | ExternalDeclaration 25 | FunctionDefinition 26 | DeclarationSpecifier 27 | TypeSpecifier Void 28 | Declarator 29 | DeclaratorKind 30 | Identifier "foo" 31 | DerivedDeclarator KRFunction 32 | Statement Compound 33 | BlockItem 34 | Statement 35 | ForStatement 36 | ForInitializer 37 | Declaration 38 | DeclarationSpecifier 39 | TypeSpecifier TypedefName 40 | Identifier "a" 41 | InitDeclarator 42 | Declarator 43 | DeclaratorKind 44 | Identifier "a" 45 | Statement 46 | Expression 47 | BinaryOperatorExpression 48 | Expression 49 | Identifier "a" 50 | Expression 51 | Identifier "a" 52 | BinaryOperator Assign 53 | BlockItem 54 | Statement 55 | WhileStatement 56 | Expression 57 | Identifier "true" 58 | Statement Compound 59 | BlockItem 60 | Declaration 61 | DeclarationSpecifier 62 | TypeSpecifier Int 63 | InitDeclarator 64 | Declarator 65 | DeclaratorKind 66 | Identifier "a" 67 | BlockItem 68 | Statement 69 | DoWhileStatement 70 | Statement Compound 71 | BlockItem 72 | Declaration 73 | DeclarationSpecifier 74 | TypeSpecifier Int 75 | InitDeclarator 76 | Declarator 77 | DeclaratorKind 78 | Identifier "a" 79 | Expression 80 | Identifier "true" 81 | BlockItem 82 | Declaration 83 | DeclarationSpecifier 84 | TypeSpecifier Atomic 85 | TypeName 86 | SpecifierQualifier 87 | TypeSpecifier TypedefName 88 | Identifier "a" 89 | InitDeclarator 90 | Declarator 91 | DeclaratorKind 92 | Identifier "b" 93 | ===*/ 94 | -------------------------------------------------------------------------------- /reftests/translation_unit-2190.c: -------------------------------------------------------------------------------- 1 | // Test that scope of "if" condition and statement is cleaned up. 2 | #pragma gnu 3 | 4 | typedef int a, b; 5 | int x; 6 | void foo() { 7 | if (sizeof(enum {a})) x = sizeof(enum{b}); 8 | else x = b; 9 | switch (sizeof(enum {b})) x = b; 10 | a x, y; 11 | b z, w; 12 | } 13 | 14 | /*=== 15 | TranslationUnit 16 | ExternalDeclaration 17 | Declaration 18 | DeclarationSpecifier 19 | StorageClassSpecifier Typedef 20 | DeclarationSpecifier 21 | TypeSpecifier Int 22 | InitDeclarator 23 | Declarator 24 | DeclaratorKind 25 | Identifier "a" 26 | InitDeclarator 27 | Declarator 28 | DeclaratorKind 29 | Identifier "b" 30 | ExternalDeclaration 31 | Declaration 32 | DeclarationSpecifier 33 | TypeSpecifier Int 34 | InitDeclarator 35 | Declarator 36 | DeclaratorKind 37 | Identifier "x" 38 | ExternalDeclaration 39 | FunctionDefinition 40 | DeclarationSpecifier 41 | TypeSpecifier Void 42 | Declarator 43 | DeclaratorKind 44 | Identifier "foo" 45 | DerivedDeclarator KRFunction 46 | Statement Compound 47 | BlockItem 48 | Statement 49 | IfStatement 50 | Expression 51 | SizeOfTy 52 | TypeName 53 | SpecifierQualifier 54 | TypeSpecifier 55 | EnumType 56 | Enumerator 57 | Identifier "a" 58 | Statement 59 | Expression 60 | BinaryOperatorExpression 61 | Expression 62 | Identifier "x" 63 | Expression 64 | SizeOfTy 65 | TypeName 66 | SpecifierQualifier 67 | TypeSpecifier 68 | EnumType 69 | Enumerator 70 | Identifier "b" 71 | BinaryOperator Assign 72 | Statement 73 | Expression 74 | BinaryOperatorExpression 75 | Expression 76 | Identifier "x" 77 | Expression 78 | Identifier "b" 79 | BinaryOperator Assign 80 | BlockItem 81 | Statement 82 | SwitchStatement 83 | Expression 84 | SizeOfTy 85 | TypeName 86 | SpecifierQualifier 87 | TypeSpecifier 88 | EnumType 89 | Enumerator 90 | Identifier "b" 91 | Statement 92 | Expression 93 | BinaryOperatorExpression 94 | Expression 95 | Identifier "x" 96 | Expression 97 | Identifier "b" 98 | BinaryOperator Assign 99 | BlockItem 100 | Declaration 101 | DeclarationSpecifier 102 | TypeSpecifier TypedefName 103 | Identifier "a" 104 | InitDeclarator 105 | Declarator 106 | DeclaratorKind 107 | Identifier "x" 108 | InitDeclarator 109 | Declarator 110 | DeclaratorKind 111 | Identifier "y" 112 | BlockItem 113 | Declaration 114 | DeclarationSpecifier 115 | TypeSpecifier TypedefName 116 | Identifier "b" 117 | InitDeclarator 118 | Declarator 119 | DeclaratorKind 120 | Identifier "z" 121 | InitDeclarator 122 | Declarator 123 | DeclaratorKind 124 | Identifier "w" 125 | ===*/ 126 | -------------------------------------------------------------------------------- /reftests/translation_unit-2208.c: -------------------------------------------------------------------------------- 1 | // Test that "if" condition enum constants are defined within its scope. 2 | 3 | #pragma gnu 4 | 5 | typedef int a; 6 | void foo() { 7 | int x; 8 | if (sizeof(enum {a})) x = (_Atomic(a))1; 9 | } 10 | 11 | /*=== 12 | ~ERROR 13 | ===*/ 14 | -------------------------------------------------------------------------------- /reftests/translation_unit-2270.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | __extension__ union { long l; }; 3 | 4 | /*=== 5 | TranslationUnit 6 | ExternalDeclaration 7 | Declaration 8 | DeclarationSpecifier 9 | TypeSpecifier 10 | StructType 11 | StructKind Union 12 | StructDeclaration 13 | StructField 14 | SpecifierQualifier 15 | TypeSpecifier Long 16 | StructDeclarator 17 | Declarator 18 | DeclaratorKind 19 | Identifier "l" 20 | ===*/ 21 | -------------------------------------------------------------------------------- /reftests/translation_unit-2300.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | __extension__ _Static_assert(1,"ERR"); 3 | 4 | /*=== 5 | TranslationUnit 6 | ExternalDeclaration 7 | StaticAssert 8 | Expression 9 | Constant 10 | Integer "1" 11 | IntegerBase Decimal 12 | IntegerSuffix false false 13 | IntegerSize Int 14 | StringLiteral ["\"ERR\""] 15 | ===*/ 16 | -------------------------------------------------------------------------------- /reftests/translation_unit-2373.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | int main(argc, argv) int argc; char **argv; { } 3 | 4 | /*=== 5 | TranslationUnit 6 | ExternalDeclaration 7 | FunctionDefinition 8 | DeclarationSpecifier 9 | TypeSpecifier Int 10 | Declarator 11 | DeclaratorKind 12 | Identifier "main" 13 | DerivedDeclarator KRFunction 14 | Identifier "argc" 15 | Identifier "argv" 16 | Declaration 17 | DeclarationSpecifier 18 | TypeSpecifier Int 19 | InitDeclarator 20 | Declarator 21 | DeclaratorKind 22 | Identifier "argc" 23 | Declaration 24 | DeclarationSpecifier 25 | TypeSpecifier Char 26 | InitDeclarator 27 | Declarator 28 | DeclaratorKind 29 | Identifier "argv" 30 | DerivedDeclarator Pointer 31 | DerivedDeclarator Pointer 32 | Statement Compound 33 | ===*/ 34 | -------------------------------------------------------------------------------- /reftests/translation_unit-31-semicolon.c: -------------------------------------------------------------------------------- 1 | #pragma gnu 2 | 3 | void f(void) { 4 | }; 5 | 6 | 7 | /*=== 8 | TranslationUnit 9 | ExternalDeclaration 10 | FunctionDefinition 11 | DeclarationSpecifier 12 | TypeSpecifier Void 13 | Declarator 14 | DeclaratorKind 15 | Identifier "f" 16 | DerivedDeclarator 17 | FunctionDeclarator 18 | ParameterDeclaration 19 | DeclarationSpecifier 20 | TypeSpecifier Void 21 | Ellipsis None 22 | Statement Compound 23 | ===*/ 24 | -------------------------------------------------------------------------------- /src/astutil.rs: -------------------------------------------------------------------------------- 1 | use ast::*; 2 | use span::{Node, Span}; 3 | 4 | #[cfg_attr(test, derive(Debug, PartialEq, Clone))] 5 | pub enum Operation { 6 | Member(Node, Node), 7 | Unary(Node), 8 | Binary(Node, Node), 9 | Call(Vec>), 10 | } 11 | 12 | fn apply_op(a: Node, op: Node) -> Node { 13 | let span = Span::span(a.span.start, op.span.end); 14 | let expr = match op.node { 15 | Operation::Member(op, id) => Expression::Member(Box::new(Node::new( 16 | MemberExpression { 17 | operator: op, 18 | expression: Box::new(a), 19 | identifier: id, 20 | }, 21 | span, 22 | ))), 23 | Operation::Unary(op) => Expression::UnaryOperator(Box::new(Node::new( 24 | UnaryOperatorExpression { 25 | operator: op, 26 | operand: Box::new(a), 27 | }, 28 | span, 29 | ))), 30 | Operation::Binary(op, b) => Expression::BinaryOperator(Box::new(Node::new( 31 | BinaryOperatorExpression { 32 | operator: op, 33 | lhs: Box::new(a), 34 | rhs: Box::new(b), 35 | }, 36 | span, 37 | ))), 38 | Operation::Call(args) => Expression::Call(Box::new(Node::new( 39 | CallExpression { 40 | callee: Box::new(a), 41 | arguments: args, 42 | }, 43 | span, 44 | ))), 45 | }; 46 | 47 | Node::new(expr, span) 48 | } 49 | 50 | pub fn apply_ops(ops: Vec>, expr: Node) -> Node { 51 | ops.into_iter().fold(expr, apply_op) 52 | } 53 | 54 | pub fn concat(mut a: Vec, b: Vec) -> Vec { 55 | a.extend(b); 56 | a 57 | } 58 | 59 | pub fn infix( 60 | node: Node<()>, 61 | op: BinaryOperator, 62 | lhs: Node, 63 | rhs: Node, 64 | ) -> Node { 65 | let span = Span::span(lhs.span.start, rhs.span.end); 66 | Node::new( 67 | Expression::BinaryOperator(Box::new(Node::new( 68 | BinaryOperatorExpression { 69 | operator: Node::new(op, node.span), 70 | lhs: Box::new(lhs), 71 | rhs: Box::new(rhs), 72 | }, 73 | span, 74 | ))), 75 | span, 76 | ) 77 | } 78 | 79 | pub fn with_ext(mut d: Node, e: Option>>) -> Node { 80 | if let Some(e) = e { 81 | d.node.extensions.extend(e); 82 | } 83 | d 84 | } 85 | 86 | pub fn ts18661_float(binary: bool, width: usize, extended: bool) -> TS18661FloatType { 87 | TS18661FloatType { 88 | format: match (binary, extended) { 89 | (true, false) => TS18661FloatFormat::BinaryInterchange, 90 | (true, true) => TS18661FloatFormat::BinaryExtended, 91 | (false, false) => TS18661FloatFormat::DecimalInterchange, 92 | (false, true) => TS18661FloatFormat::DecimalExtended, 93 | }, 94 | width: width, 95 | } 96 | } 97 | 98 | pub fn int_suffix(mut s: &str) -> Result { 99 | let mut l = IntegerSize::Int; 100 | let mut u = false; 101 | let mut i = false; 102 | 103 | while s.len() > 0 { 104 | if l == IntegerSize::Int && (s.starts_with("ll") || s.starts_with("LL")) { 105 | l = IntegerSize::LongLong; 106 | s = &s[2..]; 107 | } else if l == IntegerSize::Int && (s.starts_with("l") || s.starts_with("L")) { 108 | l = IntegerSize::Long; 109 | s = &s[1..]; 110 | } else if !u && (s.starts_with("u") || s.starts_with("U")) { 111 | u = true; 112 | s = &s[1..]; 113 | } else if !i 114 | && (s.starts_with("i") 115 | || s.starts_with("I") 116 | || s.starts_with("j") 117 | || s.starts_with("J")) 118 | { 119 | i = true; 120 | s = &s[1..]; 121 | } else { 122 | return Err("integer suffix"); 123 | } 124 | } 125 | 126 | Ok(IntegerSuffix { 127 | size: l, 128 | unsigned: u, 129 | imaginary: i, 130 | }) 131 | } 132 | -------------------------------------------------------------------------------- /src/bin/dump.rs: -------------------------------------------------------------------------------- 1 | //! Parse a C file and dump the AST. 2 | 3 | extern crate lang_c; 4 | 5 | use std::process::exit; 6 | 7 | use lang_c::driver::{Config, Flavor}; 8 | use lang_c::visit::Visit; 9 | 10 | fn main() { 11 | let mut config = Config::default(); 12 | let mut source = None; 13 | let mut quiet = false; 14 | 15 | for opt in std::env::args().skip(1) { 16 | if opt == "-use-gcc" { 17 | config = Config::with_gcc(); 18 | } else if opt == "-use-clang" { 19 | config = Config::with_clang(); 20 | } else if opt == "-use-std" { 21 | config.flavor = Flavor::StdC11; 22 | } else if opt == "-q" { 23 | quiet = true; 24 | } else if opt.starts_with("-") { 25 | config.cpp_options.push(opt); 26 | } else { 27 | if source.is_none() { 28 | source = Some(opt); 29 | } else { 30 | println!("multiple input files given"); 31 | exit(1); 32 | } 33 | } 34 | } 35 | 36 | let source = match source { 37 | Some(s) => s, 38 | None => { 39 | println!("input file required"); 40 | exit(1); 41 | } 42 | }; 43 | 44 | match lang_c::driver::parse(&config, &source) { 45 | Ok(parse) => { 46 | if !quiet { 47 | let mut buf = String::new(); 48 | { 49 | let mut printer = lang_c::print::Printer::new(&mut buf); 50 | printer.visit_translation_unit(&parse.unit); 51 | } 52 | println!("{}", buf); 53 | } 54 | } 55 | Err(err) => { 56 | println!("{}", err); 57 | exit(1); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/bin/meminfo.rs: -------------------------------------------------------------------------------- 1 | extern crate lang_c; 2 | use lang_c::ast::*; 3 | use std::mem::size_of; 4 | 5 | macro_rules! ps { 6 | ($( $i:ident )+) => ({ $(println!("{:3} {}", size_of::<$i>(), stringify!($i));)+ }) 7 | } 8 | 9 | fn main() { 10 | ps! { 11 | TypeOf 12 | Identifier 13 | Constant 14 | Integer 15 | Float 16 | Expression 17 | MemberOperator 18 | GenericAssociation 19 | UnaryOperator 20 | BinaryOperator 21 | OffsetDesignator 22 | OffsetMember 23 | Declaration 24 | DeclarationSpecifier 25 | InitDeclarator 26 | StorageClassSpecifier 27 | TypeSpecifier 28 | StructType 29 | StructDeclaration 30 | SpecifierQualifier 31 | StructDeclarator 32 | Enumerator 33 | TypeQualifier 34 | FunctionSpecifier 35 | AlignmentSpecifier 36 | Declarator 37 | DeclaratorKind 38 | DerivedDeclarator 39 | PointerQualifier 40 | ArraySize 41 | ParameterDeclaration 42 | Ellipsis 43 | TypeName 44 | Initializer 45 | InitializerListItem 46 | Designator 47 | StaticAssert 48 | Statement 49 | Label 50 | ForInitializer 51 | BlockItem 52 | TranslationUnit 53 | ExternalDeclaration 54 | FunctionDefinition 55 | Extension 56 | AsmStatement 57 | GnuAsmOperand 58 | TypeOf 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/driver.rs: -------------------------------------------------------------------------------- 1 | //! Preprocess and parse C source file into an abstract syntax tree 2 | 3 | use std::collections::HashSet; 4 | use std::error; 5 | use std::fmt; 6 | use std::io; 7 | use std::path::Path; 8 | use std::process::Command; 9 | 10 | use ast::TranslationUnit; 11 | use env::Env; 12 | use loc; 13 | use parser::translation_unit; 14 | 15 | /// Parser configuration 16 | #[derive(Clone, Debug)] 17 | pub struct Config { 18 | /// Command used to invoke C preprocessor 19 | pub cpp_command: String, 20 | /// Options to pass to the preprocessor program 21 | pub cpp_options: Vec, 22 | /// Language flavor to parse 23 | pub flavor: Flavor, 24 | } 25 | 26 | impl Config { 27 | /// Use `gcc` as a pre-processor and enable gcc extensions 28 | pub fn with_gcc() -> Config { 29 | Config { 30 | cpp_command: "gcc".into(), 31 | cpp_options: vec!["-E".into()], 32 | flavor: Flavor::GnuC11, 33 | } 34 | } 35 | 36 | /// Use `clang` as a pre-processor and enable Clang extensions 37 | pub fn with_clang() -> Config { 38 | Config { 39 | cpp_command: "clang".into(), 40 | cpp_options: vec!["-E".into()], 41 | flavor: Flavor::ClangC11, 42 | } 43 | } 44 | } 45 | 46 | impl Default for Config { 47 | #[cfg(target_os = "macos")] 48 | fn default() -> Config { 49 | Self::with_clang() 50 | } 51 | 52 | #[cfg(not(target_os = "macos"))] 53 | fn default() -> Config { 54 | Self::with_gcc() 55 | } 56 | } 57 | 58 | /// C language flavors 59 | #[derive(Copy, Clone, PartialEq, Debug)] 60 | pub enum Flavor { 61 | /// Strict standard C11 62 | StdC11, 63 | /// Standard C11 with GNU extensions 64 | GnuC11, 65 | /// Standard C11 with Clang extensions 66 | ClangC11, 67 | } 68 | 69 | /// Result of a successful parse 70 | #[derive(Clone, Debug)] 71 | pub struct Parse { 72 | /// Pre-processed source text 73 | pub source: String, 74 | /// Root of the abstract syntax tree 75 | pub unit: TranslationUnit, 76 | } 77 | 78 | #[derive(Debug)] 79 | /// Error type returned from `parse` 80 | pub enum Error { 81 | PreprocessorError(io::Error), 82 | SyntaxError(SyntaxError), 83 | } 84 | 85 | impl From for Error { 86 | fn from(e: SyntaxError) -> Error { 87 | Error::SyntaxError(e) 88 | } 89 | } 90 | 91 | impl fmt::Display for Error { 92 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 93 | match self { 94 | &Error::PreprocessorError(ref e) => write!(fmt, "preprocessor error: {}", e), 95 | &Error::SyntaxError(ref e) => write!(fmt, "syntax error: {}", e), 96 | } 97 | } 98 | } 99 | 100 | impl error::Error for Error { 101 | fn description(&self) -> &str { 102 | match self { 103 | &Error::PreprocessorError(_) => "preprocessor error", 104 | &Error::SyntaxError(_) => "syntax error", 105 | } 106 | } 107 | } 108 | 109 | /// Syntax error during parsing 110 | #[derive(Debug, Clone)] 111 | pub struct SyntaxError { 112 | /// Pre-processed source text 113 | pub source: String, 114 | /// Line number in the preprocessed source 115 | pub line: usize, 116 | /// Column number in the preprocessed source 117 | pub column: usize, 118 | /// Byte position in the preproccessed source 119 | pub offset: usize, 120 | /// Tokens expected at the error location 121 | pub expected: HashSet<&'static str>, 122 | } 123 | 124 | impl SyntaxError { 125 | /// Quoted and comma-separated list of expected tokens 126 | pub fn format_expected(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 127 | let mut list = self.expected.iter().collect::>(); 128 | list.sort(); 129 | for (i, t) in list.iter().enumerate() { 130 | if i > 0 { 131 | try!(write!(fmt, ", ")); 132 | } 133 | try!(write!(fmt, "'{}'", t)); 134 | } 135 | 136 | Ok(()) 137 | } 138 | 139 | pub fn get_location(&self) -> (loc::Location, Vec) { 140 | loc::get_location_for_offset(&self.source, self.offset) 141 | } 142 | } 143 | 144 | impl fmt::Display for SyntaxError { 145 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 146 | let (loc, inc) = self.get_location(); 147 | try!(write!( 148 | fmt, 149 | "unexpected token at \"{}\" line {} column {}, expected ", 150 | loc.file, loc.line, self.column 151 | )); 152 | try!(self.format_expected(fmt)); 153 | for loc in inc { 154 | try!(write!(fmt, "\n included from {}:{}", loc.file, loc.line)); 155 | } 156 | Ok(()) 157 | } 158 | } 159 | 160 | /// Parse a C file 161 | pub fn parse>(config: &Config, source: P) -> Result { 162 | let processed = match preprocess(config, source.as_ref()) { 163 | Ok(s) => s, 164 | Err(e) => return Err(Error::PreprocessorError(e)), 165 | }; 166 | 167 | Ok(try!(parse_preprocessed(config, processed))) 168 | } 169 | 170 | pub fn parse_preprocessed(config: &Config, source: String) -> Result { 171 | let mut env = match config.flavor { 172 | Flavor::StdC11 => Env::with_core(), 173 | Flavor::GnuC11 => Env::with_gnu(), 174 | Flavor::ClangC11 => Env::with_clang(), 175 | }; 176 | 177 | match translation_unit(&source, &mut env) { 178 | Ok(unit) => Ok(Parse { 179 | source: source, 180 | unit: unit, 181 | }), 182 | Err(err) => Err(SyntaxError { 183 | source: source, 184 | line: err.line, 185 | column: err.column, 186 | offset: err.offset, 187 | expected: err.expected, 188 | }), 189 | } 190 | } 191 | 192 | fn preprocess(config: &Config, source: &Path) -> io::Result { 193 | let mut cmd = Command::new(&config.cpp_command); 194 | 195 | for item in &config.cpp_options { 196 | cmd.arg(item); 197 | } 198 | 199 | cmd.arg(source); 200 | 201 | let output = try!(cmd.output()); 202 | 203 | if output.status.success() { 204 | match String::from_utf8(output.stdout) { 205 | Ok(s) => Ok(s), 206 | Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), 207 | } 208 | } else { 209 | match String::from_utf8(output.stderr) { 210 | Ok(s) => Err(io::Error::new(io::ErrorKind::Other, s)), 211 | Err(_) => Err(io::Error::new( 212 | io::ErrorKind::Other, 213 | "cpp error contains invalid utf-8", 214 | )), 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/env.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet}; 2 | 3 | use ast::*; 4 | use span::Node; 5 | use strings; 6 | 7 | #[derive(Clone, Copy, Debug, PartialEq, Hash)] 8 | pub enum Symbol { 9 | Typename, 10 | Identifier, 11 | } 12 | 13 | pub struct Env { 14 | pub symbols: Vec>, 15 | pub extensions_gnu: bool, 16 | pub extensions_clang: bool, 17 | pub reserved: HashSet<&'static str>, 18 | } 19 | 20 | impl Env { 21 | pub fn with_core() -> Env { 22 | let mut reserved = HashSet::default(); 23 | reserved.extend(strings::RESERVED_C11.iter()); 24 | Env { 25 | extensions_gnu: false, 26 | extensions_clang: false, 27 | symbols: vec![HashMap::default()], 28 | reserved: reserved, 29 | } 30 | } 31 | 32 | pub fn with_gnu() -> Env { 33 | let mut symbols = HashMap::default(); 34 | let mut reserved = HashSet::default(); 35 | symbols.insert("__builtin_va_list".to_owned(), Symbol::Typename); 36 | reserved.extend(strings::RESERVED_C11.iter()); 37 | reserved.extend(strings::RESERVED_GNU.iter()); 38 | Env { 39 | extensions_gnu: true, 40 | extensions_clang: false, 41 | symbols: vec![symbols], 42 | reserved: reserved, 43 | } 44 | } 45 | 46 | pub fn with_clang() -> Env { 47 | let mut symbols = HashMap::default(); 48 | let mut reserved = HashSet::default(); 49 | symbols.insert("__builtin_va_list".to_owned(), Symbol::Typename); 50 | reserved.extend(strings::RESERVED_C11.iter()); 51 | reserved.extend(strings::RESERVED_GNU.iter()); 52 | reserved.extend(strings::RESERVED_CLANG.iter()); 53 | Env { 54 | extensions_gnu: true, 55 | extensions_clang: true, 56 | symbols: vec![symbols], 57 | reserved: reserved, 58 | } 59 | } 60 | 61 | pub fn enter_scope(&mut self) { 62 | self.symbols.push(HashMap::new()); 63 | } 64 | 65 | pub fn leave_scope(&mut self) { 66 | self.symbols.pop().expect("more scope pops than pushes"); 67 | } 68 | 69 | pub fn is_typename(&self, ident: &str) -> bool { 70 | for scope in self.symbols.iter().rev() { 71 | if let Some(symbol) = scope.get(ident) { 72 | return *symbol == Symbol::Typename; 73 | } 74 | } 75 | false 76 | } 77 | 78 | pub fn handle_declarator(&mut self, d: &Node, sym: Symbol) { 79 | if let Some(name) = find_declarator_name(&d.node.kind.node) { 80 | self.add_symbol(name, sym) 81 | } 82 | } 83 | 84 | pub fn add_symbol(&mut self, s: &str, symbol: Symbol) { 85 | let scope = self 86 | .symbols 87 | .last_mut() 88 | .expect("at least one scope should be always present"); 89 | scope.insert(s.to_string(), symbol); 90 | } 91 | 92 | #[cfg(test)] 93 | pub fn add_typename(&mut self, s: &str) { 94 | self.add_symbol(s, Symbol::Typename) 95 | } 96 | } 97 | 98 | fn find_declarator_name(d: &DeclaratorKind) -> Option<&str> { 99 | match d { 100 | &DeclaratorKind::Abstract => None, 101 | &DeclaratorKind::Identifier(ref i) => Some(&i.node.name), 102 | &DeclaratorKind::Declarator(ref d) => find_declarator_name(&d.node.kind.node), 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! C language parser and abstract syntax tree 2 | //! 3 | //! ``` 4 | //! use lang_c::driver::{Config, parse}; 5 | //! 6 | //! fn main() { 7 | //! let config = Config::default(); 8 | //! println!("{:?}", parse(&config, "example.c")); 9 | //! } 10 | //! ``` 11 | 12 | #![allow(deprecated)] 13 | #![allow(ellipsis_inclusive_range_patterns)] 14 | 15 | pub mod ast; 16 | pub mod driver; 17 | pub mod loc; 18 | pub mod print; 19 | pub mod span; 20 | pub mod visit; 21 | 22 | mod astutil; 23 | mod env; 24 | mod parser; 25 | mod strings; 26 | 27 | #[cfg(test)] 28 | mod tests; 29 | -------------------------------------------------------------------------------- /src/loc.rs: -------------------------------------------------------------------------------- 1 | //! Convert byte offsets into line numbers 2 | const F_NEW: u32 = 1; 3 | const F_RET: u32 = 2; 4 | 5 | #[derive(Debug, Clone, Copy, PartialEq)] 6 | pub struct Location<'a> { 7 | pub file: &'a str, 8 | pub line: usize, 9 | } 10 | 11 | /// Find file name and line number that correspond to an offset in a preprocessed source. 12 | /// 13 | /// If location was in an included file, second element of the returned tuple contains a list of 14 | /// locations of `#include` directives, in the order they were procssed (top-level file first, then 15 | /// all intermediate included files). 16 | pub fn get_location_for_offset<'a>(src: &'a str, pos: usize) -> (Location<'a>, Vec>) { 17 | let mut p = 0; 18 | let mut inc = Vec::new(); 19 | let mut loc = Location { file: "", line: 1 }; 20 | 21 | while p < pos { 22 | let n = p + src[p..].find("\n").unwrap_or(src[p..].len()); 23 | if pos <= n { 24 | break; 25 | } 26 | 27 | if let Some((l, f)) = parse_line_directive(&src[p..n]) { 28 | if f & F_NEW == F_NEW { 29 | inc.push(loc); 30 | } 31 | if f & F_RET == F_RET { 32 | inc.pop(); 33 | } 34 | loc = l; 35 | } else { 36 | loc.line += 1; 37 | } 38 | 39 | p = n + 1; 40 | } 41 | (loc, inc) 42 | } 43 | 44 | #[test] 45 | fn test_get_location_for_offset() { 46 | fn t(src: &str, pos: usize, file: &str, line: usize, includes: &[(&str, usize)]) { 47 | let (loc, inc) = get_location_for_offset(src, pos); 48 | assert_eq!( 49 | loc, 50 | Location { 51 | file: file, 52 | line: line 53 | } 54 | ); 55 | assert_eq!(inc.len(), includes.len()); 56 | for (loc, &(f, l)) in inc.iter().zip(includes) { 57 | assert_eq!(loc, &Location { file: f, line: l }); 58 | } 59 | } 60 | 61 | t("# 10 \"init\"", 0, "", 1, &[]); 62 | t("# 10 \"init\"", 1, "", 1, &[]); 63 | t("# 10 \"init\"\na\nb\n", 12, "init", 10, &[]); 64 | t("# 10 \"init\"\na\nb\n", 13, "init", 10, &[]); 65 | t("# 10 \"init\"\na\nb\n", 14, "init", 11, &[]); 66 | t("# 10 \"init\"\na\nb\n", 15, "init", 11, &[]); 67 | 68 | const T: &'static str = r#" 69 | # 10 "foo" 70 | ... 71 | # 1 "bar" 1 3 4 72 | # 5 "bar" 3 73 | # 11 "baz" 1 74 | ... 75 | ... 76 | # 6 "bar" 2 77 | ... 78 | # 15 "foo" 2 79 | ... 80 | ... 81 | # 2 "ook" 1 82 | "#; 83 | t(T, 12, "foo", 10, &[]); 84 | t(T, 32, "bar", 1, &[("foo", 11)]); 85 | t(T, 61, "baz", 12, &[("foo", 11), ("bar", 5)]); 86 | t(T, 77, "bar", 6, &[("foo", 11)]); 87 | t(T, 98, "foo", 16, &[]); 88 | t(T, 102, "foo", 17, &[]); 89 | t(T, 114, "ook", 2, &[("foo", 17)]); 90 | } 91 | 92 | macro_rules! otry { 93 | ($e:expr) => { 94 | match $e { 95 | Some(v) => v, 96 | None => return None, 97 | } 98 | }; 99 | } 100 | 101 | fn strip_prefix<'a>(s: &'a str, p: &str) -> Option<&'a str> { 102 | if s.starts_with(p) { 103 | Some(&s[p.len()..]) 104 | } else { 105 | None 106 | } 107 | } 108 | 109 | // https://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html 110 | fn parse_line_directive(s: &str) -> Option<(Location, u32)> { 111 | let s = otry!(strip_prefix(s, "# ")); 112 | let n = otry!(s.find(" ")); 113 | let line = otry!(usize::from_str_radix(&s[..n], 10).ok()); 114 | 115 | let s = otry!(strip_prefix(&s[n..], " \"")); 116 | let mut n = 0; 117 | while n < s.len() { 118 | n += otry!(s[n..].find(&['"', '\\'][..])); 119 | if s[n..].starts_with('"') { 120 | break; 121 | } 122 | n += otry!(s[n..].char_indices().nth(2).map(|p| p.0)); 123 | } 124 | let file = &s[..n]; 125 | let s = otry!(strip_prefix(&s[n..], "\"")); 126 | 127 | let flags = s.bytes().filter(|&c| c >= b'1' && c <= b'4'); 128 | let flags = flags.fold(0, |a, f| a | 1 << (f - b'1')); 129 | 130 | Some(( 131 | Location { 132 | file: file, 133 | line: line, 134 | }, 135 | flags, 136 | )) 137 | } 138 | 139 | #[test] 140 | fn test_line_directive() { 141 | assert_eq!( 142 | parse_line_directive(r#"# 14 "ab\"\000" 1 2 3 4"#), 143 | Some(( 144 | Location { 145 | file: r#"ab\"\000"#, 146 | line: 14 147 | }, 148 | 15, 149 | )) 150 | ); 151 | assert_eq!(parse_line_directive("#"), None); 152 | assert_eq!(parse_line_directive("# 1 "), None); 153 | assert_eq!(parse_line_directive("# 1 \""), None); 154 | assert_eq!(parse_line_directive("# -1 \"\""), None); 155 | assert_eq!( 156 | parse_line_directive("# 0 \"\""), 157 | Some((Location { file: "", line: 0 }, 0)) 158 | ); 159 | assert_eq!(parse_line_directive("# 0 \"# #\x0a\x0a\\"), None); 160 | assert_eq!(parse_line_directive("# 0 \"\\"), None); 161 | assert_eq!(parse_line_directive("# 0 \"\\…"), None); 162 | } 163 | -------------------------------------------------------------------------------- /src/print.rs: -------------------------------------------------------------------------------- 1 | #![allow(unknown_lints)] 2 | #![allow(bare_trait_objects)] 3 | 4 | //! Debug printer for abstract syntax tree 5 | //! 6 | //! ```no_run 7 | //! # use lang_c::print::Printer; 8 | //! use lang_c::visit::Visit; 9 | //! # let unit = panic!(); 10 | //! let s = &mut String::new(); 11 | //! Printer::new(s).visit_translation_unit(unit); 12 | //! ``` 13 | use std::fmt; 14 | 15 | use ast::*; 16 | use span::Span; 17 | use visit::*; 18 | 19 | /// Printing visitor 20 | /// 21 | /// Recursively prints the AST tree as indented list of AST nodes, one node per line. 22 | /// Each line contains name of the AST node type, followed by the enum variant 23 | /// (when it does not match name of contained node), and primitive fields. 24 | pub struct Printer<'a> { 25 | w: &'a mut fmt::Write, 26 | offset: usize, 27 | } 28 | 29 | impl<'a> Printer<'a> { 30 | pub fn new(w: &mut fmt::Write) -> Printer { 31 | Printer { w: w, offset: 0 } 32 | } 33 | 34 | fn block(&mut self) -> Printer { 35 | writeln!(&mut self.w, "").unwrap(); 36 | Printer { 37 | w: &mut self.w, 38 | offset: self.offset + 1, 39 | } 40 | } 41 | 42 | fn name(&mut self, name: &str) { 43 | write!(&mut self.w, "{2:1$}{0}", name, self.offset * 4, "").unwrap(); 44 | } 45 | 46 | fn field(&mut self, s: T) { 47 | write!(&mut self.w, " {}", s).unwrap(); 48 | } 49 | 50 | fn field_str(&mut self, s: &str) { 51 | self.field_str_ext(" ", s); 52 | } 53 | 54 | fn field_str_ext(&mut self, prefix: &str, str: &str) { 55 | write!(&mut self.w, "{}\"{}\"", prefix, Escape(str)).unwrap(); 56 | } 57 | } 58 | 59 | impl<'ast, 'a> Visit<'ast> for Printer<'a> { 60 | fn visit_identifier(&mut self, n: &'ast Identifier, span: &'ast Span) { 61 | self.name("Identifier"); 62 | self.field_str(&n.name); 63 | visit_identifier(&mut self.block(), n, span); 64 | } 65 | fn visit_constant(&mut self, n: &'ast Constant, span: &'ast Span) { 66 | self.name("Constant"); 67 | match *n { 68 | Constant::Character(ref c) => { 69 | self.field("Character"); 70 | self.field(c); 71 | } 72 | _ => {}, 73 | } 74 | 75 | visit_constant(&mut self.block(), n, span); 76 | } 77 | fn visit_integer(&mut self, n: &'ast Integer, span: &'ast Span) { 78 | self.name("Integer"); 79 | self.field_str(&n.number); 80 | visit_integer(&mut self.block(), n, span); 81 | } 82 | fn visit_integer_base(&mut self, n: &'ast IntegerBase, span: &'ast Span) { 83 | self.name("IntegerBase"); 84 | self.field(match *n { 85 | IntegerBase::Decimal => "Decimal", 86 | IntegerBase::Octal => "Octal", 87 | IntegerBase::Hexadecimal => "Hexadecimal", 88 | IntegerBase::Binary => "Binary", 89 | }); 90 | visit_integer_base(&mut self.block(), n, span); 91 | } 92 | fn visit_integer_suffix(&mut self, n: &'ast IntegerSuffix, span: &'ast Span) { 93 | self.name("IntegerSuffix"); 94 | self.field(n.unsigned); 95 | self.field(n.imaginary); 96 | visit_integer_suffix(&mut self.block(), n, span); 97 | } 98 | fn visit_integer_size(&mut self, n: &'ast IntegerSize, span: &'ast Span) { 99 | self.name("IntegerSize"); 100 | self.field(match *n { 101 | IntegerSize::Int => "Int", 102 | IntegerSize::Long => "Long", 103 | IntegerSize::LongLong => "LongLong", 104 | }); 105 | visit_integer_size(&mut self.block(), n, span); 106 | } 107 | fn visit_float(&mut self, n: &'ast Float, span: &'ast Span) { 108 | self.name("Float"); 109 | self.field_str(&n.number); 110 | visit_float(&mut self.block(), n, span); 111 | } 112 | fn visit_float_base(&mut self, n: &'ast FloatBase, span: &'ast Span) { 113 | self.name("FloatBase"); 114 | self.field(match *n { 115 | FloatBase::Decimal => "Decimal", 116 | FloatBase::Hexadecimal => "Hexadecimal", 117 | }); 118 | visit_float_base(&mut self.block(), n, span); 119 | } 120 | fn visit_float_suffix(&mut self, n: &'ast FloatSuffix, span: &'ast Span) { 121 | self.name("FloatSuffix"); 122 | self.field(n.imaginary); 123 | visit_float_suffix(&mut self.block(), n, span); 124 | } 125 | fn visit_float_format(&mut self, n: &'ast FloatFormat, span: &'ast Span) { 126 | self.name("FloatFormat"); 127 | print_float_format(self, n); 128 | visit_float_format(&mut self.block(), n, span); 129 | } 130 | fn visit_string_literal(&mut self, n: &'ast StringLiteral, span: &'ast Span) { 131 | self.name("StringLiteral"); 132 | 133 | self.w.write_str(" [").unwrap(); 134 | let mut comma = false; 135 | for p in n { 136 | self.field_str_ext(if comma { ", " } else { "" }, p); 137 | comma = true; 138 | } 139 | self.w.write_str("]").unwrap(); 140 | 141 | visit_string_literal(&mut self.block(), n, span); 142 | } 143 | fn visit_expression(&mut self, n: &'ast Expression, span: &'ast Span) { 144 | self.name("Expression"); 145 | visit_expression(&mut self.block(), n, span); 146 | } 147 | fn visit_member_operator(&mut self, n: &'ast MemberOperator, span: &'ast Span) { 148 | self.name("MemberOperator"); 149 | self.field(match *n { 150 | MemberOperator::Direct => "Direct", 151 | MemberOperator::Indirect => "Indirect", 152 | }); 153 | visit_member_operator(&mut self.block(), n, span); 154 | } 155 | fn visit_generic_selection(&mut self, n: &'ast GenericSelection, span: &'ast Span) { 156 | self.name("GenericSelection"); 157 | visit_generic_selection(&mut self.block(), n, span); 158 | } 159 | fn visit_generic_association(&mut self, n: &'ast GenericAssociation, span: &'ast Span) { 160 | self.name("GenericAssociation"); 161 | visit_generic_association(&mut self.block(), n, span); 162 | } 163 | fn visit_generic_association_type( 164 | &mut self, 165 | n: &'ast GenericAssociationType, 166 | span: &'ast Span, 167 | ) { 168 | self.name("GenericAssociationType"); 169 | visit_generic_association_type(&mut self.block(), n, span); 170 | } 171 | fn visit_member_expression(&mut self, n: &'ast MemberExpression, span: &'ast Span) { 172 | self.name("MemberExpression"); 173 | visit_member_expression(&mut self.block(), n, span); 174 | } 175 | fn visit_call_expression(&mut self, n: &'ast CallExpression, span: &'ast Span) { 176 | self.name("CallExpression"); 177 | visit_call_expression(&mut self.block(), n, span); 178 | } 179 | fn visit_compound_literal(&mut self, n: &'ast CompoundLiteral, span: &'ast Span) { 180 | self.name("CompoundLiteral"); 181 | visit_compound_literal(&mut self.block(), n, span); 182 | } 183 | fn visit_sizeofty(&mut self, n: &'ast SizeOfTy, span: &'ast Span) { 184 | self.name("SizeOfTy"); 185 | visit_sizeofty(&mut self.block(), n, span); 186 | } 187 | fn visit_sizeofval(&mut self, n: &'ast SizeOfVal, span: &'ast Span) { 188 | self.name("SizeOfVal"); 189 | visit_sizeofval(&mut self.block(), n, span); 190 | } 191 | fn visit_alignof(&mut self, n: &'ast AlignOf, span: &'ast Span) { 192 | self.name("AlignOf"); 193 | visit_alignof(&mut self.block(), n, span); 194 | } 195 | fn visit_unary_operator(&mut self, n: &'ast UnaryOperator, span: &'ast Span) { 196 | self.name("UnaryOperator"); 197 | self.field(match *n { 198 | UnaryOperator::PostIncrement => "PostIncrement", 199 | UnaryOperator::PostDecrement => "PostDecrement", 200 | UnaryOperator::PreIncrement => "PreIncrement", 201 | UnaryOperator::PreDecrement => "PreDecrement", 202 | UnaryOperator::Address => "Address", 203 | UnaryOperator::Indirection => "Indirection", 204 | UnaryOperator::Plus => "Plus", 205 | UnaryOperator::Minus => "Minus", 206 | UnaryOperator::Complement => "Complement", 207 | UnaryOperator::Negate => "Negate", 208 | }); 209 | visit_unary_operator(&mut self.block(), n, span); 210 | } 211 | fn visit_unary_operator_expression( 212 | &mut self, 213 | n: &'ast UnaryOperatorExpression, 214 | span: &'ast Span, 215 | ) { 216 | self.name("UnaryOperatorExpression"); 217 | visit_unary_operator_expression(&mut self.block(), n, span); 218 | } 219 | fn visit_cast_expression(&mut self, n: &'ast CastExpression, span: &'ast Span) { 220 | self.name("CastExpression"); 221 | visit_cast_expression(&mut self.block(), n, span); 222 | } 223 | fn visit_binary_operator(&mut self, n: &'ast BinaryOperator, span: &'ast Span) { 224 | self.name("BinaryOperator"); 225 | self.field(match *n { 226 | BinaryOperator::Index => "Index", 227 | BinaryOperator::Multiply => "Multiply", 228 | BinaryOperator::Divide => "Divide", 229 | BinaryOperator::Modulo => "Modulo", 230 | BinaryOperator::Plus => "Plus", 231 | BinaryOperator::Minus => "Minus", 232 | BinaryOperator::ShiftLeft => "ShiftLeft", 233 | BinaryOperator::ShiftRight => "ShiftRight", 234 | BinaryOperator::Less => "Less", 235 | BinaryOperator::Greater => "Greater", 236 | BinaryOperator::LessOrEqual => "LessOrEqual", 237 | BinaryOperator::GreaterOrEqual => "GreaterOrEqual", 238 | BinaryOperator::Equals => "Equals", 239 | BinaryOperator::NotEquals => "NotEquals", 240 | BinaryOperator::BitwiseAnd => "BitwiseAnd", 241 | BinaryOperator::BitwiseXor => "BitwiseXor", 242 | BinaryOperator::BitwiseOr => "BitwiseOr", 243 | BinaryOperator::LogicalAnd => "LogicalAnd", 244 | BinaryOperator::LogicalOr => "LogicalOr", 245 | BinaryOperator::Assign => "Assign", 246 | BinaryOperator::AssignMultiply => "AssignMultiply", 247 | BinaryOperator::AssignDivide => "AssignDivide", 248 | BinaryOperator::AssignModulo => "AssignModulo", 249 | BinaryOperator::AssignPlus => "AssignPlus", 250 | BinaryOperator::AssignMinus => "AssignMinus", 251 | BinaryOperator::AssignShiftLeft => "AssignShiftLeft", 252 | BinaryOperator::AssignShiftRight => "AssignShiftRight", 253 | BinaryOperator::AssignBitwiseAnd => "AssignBitwiseAnd", 254 | BinaryOperator::AssignBitwiseXor => "AssignBitwiseXor", 255 | BinaryOperator::AssignBitwiseOr => "AssignBitwiseOr", 256 | }); 257 | visit_binary_operator(&mut self.block(), n, span); 258 | } 259 | fn visit_binary_operator_expression( 260 | &mut self, 261 | n: &'ast BinaryOperatorExpression, 262 | span: &'ast Span, 263 | ) { 264 | self.name("BinaryOperatorExpression"); 265 | visit_binary_operator_expression(&mut self.block(), n, span); 266 | } 267 | fn visit_conditional_expression(&mut self, n: &'ast ConditionalExpression, span: &'ast Span) { 268 | self.name("ConditionalExpression"); 269 | visit_conditional_expression(&mut self.block(), n, span); 270 | } 271 | fn visit_va_arg_expression(&mut self, n: &'ast VaArgExpression, span: &'ast Span) { 272 | self.name("VaArgExpression"); 273 | visit_va_arg_expression(&mut self.block(), n, span); 274 | } 275 | fn visit_offset_of_expression(&mut self, n: &'ast OffsetOfExpression, span: &'ast Span) { 276 | self.name("OffsetOfExpression"); 277 | visit_offset_of_expression(&mut self.block(), n, span); 278 | } 279 | fn visit_offset_designator(&mut self, n: &'ast OffsetDesignator, span: &'ast Span) { 280 | self.name("OffsetDesignator"); 281 | visit_offset_designator(&mut self.block(), n, span); 282 | } 283 | fn visit_offset_member(&mut self, n: &'ast OffsetMember, span: &'ast Span) { 284 | self.name("OffsetMember"); 285 | print_offset_member(self, n); 286 | visit_offset_member(&mut self.block(), n, span); 287 | } 288 | fn visit_declaration(&mut self, n: &'ast Declaration, span: &'ast Span) { 289 | self.name("Declaration"); 290 | visit_declaration(&mut self.block(), n, span); 291 | } 292 | fn visit_declaration_specifier(&mut self, n: &'ast DeclarationSpecifier, span: &'ast Span) { 293 | self.name("DeclarationSpecifier"); 294 | visit_declaration_specifier(&mut self.block(), n, span); 295 | } 296 | fn visit_init_declarator(&mut self, n: &'ast InitDeclarator, span: &'ast Span) { 297 | self.name("InitDeclarator"); 298 | visit_init_declarator(&mut self.block(), n, span); 299 | } 300 | fn visit_storage_class_specifier(&mut self, n: &'ast StorageClassSpecifier, span: &'ast Span) { 301 | self.name("StorageClassSpecifier"); 302 | self.field(match *n { 303 | StorageClassSpecifier::Typedef => "Typedef", 304 | StorageClassSpecifier::Extern => "Extern", 305 | StorageClassSpecifier::Static => "Static", 306 | StorageClassSpecifier::ThreadLocal => "ThreadLocal", 307 | StorageClassSpecifier::Auto => "Auto", 308 | StorageClassSpecifier::Register => "Register", 309 | }); 310 | visit_storage_class_specifier(&mut self.block(), n, span); 311 | } 312 | fn visit_type_specifier(&mut self, n: &'ast TypeSpecifier, span: &'ast Span) { 313 | self.name("TypeSpecifier"); 314 | print_type_specifier(self, n); 315 | visit_type_specifier(&mut self.block(), n, span); 316 | } 317 | fn visit_ts18661_float_type(&mut self, n: &'ast TS18661FloatType, span: &'ast Span) { 318 | self.name("TS18661FloatType"); 319 | self.field(n.width); 320 | visit_ts18661_float_type(&mut self.block(), n, span); 321 | } 322 | fn visit_ts18661_float_format(&mut self, n: &'ast TS18661FloatFormat, span: &'ast Span) { 323 | self.name("TS18661FloatFormat"); 324 | self.field(match *n { 325 | TS18661FloatFormat::BinaryInterchange => "BinaryInterchange", 326 | TS18661FloatFormat::BinaryExtended => "BinaryExtended", 327 | TS18661FloatFormat::DecimalInterchange => "DecimalInterchange", 328 | TS18661FloatFormat::DecimalExtended => "DecimalExtended", 329 | }); 330 | visit_ts18661_float_format(&mut self.block(), n, span); 331 | } 332 | fn visit_struct_type(&mut self, n: &'ast StructType, span: &'ast Span) { 333 | self.name("StructType"); 334 | visit_struct_type(&mut self.block(), n, span); 335 | } 336 | fn visit_struct_kind(&mut self, n: &'ast StructKind, span: &'ast Span) { 337 | self.name("StructKind"); 338 | self.field(match *n { 339 | StructKind::Struct => "Struct", 340 | StructKind::Union => "Union", 341 | }); 342 | visit_struct_kind(&mut self.block(), n, span); 343 | } 344 | fn visit_struct_declaration(&mut self, n: &'ast StructDeclaration, span: &'ast Span) { 345 | self.name("StructDeclaration"); 346 | visit_struct_declaration(&mut self.block(), n, span); 347 | } 348 | fn visit_struct_field(&mut self, n: &'ast StructField, span: &'ast Span) { 349 | self.name("StructField"); 350 | visit_struct_field(&mut self.block(), n, span); 351 | } 352 | fn visit_specifier_qualifier(&mut self, n: &'ast SpecifierQualifier, span: &'ast Span) { 353 | self.name("SpecifierQualifier"); 354 | visit_specifier_qualifier(&mut self.block(), n, span); 355 | } 356 | fn visit_struct_declarator(&mut self, n: &'ast StructDeclarator, span: &'ast Span) { 357 | self.name("StructDeclarator"); 358 | visit_struct_declarator(&mut self.block(), n, span); 359 | } 360 | fn visit_enum_type(&mut self, n: &'ast EnumType, span: &'ast Span) { 361 | self.name("EnumType"); 362 | visit_enum_type(&mut self.block(), n, span); 363 | } 364 | fn visit_enumerator(&mut self, n: &'ast Enumerator, span: &'ast Span) { 365 | self.name("Enumerator"); 366 | visit_enumerator(&mut self.block(), n, span); 367 | } 368 | fn visit_type_qualifier(&mut self, n: &'ast TypeQualifier, span: &'ast Span) { 369 | self.name("TypeQualifier"); 370 | self.field(match *n { 371 | TypeQualifier::Const => "Const", 372 | TypeQualifier::Restrict => "Restrict", 373 | TypeQualifier::Volatile => "Volatile", 374 | TypeQualifier::Nonnull => "Nonnull", 375 | TypeQualifier::NullUnspecified => "NullUnspecified", 376 | TypeQualifier::Nullable => "Nullable", 377 | TypeQualifier::Atomic => "Atomic", 378 | }); 379 | visit_type_qualifier(&mut self.block(), n, span); 380 | } 381 | fn visit_function_specifier(&mut self, n: &'ast FunctionSpecifier, span: &'ast Span) { 382 | self.name("FunctionSpecifier"); 383 | self.field(match *n { 384 | FunctionSpecifier::Inline => "Inline", 385 | FunctionSpecifier::Noreturn => "Noreturn", 386 | }); 387 | visit_function_specifier(&mut self.block(), n, span); 388 | } 389 | fn visit_alignment_specifier(&mut self, n: &'ast AlignmentSpecifier, span: &'ast Span) { 390 | self.name("AlignmentSpecifier"); 391 | visit_alignment_specifier(&mut self.block(), n, span); 392 | } 393 | fn visit_declarator(&mut self, n: &'ast Declarator, span: &'ast Span) { 394 | self.name("Declarator"); 395 | visit_declarator(&mut self.block(), n, span); 396 | } 397 | fn visit_declarator_kind(&mut self, n: &'ast DeclaratorKind, span: &'ast Span) { 398 | self.name("DeclaratorKind"); 399 | print_declarator_kind(self, n); 400 | visit_declarator_kind(&mut self.block(), n, span); 401 | } 402 | fn visit_derived_declarator(&mut self, n: &'ast DerivedDeclarator, span: &'ast Span) { 403 | self.name("DerivedDeclarator"); 404 | print_derived_declarator(self, n); 405 | visit_derived_declarator(&mut self.block(), n, span); 406 | } 407 | fn visit_array_declarator(&mut self, n: &'ast ArrayDeclarator, span: &'ast Span) { 408 | self.name("ArrayDeclarator"); 409 | visit_array_declarator(&mut self.block(), n, span); 410 | } 411 | fn visit_function_declarator(&mut self, n: &'ast FunctionDeclarator, span: &'ast Span) { 412 | self.name("FunctionDeclarator"); 413 | visit_function_declarator(&mut self.block(), n, span); 414 | } 415 | fn visit_pointer_qualifier(&mut self, n: &'ast PointerQualifier, span: &'ast Span) { 416 | self.name("PointerQualifier"); 417 | visit_pointer_qualifier(&mut self.block(), n, span); 418 | } 419 | fn visit_array_size(&mut self, n: &'ast ArraySize, span: &'ast Span) { 420 | self.name("ArraySize"); 421 | print_array_size(self, n); 422 | visit_array_size(&mut self.block(), n, span); 423 | } 424 | fn visit_parameter_declaration(&mut self, n: &'ast ParameterDeclaration, span: &'ast Span) { 425 | self.name("ParameterDeclaration"); 426 | visit_parameter_declaration(&mut self.block(), n, span); 427 | } 428 | fn visit_ellipsis(&mut self, n: &'ast Ellipsis, span: &'ast Span) { 429 | self.name("Ellipsis"); 430 | self.field(match *n { 431 | Ellipsis::Some => "Some", 432 | Ellipsis::None => "None", 433 | }); 434 | visit_ellipsis(&mut self.block(), n, span); 435 | } 436 | fn visit_type_name(&mut self, n: &'ast TypeName, span: &'ast Span) { 437 | self.name("TypeName"); 438 | visit_type_name(&mut self.block(), n, span); 439 | } 440 | fn visit_initializer(&mut self, n: &'ast Initializer, span: &'ast Span) { 441 | self.name("Initializer"); 442 | visit_initializer(&mut self.block(), n, span); 443 | } 444 | fn visit_initializer_list_item(&mut self, n: &'ast InitializerListItem, span: &'ast Span) { 445 | self.name("InitializerListItem"); 446 | visit_initializer_list_item(&mut self.block(), n, span); 447 | } 448 | fn visit_designator(&mut self, n: &'ast Designator, span: &'ast Span) { 449 | self.name("Designator"); 450 | visit_designator(&mut self.block(), n, span); 451 | } 452 | fn visit_range_designator(&mut self, n: &'ast RangeDesignator, span: &'ast Span) { 453 | self.name("RangeDesignator"); 454 | visit_range_designator(&mut self.block(), n, span); 455 | } 456 | fn visit_static_assert(&mut self, n: &'ast StaticAssert, span: &'ast Span) { 457 | self.name("StaticAssert"); 458 | visit_static_assert(&mut self.block(), n, span); 459 | } 460 | fn visit_statement(&mut self, n: &'ast Statement, span: &'ast Span) { 461 | self.name("Statement"); 462 | print_statement(self, n); 463 | visit_statement(&mut self.block(), n, span); 464 | } 465 | fn visit_labeled_statement(&mut self, n: &'ast LabeledStatement, span: &'ast Span) { 466 | self.name("LabeledStatement"); 467 | visit_labeled_statement(&mut self.block(), n, span); 468 | } 469 | fn visit_if_statement(&mut self, n: &'ast IfStatement, span: &'ast Span) { 470 | self.name("IfStatement"); 471 | visit_if_statement(&mut self.block(), n, span); 472 | } 473 | fn visit_switch_statement(&mut self, n: &'ast SwitchStatement, span: &'ast Span) { 474 | self.name("SwitchStatement"); 475 | visit_switch_statement(&mut self.block(), n, span); 476 | } 477 | fn visit_while_statement(&mut self, n: &'ast WhileStatement, span: &'ast Span) { 478 | self.name("WhileStatement"); 479 | visit_while_statement(&mut self.block(), n, span); 480 | } 481 | fn visit_do_while_statement(&mut self, n: &'ast DoWhileStatement, span: &'ast Span) { 482 | self.name("DoWhileStatement"); 483 | visit_do_while_statement(&mut self.block(), n, span); 484 | } 485 | fn visit_for_statement(&mut self, n: &'ast ForStatement, span: &'ast Span) { 486 | self.name("ForStatement"); 487 | visit_for_statement(&mut self.block(), n, span); 488 | } 489 | fn visit_label(&mut self, n: &'ast Label, span: &'ast Span) { 490 | self.name("Label"); 491 | print_label(self, n); 492 | visit_label(&mut self.block(), n, span); 493 | } 494 | fn visit_case_range(&mut self, n: &'ast CaseRange, span: &'ast Span) { 495 | self.name("CaseRange"); 496 | visit_case_range(&mut self.block(), n, span); 497 | } 498 | fn visit_for_initializer(&mut self, n: &'ast ForInitializer, span: &'ast Span) { 499 | self.name("ForInitializer"); 500 | print_for_initializer(self, n); 501 | visit_for_initializer(&mut self.block(), n, span); 502 | } 503 | fn visit_block_item(&mut self, n: &'ast BlockItem, span: &'ast Span) { 504 | self.name("BlockItem"); 505 | visit_block_item(&mut self.block(), n, span); 506 | } 507 | fn visit_external_declaration(&mut self, n: &'ast ExternalDeclaration, span: &'ast Span) { 508 | self.name("ExternalDeclaration"); 509 | visit_external_declaration(&mut self.block(), n, span); 510 | } 511 | fn visit_function_definition(&mut self, n: &'ast FunctionDefinition, span: &'ast Span) { 512 | self.name("FunctionDefinition"); 513 | visit_function_definition(&mut self.block(), n, span); 514 | } 515 | fn visit_extension(&mut self, n: &'ast Extension, span: &'ast Span) { 516 | self.name("Extension"); 517 | visit_extension(&mut self.block(), n, span); 518 | } 519 | fn visit_attribute(&mut self, n: &'ast Attribute, span: &'ast Span) { 520 | self.name("Attribute"); 521 | self.field_str(&n.name.node); 522 | visit_attribute(&mut self.block(), n, span); 523 | } 524 | fn visit_asm_statement(&mut self, n: &'ast AsmStatement, span: &'ast Span) { 525 | self.name("AsmStatement"); 526 | visit_asm_statement(&mut self.block(), n, span); 527 | } 528 | fn visit_availability_attribute(&mut self, n: &'ast AvailabilityAttribute, span: &'ast Span) { 529 | self.name("AvailabilityAttribute"); 530 | visit_availability_attribute(&mut self.block(), n, span); 531 | } 532 | fn visit_gnu_extended_asm_statement( 533 | &mut self, 534 | n: &'ast GnuExtendedAsmStatement, 535 | span: &'ast Span, 536 | ) { 537 | self.name("GnuExtendedAsmStatement"); 538 | visit_gnu_extended_asm_statement(&mut self.block(), n, span); 539 | } 540 | fn visit_gnu_asm_operand(&mut self, n: &'ast GnuAsmOperand, span: &'ast Span) { 541 | self.name("GnuAsmOperand"); 542 | visit_gnu_asm_operand(&mut self.block(), n, span); 543 | } 544 | fn visit_type_of(&mut self, n: &'ast TypeOf, span: &'ast Span) { 545 | self.name("TypeOf"); 546 | visit_type_of(&mut self.block(), n, span); 547 | } 548 | fn visit_translation_unit(&mut self, translation_unit: &'ast TranslationUnit) { 549 | self.name("TranslationUnit"); 550 | visit_translation_unit(&mut self.block(), translation_unit); 551 | } 552 | } 553 | 554 | fn print_float_format<'ast>(p: &mut Printer, n: &'ast FloatFormat) { 555 | match *n { 556 | FloatFormat::Float => p.w.write_str(" Float").unwrap(), 557 | FloatFormat::Double => p.w.write_str(" Double").unwrap(), 558 | FloatFormat::LongDouble => p.w.write_str(" LongDouble").unwrap(), 559 | _ => {} 560 | } 561 | } 562 | fn print_declarator_kind<'ast>(p: &mut Printer, n: &'ast DeclaratorKind) { 563 | match *n { 564 | DeclaratorKind::Abstract => p.w.write_str(" Abstract").unwrap(), 565 | _ => {} 566 | } 567 | } 568 | fn print_derived_declarator<'ast>(p: &mut Printer, n: &'ast DerivedDeclarator) { 569 | match *n { 570 | DerivedDeclarator::Pointer(_) => p.w.write_str(" Pointer").unwrap(), 571 | DerivedDeclarator::KRFunction(_) => p.w.write_str(" KRFunction").unwrap(), 572 | DerivedDeclarator::Block(_) => p.w.write_str(" Block").unwrap(), 573 | _ => {} 574 | } 575 | } 576 | fn print_array_size<'ast>(p: &mut Printer, n: &'ast ArraySize) { 577 | match *n { 578 | ArraySize::Unknown => p.w.write_str(" Unknown").unwrap(), 579 | ArraySize::VariableUnknown => p.w.write_str(" VariableUnknown").unwrap(), 580 | ArraySize::VariableExpression(_) => p.w.write_str(" VariableExpression").unwrap(), 581 | ArraySize::StaticExpression(_) => p.w.write_str(" StaticExpression").unwrap(), 582 | } 583 | } 584 | fn print_statement<'ast>(p: &mut Printer, n: &'ast Statement) { 585 | match *n { 586 | Statement::Compound(_) => p.w.write_str(" Compound").unwrap(), 587 | Statement::Goto(_) => p.w.write_str(" Goto").unwrap(), 588 | Statement::Continue => p.w.write_str(" Continue").unwrap(), 589 | Statement::Break => p.w.write_str(" Break").unwrap(), 590 | Statement::Return(_) => p.w.write_str(" Return").unwrap(), 591 | _ => {} 592 | } 593 | } 594 | fn print_offset_member<'ast>(p: &mut Printer, n: &'ast OffsetMember) { 595 | match *n { 596 | OffsetMember::Member(_) => p.w.write_str(" Member").unwrap(), 597 | OffsetMember::IndirectMember(_) => p.w.write_str(" IndirectMember").unwrap(), 598 | _ => {} 599 | } 600 | } 601 | fn print_label<'ast>(p: &mut Printer, n: &'ast Label) { 602 | match *n { 603 | Label::Default => p.w.write_str(" Default").unwrap(), 604 | _ => {} 605 | } 606 | } 607 | fn print_for_initializer<'ast>(p: &mut Printer, n: &'ast ForInitializer) { 608 | match *n { 609 | ForInitializer::Empty => p.w.write_str(" Empty").unwrap(), 610 | _ => {} 611 | } 612 | } 613 | fn print_type_specifier<'ast>(p: &mut Printer, n: &'ast TypeSpecifier) { 614 | match *n { 615 | TypeSpecifier::Void => p.w.write_str(" Void").unwrap(), 616 | TypeSpecifier::Char => p.w.write_str(" Char").unwrap(), 617 | TypeSpecifier::Short => p.w.write_str(" Short").unwrap(), 618 | TypeSpecifier::Int => p.w.write_str(" Int").unwrap(), 619 | TypeSpecifier::Long => p.w.write_str(" Long").unwrap(), 620 | TypeSpecifier::Float => p.w.write_str(" Float").unwrap(), 621 | TypeSpecifier::Double => p.w.write_str(" Double").unwrap(), 622 | TypeSpecifier::Signed => p.w.write_str(" Signed").unwrap(), 623 | TypeSpecifier::Unsigned => p.w.write_str(" Unsigned").unwrap(), 624 | TypeSpecifier::Complex => p.w.write_str(" Complex").unwrap(), 625 | TypeSpecifier::Atomic(_) => p.w.write_str(" Atomic").unwrap(), 626 | TypeSpecifier::TypedefName(_) => p.w.write_str(" TypedefName").unwrap(), 627 | _ => {} 628 | } 629 | } 630 | 631 | struct Escape<'a>(&'a str); 632 | 633 | impl<'a> fmt::Display for Escape<'a> { 634 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 635 | use std::fmt::Write; 636 | 637 | for c in self.0.chars() { 638 | match c { 639 | '"' | '\'' | '\\' => try!(write!(fmt, "\\{}", c)), 640 | ' '...'~' => try!(fmt.write_char(c)), 641 | _ => try!(write!(fmt, "\\u{{{:04x}}}", c as u32)), 642 | } 643 | } 644 | 645 | Ok(()) 646 | } 647 | } 648 | 649 | #[test] 650 | fn test_escape() { 651 | let s = format!("{}", Escape(r#"a'"\ あ \'"#)); 652 | assert_eq!(s, r#"a\'\"\\ \u{3042} \\\'"#); 653 | } 654 | -------------------------------------------------------------------------------- /src/span.rs: -------------------------------------------------------------------------------- 1 | //! Source text location tracking 2 | use std::usize::MAX; 3 | use std::{cmp, fmt}; 4 | 5 | /// Byte offset of a node start and end positions in the input stream 6 | #[derive(Copy, Clone)] 7 | pub struct Span { 8 | pub start: usize, 9 | pub end: usize, 10 | } 11 | 12 | impl Span { 13 | /// Create a new span for a specific location 14 | pub fn span(start: usize, end: usize) -> Span { 15 | Span { 16 | start: start, 17 | end: end, 18 | } 19 | } 20 | 21 | /// Create a new undefined span that is equal to any other span 22 | pub fn none() -> Span { 23 | Span { 24 | start: MAX, 25 | end: MAX, 26 | } 27 | } 28 | 29 | /// Test if span is undefined 30 | pub fn is_none(&self) -> bool { 31 | self.start == MAX && self.end == MAX 32 | } 33 | } 34 | 35 | impl cmp::PartialEq for Span { 36 | fn eq(&self, other: &Self) -> bool { 37 | (self.start == other.start && self.end == other.end) || self.is_none() || other.is_none() 38 | } 39 | } 40 | 41 | impl fmt::Debug for Span { 42 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 43 | if !self.is_none() { 44 | write!(fmt, "{}…{}", self.start, self.end) 45 | } else { 46 | write!(fmt, "…") 47 | } 48 | } 49 | } 50 | 51 | /// Associate a span with an arbitrary type 52 | #[derive(Debug, PartialEq, Clone)] 53 | pub struct Node { 54 | pub node: T, 55 | pub span: Span, 56 | } 57 | 58 | impl Node { 59 | /// Create new node 60 | pub fn new(node: T, span: Span) -> Node { 61 | Node { 62 | node: node, 63 | span: span, 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/strings.rs: -------------------------------------------------------------------------------- 1 | pub const RESERVED_C11: &'static [&'static str] = &[ 2 | "auto", 3 | "break", 4 | "case", 5 | "char", 6 | "const", 7 | "continue", 8 | "default", 9 | "do", 10 | "double", 11 | "else", 12 | "enum", 13 | "extern", 14 | "float", 15 | "for", 16 | "goto", 17 | "if", 18 | "inline", 19 | "int", 20 | "long", 21 | "register", 22 | "restrict", 23 | "return", 24 | "short", 25 | "signed", 26 | "sizeof", 27 | "static", 28 | "struct", 29 | "switch", 30 | "typedef", 31 | "union", 32 | "unsigned", 33 | "void", 34 | "volatile", 35 | "while", 36 | "_Alignas", 37 | "_Alignof", 38 | "_Atomic", 39 | "_Bool", 40 | "_Complex", 41 | "_Generic", 42 | "_Imaginary", 43 | "_Noreturn", 44 | "_Static_assert", 45 | "_Thread_local", 46 | "_Float16", 47 | "_Float16x", 48 | "_Float32", 49 | "_Float32x", 50 | "_Float64", 51 | "_Float64x", 52 | "_Float128", 53 | "_Float128x", 54 | "_Decimal32", 55 | "_Decimal32x", 56 | "_Decimal64", 57 | "_Decimal64x", 58 | "_Decimal128", 59 | "_Decimal128x", 60 | ]; 61 | 62 | pub const RESERVED_GNU: &'static [&'static str] = &[ 63 | "__FUNCTION__", 64 | "__PRETTY_FUNCTION__", 65 | "__alignof", 66 | "__alignof__", 67 | "__asm", 68 | "__asm__", 69 | "__attribute", 70 | "__attribute__", 71 | "__builtin_offsetof", 72 | "__builtin_va_arg", 73 | "__complex", 74 | "__complex__", 75 | "__const", 76 | "__extension__", 77 | "__func__", 78 | "__imag", 79 | "__imag__", 80 | "__inline", 81 | "__inline__", 82 | "__label__", 83 | "__null", 84 | "__real", 85 | "__real__", 86 | "__restrict", 87 | "__restrict__", 88 | "__signed", 89 | "__signed__", 90 | "__thread", 91 | "__typeof", 92 | "__volatile", 93 | "__volatile__", 94 | ]; 95 | 96 | // Ref: https://clang.llvm.org/docs/AttributeReference.html 97 | pub const RESERVED_CLANG: &'static [&'static str] = &[ 98 | // Only enabled with -fms-extensions and only affect *-*-win32 targets 99 | "__single_inheritance", 100 | "__multiple_inheritance", 101 | "__virtual_inheritance", 102 | "__unspecified_inheritance", 103 | // Calling conventions 104 | "__fastcall", 105 | "__regcall", 106 | "__stdcall", 107 | "__thiscall", 108 | "__vectorcall", 109 | // Nullability attributes 110 | "_Nonnull", 111 | "_Null_unspecified", 112 | "_Nullable", 113 | ]; 114 | -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::ffi::{OsStr, OsString}; 3 | use std::fs; 4 | use std::fs::DirEntry; 5 | use std::fs::File; 6 | use std::io; 7 | use std::io::stdout; 8 | use std::io::{BufRead, BufReader, BufWriter, Write}; 9 | use std::mem; 10 | use std::path::PathBuf; 11 | 12 | use env::Env; 13 | use parser; 14 | use print::Printer; 15 | use span::Span; 16 | use visit::Visit; 17 | 18 | struct Case { 19 | path: PathBuf, 20 | name: String, 21 | kind: Kind, 22 | pragma: Vec, 23 | source: String, 24 | expect: String, 25 | } 26 | 27 | const OUTPUT_START: &'static str = "/*==="; 28 | const OUTPUT_END: &'static str = "===*/"; 29 | 30 | impl Case { 31 | fn from_path(entry: &DirEntry) -> io::Result { 32 | let name = entry.file_name(); 33 | let name = name.to_str().expect("path to string"); 34 | let kind = name.split("-").next().expect("case contains hyphen"); 35 | let kind = Kind::from_str(&kind).expect("unknown test case kind"); 36 | 37 | let file = BufReader::new(try!(File::open(entry.path()))); 38 | 39 | let mut pragma = Vec::new(); 40 | let mut expect = String::new(); 41 | let mut source = String::new(); 42 | let mut in_exp = false; 43 | 44 | for line in file.lines() { 45 | let target = if in_exp { &mut expect } else { &mut source }; 46 | 47 | let line = try!(line); 48 | let line = line.trim_right(); 49 | if line.is_empty() || line.starts_with("//") { 50 | continue; 51 | } else if line.starts_with("#pragma") { 52 | pragma.push(Pragma::from_str(line).expect("unknown pragma")); 53 | } else if line == OUTPUT_START { 54 | in_exp = true; 55 | } else if line == OUTPUT_END { 56 | in_exp = false; 57 | } else { 58 | target.push_str(line); 59 | target.push_str("\n"); 60 | } 61 | } 62 | 63 | Ok(Case { 64 | path: entry.path(), 65 | name: name.to_owned(), 66 | kind: kind, 67 | pragma: pragma, 68 | source: source, 69 | expect: expect, 70 | }) 71 | } 72 | 73 | fn run(&self) -> bool { 74 | let mut env = None; 75 | 76 | for pragma in &self.pragma { 77 | match *pragma { 78 | Pragma::Gnu => env = Some(Env::with_gnu()), 79 | Pragma::Clang => env = Some(Env::with_clang()), 80 | _ => {} 81 | } 82 | } 83 | 84 | let mut env = env.unwrap_or_else(Env::with_core); 85 | 86 | for pragma in &self.pragma { 87 | match *pragma { 88 | Pragma::Typedef(ref name) => env.add_typename(&name), 89 | _ => {} 90 | } 91 | } 92 | 93 | pegviz::marker_start(&self.source); 94 | 95 | let (actual, error) = match self.kind.parse_and_print(&self.source, &mut env) { 96 | Ok(s) => (s, None), 97 | Err(e) => ("~ERROR\n".to_string(), Some(e)), 98 | }; 99 | 100 | pegviz::marker_stop(); 101 | 102 | let pragma_fail = self 103 | .pragma 104 | .iter() 105 | .filter(|p| match **p { 106 | Pragma::IsTypename(ref name) => !env.is_typename(name), 107 | _ => false, 108 | }) 109 | .collect::>(); 110 | 111 | let output_matches = actual == self.expect; 112 | let success = output_matches && pragma_fail.is_empty(); 113 | 114 | if !success { 115 | writeln!(stdout(), "\n{}:", self.name).unwrap(); 116 | writeln!(stdout(), "{}", self.source).unwrap(); 117 | if let Some(e) = error { 118 | writeln!(stdout(), "ERROR:\n{}", e).unwrap(); 119 | } 120 | } 121 | 122 | if !pragma_fail.is_empty() { 123 | writeln!(stdout(), "Failed checks: ").unwrap(); 124 | for failed in &pragma_fail { 125 | writeln!(stdout(), " {:?}", failed).unwrap(); 126 | } 127 | } 128 | 129 | if !output_matches { 130 | let width = self.expect.lines().map(|s| s.len()).max().unwrap_or(25); 131 | let mut alines = Some(self.expect.lines()); 132 | let mut blines = Some(actual.lines()); 133 | while alines.is_some() || blines.is_some() { 134 | let a = match alines.as_mut().and_then(|i| i.next()) { 135 | Some(l) => l, 136 | None => { 137 | alines = None; 138 | "" 139 | } 140 | }; 141 | let b = match blines.as_mut().and_then(|i| i.next()) { 142 | Some(l) => l, 143 | None => { 144 | blines = None; 145 | "" 146 | } 147 | }; 148 | writeln!(stdout(), "{:w$} | {}", a, b, w = width).unwrap(); 149 | } 150 | 151 | if env::var_os("TEST_UPDATE").is_some() { 152 | self.save(&actual).expect("failed to update test output"); 153 | } 154 | } 155 | 156 | success 157 | } 158 | 159 | fn save(&self, actual: &str) -> io::Result<()> { 160 | let mut buf = String::new(); 161 | let mut file = BufReader::new(try!(File::open(&self.path))); 162 | let mut content = Vec::new(); 163 | while try!(file.read_line(&mut buf)) > 0 { 164 | content.push(mem::replace(&mut buf, String::new())); 165 | } 166 | 167 | let mut file = BufWriter::new(try!(File::create(&self.path))); 168 | let mut lines = content.into_iter(); 169 | 170 | for line in &mut lines { 171 | if line.trim_right() == OUTPUT_START { 172 | break; 173 | } 174 | try!(file.write_all(line.as_bytes())); 175 | } 176 | 177 | try!(write!( 178 | &mut file, 179 | "{}\n{}{}\n", 180 | OUTPUT_START, actual, OUTPUT_END 181 | )); 182 | 183 | for line in &mut lines { 184 | if line.trim_right() == OUTPUT_END { 185 | break; 186 | } 187 | } 188 | for line in &mut lines { 189 | try!(file.write_all(line.as_bytes())); 190 | } 191 | 192 | Ok(()) 193 | } 194 | } 195 | 196 | enum Kind { 197 | Constant, 198 | Declaration, 199 | Expression, 200 | Statement, 201 | TranslationUnit, 202 | } 203 | 204 | impl Kind { 205 | fn from_str(kind: &str) -> Option { 206 | Some(match kind { 207 | "constant" => Kind::Constant, 208 | "declaration" => Kind::Declaration, 209 | "expression" => Kind::Expression, 210 | "statement" => Kind::Statement, 211 | "translation_unit" => Kind::TranslationUnit, 212 | _ => return None, 213 | }) 214 | } 215 | 216 | fn parse_and_print(&self, source: &str, env: &mut Env) -> Result { 217 | let source = source.trim_right(); 218 | 219 | let mut s = "".to_string(); 220 | { 221 | let mut p = Printer::new(&mut s); 222 | match *self { 223 | Kind::Constant => { 224 | let n = try!(parser::constant(source, env)); 225 | p.visit_constant(&n, &Span::none()); 226 | } 227 | Kind::Declaration => { 228 | let n = try!(parser::declaration(source, env)); 229 | p.visit_declaration(&n.node, &n.span); 230 | } 231 | Kind::Statement => { 232 | let n = try!(parser::statement(source, env)); 233 | p.visit_statement(&n.node, &n.span); 234 | } 235 | Kind::Expression => { 236 | let n = try!(parser::expression(source, env)); 237 | p.visit_expression(&n.node, &n.span); 238 | } 239 | Kind::TranslationUnit => { 240 | let n = try!(parser::translation_unit(source, env)); 241 | p.visit_translation_unit(&n); 242 | } 243 | } 244 | } 245 | 246 | Ok(s) 247 | } 248 | } 249 | 250 | #[derive(Debug)] 251 | enum Pragma { 252 | /// Enable gnu extensions 253 | Gnu, 254 | // Enable clang extensions 255 | Clang, 256 | /// Define typename 257 | Typedef(String), 258 | /// Assert argument is a typename 259 | IsTypename(String), 260 | } 261 | 262 | impl Pragma { 263 | fn from_str(line: &str) -> Option { 264 | let mut line = line 265 | .split(" ") 266 | .skip(1) 267 | .map(|w| w.trim().to_owned()) 268 | .collect::>(); 269 | Some(match line[0].trim() { 270 | "gnu" => Pragma::Gnu, 271 | "clang" => Pragma::Clang, 272 | "typedef" => Pragma::Typedef(match line.pop() { 273 | Some(v) => v, 274 | None => return None, 275 | }), 276 | "is_typename" => Pragma::IsTypename(match line.pop() { 277 | Some(v) => v, 278 | None => return None, 279 | }), 280 | _ => return None, 281 | }) 282 | } 283 | } 284 | 285 | fn filter_entry(a: &DirEntry, filter: Option<&OsString>) -> bool { 286 | let path = a.path(); 287 | let name = match path.file_name().and_then(OsStr::to_str) { 288 | Some(name) => name, 289 | None => return false, 290 | }; 291 | if name.starts_with('.') || name.ends_with('~') { 292 | return false; 293 | } 294 | if let Some(filter) = filter.and_then(|s| s.to_str()) { 295 | return name.starts_with(filter); 296 | } 297 | 298 | true 299 | } 300 | 301 | #[test] 302 | fn reftest_main() { 303 | let mut cases = Vec::new(); 304 | let filter = env::var_os("TEST_FILTER"); 305 | for entry in fs::read_dir("reftests").expect("listing reftests/") { 306 | let entry = entry.expect("failed to read reftests/ entry"); 307 | if !filter_entry(&entry, filter.as_ref()) { 308 | continue; 309 | } 310 | let case = match Case::from_path(&entry) { 311 | Ok(case) => case, 312 | Err(err) => { 313 | panic!("{}: {}", entry.path().to_string_lossy(), err); 314 | } 315 | }; 316 | cases.push(case); 317 | } 318 | 319 | let failed = cases.iter().filter(|c| !c.run()).count(); 320 | if failed > 0 { 321 | panic!("{} cases failed", failed); 322 | } 323 | } 324 | 325 | #[cfg(feature = "dev-pegviz")] 326 | mod pegviz { 327 | pub fn marker_start(source: &str) { 328 | println!("[PEG_INPUT_START]\n{}\n[PEG_TRACE_START]", source); 329 | } 330 | pub fn marker_stop() { 331 | println!("[PEG_TRACE_STOP]"); 332 | } 333 | } 334 | 335 | #[cfg(not(feature = "dev-pegviz"))] 336 | mod pegviz { 337 | pub fn marker_start(_: &str) {} 338 | pub fn marker_stop() {} 339 | } 340 | --------------------------------------------------------------------------------