├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── codequality
├── HEADER
└── checkstyle.xml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── install
├── settings.gradle
└── src
├── main
├── ghpages
│ └── index.html
├── java
│ └── org
│ │ └── anarres
│ │ └── cpp
│ │ ├── Argument.java
│ │ ├── BuildMetadata.java
│ │ ├── ChrootFileSystem.java
│ │ ├── CppReader.java
│ │ ├── CppTask.java
│ │ ├── DefaultPreprocessorListener.java
│ │ ├── Feature.java
│ │ ├── FileLexerSource.java
│ │ ├── FixedTokenSource.java
│ │ ├── InputLexerSource.java
│ │ ├── InternalException.java
│ │ ├── JavaFileSystem.java
│ │ ├── JoinReader.java
│ │ ├── LexerException.java
│ │ ├── LexerSource.java
│ │ ├── Macro.java
│ │ ├── MacroTokenSource.java
│ │ ├── Main.java
│ │ ├── NumericValue.java
│ │ ├── Preprocessor.java
│ │ ├── PreprocessorCommand.java
│ │ ├── PreprocessorListener.java
│ │ ├── ResourceFileSystem.java
│ │ ├── Source.java
│ │ ├── SourceIterator.java
│ │ ├── State.java
│ │ ├── StringLexerSource.java
│ │ ├── Token.java
│ │ ├── TokenSnifferSource.java
│ │ ├── TokenType.java
│ │ ├── VirtualFile.java
│ │ ├── VirtualFileSystem.java
│ │ └── Warning.java
└── velocity
│ └── org
│ └── anarres
│ └── cpp
│ └── Version.java
├── scripts
├── jcpp
└── release.sh
└── test
├── java
└── org
│ └── anarres
│ └── cpp
│ ├── BuildMetadataTest.java
│ ├── CppReaderTest.java
│ ├── ErrorTest.java
│ ├── IncludeAbsoluteTest.java
│ ├── JavaFileSystemTest.java
│ ├── JoinReaderTest.java
│ ├── LexerSourceTest.java
│ ├── MainTest.java
│ ├── NumericValueTest.java
│ ├── PragmaTest.java
│ ├── PreprocessorTest.java
│ ├── RegressionTest.java
│ ├── TokenPastingWhitespaceTest.java
│ └── VaArgsPastingTest.java
└── resources
├── absolute.h
├── lines.c
├── lines1.h
├── lines2.h
├── once.c
├── once.h
├── pragma.c
├── regression
└── lex-char.in
├── test0.c
├── test0.h
├── test1.c
├── test1.h
├── trigraph.c
└── varargs.c
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled source #
2 | ###################
3 | *.com
4 | *.class
5 | *.dll
6 | *.exe
7 | *.o
8 | *.so
9 |
10 | # Packages #
11 | ############
12 | # it's better to unpack these files and commit the raw source
13 | # git has its own built in compression methods
14 | *.7z
15 | *.dmg
16 | *.gz
17 | *.iso
18 | *.rar
19 | *.tar
20 | *.zip
21 |
22 | # Logs and databases #
23 | ######################
24 | *.log
25 |
26 | # OS generated files #
27 | ######################
28 | .DS_Store*
29 | ehthumbs.db
30 | Icon?
31 | Thumbs.db
32 |
33 | # Editor Files #
34 | ################
35 | *~
36 | *.swp
37 |
38 | # Gradle Files #
39 | ################
40 | .gradle
41 |
42 | # Build output directies
43 | /target
44 | */target
45 | /build
46 | */build
47 |
48 | # IntelliJ specific files/directories
49 | out
50 | .idea
51 | *.ipr
52 | *.iws
53 | *.iml
54 | atlassian-ide-plugin.xml
55 |
56 | # Eclipse specific files/directories
57 | .classpath
58 | .project
59 | .settings
60 | .metadata
61 |
62 | # NetBeans specific files/directories
63 | .nbattrs
64 | .nb-gradle
65 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | The C Preprocessor is an interesting standard. It appears to be
4 | derived from the de-facto behaviour of the first preprocessors, and
5 | has evolved over the years. Implementation is therefore difficult.
6 |
7 | JCPP is a complete, compliant, standalone, pure Java implementation
8 | of the C preprocessor. It is intended to be of use to people writing
9 | C-style compilers in Java using tools like sablecc, antlr, JLex,
10 | CUP and so forth (although if you aren't using sablecc, you need your
11 | head examined).
12 |
13 | This project has has been used to successfully preprocess much of
14 | the source code of the GNU C library. As of version 1.2.5, it can
15 | also preprocess the Apple Objective C library.
16 |
17 | # Documentation
18 |
19 | * [JavaDoc API](http://shevek.github.io/jcpp/docs/javadoc/)
20 | * [Coverage Report](http://shevek.github.io/jcpp/docs/cobertura/)
21 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | // mavenLocal()
4 | mavenCentral()
5 | jcenter()
6 | // maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
7 | }
8 |
9 | dependencies {
10 | classpath 'org.anarres.gradle:gradle-stdproject-plugin:1.0.9'
11 | }
12 | }
13 |
14 | apply plugin: 'org.anarres.stdproject'
15 | stdproject {
16 | javadocLinkSource = true;
17 | }
18 |
19 | group = "org.anarres"
20 |
21 | apply plugin: 'org.anarres.stdmodule'
22 | stdmodule {
23 | description "An embeddable C Preprocessor for the JVM."
24 | author id: 'shevek', name: 'Shevek', email: 'github@anarres.org'
25 | license 'Apache-2.0'
26 | }
27 |
28 | sourceCompatibility = 1.5
29 |
30 | dependencies {
31 | compile 'com.google.code.findbugs:annotations:3.0.1'
32 | compile 'org.slf4j:slf4j-api:1.7.12'
33 |
34 | compile 'net.sf.jopt-simple:jopt-simple:4.7'
35 | compile 'org.apache.ant:ant:1.7.0'
36 | compile 'com.github.zafarkhaja:java-semver:0.8.0'
37 |
38 | testCompile 'com.google.guava:guava:18.0'
39 | }
40 |
41 | // This ensures that the info-plugin's properties file is in the
42 | // same location for the test suite as in the JAR.
43 | task('processTestVersionResources', type: Copy, dependsOn: processTestResources) {
44 | into project.sourceSets.test.output.resourcesDir
45 | from(writeManifestProperties) {
46 | into "META-INF"
47 | }
48 | }
49 | testClasses.dependsOn(processTestVersionResources)
50 |
51 | apply plugin: 'application'
52 |
53 | mainClassName = "org.anarres.cpp.Main"
54 |
--------------------------------------------------------------------------------
/codequality/HEADER:
--------------------------------------------------------------------------------
1 | Copyright ${year} Shevek.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/codequality/checkstyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | version=1.4.15-SNAPSHOT
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shevek/jcpp/5e50e75ec33f5b4567cabfd60b6baca39524a8b7/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/install:
--------------------------------------------------------------------------------
1 | build/install/jcpp/
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name='jcpp'
2 |
--------------------------------------------------------------------------------
/src/main/ghpages/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Javadoc
4 | Coverage
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/Argument.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.IOException;
20 | import java.util.ArrayList;
21 | import java.util.Iterator;
22 | import java.util.List;
23 | import javax.annotation.Nonnull;
24 |
25 | /**
26 | * A macro argument.
27 | *
28 | * This encapsulates a raw and preprocessed token stream.
29 | */
30 | /* pp */ class Argument extends ArrayList {
31 |
32 | private List expansion;
33 |
34 | public Argument() {
35 | this.expansion = null;
36 | }
37 |
38 | public void addToken(@Nonnull Token tok) {
39 | add(tok);
40 | }
41 |
42 | /* pp */ void expand(@Nonnull Preprocessor p)
43 | throws IOException,
44 | LexerException {
45 | /* Cache expansion. */
46 | if (expansion == null) {
47 | this.expansion = p.expand(this);
48 | // System.out.println("Expanded arg " + this);
49 | }
50 | }
51 |
52 | @Nonnull
53 | public Iterator expansion() {
54 | return expansion.iterator();
55 | }
56 |
57 | @Override
58 | public String toString() {
59 | StringBuilder buf = new StringBuilder();
60 | buf.append("Argument(");
61 | // buf.append(super.toString());
62 | buf.append("raw=[ ");
63 | for (int i = 0; i < size(); i++)
64 | buf.append(get(i).getText());
65 | buf.append(" ];expansion=[ ");
66 | if (expansion == null)
67 | buf.append("null");
68 | else
69 | for (Token token : expansion)
70 | buf.append(token.getText());
71 | buf.append(" ])");
72 | return buf.toString();
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/BuildMetadata.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.net.URL;
6 | import java.text.ParseException;
7 | import java.text.SimpleDateFormat;
8 | import java.util.Date;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 | import java.util.Properties;
12 | import javax.annotation.Nonnull;
13 |
14 | /**
15 | * Returns information about the build.
16 | *
17 | * @author shevek
18 | */
19 | public class BuildMetadata {
20 |
21 | public static final String RESOURCE = "/META-INF/jcpp.properties";
22 | private static BuildMetadata INSTANCE;
23 |
24 | /** @throws RuntimeException if the properties file cannot be found on the classpath. */
25 | @Nonnull
26 | public static synchronized BuildMetadata getInstance() {
27 | try {
28 | if (INSTANCE == null)
29 | INSTANCE = new BuildMetadata();
30 | return INSTANCE;
31 | } catch (IOException e) {
32 | throw new RuntimeException(e);
33 | }
34 | }
35 |
36 | private final Properties properties = new Properties();
37 |
38 | private BuildMetadata() throws IOException {
39 | URL url = BuildMetadata.class.getResource(RESOURCE);
40 | InputStream in = url.openStream();
41 | try {
42 | properties.load(in);
43 | } finally {
44 | in.close();
45 | }
46 | }
47 |
48 | @Nonnull
49 | public Map extends String, ? extends String> asMap() {
50 | Map out = new HashMap();
51 | for (Map.Entry e : properties.entrySet())
52 | out.put(String.valueOf(e.getKey()), String.valueOf(e.getValue()));
53 | return out;
54 | }
55 |
56 | @Nonnull
57 | public com.github.zafarkhaja.semver.Version getVersion() {
58 | return com.github.zafarkhaja.semver.Version.valueOf(properties.getProperty("Implementation-Version"));
59 | }
60 |
61 | @Nonnull
62 | public Date getBuildDate() throws ParseException {
63 | // Build-Date=2015-01-01_10:09:09
64 | String text = properties.getProperty("Build-Date");
65 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
66 | return format.parse(text);
67 | }
68 |
69 | public String getChangeId() {
70 | return properties.getProperty("Change");
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/ChrootFileSystem.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.File;
20 | import java.io.IOException;
21 |
22 | /**
23 | * A virtual filesystem implementation using java.io in a virtual
24 | * chroot.
25 | */
26 | public class ChrootFileSystem implements VirtualFileSystem {
27 |
28 | private File root;
29 |
30 | public ChrootFileSystem(File root) {
31 | this.root = root;
32 | }
33 |
34 | @Override
35 | public VirtualFile getFile(String path) {
36 | return new ChrootFile(path);
37 | }
38 |
39 | @Override
40 | public VirtualFile getFile(String dir, String name) {
41 | return new ChrootFile(dir, name);
42 | }
43 |
44 | private class ChrootFile extends File implements VirtualFile {
45 |
46 | private File rfile;
47 |
48 | public ChrootFile(String path) {
49 | super(path);
50 | }
51 |
52 | public ChrootFile(String dir, String name) {
53 | super(dir, name);
54 | }
55 |
56 | /* private */
57 | public ChrootFile(File dir, String name) {
58 | super(dir, name);
59 | }
60 |
61 | @Override
62 | public ChrootFile getParentFile() {
63 | return new ChrootFile(getParent());
64 | }
65 |
66 | @Override
67 | public ChrootFile getChildFile(String name) {
68 | return new ChrootFile(this, name);
69 | }
70 |
71 | @Override
72 | public boolean isFile() {
73 | File real = new File(root, getPath());
74 | return real.isFile();
75 | }
76 |
77 | @Override
78 | public Source getSource() throws IOException {
79 | return new FileLexerSource(new File(root, getPath()),
80 | getPath());
81 | }
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/CppReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.Closeable;
20 | import java.io.IOException;
21 | import java.io.Reader;
22 | import javax.annotation.Nonnull;
23 | import static org.anarres.cpp.Token.CCOMMENT;
24 | import static org.anarres.cpp.Token.CPPCOMMENT;
25 | import static org.anarres.cpp.Token.EOF;
26 |
27 | /**
28 | * A Reader wrapper around the Preprocessor.
29 | *
30 | * This is a utility class to provide a transparent {@link Reader}
31 | * which preprocesses the input text.
32 | *
33 | * @see Preprocessor
34 | * @see Reader
35 | */
36 | public class CppReader extends Reader implements Closeable {
37 |
38 | private final Preprocessor cpp;
39 | private String token;
40 | private int idx;
41 |
42 | public CppReader(@Nonnull final Reader r) {
43 | cpp = new Preprocessor(new LexerSource(r, true) {
44 | @Override
45 | public String getName() {
46 | return "";
48 | }
49 | });
50 | token = "";
51 | idx = 0;
52 | }
53 |
54 | public CppReader(@Nonnull Preprocessor p) {
55 | cpp = p;
56 | token = "";
57 | idx = 0;
58 | }
59 |
60 | /**
61 | * Returns the Preprocessor used by this CppReader.
62 | */
63 | @Nonnull
64 | public Preprocessor getPreprocessor() {
65 | return cpp;
66 | }
67 |
68 | /**
69 | * Defines the given name as a macro.
70 | *
71 | * This is a convnience method.
72 | */
73 | public void addMacro(@Nonnull String name)
74 | throws LexerException {
75 | cpp.addMacro(name);
76 | }
77 |
78 | /**
79 | * Defines the given name as a macro.
80 | *
81 | * This is a convnience method.
82 | */
83 | public void addMacro(@Nonnull String name, @Nonnull String value)
84 | throws LexerException {
85 | cpp.addMacro(name, value);
86 | }
87 |
88 | private boolean refill()
89 | throws IOException {
90 | try {
91 | assert cpp != null : "cpp is null : was it closed?";
92 | if (token == null)
93 | return false;
94 | while (idx >= token.length()) {
95 | Token tok = cpp.token();
96 | switch (tok.getType()) {
97 | case EOF:
98 | token = null;
99 | return false;
100 | case CCOMMENT:
101 | case CPPCOMMENT:
102 | if (!cpp.getFeature(Feature.KEEPCOMMENTS)) {
103 | token = " ";
104 | break;
105 | }
106 | default:
107 | token = tok.getText();
108 | break;
109 | }
110 | idx = 0;
111 | }
112 | return true;
113 | } catch (LexerException e) {
114 | // new IOException(String, Throwable) is since 1.6
115 | IOException _e = new IOException(String.valueOf(e));
116 | _e.initCause(e);
117 | throw _e;
118 | }
119 | }
120 |
121 | @Override
122 | public int read()
123 | throws IOException {
124 | if (!refill())
125 | return -1;
126 | return token.charAt(idx++);
127 | }
128 |
129 | @Override
130 | /* XXX Very slow and inefficient. */
131 | public int read(char cbuf[], int off, int len)
132 | throws IOException {
133 | if (token == null)
134 | return -1;
135 | for (int i = 0; i < len; i++) {
136 | int ch = read();
137 | if (ch == -1)
138 | return i;
139 | cbuf[off + i] = (char) ch;
140 | }
141 | return len;
142 | }
143 |
144 | @Override
145 | public void close()
146 | throws IOException {
147 | cpp.close();
148 | token = null;
149 | }
150 |
151 | }
152 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/CppTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.File;
20 | import java.io.FileWriter;
21 | import java.io.IOException;
22 | import java.util.ArrayList;
23 | import java.util.Arrays;
24 | import java.util.Enumeration;
25 | import java.util.List;
26 | import org.apache.tools.ant.BuildException;
27 | import org.apache.tools.ant.taskdefs.Copy;
28 | import org.apache.tools.ant.types.Path;
29 |
30 | /**
31 | * An ant task for jcpp.
32 | */
33 | public class CppTask extends Copy {
34 |
35 | private class Listener extends DefaultPreprocessorListener {
36 |
37 | @Override
38 | protected void print(String msg) {
39 | log(msg);
40 | }
41 | }
42 |
43 | public static class Macro {
44 |
45 | private String name;
46 | private String value;
47 |
48 | public void setName(String name) {
49 | this.name = name;
50 | }
51 |
52 | public String getName() {
53 | return name;
54 | }
55 |
56 | public void setValue(String value) {
57 | this.value = value;
58 | }
59 |
60 | public String getValue() {
61 | return value;
62 | }
63 | }
64 |
65 | private final Listener listener = new Listener();
66 | private final List macros = new ArrayList();
67 | private Path systemincludepath;
68 | private Path localincludepath;
69 |
70 | public void addMacro(Macro macro) {
71 | macros.add(macro);
72 | }
73 |
74 | public void addSystemincludepath(Path path) {
75 | if (systemincludepath == null)
76 | systemincludepath = new Path(getProject());
77 | systemincludepath.add(path);
78 | }
79 |
80 | public void addLocalincludepath(Path path) {
81 | if (localincludepath == null)
82 | localincludepath = new Path(getProject());
83 | localincludepath.add(path);
84 | }
85 |
86 | /*
87 | public void execute() {
88 | FileWriter writer = null;
89 | try {
90 | if (input == null)
91 | throw new BuildException("Input not specified");
92 | if (output == null)
93 | throw new BuildException("Output not specified");
94 | cpp.addInput(this.input);
95 | writer = new FileWriter(this.output);
96 | for (;;) {
97 | Token tok = cpp.token();
98 | if (tok != null && tok.getType() == Token.EOF)
99 | break;
100 | writer.write(tok.getText());
101 | }
102 | }
103 | catch (Exception e) {
104 | throw new BuildException(e);
105 | }
106 | finally {
107 | if (writer != null) {
108 | try {
109 | writer.close();
110 | }
111 | catch (IOException e) {
112 | }
113 | }
114 | }
115 | }
116 | */
117 | private void preprocess(File input, File output) throws Exception {
118 | if (input == null)
119 | throw new BuildException("Input not specified");
120 | if (output == null)
121 | throw new BuildException("Output not specified");
122 |
123 | Preprocessor cpp = new Preprocessor();
124 | cpp.setListener(listener);
125 | for (Macro macro : macros)
126 | cpp.addMacro(macro.getName(), macro.getValue());
127 | if (systemincludepath != null)
128 | cpp.setSystemIncludePath(Arrays.asList(systemincludepath.list()));
129 | if (localincludepath != null)
130 | cpp.setQuoteIncludePath(Arrays.asList(localincludepath.list()));
131 |
132 | File dir = output.getParentFile();
133 | if (!dir.exists()) {
134 | if (!dir.mkdirs())
135 | throw new BuildException("Failed to make parent directory " + dir);
136 | } else if (!dir.isDirectory()) {
137 | throw new BuildException("Parent directory of output file " + output + " exists, but is not a directory.");
138 | }
139 | FileWriter writer = null;
140 | try {
141 | cpp.addInput(input);
142 | writer = new FileWriter(output);
143 | for (;;) {
144 | Token tok = cpp.token();
145 | if (tok == null)
146 | break;
147 | if (tok.getType() == Token.EOF)
148 | break;
149 | writer.write(tok.getText());
150 | }
151 | } finally {
152 | if (writer != null) {
153 | try {
154 | writer.close();
155 | } catch (IOException e) {
156 | }
157 | }
158 | }
159 | }
160 |
161 | @Override
162 | protected void doFileOperations() {
163 | if (fileCopyMap.size() > 0) {
164 | log("Copying " + fileCopyMap.size()
165 | + " file" + (fileCopyMap.size() == 1 ? "" : "s")
166 | + " to " + destDir.getAbsolutePath());
167 |
168 | Enumeration e = fileCopyMap.keys();
169 |
170 | while (e.hasMoreElements()) {
171 | String fromFile = e.nextElement();
172 | String[] toFiles = (String[]) fileCopyMap.get(fromFile);
173 |
174 | for (String toFile : toFiles) {
175 | if (fromFile.equals(toFile)) {
176 | log("Skipping self-copy of " + fromFile, verbosity);
177 | continue;
178 | }
179 |
180 | try {
181 | log("Copying " + fromFile + " to " + toFile, verbosity);
182 |
183 | /*
184 | FilterSetCollection executionFilters
185 | = new FilterSetCollection();
186 | if (filtering) {
187 | executionFilters
188 | .addFilterSet(getProject().getGlobalFilterSet());
189 | }
190 | for (Enumeration filterEnum = getFilterSets().elements();
191 | filterEnum.hasMoreElements();) {
192 | executionFilters
193 | .addFilterSet((FilterSet) filterEnum.nextElement());
194 | }
195 | */
196 | File srcFile = new File(fromFile);
197 | File dstFile = new File(toFile);
198 | preprocess(srcFile, dstFile);
199 | } catch (Exception ioe) {
200 | // ioe.printStackTrace();
201 | String msg = "Failed to copy " + fromFile + " to " + toFile
202 | + " due to " + ioe.getMessage();
203 | File targetFile = new File(toFile);
204 | if (targetFile.exists() && !targetFile.delete()) {
205 | msg += " and I couldn't delete the corrupt " + toFile;
206 | }
207 | throw new BuildException(msg, ioe, getLocation());
208 | }
209 | }
210 | }
211 | }
212 |
213 | }
214 |
215 | }
216 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/DefaultPreprocessorListener.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | /*
4 | * Anarres C Preprocessor
5 | * Copyright (c) 2007-2015, Shevek
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
16 | * or implied. See the License for the specific language governing
17 | * permissions and limitations under the License.
18 | */
19 | import javax.annotation.Nonnegative;
20 | import javax.annotation.Nonnull;
21 | import org.slf4j.Logger;
22 | import org.slf4j.LoggerFactory;
23 |
24 | /**
25 | * A handler for preprocessor events, primarily errors and warnings.
26 | *
27 | * If no PreprocessorListener is installed in a Preprocessor, all
28 | * error and warning events will throw an exception. Installing a
29 | * listener allows more intelligent handling of these events.
30 | */
31 | public class DefaultPreprocessorListener implements PreprocessorListener {
32 |
33 | private static final Logger LOG = LoggerFactory.getLogger(DefaultPreprocessorListener.class);
34 |
35 | private int errors;
36 | private int warnings;
37 |
38 | public DefaultPreprocessorListener() {
39 | clear();
40 | }
41 |
42 | public void clear() {
43 | errors = 0;
44 | warnings = 0;
45 | }
46 |
47 | @Nonnegative
48 | public int getErrors() {
49 | return errors;
50 | }
51 |
52 | @Nonnegative
53 | public int getWarnings() {
54 | return warnings;
55 | }
56 |
57 | protected void print(@Nonnull String msg) {
58 | LOG.info(msg);
59 | }
60 |
61 | /**
62 | * Handles a warning.
63 | *
64 | * The behaviour of this method is defined by the
65 | * implementation. It may simply record the error message, or
66 | * it may throw an exception.
67 | */
68 | @Override
69 | public void handleWarning(Source source, int line, int column,
70 | String msg)
71 | throws LexerException {
72 | warnings++;
73 | print(source.getName() + ":" + line + ":" + column
74 | + ": warning: " + msg);
75 | }
76 |
77 | /**
78 | * Handles an error.
79 | *
80 | * The behaviour of this method is defined by the
81 | * implementation. It may simply record the error message, or
82 | * it may throw an exception.
83 | */
84 | @Override
85 | public void handleError(Source source, int line, int column,
86 | String msg)
87 | throws LexerException {
88 | errors++;
89 | print(source.getName() + ":" + line + ":" + column
90 | + ": error: " + msg);
91 | }
92 |
93 | @Override
94 | public void handleSourceChange(Source source, SourceChangeEvent event) {
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/Feature.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | /**
20 | * Features of the Preprocessor, which may be enabled or disabled.
21 | */
22 | public enum Feature {
23 |
24 | /** Supports ANSI digraphs. */
25 | DIGRAPHS,
26 | /** Supports ANSI trigraphs. */
27 | TRIGRAPHS,
28 | /** Outputs linemarker tokens. */
29 | LINEMARKERS,
30 | /** Reports tokens of type INVALID as errors. */
31 | CSYNTAX,
32 | /** Preserves comments in the lexed output. Like cpp -C */
33 | KEEPCOMMENTS,
34 | /** Preserves comments in the lexed output, even when inactive. */
35 | KEEPALLCOMMENTS,
36 | DEBUG,
37 | /** Supports lexing of objective-C. */
38 | OBJCSYNTAX,
39 | INCLUDENEXT,
40 | /** Random extensions. */
41 | PRAGMA_ONCE
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/FileLexerSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.BufferedReader;
20 | import java.io.File;
21 | import java.io.FileInputStream;
22 | import java.io.FileReader;
23 | import java.io.IOException;
24 | import java.nio.charset.Charset;
25 | import javax.annotation.Nonnull;
26 |
27 | /**
28 | * A {@link Source} which lexes a file.
29 | *
30 | * The input is buffered.
31 | *
32 | * @see Source
33 | */
34 | public class FileLexerSource extends InputLexerSource {
35 |
36 | private final String path;
37 | private final File file;
38 |
39 | /**
40 | * Creates a new Source for lexing the given File.
41 | *
42 | * Preprocessor directives are honoured within the file.
43 | */
44 | public FileLexerSource(@Nonnull File file, @Nonnull Charset charset, @Nonnull String path)
45 | throws IOException {
46 | super(new FileInputStream(file), charset);
47 | this.file = file;
48 | this.path = path;
49 | }
50 |
51 | public FileLexerSource(@Nonnull File file, @Nonnull String path)
52 | throws IOException {
53 | this(file, Charset.defaultCharset(), path);
54 | }
55 |
56 | public FileLexerSource(@Nonnull File file, @Nonnull Charset charset)
57 | throws IOException {
58 | this(file, charset, file.getPath());
59 | }
60 |
61 | @Deprecated
62 | public FileLexerSource(@Nonnull File file)
63 | throws IOException {
64 | this(file, Charset.defaultCharset());
65 | }
66 |
67 | public FileLexerSource(@Nonnull String path, @Nonnull Charset charset)
68 | throws IOException {
69 | this(new File(path), charset, path);
70 | }
71 |
72 | @Deprecated
73 | public FileLexerSource(@Nonnull String path)
74 | throws IOException {
75 | this(path, Charset.defaultCharset());
76 | }
77 |
78 | @Nonnull
79 | public File getFile() {
80 | return file;
81 | }
82 |
83 | /**
84 | * This is not necessarily the same as getFile().getPath() in case we are in a chroot.
85 | */
86 | @Override
87 | public String getPath() {
88 | return path;
89 | }
90 |
91 | @Override
92 | public String getName() {
93 | return getPath();
94 | }
95 |
96 | @Override
97 | public String toString() {
98 | return "file " + getPath();
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/FixedTokenSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.IOException;
20 | import java.util.Arrays;
21 | import java.util.List;
22 |
23 | /* pp */ class FixedTokenSource extends Source {
24 |
25 | private static final Token EOF
26 | = new Token(Token.EOF, "");
27 |
28 | private final List tokens;
29 | private int idx;
30 |
31 | /* pp */ FixedTokenSource(Token... tokens) {
32 | this.tokens = Arrays.asList(tokens);
33 | this.idx = 0;
34 | }
35 |
36 | /* pp */ FixedTokenSource(List tokens) {
37 | this.tokens = tokens;
38 | this.idx = 0;
39 | }
40 |
41 | @Override
42 | public Token token()
43 | throws IOException,
44 | LexerException {
45 | if (idx >= tokens.size())
46 | return EOF;
47 | return tokens.get(idx++);
48 | }
49 |
50 | @Override
51 | public String toString() {
52 | StringBuilder buf = new StringBuilder();
53 | buf.append("constant token stream ").append(tokens);
54 | Source parent = getParent();
55 | if (parent != null)
56 | buf.append(" in ").append(String.valueOf(parent));
57 | return buf.toString();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/InputLexerSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.InputStream;
20 | import java.io.InputStreamReader;
21 | import java.io.Reader;
22 | import java.nio.charset.Charset;
23 | import javax.annotation.Nonnull;
24 |
25 | /**
26 | * A {@link Source} which lexes an {@link InputStream}.
27 | *
28 | * The input is buffered.
29 | *
30 | * @see Source
31 | */
32 | public class InputLexerSource extends LexerSource {
33 |
34 | @Deprecated
35 | public InputLexerSource(@Nonnull InputStream input) {
36 | this(input, Charset.defaultCharset());
37 | }
38 |
39 | /**
40 | * Creates a new Source for lexing the given Reader.
41 | *
42 | * Preprocessor directives are honoured within the file.
43 | */
44 | public InputLexerSource(@Nonnull InputStream input, Charset charset) {
45 | this(new InputStreamReader(input, charset));
46 | }
47 |
48 | public InputLexerSource(@Nonnull Reader input, boolean ppvalid) {
49 | super(input, true);
50 | }
51 |
52 | public InputLexerSource(@Nonnull Reader input) {
53 | this(input, true);
54 | }
55 |
56 | @Override
57 | public String getPath() {
58 | return "";
59 | }
60 |
61 | @Override
62 | public String getName() {
63 | return "standard input";
64 | }
65 |
66 | @Override
67 | public String toString() {
68 | return String.valueOf(getPath());
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/InternalException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | /**
20 | * An internal exception.
21 | *
22 | * This exception is thrown when an internal state violation is
23 | * encountered. This should never happen. If it ever happens, please
24 | * report it as a bug.
25 | */
26 | public class InternalException extends RuntimeException {
27 |
28 | public InternalException(String msg) {
29 | super(msg);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/JavaFileSystem.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.File;
20 | import java.io.IOException;
21 |
22 | /**
23 | * A virtual filesystem implementation using java.io.
24 | */
25 | public class JavaFileSystem implements VirtualFileSystem {
26 |
27 | @Override
28 | public VirtualFile getFile(String path) {
29 | return new JavaFile(path);
30 | }
31 |
32 | @Override
33 | public VirtualFile getFile(String dir, String name) {
34 | return new JavaFile(dir, name);
35 | }
36 |
37 | private class JavaFile extends File implements VirtualFile {
38 |
39 | public JavaFile(String path) {
40 | super(path);
41 | }
42 |
43 | public JavaFile(String dir, String name) {
44 | super(dir, name);
45 | }
46 |
47 | /* private */
48 | public JavaFile(File dir, String name) {
49 | super(dir, name);
50 | }
51 |
52 | /*
53 | @Override
54 | public String getPath() {
55 | return getCanonicalPath();
56 | }
57 | */
58 | @Override
59 | public JavaFile getParentFile() {
60 | String parent = getParent();
61 | if (parent != null)
62 | return new JavaFile(parent);
63 | File absolute = getAbsoluteFile();
64 | parent = absolute.getParent();
65 | /*
66 | if (parent == null)
67 | return null;
68 | */
69 | return new JavaFile(parent);
70 | }
71 |
72 | @Override
73 | public JavaFile getChildFile(String name) {
74 | return new JavaFile(this, name);
75 | }
76 |
77 | @Override
78 | public Source getSource() throws IOException {
79 | return new FileLexerSource(this);
80 | }
81 |
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/JoinReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.Closeable;
20 | import java.io.IOException;
21 | import java.io.Reader;
22 |
23 | /* pp */ class JoinReader /* extends Reader */ implements Closeable {
24 |
25 | private final Reader in;
26 |
27 | private PreprocessorListener listener;
28 | private LexerSource source;
29 | private boolean trigraphs;
30 | private boolean warnings;
31 |
32 | private int newlines;
33 | private boolean flushnl;
34 | private int[] unget;
35 | private int uptr;
36 |
37 | public JoinReader(Reader in, boolean trigraphs) {
38 | this.in = in;
39 | this.trigraphs = trigraphs;
40 | this.newlines = 0;
41 | this.flushnl = false;
42 | this.unget = new int[2];
43 | this.uptr = 0;
44 | }
45 |
46 | public JoinReader(Reader in) {
47 | this(in, false);
48 | }
49 |
50 | public void setTrigraphs(boolean enable, boolean warnings) {
51 | this.trigraphs = enable;
52 | this.warnings = warnings;
53 | }
54 |
55 | /* pp */ void init(Preprocessor pp, LexerSource s) {
56 | this.listener = pp.getListener();
57 | this.source = s;
58 | setTrigraphs(pp.getFeature(Feature.TRIGRAPHS),
59 | pp.getWarning(Warning.TRIGRAPHS));
60 | }
61 |
62 | private int __read() throws IOException {
63 | if (uptr > 0)
64 | return unget[--uptr];
65 | return in.read();
66 | }
67 |
68 | private void _unread(int c) {
69 | if (c != -1)
70 | unget[uptr++] = c;
71 | assert uptr <= unget.length :
72 | "JoinReader ungets too many characters";
73 | }
74 |
75 | protected void warning(String msg)
76 | throws LexerException {
77 | if (source != null)
78 | source.warning(msg);
79 | else
80 | throw new LexerException(msg);
81 | }
82 |
83 | private char trigraph(char raw, char repl)
84 | throws IOException, LexerException {
85 | if (trigraphs) {
86 | if (warnings)
87 | warning("trigraph ??" + raw + " converted to " + repl);
88 | return repl;
89 | } else {
90 | if (warnings)
91 | warning("trigraph ??" + raw + " ignored");
92 | _unread(raw);
93 | _unread('?');
94 | return '?';
95 | }
96 | }
97 |
98 | private int _read()
99 | throws IOException, LexerException {
100 | int c = __read();
101 | if (c == '?' && (trigraphs || warnings)) {
102 | int d = __read();
103 | if (d == '?') {
104 | int e = __read();
105 | switch (e) {
106 | case '(':
107 | return trigraph('(', '[');
108 | case ')':
109 | return trigraph(')', ']');
110 | case '<':
111 | return trigraph('<', '{');
112 | case '>':
113 | return trigraph('>', '}');
114 | case '=':
115 | return trigraph('=', '#');
116 | case '/':
117 | return trigraph('/', '\\');
118 | case '\'':
119 | return trigraph('\'', '^');
120 | case '!':
121 | return trigraph('!', '|');
122 | case '-':
123 | return trigraph('-', '~');
124 | }
125 | _unread(e);
126 | }
127 | _unread(d);
128 | }
129 | return c;
130 | }
131 |
132 | public int read()
133 | throws IOException, LexerException {
134 | if (flushnl) {
135 | if (newlines > 0) {
136 | newlines--;
137 | return '\n';
138 | }
139 | flushnl = false;
140 | }
141 |
142 | for (;;) {
143 | int c = _read();
144 | switch (c) {
145 | case '\\':
146 | int d = _read();
147 | switch (d) {
148 | case '\n':
149 | newlines++;
150 | continue;
151 | case '\r':
152 | newlines++;
153 | int e = _read();
154 | if (e != '\n')
155 | _unread(e);
156 | continue;
157 | default:
158 | _unread(d);
159 | return c;
160 | }
161 | case '\r':
162 | case '\n':
163 | case '\u2028':
164 | case '\u2029':
165 | case '\u000B':
166 | case '\u000C':
167 | case '\u0085':
168 | flushnl = true;
169 | return c;
170 | case -1:
171 | if (newlines > 0) {
172 | newlines--;
173 | return '\n';
174 | }
175 | default:
176 | return c;
177 | }
178 | }
179 | }
180 |
181 | public int read(char cbuf[], int off, int len)
182 | throws IOException, LexerException {
183 | for (int i = 0; i < len; i++) {
184 | int ch = read();
185 | if (ch == -1)
186 | return i;
187 | cbuf[off + i] = (char) ch;
188 | }
189 | return len;
190 | }
191 |
192 | @Override
193 | public void close()
194 | throws IOException {
195 | in.close();
196 | }
197 |
198 | @Override
199 | public String toString() {
200 | return "JoinReader(nl=" + newlines + ")";
201 | }
202 |
203 | /*
204 | public static void main(String[] args) throws IOException {
205 | FileReader f = new FileReader(new File(args[0]));
206 | BufferedReader b = new BufferedReader(f);
207 | JoinReader r = new JoinReader(b);
208 | BufferedWriter w = new BufferedWriter(
209 | new java.io.OutputStreamWriter(System.out)
210 | );
211 | int c;
212 | while ((c = r.read()) != -1) {
213 | w.write((char)c);
214 | }
215 | w.close();
216 | }
217 | */
218 | }
219 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/LexerException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | /**
20 | * A preprocessor exception.
21 | *
22 | * Note to users: I don't really like the name of this class. S.
23 | */
24 | public class LexerException extends Exception {
25 |
26 | public LexerException(String msg) {
27 | super(msg);
28 | }
29 |
30 | public LexerException(Throwable cause) {
31 | super(cause);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/Macro.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Iterator;
21 | import java.util.List;
22 |
23 | /**
24 | * A macro object.
25 | *
26 | * This encapsulates a name, an argument count, and a token stream
27 | * for replacement. The replacement token stream may contain the
28 | * extra tokens {@link Token#M_ARG} and {@link Token#M_STRING}.
29 | */
30 | public class Macro {
31 |
32 | private Source source;
33 | private String name;
34 | /* It's an explicit decision to keep these around here. We don't
35 | * need to; the argument token type is M_ARG and the value
36 | * is the index. The strings themselves are only used in
37 | * stringification of the macro, for debugging. */
38 | private List args;
39 | private boolean variadic;
40 | private List tokens;
41 |
42 | public Macro(Source source, String name) {
43 | this.source = source;
44 | this.name = name;
45 | this.args = null;
46 | this.variadic = false;
47 | this.tokens = new ArrayList();
48 | }
49 |
50 | public Macro(String name) {
51 | this(null, name);
52 | }
53 |
54 | /**
55 | * Sets the Source from which this macro was parsed.
56 | */
57 | public void setSource(Source s) {
58 | this.source = s;
59 | }
60 |
61 | /**
62 | * Returns the Source from which this macro was parsed.
63 | *
64 | * This method may return null if the macro was not parsed
65 | * from a regular file.
66 | */
67 | public Source getSource() {
68 | return source;
69 | }
70 |
71 | /**
72 | * Returns the name of this macro.
73 | */
74 | public String getName() {
75 | return name;
76 | }
77 |
78 | /**
79 | * Sets the arguments to this macro.
80 | */
81 | public void setArgs(List args) {
82 | this.args = args;
83 | }
84 |
85 | /**
86 | * Returns true if this is a function-like macro.
87 | */
88 | public boolean isFunctionLike() {
89 | return args != null;
90 | }
91 |
92 | /**
93 | * Returns the number of arguments to this macro.
94 | */
95 | public int getArgs() {
96 | return args.size();
97 | }
98 |
99 | /**
100 | * Sets the variadic flag on this Macro.
101 | */
102 | public void setVariadic(boolean b) {
103 | this.variadic = b;
104 | }
105 |
106 | /**
107 | * Returns true if this is a variadic function-like macro.
108 | */
109 | public boolean isVariadic() {
110 | return variadic;
111 | }
112 |
113 | /**
114 | * Adds a token to the expansion of this macro.
115 | */
116 | public void addToken(Token tok) {
117 | this.tokens.add(tok);
118 | }
119 |
120 | /**
121 | * Adds a "paste" operator to the expansion of this macro.
122 | *
123 | * A paste operator causes the next token added to be pasted
124 | * to the previous token when the macro is expanded.
125 | * It is an error for a macro to end with a paste token.
126 | */
127 | public void addPaste(Token tok) {
128 | /*
129 | * Given: tok0 ## tok1
130 | * We generate: M_PASTE, tok0, tok1
131 | * This extends as per a stack language:
132 | * tok0 ## tok1 ## tok2 ->
133 | * M_PASTE, tok0, M_PASTE, tok1, tok2
134 | */
135 | this.tokens.add(tokens.size() - 1, tok);
136 | }
137 |
138 | /* pp */ List getTokens() {
139 | return tokens;
140 | }
141 |
142 | /* Paste tokens are inserted before the first of the two pasted
143 | * tokens, so it's a kind of bytecode notation. This method
144 | * swaps them around again. We know that there will never be two
145 | * sequential paste tokens, so a boolean is sufficient. */
146 | public String getText() {
147 | StringBuilder buf = new StringBuilder();
148 | boolean paste = false;
149 | for (Token tok : tokens) {
150 | if (tok.getType() == Token.M_PASTE) {
151 | assert paste == false : "Two sequential pastes.";
152 | paste = true;
153 | continue;
154 | } else {
155 | buf.append(tok.getText());
156 | }
157 | if (paste) {
158 | buf.append(" #" + "# ");
159 | paste = false;
160 | }
161 | // buf.append(tokens.get(i));
162 | }
163 | return buf.toString();
164 | }
165 |
166 | @Override
167 | public String toString() {
168 | StringBuilder buf = new StringBuilder(name);
169 | if (args != null) {
170 | buf.append('(');
171 | Iterator it = args.iterator();
172 | while (it.hasNext()) {
173 | buf.append(it.next());
174 | if (it.hasNext())
175 | buf.append(", ");
176 | else if (isVariadic())
177 | buf.append("...");
178 | }
179 | buf.append(')');
180 | }
181 | if (!tokens.isEmpty()) {
182 | buf.append(" => ").append(getText());
183 | }
184 | return buf.toString();
185 | }
186 |
187 | }
188 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/MacroTokenSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.IOException;
20 | import java.util.Iterator;
21 | import java.util.List;
22 | import javax.annotation.Nonnegative;
23 | import javax.annotation.Nonnull;
24 | import org.slf4j.Logger;
25 | import org.slf4j.LoggerFactory;
26 | import static org.anarres.cpp.Token.*;
27 |
28 | /* This source should always be active, since we don't expand macros
29 | * in any inactive context. */
30 | /* pp */ class MacroTokenSource extends Source {
31 |
32 | private static final Logger LOG = LoggerFactory.getLogger(MacroTokenSource.class);
33 | private final Macro macro;
34 | private final Iterator tokens; /* Pointer into the macro. */
35 |
36 | private final List args; /* { unexpanded, expanded } */
37 |
38 | private Iterator arg; /* "current expansion" */
39 |
40 | /* pp */ MacroTokenSource(@Nonnull Macro m, @Nonnull List args) {
41 | this.macro = m;
42 | this.tokens = m.getTokens().iterator();
43 | this.args = args;
44 | this.arg = null;
45 | }
46 |
47 | @Override
48 | /* pp */ boolean isExpanding(@Nonnull Macro m) {
49 | /* When we are expanding an arg, 'this' macro is not
50 | * being expanded, and thus we may re-expand it. */
51 | if (/* XXX this.arg == null && */this.macro == m)
52 | return true;
53 | return super.isExpanding(m);
54 | }
55 |
56 | /* XXX Called from Preprocessor [ugly]. */
57 | /* pp */ static void escape(@Nonnull StringBuilder buf, @Nonnull CharSequence cs) {
58 | if (buf == null)
59 | throw new NullPointerException("Buffer was null.");
60 | if (cs == null)
61 | throw new NullPointerException("CharSequence was null.");
62 | for (int i = 0; i < cs.length(); i++) {
63 | char c = cs.charAt(i);
64 | switch (c) {
65 | case '\\':
66 | buf.append("\\\\");
67 | break;
68 | case '"':
69 | buf.append("\\\"");
70 | break;
71 | case '\n':
72 | buf.append("\\n");
73 | break;
74 | case '\r':
75 | buf.append("\\r");
76 | break;
77 | default:
78 | buf.append(c);
79 | }
80 | }
81 | }
82 |
83 | private void concat(@Nonnull StringBuilder buf, @Nonnull Argument arg) {
84 | for (Token tok : arg) {
85 | buf.append(tok.getText());
86 | }
87 | }
88 |
89 | @Nonnull
90 | private Token stringify(@Nonnull Token pos, @Nonnull Argument arg) {
91 | StringBuilder buf = new StringBuilder();
92 | concat(buf, arg);
93 | // System.out.println("Concat: " + arg + " -> " + buf);
94 | StringBuilder str = new StringBuilder("\"");
95 | escape(str, buf);
96 | str.append("\"");
97 | // System.out.println("Escape: " + buf + " -> " + str);
98 | return new Token(STRING,
99 | pos.getLine(), pos.getColumn(),
100 | str.toString(), buf.toString());
101 | }
102 |
103 | /**
104 | * Returns true if the given argumentIndex is the last argument of a variadic macro.
105 | *
106 | * @param argumentIndex The index of the argument to inspect.
107 | * @return true if the given argumentIndex is the last argument of a variadic macro.
108 | */
109 | private boolean isVariadicArgument(@Nonnegative int argumentIndex) {
110 | if (!macro.isVariadic())
111 | return false;
112 | return argumentIndex == args.size() - 1;
113 | }
114 |
115 | /* At this point, we have consumed the first M_PASTE.
116 | * @see Macro#addPaste(Token) */
117 | private void paste(@Nonnull Token ptok)
118 | throws IOException,
119 | LexerException {
120 | // List out = new ArrayList();
121 | StringBuilder buf = new StringBuilder();
122 | // Token err = null;
123 | /* We know here that arg is null or expired,
124 | * since we cannot paste an expanded arg. */
125 |
126 | int count = 2;
127 | // While I hate auxiliary booleans, this does actually seem to be the simplest solution,
128 | // as it avoids duplicating all the logic around hasNext() in case COMMA.
129 | boolean comma = false;
130 | TOKEN:
131 | for (int i = 0; i < count; i++) {
132 | if (!tokens.hasNext()) {
133 | /* XXX This one really should throw. */
134 | error(ptok.getLine(), ptok.getColumn(),
135 | "Paste at end of expansion");
136 | buf.append(' ').append(ptok.getText());
137 | break;
138 | }
139 | Token tok = tokens.next();
140 | // System.out.println("Paste " + tok);
141 | switch (tok.getType()) {
142 | case M_PASTE:
143 | /* One extra to paste, plus one because the
144 | * paste token didn't count. */
145 | count += 2;
146 | ptok = tok;
147 | break;
148 | case M_ARG:
149 | int idx = ((Integer) tok.getValue()).intValue();
150 | Argument arg = args.get(idx);
151 | if (comma && isVariadicArgument(idx) && arg.isEmpty()) {
152 | // Ugly way to strip the comma.
153 | buf.setLength(buf.length() - 1);
154 | } else {
155 | concat(buf, arg);
156 | }
157 | break;
158 | /* XXX Test this. */
159 | case CCOMMENT:
160 | case CPPCOMMENT:
161 | // TODO: In cpp, -CC keeps these comments too,
162 | // but turns all C++ comments into C comments.
163 | break;
164 | case ',':
165 | comma = true;
166 | buf.append(tok.getText());
167 | continue TOKEN;
168 | default:
169 | buf.append(tok.getText());
170 | break;
171 | }
172 | comma = false;
173 | }
174 |
175 | /* Push and re-lex. */
176 | /*
177 | StringBuilder src = new StringBuilder();
178 | escape(src, buf);
179 | StringLexerSource sl = new StringLexerSource(src.toString());
180 | */
181 | StringLexerSource sl = new StringLexerSource(buf.toString());
182 |
183 | /* XXX Check that concatenation produces a valid token. */
184 | arg = new SourceIterator(sl);
185 | }
186 |
187 | @Override
188 | public Token token()
189 | throws IOException,
190 | LexerException {
191 | for (;;) {
192 | /* Deal with lexed tokens first. */
193 |
194 | if (arg != null) {
195 | if (arg.hasNext()) {
196 | Token tok = arg.next();
197 | /* XXX PASTE -> INVALID. */
198 | assert tok.getType() != M_PASTE :
199 | "Unexpected paste token";
200 | return tok;
201 | }
202 | arg = null;
203 | }
204 |
205 | if (!tokens.hasNext())
206 | return new Token(EOF, -1, -1, ""); /* End of macro. */
207 |
208 | Token tok = tokens.next();
209 | int idx;
210 | switch (tok.getType()) {
211 | case M_STRING:
212 | /* Use the nonexpanded arg. */
213 | idx = ((Integer) tok.getValue()).intValue();
214 | return stringify(tok, args.get(idx));
215 | case M_ARG:
216 | /* Expand the arg. */
217 | idx = ((Integer) tok.getValue()).intValue();
218 | // System.out.println("Pushing arg " + args.get(idx));
219 | arg = args.get(idx).expansion();
220 | break;
221 | case M_PASTE:
222 | paste(tok);
223 | break;
224 | default:
225 | return tok;
226 | }
227 | } /* for */
228 |
229 | }
230 |
231 | @Override
232 | public String toString() {
233 | StringBuilder buf = new StringBuilder();
234 | buf.append("expansion of ").append(macro.getName());
235 | Source parent = getParent();
236 | if (parent != null)
237 | buf.append(" in ").append(String.valueOf(parent));
238 | return buf.toString();
239 | }
240 | }
241 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/Main.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.File;
20 | import java.io.PrintStream;
21 | import java.util.Arrays;
22 | import java.util.EnumSet;
23 | import java.util.List;
24 | import javax.annotation.Nonnull;
25 | import joptsimple.OptionParser;
26 | import joptsimple.OptionSet;
27 | import joptsimple.OptionSpec;
28 | import org.slf4j.Logger;
29 | import org.slf4j.LoggerFactory;
30 |
31 | /**
32 | * (Currently a simple test class).
33 | */
34 | public class Main {
35 |
36 | private static final Logger LOG = LoggerFactory.getLogger(Main.class);
37 |
38 | @Nonnull
39 | private static CharSequence getWarnings() {
40 | StringBuilder buf = new StringBuilder();
41 | for (Warning w : Warning.values()) {
42 | if (buf.length() > 0)
43 | buf.append(", ");
44 | String name = w.name().toLowerCase();
45 | buf.append(name.replace('_', '-'));
46 | }
47 | return buf;
48 | }
49 |
50 | public static void main(String[] args) throws Exception {
51 | (new Main()).run(args);
52 | }
53 |
54 | public void run(String[] args) throws Exception {
55 |
56 | OptionParser parser = new OptionParser();
57 | OptionSpec> helpOption = parser.accepts("help",
58 | "Displays command-line help.")
59 | .forHelp();
60 | OptionSpec> versionOption = parser.acceptsAll(Arrays.asList("version"),
61 | "Displays the product version (" + BuildMetadata.getInstance().getVersion() + ") and exits.")
62 | .forHelp();
63 |
64 | OptionSpec> debugOption = parser.acceptsAll(Arrays.asList("debug"),
65 | "Enables debug output.");
66 |
67 | OptionSpec defineOption = parser.acceptsAll(Arrays.asList("define", "D"),
68 | "Defines the given macro.")
69 | .withRequiredArg().ofType(String.class).describedAs("name[=definition]");
70 | OptionSpec undefineOption = parser.acceptsAll(Arrays.asList("undefine", "U"),
71 | "Undefines the given macro, previously either builtin or defined using -D.")
72 | .withRequiredArg().describedAs("name");
73 | OptionSpec includeOption = parser.accepts("include",
74 | "Process file as if \"#" + "include \"file\"\" appeared as the first line of the primary source file.")
75 | .withRequiredArg().ofType(File.class).describedAs("file");
76 | OptionSpec incdirOption = parser.acceptsAll(Arrays.asList("incdir", "I"),
77 | "Adds the directory dir to the list of directories to be searched for header files.")
78 | .withRequiredArg().ofType(File.class).describedAs("dir");
79 | OptionSpec iquoteOption = parser.acceptsAll(Arrays.asList("iquote"),
80 | "Adds the directory dir to the list of directories to be searched for header files included using \"\".")
81 | .withRequiredArg().ofType(File.class).describedAs("dir");
82 | OptionSpec warningOption = parser.acceptsAll(Arrays.asList("warning", "W"),
83 | "Enables the named warning class (" + getWarnings() + ").")
84 | .withRequiredArg().ofType(String.class).describedAs("warning");
85 | OptionSpec noWarningOption = parser.acceptsAll(Arrays.asList("no-warnings", "w"),
86 | "Disables ALL warnings.");
87 | OptionSpec inputsOption = parser.nonOptions()
88 | .ofType(File.class).describedAs("Files to process.");
89 |
90 | OptionSet options = parser.parse(args);
91 |
92 | if (options.has(helpOption)) {
93 | parser.printHelpOn(System.out);
94 | return;
95 | }
96 |
97 | if (options.has(versionOption)) {
98 | version(System.out);
99 | return;
100 | }
101 |
102 | Preprocessor pp = new Preprocessor();
103 | pp.addFeature(Feature.DIGRAPHS);
104 | pp.addFeature(Feature.TRIGRAPHS);
105 | pp.addFeature(Feature.LINEMARKERS);
106 | pp.addWarning(Warning.IMPORT);
107 | pp.setListener(new DefaultPreprocessorListener());
108 | pp.addMacro("__JCPP__");
109 | pp.getSystemIncludePath().add("/usr/local/include");
110 | pp.getSystemIncludePath().add("/usr/include");
111 | pp.getFrameworksPath().add("/System/Library/Frameworks");
112 | pp.getFrameworksPath().add("/Library/Frameworks");
113 | pp.getFrameworksPath().add("/Local/Library/Frameworks");
114 |
115 | if (options.has(debugOption))
116 | pp.addFeature(Feature.DEBUG);
117 |
118 | if (options.has(noWarningOption))
119 | pp.getWarnings().clear();
120 |
121 | for (String warning : options.valuesOf(warningOption)) {
122 | warning = warning.toUpperCase();
123 | warning = warning.replace('-', '_');
124 | if (warning.equals("ALL"))
125 | pp.addWarnings(EnumSet.allOf(Warning.class));
126 | else
127 | pp.addWarning(Enum.valueOf(Warning.class, warning));
128 | }
129 |
130 | for (String arg : options.valuesOf(defineOption)) {
131 | int idx = arg.indexOf('=');
132 | if (idx == -1)
133 | pp.addMacro(arg);
134 | else
135 | pp.addMacro(arg.substring(0, idx), arg.substring(idx + 1));
136 | }
137 | for (String arg : options.valuesOf(undefineOption)) {
138 | pp.getMacros().remove(arg);
139 | }
140 |
141 | for (File dir : options.valuesOf(incdirOption))
142 | pp.getSystemIncludePath().add(dir.getAbsolutePath());
143 | for (File dir : options.valuesOf(iquoteOption))
144 | pp.getQuoteIncludePath().add(dir.getAbsolutePath());
145 | for (File file : options.valuesOf(includeOption))
146 | // Comply exactly with spec.
147 | pp.addInput(new StringLexerSource("#" + "include \"" + file + "\"\n"));
148 |
149 | List inputs = options.valuesOf(inputsOption);
150 | if (inputs.isEmpty()) {
151 | pp.addInput(new InputLexerSource(System.in));
152 | } else {
153 | for (File input : inputs)
154 | pp.addInput(new FileLexerSource(input));
155 | }
156 |
157 | if (pp.getFeature(Feature.DEBUG)) {
158 | LOG.info("#" + "include \"...\" search starts here:");
159 | for (String dir : pp.getQuoteIncludePath())
160 | LOG.info(" " + dir);
161 | LOG.info("#" + "include <...> search starts here:");
162 | for (String dir : pp.getSystemIncludePath())
163 | LOG.info(" " + dir);
164 | LOG.info("End of search list.");
165 | }
166 |
167 | try {
168 | for (;;) {
169 | Token tok = pp.token();
170 | if (tok == null)
171 | break;
172 | if (tok.getType() == Token.EOF)
173 | break;
174 | System.out.print(tok.getText());
175 | }
176 | } catch (Exception e) {
177 | StringBuilder buf = new StringBuilder("Preprocessor failed:\n");
178 | Source s = pp.getSource();
179 | while (s != null) {
180 | buf.append(" -> ").append(s).append("\n");
181 | s = s.getParent();
182 | }
183 | LOG.error(buf.toString(), e);
184 | }
185 |
186 | }
187 |
188 | private static void version(@Nonnull PrintStream out) {
189 | BuildMetadata metadata = BuildMetadata.getInstance();
190 | out.println("Anarres Java C Preprocessor version " + metadata.getVersion() + " change-id " + metadata.getChangeId());
191 | out.println("Copyright (C) 2007-2015 Shevek (http://www.anarres.org/).");
192 | out.println("This is free software; see the source for copying conditions. There is NO");
193 | out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/NumericValue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.math.BigDecimal;
20 | import java.math.BigInteger;
21 | import javax.annotation.CheckForNull;
22 | import javax.annotation.CheckForSigned;
23 | import javax.annotation.Nonnegative;
24 | import javax.annotation.Nonnull;
25 |
26 | public class NumericValue extends Number {
27 |
28 | public static final int F_UNSIGNED = 1;
29 | public static final int F_INT = 2;
30 | public static final int F_LONG = 4;
31 | public static final int F_LONGLONG = 8;
32 | public static final int F_FLOAT = 16;
33 | public static final int F_DOUBLE = 32;
34 |
35 | public static final int FF_SIZE = F_INT | F_LONG | F_LONGLONG | F_FLOAT | F_DOUBLE;
36 |
37 | private final int base;
38 | private final String integer;
39 | private String fraction;
40 | private int expbase = 0;
41 | private String exponent;
42 | private int flags;
43 |
44 | public NumericValue(@Nonnegative int base, @Nonnull String integer) {
45 | this.base = base;
46 | this.integer = integer;
47 | }
48 |
49 | @Nonnegative
50 | public int getBase() {
51 | return base;
52 | }
53 |
54 | @Nonnull
55 | public String getIntegerPart() {
56 | return integer;
57 | }
58 |
59 | @CheckForNull
60 | public String getFractionalPart() {
61 | return fraction;
62 | }
63 |
64 | /* pp */ void setFractionalPart(@Nonnull String fraction) {
65 | this.fraction = fraction;
66 | }
67 |
68 | @CheckForSigned
69 | public int getExponentBase() {
70 | return expbase;
71 | }
72 |
73 | @CheckForNull
74 | public String getExponent() {
75 | return exponent;
76 | }
77 |
78 | /* pp */ void setExponent(@Nonnegative int expbase, @Nonnull String exponent) {
79 | this.expbase = expbase;
80 | this.exponent = exponent;
81 | }
82 |
83 | public int getFlags() {
84 | return flags;
85 | }
86 |
87 | /* pp */ void setFlags(int flags) {
88 | this.flags = flags;
89 | }
90 |
91 | /**
92 | * So, it turns out that parsing arbitrary bases into arbitrary
93 | * precision numbers is nontrivial, and this routine gets it wrong
94 | * in many important cases.
95 | */
96 | @Nonnull
97 | public BigDecimal toBigDecimal() {
98 | int scale = 0;
99 | String text = getIntegerPart();
100 | String t_fraction = getFractionalPart();
101 | if (t_fraction != null) {
102 | text += getFractionalPart();
103 | // XXX Wrong for anything but base 10.
104 | scale += t_fraction.length();
105 | }
106 | String t_exponent = getExponent();
107 | if (t_exponent != null)
108 | scale -= Integer.parseInt(t_exponent);
109 | BigInteger unscaled = new BigInteger(text, getBase());
110 | return new BigDecimal(unscaled, scale);
111 | }
112 |
113 | // We could construct a heuristic for when an 'int' is large enough.
114 | // private static final int S_MAXLEN_LONG = String.valueOf(Long.MAX_VALUE).length();
115 | // private static final int S_MAXLEN_INT = String.valueOf(Integer.MAX_VALUE).length();
116 |
117 | @Nonnull
118 | public Number toJavaLangNumber() {
119 | int flags = getFlags();
120 | if ((flags & F_DOUBLE) != 0)
121 | return doubleValue();
122 | else if ((flags & F_FLOAT) != 0)
123 | return floatValue();
124 | else if ((flags & (F_LONG | F_LONGLONG)) != 0)
125 | return longValue();
126 | else if ((flags & F_INT) != 0)
127 | return intValue();
128 | else if (getFractionalPart() != null)
129 | return doubleValue(); // .1 is a double in Java.
130 | else if (getExponent() != null)
131 | return doubleValue();
132 | else {
133 | // This is an attempt to avoid overflowing on over-long integers.
134 | // However, now we just overflow on over-long longs.
135 | // We should really use BigInteger.
136 | long value = longValue();
137 | if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE)
138 | return (int) value;
139 | return value;
140 | }
141 | }
142 |
143 | private int exponentValue() {
144 | return Integer.parseInt(exponent, 10);
145 | }
146 |
147 | @Override
148 | public int intValue() {
149 | // String.isEmpty() is since 1.6
150 | int v = integer.length() == 0 ? 0 : Integer.parseInt(integer, base);
151 | if (expbase == 2)
152 | v = v << exponentValue();
153 | else if (expbase != 0)
154 | v = (int) (v * Math.pow(expbase, exponentValue()));
155 | return v;
156 | }
157 |
158 | @Override
159 | public long longValue() {
160 | // String.isEmpty() is since 1.6
161 | long v = integer.length() == 0 ? 0 : Long.parseLong(integer, base);
162 | if (expbase == 2)
163 | v = v << exponentValue();
164 | else if (expbase != 0)
165 | v = (long) (v * Math.pow(expbase, exponentValue()));
166 | return v;
167 | }
168 |
169 | @Override
170 | public float floatValue() {
171 | if (getBase() != 10)
172 | return longValue();
173 | return Float.parseFloat(toString());
174 | }
175 |
176 | @Override
177 | public double doubleValue() {
178 | if (getBase() != 10)
179 | return longValue();
180 | return Double.parseDouble(toString());
181 | }
182 |
183 | private boolean appendFlags(StringBuilder buf, String suffix, int flag) {
184 | if ((getFlags() & flag) != flag)
185 | return false;
186 | buf.append(suffix);
187 | return true;
188 | }
189 |
190 | @Override
191 | public String toString() {
192 | StringBuilder buf = new StringBuilder();
193 | switch (base) {
194 | case 8:
195 | buf.append('0');
196 | break;
197 | case 10:
198 | break;
199 | case 16:
200 | buf.append("0x");
201 | break;
202 | case 2:
203 | buf.append('b');
204 | break;
205 | default:
206 | buf.append("[base-").append(base).append("]");
207 | break;
208 | }
209 | buf.append(getIntegerPart());
210 | if (getFractionalPart() != null)
211 | buf.append('.').append(getFractionalPart());
212 | if (getExponent() != null) {
213 | buf.append(base > 10 ? 'p' : 'e');
214 | buf.append(getExponent());
215 | }
216 | /*
217 | if (appendFlags(buf, "ui", F_UNSIGNED | F_INT));
218 | else if (appendFlags(buf, "ul", F_UNSIGNED | F_LONG));
219 | else if (appendFlags(buf, "ull", F_UNSIGNED | F_LONGLONG));
220 | else if (appendFlags(buf, "i", F_INT));
221 | else if (appendFlags(buf, "l", F_LONG));
222 | else if (appendFlags(buf, "ll", F_LONGLONG));
223 | else if (appendFlags(buf, "f", F_FLOAT));
224 | else if (appendFlags(buf, "d", F_DOUBLE));
225 | */
226 | return buf.toString();
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/PreprocessorCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.anarres.cpp;
7 |
8 | import javax.annotation.CheckForNull;
9 | import javax.annotation.Nonnull;
10 |
11 | /**
12 | *
13 | * @author shevek
14 | */
15 | public enum PreprocessorCommand {
16 |
17 | PP_DEFINE("define"),
18 | PP_ELIF("elif"),
19 | PP_ELSE("else"),
20 | PP_ENDIF("endif"),
21 | PP_ERROR("error"),
22 | PP_IF("if"),
23 | PP_IFDEF("ifdef"),
24 | PP_IFNDEF("ifndef"),
25 | PP_INCLUDE("include"),
26 | PP_LINE("line"),
27 | PP_PRAGMA("pragma"),
28 | PP_UNDEF("undef"),
29 | PP_WARNING("warning"),
30 | PP_INCLUDE_NEXT("include_next"),
31 | PP_IMPORT("import");
32 | private final String text;
33 | /* pp */ PreprocessorCommand(String text) {
34 | this.text = text;
35 | }
36 |
37 | @CheckForNull
38 | public static PreprocessorCommand forText(@Nonnull String text) {
39 | for (PreprocessorCommand ppcmd : PreprocessorCommand.values())
40 | if (ppcmd.text.equals(text))
41 | return ppcmd;
42 | return null;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/PreprocessorListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import javax.annotation.Nonnull;
20 |
21 | /**
22 | * A handler for preprocessor events, primarily errors and warnings.
23 | *
24 | * If no PreprocessorListener is installed in a Preprocessor, all
25 | * error and warning events will throw an exception. Installing a
26 | * listener allows more intelligent handling of these events.
27 | */
28 | public interface PreprocessorListener {
29 |
30 | /**
31 | * Handles a warning.
32 | *
33 | * The behaviour of this method is defined by the
34 | * implementation. It may simply record the error message, or
35 | * it may throw an exception.
36 | */
37 | public void handleWarning(@Nonnull Source source, int line, int column,
38 | @Nonnull String msg)
39 | throws LexerException;
40 |
41 | /**
42 | * Handles an error.
43 | *
44 | * The behaviour of this method is defined by the
45 | * implementation. It may simply record the error message, or
46 | * it may throw an exception.
47 | */
48 | public void handleError(@Nonnull Source source, int line, int column,
49 | @Nonnull String msg)
50 | throws LexerException;
51 |
52 | public enum SourceChangeEvent {
53 |
54 | SUSPEND, PUSH, POP, RESUME;
55 | }
56 |
57 | public void handleSourceChange(@Nonnull Source source, @Nonnull SourceChangeEvent event);
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/ResourceFileSystem.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.anarres.cpp;
7 |
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.nio.charset.Charset;
11 | import javax.annotation.Nonnull;
12 |
13 | /**
14 | *
15 | * @author shevek
16 | */
17 | public class ResourceFileSystem implements VirtualFileSystem {
18 |
19 | private final ClassLoader loader;
20 | private final Charset charset;
21 |
22 | public ResourceFileSystem(@Nonnull ClassLoader loader, @Nonnull Charset charset) {
23 | this.loader = loader;
24 | this.charset = charset;
25 | }
26 |
27 | @Override
28 | public VirtualFile getFile(String path) {
29 | return new ResourceFile(loader, path);
30 | }
31 |
32 | @Override
33 | public VirtualFile getFile(String dir, String name) {
34 | return getFile(dir + "/" + name);
35 | }
36 |
37 | private class ResourceFile implements VirtualFile {
38 |
39 | private final ClassLoader loader;
40 | private final String path;
41 |
42 | public ResourceFile(ClassLoader loader, String path) {
43 | this.loader = loader;
44 | this.path = path;
45 | }
46 |
47 | @Override
48 | public boolean isFile() {
49 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
50 | }
51 |
52 | @Override
53 | public String getPath() {
54 | return path;
55 | }
56 |
57 | @Override
58 | public String getName() {
59 | return path.substring(path.lastIndexOf('/') + 1);
60 | }
61 |
62 | @Override
63 | public ResourceFile getParentFile() {
64 | int idx = path.lastIndexOf('/');
65 | if (idx < 1)
66 | return null;
67 | return new ResourceFile(loader, path.substring(0, idx));
68 | }
69 |
70 | @Override
71 | public ResourceFile getChildFile(String name) {
72 | return new ResourceFile(loader, path + "/" + name);
73 | }
74 |
75 | @Override
76 | public Source getSource() throws IOException {
77 | InputStream stream = loader.getResourceAsStream(path);
78 | return new InputLexerSource(stream, charset);
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/Source.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.Closeable;
20 | import java.io.IOException;
21 | import java.util.Iterator;
22 | import javax.annotation.CheckForNull;
23 | import javax.annotation.Nonnegative;
24 | import javax.annotation.Nonnull;
25 | import static org.anarres.cpp.Token.CCOMMENT;
26 | import static org.anarres.cpp.Token.CPPCOMMENT;
27 | import static org.anarres.cpp.Token.EOF;
28 | import static org.anarres.cpp.Token.NL;
29 | import static org.anarres.cpp.Token.WHITESPACE;
30 |
31 | /**
32 | * An input to the Preprocessor.
33 | *
34 | * Inputs may come from Files, Strings or other sources. The
35 | * preprocessor maintains a stack of Sources. Operations such as
36 | * file inclusion or token pasting will push a new source onto
37 | * the Preprocessor stack. Sources pop from the stack when they
38 | * are exhausted; this may be transparent or explicit.
39 | *
40 | * BUG: Error messages are not handled properly.
41 | */
42 | public abstract class Source implements Iterable, Closeable {
43 |
44 | private Source parent;
45 | private boolean autopop;
46 | private PreprocessorListener listener;
47 | private boolean active;
48 | private boolean werror;
49 |
50 | /* LineNumberReader */
51 |
52 | /*
53 | // We can't do this, since we would lose the LexerException
54 | private class Itr implements Iterator {
55 | private Token next = null;
56 | private void advance() {
57 | try {
58 | if (next != null)
59 | next = token();
60 | }
61 | catch (IOException e) {
62 | throw new UnsupportedOperationException(
63 | "Failed to advance token iterator: " +
64 | e.getMessage()
65 | );
66 | }
67 | }
68 | public boolean hasNext() {
69 | return next.getType() != EOF;
70 | }
71 | public Token next() {
72 | advance();
73 | Token t = next;
74 | next = null;
75 | return t;
76 | }
77 | public void remove() {
78 | throw new UnsupportedOperationException(
79 | "Cannot remove tokens from a Source."
80 | );
81 | }
82 | }
83 | */
84 | public Source() {
85 | this.parent = null;
86 | this.autopop = false;
87 | this.listener = null;
88 | this.active = true;
89 | this.werror = false;
90 | }
91 |
92 | /**
93 | * Sets the parent source of this source.
94 | *
95 | * Sources form a singly linked list.
96 | */
97 | /* pp */ void setParent(Source parent, boolean autopop) {
98 | this.parent = parent;
99 | this.autopop = autopop;
100 | }
101 |
102 | /**
103 | * Returns the parent source of this source.
104 | *
105 | * Sources form a singly linked list.
106 | */
107 | /* pp */ final Source getParent() {
108 | return parent;
109 | }
110 |
111 |
112 | // @OverrideMustInvoke
113 | /* pp */ void init(Preprocessor pp) {
114 | setListener(pp.getListener());
115 | this.werror = pp.getWarnings().contains(Warning.ERROR);
116 | }
117 |
118 | /**
119 | * Sets the listener for this Source.
120 | *
121 | * Normally this is set by the Preprocessor when a Source is
122 | * used, but if you are using a Source as a standalone object,
123 | * you may wish to call this.
124 | */
125 | public void setListener(PreprocessorListener pl) {
126 | this.listener = pl;
127 | }
128 |
129 | /**
130 | * Returns the File currently being lexed.
131 | *
132 | * If this Source is not a {@link FileLexerSource}, then
133 | * it will ask the parent Source, and so forth recursively.
134 | * If no Source on the stack is a FileLexerSource, returns null.
135 | */
136 | @CheckForNull
137 | public String getPath() {
138 | Source parent = getParent();
139 | if (parent != null)
140 | return parent.getPath();
141 | return null;
142 | }
143 |
144 | /**
145 | * Returns the human-readable name of the current Source.
146 | */
147 | @CheckForNull
148 | public String getName() {
149 | Source parent = getParent();
150 | if (parent != null)
151 | return parent.getName();
152 | return null;
153 | }
154 |
155 | /**
156 | * Returns the current line number within this Source.
157 | */
158 | @Nonnegative
159 | public int getLine() {
160 | Source parent = getParent();
161 | if (parent == null)
162 | return 0;
163 | return parent.getLine();
164 | }
165 |
166 | /**
167 | * Returns the current column number within this Source.
168 | */
169 | public int getColumn() {
170 | Source parent = getParent();
171 | if (parent == null)
172 | return 0;
173 | return parent.getColumn();
174 | }
175 |
176 | /**
177 | * Returns true if this Source is expanding the given macro.
178 | *
179 | * This is used to prevent macro recursion.
180 | */
181 | /* pp */ boolean isExpanding(@Nonnull Macro m) {
182 | Source parent = getParent();
183 | if (parent != null)
184 | return parent.isExpanding(m);
185 | return false;
186 | }
187 |
188 | /**
189 | * Returns true if this Source should be transparently popped
190 | * from the input stack.
191 | *
192 | * Examples of such sources are macro expansions.
193 | */
194 | /* pp */ boolean isAutopop() {
195 | return autopop;
196 | }
197 |
198 | /**
199 | * Returns true if this source has line numbers.
200 | */
201 | /* pp */ boolean isNumbered() {
202 | return false;
203 | }
204 |
205 | /* This is an incredibly lazy way of disabling warnings when
206 | * the source is not active. */
207 | /* pp */ void setActive(boolean b) {
208 | this.active = b;
209 | }
210 |
211 | /* pp */ boolean isActive() {
212 | return active;
213 | }
214 |
215 | /**
216 | * Returns the next Token parsed from this input stream.
217 | *
218 | * @see Token
219 | */
220 | @Nonnull
221 | public abstract Token token()
222 | throws IOException,
223 | LexerException;
224 |
225 | /**
226 | * Returns a token iterator for this Source.
227 | */
228 | @Override
229 | public Iterator iterator() {
230 | return new SourceIterator(this);
231 | }
232 |
233 | /**
234 | * Skips tokens until the end of line.
235 | *
236 | * @param white true if only whitespace is permitted on the
237 | * remainder of the line.
238 | * @return the NL token.
239 | */
240 | @Nonnull
241 | public Token skipline(boolean white)
242 | throws IOException,
243 | LexerException {
244 | for (;;) {
245 | Token tok = token();
246 | switch (tok.getType()) {
247 | case EOF:
248 | /* There ought to be a newline before EOF.
249 | * At least, in any skipline context. */
250 | /* XXX Are we sure about this? */
251 | warning(tok.getLine(), tok.getColumn(),
252 | "No newline before end of file");
253 | return new Token(NL,
254 | tok.getLine(), tok.getColumn(),
255 | "\n");
256 | // return tok;
257 | case NL:
258 | /* This may contain one or more newlines. */
259 | return tok;
260 | case CCOMMENT:
261 | case CPPCOMMENT:
262 | case WHITESPACE:
263 | break;
264 | default:
265 | /* XXX Check white, if required. */
266 | if (white)
267 | warning(tok.getLine(), tok.getColumn(),
268 | "Unexpected nonwhite token");
269 | break;
270 | }
271 | }
272 | }
273 |
274 | protected void error(int line, int column, String msg)
275 | throws LexerException {
276 | if (listener != null)
277 | listener.handleError(this, line, column, msg);
278 | else
279 | throw new LexerException("Error at " + line + ":" + column + ": " + msg);
280 | }
281 |
282 | protected void warning(int line, int column, String msg)
283 | throws LexerException {
284 | if (werror)
285 | error(line, column, msg);
286 | else if (listener != null)
287 | listener.handleWarning(this, line, column, msg);
288 | else
289 | throw new LexerException("Warning at " + line + ":" + column + ": " + msg);
290 | }
291 |
292 | public void close()
293 | throws IOException {
294 | }
295 |
296 | }
297 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/SourceIterator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.IOException;
20 | import java.util.Iterator;
21 | import java.util.NoSuchElementException;
22 | import javax.annotation.Nonnull;
23 | import static org.anarres.cpp.Token.EOF;
24 |
25 | /**
26 | * An Iterator for {@link Source Sources},
27 | * returning {@link Token Tokens}.
28 | */
29 | public class SourceIterator implements Iterator {
30 |
31 | private final Source source;
32 | private Token tok;
33 |
34 | public SourceIterator(@Nonnull Source s) {
35 | this.source = s;
36 | this.tok = null;
37 | }
38 |
39 | /**
40 | * Rethrows IOException inside IllegalStateException.
41 | */
42 | private void advance() {
43 | try {
44 | if (tok == null)
45 | tok = source.token();
46 | } catch (LexerException e) {
47 | throw new IllegalStateException(e);
48 | } catch (IOException e) {
49 | throw new IllegalStateException(e);
50 | }
51 | }
52 |
53 | /**
54 | * Returns true if the enclosed Source has more tokens.
55 | *
56 | * The EOF token is never returned by the iterator.
57 | * @throws IllegalStateException if the Source
58 | * throws a LexerException or IOException
59 | */
60 | @Override
61 | public boolean hasNext() {
62 | advance();
63 | return tok.getType() != EOF;
64 | }
65 |
66 | /**
67 | * Returns the next token from the enclosed Source.
68 | *
69 | * The EOF token is never returned by the iterator.
70 | * @throws IllegalStateException if the Source
71 | * throws a LexerException or IOException
72 | */
73 | @Override
74 | public Token next() {
75 | if (!hasNext())
76 | throw new NoSuchElementException();
77 | Token t = this.tok;
78 | this.tok = null;
79 | return t;
80 | }
81 |
82 | /**
83 | * Not supported.
84 | *
85 | * @throws UnsupportedOperationException unconditionally.
86 | */
87 | @Override
88 | public void remove() {
89 | throw new UnsupportedOperationException();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/State.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | /* pp */ class State {
20 |
21 | boolean parent;
22 | boolean active;
23 | boolean sawElse;
24 |
25 | /* pp */ State() {
26 | this.parent = true;
27 | this.active = true;
28 | this.sawElse = false;
29 | }
30 |
31 | /* pp */ State(State parent) {
32 | this.parent = parent.isParentActive() && parent.isActive();
33 | this.active = true;
34 | this.sawElse = false;
35 | }
36 |
37 | /* Required for #elif */
38 | /* pp */ void setParentActive(boolean b) {
39 | this.parent = b;
40 | }
41 |
42 | /* pp */ boolean isParentActive() {
43 | return parent;
44 | }
45 |
46 | /* pp */ void setActive(boolean b) {
47 | this.active = b;
48 | }
49 |
50 | /* pp */ boolean isActive() {
51 | return active;
52 | }
53 |
54 | /* pp */ void setSawElse() {
55 | sawElse = true;
56 | }
57 |
58 | /* pp */ boolean sawElse() {
59 | return sawElse;
60 | }
61 |
62 | @Override
63 | public String toString() {
64 | return "parent=" + parent
65 | + ", active=" + active
66 | + ", sawelse=" + sawElse;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/StringLexerSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.StringReader;
20 |
21 | /**
22 | * A Source for lexing a String.
23 | *
24 | * This class is used by token pasting, but can be used by user
25 | * code.
26 | */
27 | public class StringLexerSource extends LexerSource {
28 |
29 | /**
30 | * Creates a new Source for lexing the given String.
31 | *
32 | * @param string The input string to lex.
33 | * @param ppvalid true if preprocessor directives are to be
34 | * honoured within the string.
35 | */
36 | public StringLexerSource(String string, boolean ppvalid) {
37 | super(new StringReader(string), ppvalid);
38 | }
39 |
40 | /**
41 | * Creates a new Source for lexing the given String.
42 | *
43 | * Equivalent to calling new StringLexerSource(string, false)
.
44 | *
45 | * By default, preprocessor directives are not honoured within
46 | * the string.
47 | *
48 | * @param string The input string to lex.
49 | */
50 | public StringLexerSource(String string) {
51 | this(string, false);
52 | }
53 |
54 | @Override
55 | public String toString() {
56 | return "string literal";
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/Token.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import javax.annotation.CheckForNull;
20 | import javax.annotation.Nonnull;
21 |
22 | /**
23 | * A Preprocessor token.
24 | *
25 | * @see Preprocessor
26 | */
27 | public final class Token {
28 |
29 | // public static final int EOF = -1;
30 | private final int type;
31 | private int line;
32 | private int column;
33 | private final Object value;
34 | private final String text;
35 |
36 | public Token(int type, int line, int column,
37 | String text, Object value) {
38 | this.type = type;
39 | this.line = line;
40 | this.column = column;
41 | this.text = text;
42 | this.value = value;
43 | }
44 |
45 | public Token(int type, int line, int column, String text) {
46 | this(type, line, column, text, null);
47 | }
48 |
49 | /* pp */ Token(int type, String text, Object value) {
50 | this(type, -1, -1, text, value);
51 | }
52 |
53 | /* pp */ Token(int type, String text) {
54 | this(type, text, null);
55 | }
56 |
57 | /* pp */ Token(int type) {
58 | this(type, TokenType.getTokenText(type));
59 | }
60 |
61 | /**
62 | * Returns the semantic type of this token.
63 | *
64 | * @return the semantic type of this token.
65 | * @see #getTokenName(int)
66 | */
67 | public int getType() {
68 | return type;
69 | }
70 |
71 | /* pp */ void setLocation(int line, int column) {
72 | this.line = line;
73 | this.column = column;
74 | }
75 |
76 | /**
77 | * Returns the line at which this token started.
78 | *
79 | * Lines are numbered from 1.
80 | *
81 | * @return the line at which this token started.
82 | * @see LexerSource#getLine()
83 | */
84 | // Not @Nonnegative - might not have been assigned?
85 | public int getLine() {
86 | return line;
87 | }
88 |
89 | /**
90 | * Returns the column at which this token started.
91 | *
92 | * Columns are numbered from 0.
93 | *
94 | * @return the column at which this token started.
95 | * @see LexerSource#getColumn()
96 | */
97 | // Not @Nonnegative - might not have been assigned?
98 | public int getColumn() {
99 | return column;
100 | }
101 |
102 | /**
103 | * Returns the original or generated text of this token.
104 | *
105 | * This is distinct from the semantic value of the token.
106 | *
107 | * @return the original or generated text of this token.
108 | * @see #getValue()
109 | */
110 | // Not @Nonnull - might not have been assigned?
111 | public String getText() {
112 | return text;
113 | }
114 |
115 | /**
116 | * Returns the semantic value of this token.
117 | *
118 | * For strings, this is the parsed String.
119 | * For integers, this is an Integer object.
120 | * For other token types, as appropriate.
121 | *
122 | * @return the semantic value of this token, or null.
123 | * @see #getText()
124 | */
125 | // @CheckForNull // Not useful to annotate, as we have usually checked the type before calling this.
126 | public Object getValue() {
127 | return value;
128 | }
129 |
130 | /**
131 | * Returns a description of this token, for debugging purposes.
132 | */
133 | @Override
134 | public String toString() {
135 | StringBuilder buf = new StringBuilder();
136 |
137 | buf.append('[').append(getTokenName(type));
138 | if (line != -1) {
139 | buf.append('@').append(line);
140 | if (column != -1)
141 | buf.append(',').append(column);
142 | }
143 | buf.append("]:");
144 | if (text != null)
145 | buf.append('"').append(text).append('"');
146 | else if (type > 3 && type < 256)
147 | buf.append((char) type);
148 | else
149 | buf.append('<').append(type).append('>');
150 | if (value != null)
151 | buf.append('=').append(value);
152 | return buf.toString();
153 | }
154 |
155 | /**
156 | * Returns the descriptive name of the given token type.
157 | *
158 | * This is mostly used for stringification and debugging.
159 | *
160 | * @param type The type constant from this class to name.
161 | * @return the descriptive name of the given token type.
162 | * @see Token#getType()
163 | */
164 | @Nonnull
165 | public static String getTokenName(int type) {
166 | return TokenType.getTokenName(type);
167 | }
168 |
169 | public static final int AND_EQ = 257;
170 | public static final int ARROW = 258;
171 | public static final int CHARACTER = 259;
172 | public static final int CCOMMENT = 260;
173 | public static final int CPPCOMMENT = 261;
174 | public static final int DEC = 262;
175 | public static final int DIV_EQ = 263;
176 | public static final int ELLIPSIS = 264;
177 | public static final int EOF = 265;
178 | public static final int EQ = 266;
179 | public static final int GE = 267;
180 | public static final int HASH = 268;
181 | public static final int HEADER = 269;
182 | public static final int IDENTIFIER = 270;
183 | public static final int INC = 271;
184 | public static final int NUMBER = 272;
185 | public static final int LAND = 273;
186 | public static final int LAND_EQ = 274;
187 | public static final int LE = 275;
188 | public static final int LITERAL = 276;
189 | public static final int LOR = 277;
190 | public static final int LOR_EQ = 278;
191 | public static final int LSH = 279;
192 | public static final int LSH_EQ = 280;
193 | public static final int MOD_EQ = 281;
194 | public static final int MULT_EQ = 282;
195 | public static final int NE = 283;
196 | public static final int NL = 284;
197 | public static final int OR_EQ = 285;
198 | public static final int PASTE = 286;
199 | public static final int PLUS_EQ = 287;
200 | public static final int RANGE = 288;
201 | public static final int RSH = 289;
202 | public static final int RSH_EQ = 290;
203 | public static final int SQSTRING = 291;
204 | public static final int STRING = 292;
205 | public static final int SUB_EQ = 293;
206 | public static final int WHITESPACE = 294;
207 | public static final int XOR_EQ = 295;
208 | public static final int M_ARG = 296;
209 | public static final int M_PASTE = 297;
210 | public static final int M_STRING = 298;
211 | public static final int P_LINE = 299;
212 | public static final int INVALID = 300;
213 |
214 | /** The position-less space token. */
215 | /* pp */ static final Token space = new Token(WHITESPACE, -1, -1, " ");
216 | }
217 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/TokenSnifferSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.IOException;
20 | import java.util.List;
21 | import static org.anarres.cpp.Token.EOF;
22 |
23 | @Deprecated
24 | /* pp */ class TokenSnifferSource extends Source {
25 |
26 | private final List target;
27 |
28 | /* pp */ TokenSnifferSource(List target) {
29 | this.target = target;
30 | }
31 |
32 | public Token token()
33 | throws IOException,
34 | LexerException {
35 | Token tok = getParent().token();
36 | if (tok.getType() != EOF)
37 | target.add(tok);
38 | return tok;
39 | }
40 |
41 | @Override
42 | public String toString() {
43 | return getParent().toString();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/TokenType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.anarres.cpp;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import javax.annotation.CheckForNull;
11 | import javax.annotation.Nonnegative;
12 | import javax.annotation.Nonnull;
13 | import static org.anarres.cpp.Token.*;
14 |
15 | /**
16 | *
17 | * @author shevek
18 | */
19 | /* pp */ class TokenType {
20 |
21 | private static final List TYPES = new ArrayList();
22 |
23 | private static void addTokenType(@Nonnegative int type, @Nonnull String name, @CheckForNull String text) {
24 | while (TYPES.size() <= type)
25 | TYPES.add(null);
26 | TYPES.set(type, new TokenType(name, text));
27 | }
28 |
29 | private static void addTokenType(@Nonnegative int type, @Nonnull String name) {
30 | addTokenType(type, name, null);
31 | }
32 |
33 | @CheckForNull
34 | public static TokenType getTokenType(@Nonnegative int type) {
35 | try {
36 | return TYPES.get(type);
37 | } catch (IndexOutOfBoundsException e) {
38 | return null;
39 | }
40 | }
41 |
42 | @Nonnull
43 | public static String getTokenName(@Nonnegative int type) {
44 | if (type < 0)
45 | return "Invalid" + type;
46 | TokenType tokenType = getTokenType(type);
47 | if (tokenType == null)
48 | return "Unknown" + type;
49 | return tokenType.getName();
50 | }
51 |
52 | @CheckForNull
53 | public static String getTokenText(@Nonnegative int type) {
54 | TokenType tokenType = getTokenType(type);
55 | if (tokenType == null)
56 | return null;
57 | return tokenType.getText();
58 | }
59 |
60 | static {
61 | for (int i = 0; i < 255; i++) {
62 | String text = String.valueOf((char) i);
63 | addTokenType(i, text, text);
64 | }
65 | addTokenType(AND_EQ, "AND_EQ", "&=");
66 | addTokenType(ARROW, "ARROW", "->");
67 | addTokenType(CHARACTER, "CHARACTER");
68 | addTokenType(CCOMMENT, "CCOMMENT");
69 | addTokenType(CPPCOMMENT, "CPPCOMMENT");
70 | addTokenType(DEC, "DEC", "--");
71 | addTokenType(DIV_EQ, "DIV_EQ", "/=");
72 | addTokenType(ELLIPSIS, "ELLIPSIS", "...");
73 | addTokenType(EOF, "EOF");
74 | addTokenType(EQ, "EQ", "==");
75 | addTokenType(GE, "GE", ">=");
76 | addTokenType(HASH, "HASH", "#");
77 | addTokenType(HEADER, "HEADER");
78 | addTokenType(IDENTIFIER, "IDENTIFIER");
79 | addTokenType(INC, "INC", "++");
80 | addTokenType(NUMBER, "NUMBER");
81 | addTokenType(LAND, "LAND", "&&");
82 | addTokenType(LAND_EQ, "LAND_EQ", "&&=");
83 | addTokenType(LE, "LE", "<=");
84 | addTokenType(LITERAL, "LITERAL");
85 | addTokenType(LOR, "LOR", "||");
86 | addTokenType(LOR_EQ, "LOR_EQ", "||=");
87 | addTokenType(LSH, "LSH", "<<");
88 | addTokenType(LSH_EQ, "LSH_EQ", "<<=");
89 | addTokenType(MOD_EQ, "MOD_EQ", "%=");
90 | addTokenType(MULT_EQ, "MULT_EQ", "*=");
91 | addTokenType(NE, "NE", "!=");
92 | addTokenType(NL, "NL");
93 | addTokenType(OR_EQ, "OR_EQ", "|=");
94 | addTokenType(PASTE, "PASTE", "##");
95 | addTokenType(PLUS_EQ, "PLUS_EQ", "+=");
96 | addTokenType(RANGE, "RANGE", "..");
97 | addTokenType(RSH, "RSH", ">>");
98 | addTokenType(RSH_EQ, "RSH_EQ", ">>=");
99 | addTokenType(SQSTRING, "SQSTRING");
100 | addTokenType(STRING, "STRING");
101 | addTokenType(SUB_EQ, "SUB_EQ", "-=");
102 | addTokenType(WHITESPACE, "WHITESPACE");
103 | addTokenType(XOR_EQ, "XOR_EQ", "^=");
104 | addTokenType(M_ARG, "M_ARG");
105 | addTokenType(M_PASTE, "M_PASTE");
106 | addTokenType(M_STRING, "M_STRING");
107 | addTokenType(P_LINE, "P_LINE");
108 | addTokenType(INVALID, "INVALID");
109 | }
110 |
111 | private final String name;
112 | private final String text;
113 |
114 | /* pp */ TokenType(@Nonnull String name, @CheckForNull String text) {
115 | this.name = name;
116 | this.text = text;
117 | }
118 |
119 | @Nonnull
120 | public String getName() {
121 | return name;
122 | }
123 |
124 | @CheckForNull
125 | public String getText() {
126 | return text;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/VirtualFile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import java.io.IOException;
20 | import javax.annotation.CheckForNull;
21 | import javax.annotation.Nonnull;
22 |
23 | /**
24 | * An extremely lightweight virtual file interface.
25 | */
26 | public interface VirtualFile {
27 |
28 | // public String getParent();
29 | public boolean isFile();
30 |
31 | @Nonnull
32 | public String getPath();
33 |
34 | @Nonnull
35 | public String getName();
36 |
37 | @CheckForNull
38 | public VirtualFile getParentFile();
39 |
40 | @Nonnull
41 | public VirtualFile getChildFile(String name);
42 |
43 | @Nonnull
44 | public Source getSource() throws IOException;
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/VirtualFileSystem.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | import javax.annotation.Nonnull;
20 |
21 | /**
22 | * An extremely lightweight virtual file system interface.
23 | */
24 | public interface VirtualFileSystem {
25 |
26 | @Nonnull
27 | public VirtualFile getFile(@Nonnull String path);
28 |
29 | @Nonnull
30 | public VirtualFile getFile(@Nonnull String dir, @Nonnull String name);
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/anarres/cpp/Warning.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2015, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 | package org.anarres.cpp;
18 |
19 | /**
20 | * Warning classes which may optionally be emitted by the Preprocessor.
21 | */
22 | public enum Warning {
23 |
24 | TRIGRAPHS,
25 | // TRADITIONAL,
26 | IMPORT,
27 | UNDEF,
28 | UNUSED_MACROS,
29 | ENDIF_LABELS,
30 | ERROR,
31 | // SYSTEM_HEADERS
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/velocity/org/anarres/cpp/Version.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Anarres C Preprocessor
3 | * Copyright (c) 2007-2008, Shevek
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 | * or implied. See the License for the specific language governing
15 | * permissions and limitations under the License.
16 | */
17 |
18 | package org.anarres.cpp;
19 |
20 | import javax.annotation.CheckForNull;
21 | import javax.annotation.Nonnull;
22 |
23 | /**
24 | * System version metadata for Anarres Java C Preprocessor ${version}.
25 | *
26 | * This class contains a main() and may be run to print the version.
27 | */
28 | public class Version {
29 |
30 | /* Don't instantiate me */
31 | private Version() {
32 | }
33 |
34 | private static final String VERSION = "${version}";
35 |
36 | private static final int major;
37 | private static final int minor;
38 | private static final int patch;
39 | private static final String modifier;
40 |
41 | static {
42 | String[] tmp = VERSION.split("[\\.-]");
43 | major = Integer.parseInt(tmp[0]);
44 | minor = Integer.parseInt(tmp[1]);
45 | patch = Integer.parseInt(tmp[2]);
46 | modifier = (tmp.length > 3) ? tmp[3] : null;
47 | }
48 |
49 | @Nonnull
50 | public static String getVersion() {
51 | return VERSION;
52 | }
53 |
54 | public static int getMajor() {
55 | return major;
56 | }
57 |
58 | public static int getMinor() {
59 | return minor;
60 | }
61 |
62 | public static int getPatch() {
63 | return patch;
64 | }
65 |
66 | @CheckForNull
67 | public static String getModifier() {
68 | return modifier;
69 | }
70 |
71 | public static boolean isSnapshot() {
72 | return "SNAPSHOT".equalsIgnoreCase(getModifier());
73 | }
74 |
75 | public static void main(String[] args) {
76 | System.out.println("Version " + VERSION);
77 | System.out.println("getVersion() returns " + getVersion());
78 | System.out.println("getMajor() returns " + getMajor());
79 | System.out.println("getMinor() returns " + getMinor());
80 | System.out.println("getPatch() returns " + getPatch());
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/scripts/jcpp:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | CPP_JAR=anarres-cpp.jar
4 |
5 | if [ -n "$CPP_ROOT" ] ; then
6 | CPP_ROOT="$CPP_ROOT"
7 | elif [ -f lib/$CPP_JAR ] ; then
8 | CPP_ROOT="."
9 | elif [ -f ../lib/$CPP_JAR ] ; then
10 | CPP_ROOT=".."
11 | elif [ -f $(dirname $0)/lib/$CPP_JAR ] ; then
12 | CPP_ROOT=$(dirname $0)
13 | else
14 | echo "Could not find $CPP_JAR. Please set CPP_ROOT."
15 | exit 1
16 | fi
17 |
18 | if [ -z "$CPP_LIB" ] ; then
19 | CPP_LIB=$CPP_ROOT/lib
20 | fi
21 |
22 | if [ -z "$CPP_CLASSPATH" ] ; then
23 | CPP_CLASSPATH="$(ls $CPP_LIB/*.jar | tr '\n' ':')"
24 | fi
25 |
26 | if [ -z "$CPP_MAINCLASS" ] ; then
27 | CPP_MAINCLASS=org.anarres.cpp.Main
28 | fi
29 |
30 | CPP_JFLAGS="-Xmx128M"
31 |
32 | exec java $CPP_JFLAGS -cp "$CPP_CLASSPATH" $CPP_MAINCLASS "$@"
33 |
--------------------------------------------------------------------------------
/src/scripts/release.sh:
--------------------------------------------------------------------------------
1 | rsync -avP build/dist/anarres-cpp-*.tar.gz shevek@pink.anarres.org:public_html/projects/jcpp/
2 | rsync -avP --exclude=.svn --exclude=autohandler build/javadoc shevek@pink.anarres.org:public_html/projects/jcpp/
3 | cp build/tar/lib/anarres-cpp.jar /home/shevek/java/iengine/trunk/lib/runtime/jcpp/
4 | cp build/tar/lib/anarres-cpp.jar /home/shevek/java/karma/trunk/lib/dp/
5 | cp build/tar/lib/anarres-cpp.jar /home/shevek/java/dp/trunk/lib/runtime/cpp/
6 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/BuildMetadataTest.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | import com.google.common.base.Charsets;
4 | import com.google.common.io.Resources;
5 | import java.net.URL;
6 | import org.junit.Test;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | /**
11 | *
12 | * @author shevek
13 | */
14 | public class BuildMetadataTest {
15 |
16 | private static final Logger LOG = LoggerFactory.getLogger(BuildMetadataTest.class);
17 |
18 | @Test
19 | public void testProperties() throws Exception {
20 | URL url = Resources.getResource("META-INF/jcpp.properties");
21 | String text = Resources.asCharSource(url, Charsets.ISO_8859_1).read();
22 | LOG.info("Metadata is " + text);
23 | }
24 |
25 | @Test
26 | public void testMetadata() throws Exception {
27 | BuildMetadata metadata = BuildMetadata.getInstance();
28 | LOG.info("Version is " + metadata.getVersion());
29 | LOG.info("BuildDate is " + metadata.getBuildDate());
30 | LOG.info("ChangeId is " + metadata.getChangeId());
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/CppReaderTest.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.StringReader;
5 | import java.util.Collections;
6 | import javax.annotation.Nonnull;
7 | import org.junit.Test;
8 | import static org.junit.Assert.assertEquals;
9 |
10 | public class CppReaderTest {
11 |
12 | public static String testCppReader(@Nonnull String in, Feature... f)
13 | throws Exception {
14 | System.out.println("Testing " + in);
15 | StringReader r = new StringReader(in);
16 | CppReader p = new CppReader(r);
17 | p.getPreprocessor().setSystemIncludePath(
18 | Collections.singletonList("src/test/resources")
19 | );
20 | p.getPreprocessor().addFeatures(f);
21 | BufferedReader b = new BufferedReader(p);
22 |
23 | StringBuilder out = new StringBuilder();
24 | String line;
25 | while ((line = b.readLine()) != null) {
26 | System.out.println(" >> " + line);
27 | out.append(line).append("\n");
28 | }
29 |
30 | return out.toString();
31 | }
32 |
33 | @Test
34 | public void testCppReader()
35 | throws Exception {
36 | testCppReader("#include \n", Feature.LINEMARKERS);
37 | }
38 |
39 | @Test
40 | public void testVarargs()
41 | throws Exception {
42 | // The newlines are irrelevant, We want exactly one "foo"
43 | testCppReader("#include \n");
44 | }
45 |
46 | @Test
47 | public void testPragmaOnce()
48 | throws Exception {
49 | // The newlines are irrelevant, We want exactly one "foo"
50 | String out = testCppReader("#include \n", Feature.PRAGMA_ONCE);
51 | assertEquals("foo", out.trim());
52 | }
53 |
54 | @Test
55 | public void testPragmaOnceWithMarkers()
56 | throws Exception {
57 | // The newlines are irrelevant, We want exactly one "foo"
58 | testCppReader("#include \n", Feature.PRAGMA_ONCE, Feature.LINEMARKERS);
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/ErrorTest.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | import java.io.IOException;
4 | import org.junit.Test;
5 | import static org.anarres.cpp.Token.*;
6 | import static org.junit.Assert.*;
7 |
8 | public class ErrorTest {
9 |
10 | private boolean testError(Preprocessor p)
11 | throws LexerException,
12 | IOException {
13 | for (;;) {
14 | Token tok = p.token();
15 | if (tok.getType() == EOF)
16 | break;
17 | if (tok.getType() == INVALID)
18 | return true;
19 | }
20 | return false;
21 | }
22 |
23 | private void testError(String input) throws Exception {
24 | StringLexerSource sl;
25 | DefaultPreprocessorListener pl;
26 | Preprocessor p;
27 |
28 | /* Without a PreprocessorListener, throws an exception. */
29 | sl = new StringLexerSource(input, true);
30 | p = new Preprocessor();
31 | p.addFeature(Feature.CSYNTAX);
32 | p.addInput(sl);
33 | try {
34 | assertTrue(testError(p));
35 | fail("Lexing unexpectedly succeeded without listener.");
36 | } catch (LexerException e) {
37 | /* required */
38 | }
39 |
40 | /* With a PreprocessorListener, records the error. */
41 | sl = new StringLexerSource(input, true);
42 | p = new Preprocessor();
43 | p.addFeature(Feature.CSYNTAX);
44 | p.addInput(sl);
45 | pl = new DefaultPreprocessorListener();
46 | p.setListener(pl);
47 | assertNotNull("CPP has listener", p.getListener());
48 | assertTrue(testError(p));
49 | assertTrue("Listener has errors", pl.getErrors() > 0);
50 |
51 | /* Without CSYNTAX, works happily. */
52 | sl = new StringLexerSource(input, true);
53 | p = new Preprocessor();
54 | p.addInput(sl);
55 | assertTrue(testError(p));
56 | }
57 |
58 | @Test
59 | public void testErrors() throws Exception {
60 | testError("\"");
61 | testError("'");
62 | // testError("''");
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/IncludeAbsoluteTest.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | import com.google.common.io.CharStreams;
4 | import java.io.BufferedReader;
5 | import java.io.File;
6 | import java.io.Reader;
7 | import org.junit.Test;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | *
14 | * @author shevek
15 | */
16 | public class IncludeAbsoluteTest {
17 |
18 | private static final Logger LOG = LoggerFactory.getLogger(IncludeAbsoluteTest.class);
19 |
20 | @Test
21 | public void testAbsoluteInclude() throws Exception {
22 | File file = new File("build/resources/test/absolute.h");
23 | assertTrue(file.exists());
24 |
25 | String input = "#include <" + file.getAbsolutePath() + ">\n";
26 | LOG.info("Input: " + input);
27 | Preprocessor pp = new Preprocessor();
28 | pp.addInput(new StringLexerSource(input, true));
29 | Reader r = new CppReader(pp);
30 | String output = CharStreams.toString(r);
31 | r.close();
32 | LOG.info("Output: " + output);
33 | assertTrue(output.contains("absolute-result"));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/JavaFileSystemTest.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | import java.io.FileNotFoundException;
4 | import org.junit.Test;
5 | import static org.junit.Assert.assertFalse;
6 | import static org.junit.Assert.assertTrue;
7 |
8 | public class JavaFileSystemTest {
9 |
10 | @Test
11 | public void testJavaFileSystem() throws Exception {
12 | JavaFileSystem fs = new JavaFileSystem();
13 | VirtualFile f;
14 |
15 | /* Anyone who has this file on their Unix box is messed up. */
16 | f = fs.getFile("/foo/bar baz");
17 | try {
18 | f.getSource(); /* drop on floor */
19 |
20 | assertTrue("Got a source for a non-file", f.isFile());
21 | } catch (FileNotFoundException e) {
22 | assertFalse("Got no source for a file", f.isFile());
23 | }
24 |
25 | /* We hope we have this. */
26 | f = fs.getFile("/usr/include/stdio.h");
27 | try {
28 | f.getSource(); /* drop on floor */
29 |
30 | System.out.println("Opened stdio.h");
31 | assertTrue("Got a source for a non-file", f.isFile());
32 | } catch (FileNotFoundException e) {
33 | System.out.println("Failed to open stdio.h");
34 | assertFalse("Got no source for a file", f.isFile());
35 | }
36 |
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/JoinReaderTest.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | import java.io.StringReader;
4 | import org.junit.Test;
5 | import static org.junit.Assert.assertEquals;
6 |
7 | public class JoinReaderTest {
8 |
9 | private void testJoinReader(String in, String out, boolean tg)
10 | throws Exception {
11 | System.out.println("Testing " + in + " => " + out);
12 | StringReader r = new StringReader(in);
13 | JoinReader j = new JoinReader(r, tg);
14 |
15 | for (int i = 0; i < out.length(); i++) {
16 | int c = j.read();
17 | System.out.println("At offset " + i + ": " + (char) c);
18 | assertEquals(out.charAt(i), c);
19 | }
20 | assertEquals(-1, j.read());
21 | assertEquals(-1, j.read());
22 | }
23 |
24 | private void testJoinReader(String in, String out)
25 | throws Exception {
26 | testJoinReader(in, out, true);
27 | testJoinReader(in, out, false);
28 | }
29 |
30 | @Test
31 | public void testJoinReader()
32 | throws Exception {
33 | testJoinReader("ab", "ab");
34 | testJoinReader("a\\b", "a\\b");
35 | testJoinReader("a\nb", "a\nb");
36 | testJoinReader("a\\\nb", "ab\n");
37 | testJoinReader("foo??(bar", "foo[bar", true);
38 | testJoinReader("foo??/\nbar", "foobar\n", true);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/LexerSourceTest.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | import java.util.Arrays;
4 | import org.junit.Test;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import static org.anarres.cpp.PreprocessorTest.assertType;
8 | import static org.anarres.cpp.Token.*;
9 | import static org.junit.Assert.*;
10 |
11 | public class LexerSourceTest {
12 |
13 | private static final Logger LOG = LoggerFactory.getLogger(LexerSourceTest.class);
14 |
15 | public static void testLexerSource(String in, boolean textmatch, int... out)
16 | throws Exception {
17 | LOG.info("Testing '" + in + "' => "
18 | + Arrays.toString(out));
19 | StringLexerSource s = new StringLexerSource(in);
20 |
21 | StringBuilder buf = new StringBuilder();
22 | for (int i = 0; i < out.length; i++) {
23 | Token tok = s.token();
24 | LOG.info("Token is " + tok);
25 | assertType(out[i], tok);
26 | // assertEquals(col, tok.getColumn());
27 | buf.append(tok.getText());
28 | }
29 |
30 | Token tok = s.token();
31 | LOG.info("Token is " + tok);
32 | assertType(EOF, tok);
33 |
34 | if (textmatch)
35 | assertEquals(in, buf.toString());
36 | }
37 |
38 | @Test
39 | public void testLexerSource()
40 | throws Exception {
41 |
42 | testLexerSource("int a = 5;", true,
43 | IDENTIFIER, WHITESPACE, IDENTIFIER, WHITESPACE,
44 | '=', WHITESPACE, NUMBER, ';'
45 | );
46 |
47 | // \n is WHITESPACE because ppvalid = false
48 | testLexerSource("# # \r\n\n\r \rfoo", true,
49 | HASH, WHITESPACE, '#', WHITESPACE, IDENTIFIER
50 | );
51 |
52 | // No match - trigraphs
53 | testLexerSource("%:%:", false, PASTE);
54 | testLexerSource("%:?", false, '#', '?');
55 | testLexerSource("%:%=", false, '#', MOD_EQ);
56 |
57 | testLexerSource("0x1234ffdUL 0765I", true,
58 | NUMBER, WHITESPACE, NUMBER);
59 |
60 | testLexerSource("+= -= *= /= %= <= >= >>= <<= &= |= ^= x", true,
61 | PLUS_EQ, WHITESPACE,
62 | SUB_EQ, WHITESPACE,
63 | MULT_EQ, WHITESPACE,
64 | DIV_EQ, WHITESPACE,
65 | MOD_EQ, WHITESPACE,
66 | LE, WHITESPACE,
67 | GE, WHITESPACE,
68 | RSH_EQ, WHITESPACE,
69 | LSH_EQ, WHITESPACE,
70 | AND_EQ, WHITESPACE,
71 | OR_EQ, WHITESPACE,
72 | XOR_EQ, WHITESPACE,
73 | IDENTIFIER);
74 |
75 | testLexerSource("/**/", true, CCOMMENT);
76 | testLexerSource("/* /**/ */", true, CCOMMENT, WHITESPACE, '*', '/');
77 | testLexerSource("/** ** **/", true, CCOMMENT);
78 | testLexerSource("//* ** **/", true, CPPCOMMENT);
79 | testLexerSource("'\\r' '\\xf' '\\xff' 'x' 'aa' ''", true,
80 | CHARACTER, WHITESPACE,
81 | CHARACTER, WHITESPACE,
82 | CHARACTER, WHITESPACE,
83 | CHARACTER, WHITESPACE,
84 | SQSTRING, WHITESPACE,
85 | SQSTRING);
86 |
87 | if (false) // Actually, I think this is illegal.
88 | testLexerSource("1i1I1l1L1ui1ul", true,
89 | NUMBER, NUMBER,
90 | NUMBER, NUMBER,
91 | NUMBER, NUMBER);
92 |
93 | testLexerSource("'' 'x' 'xx'", true,
94 | SQSTRING, WHITESPACE, CHARACTER, WHITESPACE, SQSTRING);
95 | }
96 |
97 | @Test
98 | public void testNumbers() throws Exception {
99 | testLexerSource("0", true, NUMBER);
100 | testLexerSource("045", true, NUMBER);
101 | testLexerSource("45", true, NUMBER);
102 | testLexerSource("0.45", true, NUMBER);
103 | testLexerSource("1.45", true, NUMBER);
104 | testLexerSource("1e6", true, NUMBER);
105 | testLexerSource("1.45e6", true, NUMBER);
106 | testLexerSource(".45e6", true, NUMBER);
107 | testLexerSource("-6", true, '-', NUMBER);
108 | }
109 |
110 | @Test
111 | public void testNumbersSuffix() throws Exception {
112 | testLexerSource("6f", true, NUMBER);
113 | testLexerSource("6d", true, NUMBER);
114 | testLexerSource("6l", true, NUMBER);
115 | testLexerSource("6ll", true, NUMBER);
116 | testLexerSource("6ul", true, NUMBER);
117 | testLexerSource("6ull", true, NUMBER);
118 | testLexerSource("6e3f", true, NUMBER);
119 | testLexerSource("6e3d", true, NUMBER);
120 | testLexerSource("6e3l", true, NUMBER);
121 | testLexerSource("6e3ll", true, NUMBER);
122 | testLexerSource("6e3ul", true, NUMBER);
123 | testLexerSource("6e3ull", true, NUMBER);
124 | }
125 |
126 | @Test
127 | public void testNumbersInvalid() throws Exception {
128 | // testLexerSource("0x foo", true, INVALID, WHITESPACE, IDENTIFIER); // FAIL
129 | testLexerSource("6x foo", true, INVALID, WHITESPACE, IDENTIFIER);
130 | testLexerSource("6g foo", true, INVALID, WHITESPACE, IDENTIFIER);
131 | testLexerSource("6xsd foo", true, INVALID, WHITESPACE, IDENTIFIER);
132 | testLexerSource("6gsd foo", true, INVALID, WHITESPACE, IDENTIFIER);
133 | }
134 |
135 | @Test
136 | public void testUnterminatedComment() throws Exception {
137 | testLexerSource("5 /*", false, NUMBER, WHITESPACE, INVALID); // Bug #15
138 | testLexerSource("5 //", false, NUMBER, WHITESPACE, CPPCOMMENT);
139 | }
140 |
141 | @Test
142 | public void testUnicode()throws Exception{
143 | testLexerSource("foo \u2018bar\u2019 baz", true, IDENTIFIER, WHITESPACE, 8216, IDENTIFIER, 8217, WHITESPACE, IDENTIFIER);
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/MainTest.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | import org.junit.Test;
4 |
5 | public class MainTest {
6 |
7 | @Test
8 | public void testMain() throws Exception {
9 | Main.main(new String[]{"--version"});
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/NumericValueTest.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | import java.io.IOException;
4 | import org.junit.Test;
5 | import static org.anarres.cpp.Token.*;
6 | import static org.junit.Assert.*;
7 |
8 | /**
9 | *
10 | * @author shevek
11 | */
12 | public class NumericValueTest {
13 |
14 | private Token testNumericValue(String in) throws IOException, LexerException {
15 | StringLexerSource s = new StringLexerSource(in);
16 |
17 | Token tok = s.token();
18 | System.out.println("Token is " + tok);
19 | assertEquals(NUMBER, tok.getType());
20 |
21 | Token eof = s.token();
22 | assertEquals("Didn't get EOF, but " + tok, EOF, eof.getType());
23 |
24 | return tok;
25 | }
26 |
27 | private void testNumericValue(String in, double out) throws IOException, LexerException {
28 | System.out.println("Testing '" + in + "' -> " + out);
29 | Token tok = testNumericValue(in);
30 | assertEquals(in, tok.getText());
31 | NumericValue value = (NumericValue) tok.getValue();
32 | assertEquals("Double mismatch", out, value.doubleValue(), 0.01d);
33 | assertEquals("Float mismatch", (float) out, value.floatValue(), 0.01f);
34 | assertEquals("Long mismatch", (long) out, value.longValue());
35 | assertEquals("Integer mismatch", (int) out, value.intValue());
36 | }
37 |
38 | @Test
39 | public void testNumericValue() throws Exception {
40 |
41 | // Zero
42 | testNumericValue("0", 0);
43 |
44 | // Decimal
45 | testNumericValue("1", 1);
46 | testNumericValue("1L", 1);
47 | testNumericValue("12", 12);
48 | testNumericValue("12L", 12);
49 |
50 | // Hex
51 | testNumericValue("0xf", 0xf);
52 | testNumericValue("0xfL", 0xf);
53 | testNumericValue("0x12", 0x12);
54 | testNumericValue("0x12L", 0x12);
55 |
56 | // Negative
57 | // testNumericValue("-0", 0);
58 | // testNumericValue("-1", -1);
59 | // Negative hex
60 | // testNumericValue("-0x56", -0x56);
61 | // testNumericValue("-0x102", -0x102);
62 | // Octal and negative octal
63 | testNumericValue("0673", Integer.parseInt("673", 8));
64 | // testNumericValue("-0673", Integer.parseInt("-673", 8));
65 |
66 | // Floating point
67 | testNumericValue(".0", 0);
68 | testNumericValue(".00", 0);
69 | testNumericValue("0.", 0);
70 | testNumericValue("0.0", 0);
71 | testNumericValue("00.0", 0);
72 | testNumericValue("00.", 0);
73 |
74 | // Sign on exponents
75 | testNumericValue("1e1", 1e1);
76 | // testNumericValue("-1e1", -1e1);
77 | testNumericValue("1e-1", 1e-1);
78 | testNumericValue("1e+1", 1e+1);
79 |
80 | // Hex numbers with decimal exponents
81 | testNumericValue("0x12e3", 0x12e3);
82 | testNumericValue("0x12p3", 0x12p3);
83 |
84 | // Octal numbers with decimal exponents
85 | testNumericValue("012e3", 012e3); // Fails
86 | testNumericValue("067e4", 067e4); // Fails
87 |
88 | // Issues a warning.
89 | try {
90 | testNumericValue("097", 97);
91 | fail("No warning.");
92 | } catch (LexerException e) {
93 | }
94 |
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/PragmaTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.anarres.cpp;
7 |
8 | import com.google.common.base.Charsets;
9 | import com.google.common.io.CharSource;
10 | import com.google.common.io.CharStreams;
11 | import com.google.common.io.Files;
12 | import java.io.File;
13 | import org.junit.Test;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 | import static org.junit.Assert.*;
17 |
18 | /**
19 | *
20 | * @author shevek
21 | */
22 | public class PragmaTest {
23 |
24 | private static final Logger LOG = LoggerFactory.getLogger(PragmaTest.class);
25 |
26 | @Test
27 | public void testPragma() throws Exception {
28 | File file = new File("build/resources/test/pragma.c");
29 | assertTrue(file.exists());
30 |
31 | CharSource source = Files.asCharSource(file, Charsets.UTF_8);
32 | CppReader r = new CppReader(source.openBufferedStream());
33 | r.getPreprocessor().setListener(new DefaultPreprocessorListener());
34 | String output = CharStreams.toString(r);
35 | r.close();
36 | LOG.info("Output: " + output);
37 | // assertTrue(output.contains("absolute-result"));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/PreprocessorTest.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | import java.io.InputStreamReader;
4 | import java.io.OutputStreamWriter;
5 | import java.io.PipedInputStream;
6 | import java.io.PipedOutputStream;
7 | import org.junit.Before;
8 | import org.junit.Test;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import static org.anarres.cpp.Token.*;
12 | import static org.junit.Assert.*;
13 |
14 | public class PreprocessorTest {
15 |
16 | private static final Logger LOG = LoggerFactory.getLogger(PreprocessorTest.class);
17 |
18 | private OutputStreamWriter writer;
19 | private Preprocessor p;
20 |
21 | @Before
22 | public void setUp() throws Exception {
23 | final PipedOutputStream po = new PipedOutputStream();
24 | writer = new OutputStreamWriter(po);
25 |
26 | p = new Preprocessor();
27 | p.addInput(
28 | new LexerSource(
29 | new InputStreamReader(
30 | new PipedInputStream(po)
31 | ),
32 | true
33 | )
34 | );
35 | }
36 |
37 | private static class I {
38 |
39 | private final String t;
40 |
41 | public I(String t) {
42 | this.t = t;
43 | }
44 |
45 | public String getText() {
46 | return t;
47 | }
48 |
49 | @Override
50 | public String toString() {
51 | return getText();
52 | }
53 | }
54 |
55 | private static I I(String t) {
56 | return new I(t);
57 | }
58 |
59 | /*
60 | * When writing tests in this file, remember the preprocessor
61 | * stashes NLs, so you won't see an immediate NL at the end of any
62 | * input line. You will see it right before the next nonblank on
63 | * the following input line.
64 | */
65 | @Test
66 | public void testPreprocessor() throws Exception {
67 | /* Magic macros */
68 | testInput("line = __LINE__\n",
69 | I("line"), WHITESPACE, '=', WHITESPACE, NUMBER
70 | /*, NL - all nls deferred so as not to block the reader */
71 | );
72 | testInput("file = __FILE__\n", NL, /* from before, etc */
73 | I("file"), WHITESPACE, '=', WHITESPACE, STRING
74 | );
75 |
76 | /* Simple definitions */
77 | testInput("#define A a /* a defined */\n", NL);
78 | testInput("#define B b /* b defined */\n", NL);
79 | testInput("#define C c /* c defined */\n", NL);
80 |
81 | /* Expansion of arguments */
82 | testInput("#define EXPAND(x) x\n", NL);
83 | testInput("EXPAND(a)\n", NL, I("a"));
84 | testInput("EXPAND(A)\n", NL, I("a"));
85 |
86 | /* Stringification */
87 | testInput("#define _STRINGIFY(x) #x\n", NL);
88 | testInput("_STRINGIFY(A)\n", NL, "A");
89 | testInput("#define STRINGIFY(x) _STRINGIFY(x)\n", NL);
90 | testInput("STRINGIFY(b)\n", NL, "b");
91 | testInput("STRINGIFY(A)\n", NL, "a");
92 |
93 | /* Concatenation */
94 | testInput("#define _CONCAT(x, y) x ## y\n", NL);
95 | testInput("_CONCAT(A, B)\n", NL, I("AB"));
96 | testInput("#define A_CONCAT done_a_concat\n", NL);
97 | testInput("_CONCAT(A, _CONCAT(B, C))\n", NL,
98 | I("done_a_concat"), '(', I("b"), ',', WHITESPACE, I("c"), ')'
99 | );
100 | testInput("#define CONCAT(x, y) _CONCAT(x, y)\n", NL);
101 | testInput("CONCAT(A, CONCAT(B, C))\n", NL, I("abc"));
102 | testInput("#define _CONCAT3(x, y, z) x ## y ## z\n", NL);
103 | testInput("_CONCAT3(a, b, c)\n", NL, I("abc"));
104 | testInput("_CONCAT3(A, B, C)\n", NL, I("ABC"));
105 | testInput("_CONCAT(test_, inline)\n", NL, I("test_inline"));
106 | testInput("_CONCAT(test_, \nnewline)\n", NL, I("test_newline"));
107 |
108 | /* Redefinitions, undefinitions. */
109 | testInput("#define two three\n", NL);
110 | testInput("one /* one */\n", NL, I("one"), WHITESPACE, CCOMMENT);
111 | testInput("#define one two\n", NL);
112 | testInput("one /* three */\n", NL, I("three"), WHITESPACE, CCOMMENT);
113 | testInput("#undef two\n", NL);
114 | testInput("#define two five\n", NL);
115 | testInput("one /* five */\n", NL, I("five"), WHITESPACE, CCOMMENT);
116 | testInput("#undef two\n", NL);
117 | testInput("one /* two */\n", NL, I("two"), WHITESPACE, CCOMMENT);
118 | testInput("#undef one\n", NL);
119 | testInput("#define one four\n", NL);
120 | testInput("one /* four */\n", NL, I("four"), WHITESPACE, CCOMMENT);
121 | testInput("#undef one\n", NL);
122 | testInput("#define one one\n", NL);
123 | testInput("one /* one */\n", NL, I("one"), WHITESPACE, CCOMMENT);
124 |
125 | /* Variadic macros. */
126 | testInput("#define var(x...) a x __VA_ARGS__ b\n", NL);
127 | testInput("var(e, f, g)\n", NL,
128 | I("a"), WHITESPACE,
129 | I("e"), ',', WHITESPACE,
130 | I("f"), ',', WHITESPACE,
131 | I("g"), WHITESPACE,
132 | I("__VA_ARGS__"), WHITESPACE, // __VA_ARGS__ is not expanded in this case.
133 | I("b")
134 | );
135 | /* Missing arguments are fine. */
136 | testInput("var()\n", NL,
137 | I("a"), WHITESPACE,
138 | /* No expansion for 'x'. */ WHITESPACE,
139 | I("__VA_ARGS__"), WHITESPACE,
140 | I("b")
141 | );
142 |
143 | /* Variadic macros with anonymous args. */
144 | testInput("#define var2(x, ...) a x __VA_ARGS__ e\n", NL);
145 | testInput("var2(b, c, d)\n", NL,
146 | I("a"), WHITESPACE,
147 | I("b"), WHITESPACE,
148 | I("c"), ',', WHITESPACE,
149 | I("d"), WHITESPACE,
150 | I("e")
151 | );
152 | /* Missing arguments are fine. */
153 | testInput("var2(b)\n", NL,
154 | I("a"), WHITESPACE,
155 | I("b"), WHITESPACE,
156 | /* No expansion for '__VA_ARGS__'. */ WHITESPACE,
157 | I("e")
158 | );
159 |
160 | testInput("#define var3(...) a __VA_ARGS__ d\n", NL);
161 | testInput("var3(b, c)\n", NL,
162 | I("a"), WHITESPACE,
163 | I("b"), ',', WHITESPACE,
164 | I("c"), WHITESPACE,
165 | I("d")
166 | );
167 | testInput("var3()\n", NL,
168 | I("a"), WHITESPACE,
169 | /* No expansion for '__VA_ARGS__'. */ WHITESPACE,
170 | I("d")
171 | );
172 |
173 | testInput("#define _Widen(x) L ## x\n", NL);
174 | testInput("#define Widen(x) _Widen(x)\n", NL);
175 | testInput("#define LStr(x) _Widen(#x)\n", NL);
176 | testInput("LStr(x);\n", NL, I("L"), "x", ';');
177 |
178 | testInput("'foo'\n", NL, SQSTRING);
179 | testInput("#if 1 ? 2 : 0\nTEXT\n#endif\n", NL, NL, I("TEXT"), NL);
180 | testInput("#if 1 ? 0 : 2\nTEXT\n#endif\n", NL, NL, NL);
181 | testInput("#if 0 ? 0 : 2\nTEXT\n#endif\n", NL, NL, I("TEXT"), NL);
182 | testInput("#if 0 ? 2 : 0\nTEXT\n#endif\n", NL, NL, NL);
183 |
184 | writer.close();
185 |
186 | Token t;
187 | do {
188 | t = p.token();
189 | LOG.warn("Remaining token " + t);
190 | } while (t.getType() != EOF);
191 | }
192 |
193 | @Test
194 | public void testPreprocessorUnterminated() throws Exception {
195 | testInput("#ifndef X\na\n#else\nb\n"); // Bug #16
196 |
197 | writer.close();
198 |
199 | Token t;
200 | do {
201 | t = p.token();
202 | LOG.warn("Remaining token " + t);
203 | } while (t.getType() != EOF);
204 | }
205 |
206 | public static void assertType(int type, Token t) {
207 | String typeExpect = TokenType.getTokenName(type);
208 | String typeActual = TokenType.getTokenName(t.getType());
209 | assertEquals("Expected " + typeExpect + " but got " + typeActual, type, t.getType());
210 | }
211 |
212 | private void testInput(String in, Object... out)
213 | throws Exception {
214 | LOG.info("Input: " + in);
215 | writer.write(in);
216 | writer.flush();
217 | for (Object v : out) {
218 | Token t = p.token();
219 | LOG.info(String.valueOf(t));
220 | if (v instanceof String) {
221 | if (t.getType() != STRING)
222 | fail("Expected STRING, but got " + t);
223 | assertEquals(v, t.getValue());
224 | } else if (v instanceof I) {
225 | if (t.getType() != IDENTIFIER)
226 | fail("Expected IDENTIFIER " + v + ", but got " + t);
227 | assertEquals(((I) v).getText(), t.getText());
228 | } else if (v instanceof Character) {
229 | assertType(((Character) v).charValue(), t);
230 | } else if (v instanceof Integer) {
231 | assertType(((Number) v).intValue(), t);
232 | } else {
233 | fail("Bad object " + v.getClass());
234 | }
235 | }
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/RegressionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.anarres.cpp;
7 |
8 | import com.google.common.base.Charsets;
9 | import com.google.common.io.CharStreams;
10 | import com.google.common.io.Files;
11 | import com.google.common.io.PatternFilenameFilter;
12 | import java.io.File;
13 | import java.io.StringReader;
14 | import java.util.ArrayList;
15 | import java.util.List;
16 | import org.junit.Test;
17 | import org.junit.runner.RunWith;
18 | import org.junit.runners.Parameterized;
19 | import org.slf4j.Logger;
20 | import org.slf4j.LoggerFactory;
21 | import static org.junit.Assert.assertEquals;
22 |
23 | /**
24 | *
25 | * @author shevek
26 | */
27 | @RunWith(Parameterized.class)
28 | public class RegressionTest {
29 |
30 | private static final Logger LOG = LoggerFactory.getLogger(RegressionTest.class);
31 |
32 | @Parameterized.Parameters(name = "{0}")
33 | public static List data() throws Exception {
34 | List out = new ArrayList();
35 |
36 | File dir = new File("build/resources/test/regression");
37 | for (File inFile : dir.listFiles(new PatternFilenameFilter(".*\\.in"))) {
38 | String name = Files.getNameWithoutExtension(inFile.getName());
39 | File outFile = new File(dir, name + ".out");
40 | out.add(new Object[]{name, inFile, outFile});
41 | }
42 |
43 | return out;
44 | }
45 |
46 | private final String name;
47 | private final File inFile;
48 | private final File outFile;
49 |
50 | public RegressionTest(String name, File inFile, File outFile) {
51 | this.name = name;
52 | this.inFile = inFile;
53 | this.outFile = outFile;
54 | }
55 |
56 | @Test
57 | public void testRegression() throws Exception {
58 | String inText = Files.toString(inFile, Charsets.UTF_8);
59 | LOG.info("Read " + name + ":\n" + inText);
60 | CppReader cppReader = new CppReader(new StringReader(inText));
61 | String cppText = CharStreams.toString(cppReader);
62 | LOG.info("Generated " + name + ":\n" + cppText);
63 | if (outFile.exists()) {
64 | String outText = Files.toString(outFile, Charsets.UTF_8);
65 | LOG.info("Expected " + name + ":\n" + outText);
66 | assertEquals(outText, inText);
67 | }
68 |
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/TokenPastingWhitespaceTest.java:
--------------------------------------------------------------------------------
1 | package org.anarres.cpp;
2 |
3 | import com.google.common.io.CharStreams;
4 | import java.io.IOException;
5 | import java.io.Reader;
6 | import org.junit.Test;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import static org.junit.Assert.*;
10 |
11 | /**
12 | * https://github.com/shevek/jcpp/issues/25
13 | *
14 | * @author shevek
15 | */
16 | public class TokenPastingWhitespaceTest {
17 |
18 | private static final Logger LOG = LoggerFactory.getLogger(TokenPastingWhitespaceTest.class);
19 |
20 | @Test
21 | public void testWhitespacePasting() throws IOException {
22 | Preprocessor pp = new Preprocessor();
23 | pp.addInput(new StringLexerSource(
24 | "#define ONE(arg) one_##arg\n"
25 | + "#define TWO(arg) ONE(two_##arg)\n"
26 | + "\n"
27 | + "TWO(good)\n"
28 | + "TWO( /* evil newline */\n"
29 | + " bad)\n"
30 | + "\n"
31 | + "ONE(good)\n"
32 | + "ONE( /* evil newline */\n"
33 | + " bad)\n", true));
34 | Reader r = new CppReader(pp);
35 | String text = CharStreams.toString(r).trim();
36 | LOG.info("Output is:\n" + text);
37 | assertEquals("one_two_good\n"
38 | + "one_two_bad\n"
39 | + "\n"
40 | + "one_good\n"
41 | + "one_bad", text);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/java/org/anarres/cpp/VaArgsPastingTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.anarres.cpp;
7 |
8 | import com.google.common.io.CharStreams;
9 | import java.io.IOException;
10 | import java.io.Reader;
11 | import org.junit.Test;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 | import static org.junit.Assert.*;
15 |
16 | /**
17 | *
18 | * @author shevek
19 | */
20 | public class VaArgsPastingTest {
21 |
22 | private static final Logger LOG = LoggerFactory.getLogger(VaArgsPastingTest.class);
23 |
24 | @Test
25 | public void testWhitespacePasting() throws IOException {
26 | String input
27 | = "#define REGULAR_ARGS(x, y) foo(x, y)\n"
28 | + "#define REGULAR_ELLIPSIS(x, y...) foo(x, y)\n"
29 | + "#define REGULAR_VAARGS(x, ...) foo(x, __VA_ARGS__)\n"
30 | + "#define PASTE_ARGS(x, y) foo(x, ## y)\n"
31 | + "#define PASTE_ELLIPSIS(x, y...) foo(x, ## y)\n"
32 | + "#define PASTE_VAARGS(x, ...) foo(x, ## __VA_ARGS__)\n"
33 | + ""
34 | + "REGULAR_ARGS(a, b) // REGULAR_ARGS 2\n"
35 | + "REGULAR_ELLIPSIS(a, b) // REGULAR_ELLIPSIS 2\n"
36 | + "REGULAR_ELLIPSIS(a) // REGULAR_ELLIPSIS 1\n"
37 | + "REGULAR_VAARGS(a, b) // REGULAR_VAARGS 2\n"
38 | + "REGULAR_VAARGS(a) // REGULAR_VAARGS 1\n"
39 | + ""
40 | + "PASTE_ARGS(a, b) // PASTE_ARGS 2\n"
41 | + "PASTE_ELLIPSIS(a, b) // PASTE_ELLIPSIS 2\n"
42 | + "PASTE_ELLIPSIS(a) // PASTE_ELLIPSIS 1\n"
43 | + "PASTE_VAARGS(a, b) // PASTE_VAARGS 2\n"
44 | + "PASTE_VAARGS(a) // PASTE_VAARGS 1\n";
45 | LOG.info("Input is:\n" + input);
46 | Preprocessor pp = new Preprocessor();
47 | pp.addFeature(Feature.KEEPCOMMENTS);
48 | pp.addInput(new StringLexerSource(input, true));
49 | Reader r = new CppReader(pp);
50 | String output = CharStreams.toString(r).trim();
51 | LOG.info("Output is:\n" + output);
52 | assertEquals("foo(a, b) // REGULAR_ARGS 2\n"
53 | + "foo(a, b) // REGULAR_ELLIPSIS 2\n"
54 | + "foo(a, ) // REGULAR_ELLIPSIS 1\n"
55 | + "foo(a, b) // REGULAR_VAARGS 2\n"
56 | + "foo(a, ) // REGULAR_VAARGS 1\n"
57 | + "foo(a,b) // PASTE_ARGS 2\n" // cpp outputs a warning and a space after the comma, similar below.
58 | + "foo(a,b) // PASTE_ELLIPSIS 2\n"
59 | + "foo(a) // PASTE_ELLIPSIS 1\n"
60 | + "foo(a,b) // PASTE_VAARGS 2\n"
61 | + "foo(a) // PASTE_VAARGS 1", output);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/test/resources/absolute.h:
--------------------------------------------------------------------------------
1 | absolute-result
2 |
--------------------------------------------------------------------------------
/src/test/resources/lines.c:
--------------------------------------------------------------------------------
1 | lines-c-line-1
2 | #include
3 | lines-c-line-3
4 |
5 | lines-c-line-5
6 |
7 | #include
8 |
9 | lines-c-line-9
10 |
--------------------------------------------------------------------------------
/src/test/resources/lines1.h:
--------------------------------------------------------------------------------
1 |
2 | lines1-h-line-2
3 |
4 | /* multi
5 | line
6 | comment
7 | */
8 |
9 | #include
10 | lines1-h-line-10
11 |
12 | lines1-h-line-12
13 | #include
14 |
15 | /* trailing multiline comment
16 | with
17 | more lines
18 | */
19 |
--------------------------------------------------------------------------------
/src/test/resources/lines2.h:
--------------------------------------------------------------------------------
1 |
2 | lines2-h-line-2
3 |
4 | /*
5 | comment
6 |
7 | blank and multiline*/
8 |
9 | lines2-h-line-9
10 |
11 |
--------------------------------------------------------------------------------
/src/test/resources/once.c:
--------------------------------------------------------------------------------
1 | #include "once.h"
2 | #include "once.h"
3 |
--------------------------------------------------------------------------------
/src/test/resources/once.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | foo
3 |
--------------------------------------------------------------------------------
/src/test/resources/pragma.c:
--------------------------------------------------------------------------------
1 |
2 | #pragma
3 | #pragma once
4 | #pragma foo(bar)
5 | #pragma #pragma
6 | #pragma #include
7 | #pragma #include
8 |
9 |
--------------------------------------------------------------------------------
/src/test/resources/regression/lex-char.in:
--------------------------------------------------------------------------------
1 | #define EXAMPLE_X 'a'
2 |
3 | #if EXAMPLE == EXAMPLE_X
4 | #endif
5 |
--------------------------------------------------------------------------------
/src/test/resources/test0.c:
--------------------------------------------------------------------------------
1 | line = __LINE__
2 | file = __FILE__
3 |
4 | #define A a /* a defined */
5 | #define B b /* b defined */
6 | #define C c /* c defined */
7 |
8 | #define EXPAND(x) x
9 | EXPAND(a) -> a
10 | EXPAND(A) -> a
11 |
12 | #define _STRINGIFY(x) #x
13 | _STRINGIFY(A) -> "A"
14 |
15 | #define STRINGIFY(x) _STRINGIFY(x)
16 | STRINGIFY(b) -> "b"
17 | STRINGIFY(A) -> "a"
18 |
19 | #define _CONCAT(x, y) x ## y
20 | _CONCAT(A, B) -> AB
21 |
22 | #define A_CONCAT done_a_concat
23 | _CONCAT(A, _CONCAT(B, C)) -> done_a_concat(b, c)
24 |
25 | #define CONCAT(x, y) _CONCAT(x, y)
26 | CONCAT(A, CONCAT(B, C)) -> abc
27 |
28 | #define _CONCAT3(x, y, z) x ## y ## z
29 | _CONCAT3(a, b, c) -> abc
30 | _CONCAT3(A, B, C) -> ABC
31 | _CONCAT3(A, EXPAND(B), C) -> AEXPAND(b)C
32 |
33 | Line is __LINE__
34 | File is __FILE__
35 |
36 | #define two three
37 | one /* one */
38 | #define one two
39 | one /* three */
40 | #undef two
41 | #define two five
42 | one /* five */
43 | #undef two
44 | one /* two */
45 | #undef one
46 | #define one four
47 | one /* four */
48 | #undef one
49 | #define one one
50 | one /* one */
51 |
52 | /* warning line 57 column 0 */
53 | #warning arse
54 |
55 | #define foo(x) foo(x, b)
56 | foo(1) -> _foo(1, b) without the _
57 | foo(foo(2)) -> _foo(_foo(2, b), b) without the _
58 | // foo(y, z)
59 |
60 | #define var(x...) a x b
61 | var(e, f, g) -> a e, f, g b
62 |
--------------------------------------------------------------------------------
/src/test/resources/test0.h:
--------------------------------------------------------------------------------
1 |
2 | test0start_2
3 |
4 | #include "test1.h"
5 |
6 | test0end___6
7 |
8 |
--------------------------------------------------------------------------------
/src/test/resources/test1.c:
--------------------------------------------------------------------------------
1 | #include "./test0.h"
2 | #include
3 |
--------------------------------------------------------------------------------
/src/test/resources/test1.h:
--------------------------------------------------------------------------------
1 |
2 | test1start_2
3 |
4 | test1mid___4
5 |
6 | test1end___6
7 |
8 |
--------------------------------------------------------------------------------
/src/test/resources/trigraph.c:
--------------------------------------------------------------------------------
1 | ??/
2 |
--------------------------------------------------------------------------------
/src/test/resources/varargs.c:
--------------------------------------------------------------------------------
1 | #define var(x...) a x __VA_ARGS__ b
2 | var(b, c, d)
3 |
4 | #define var2(x, ...) a x __VA_ARGS__ b
5 | var2(b, c, d)
6 |
7 | #define var3(...) a x __VA_ARGS__ b
8 | var3(b, c, d)
9 |
--------------------------------------------------------------------------------