diff --git a/src/main/java/org/anarres/cpp/Feature.java b/src/main/java/org/anarres/cpp/Feature.java index a514269..eb14010 100644 --- a/src/main/java/org/anarres/cpp/Feature.java +++ b/src/main/java/org/anarres/cpp/Feature.java @@ -37,6 +37,6 @@ public enum Feature { /** Supports lexing of objective-C. */ OBJCSYNTAX, INCLUDENEXT, - /** Random extensions. */ + GCC_SUFFIXES, /** Random extensions. */ PRAGMA_ONCE } diff --git a/src/main/java/org/anarres/cpp/LexerSource.java b/src/main/java/org/anarres/cpp/LexerSource.java index cf4296f..81ea636 100644 --- a/src/main/java/org/anarres/cpp/LexerSource.java +++ b/src/main/java/org/anarres/cpp/LexerSource.java @@ -40,6 +40,7 @@ protected static BufferedReader toBufferedReader(@Nonnull Reader r) { private boolean include; private boolean digraphs; + private boolean gccSuffixes; /* Unread. */ private int u0, u1; @@ -60,6 +61,7 @@ public LexerSource(Reader r, boolean ppvalid) { this.include = false; this.digraphs = true; + this.gccSuffixes = false; this.ucount = 0; @@ -73,6 +75,7 @@ public LexerSource(Reader r, boolean ppvalid) { /* pp */ void init(Preprocessor pp) { super.init(pp); this.digraphs = pp.getFeature(Feature.DIGRAPHS); + this.gccSuffixes = pp.getFeature(Feature.GCC_SUFFIXES); this.reader.init(pp, this); } @@ -512,8 +515,20 @@ private Token _number_suffix(StringBuilder text, NumericValue value, int d) text.append((char) d); d = read(); } else if (d == 'L' || d == 'l') { - if ((flags & NumericValue.FF_SIZE) != 0) - warning("Multiple length suffixes after " + text); + if ((flags & NumericValue.FF_SIZE) != 0) { + // Added special code for GCC extended numeric types + if (gccSuffixes) { + if ((flags & NumericValue.F_UNSIGNED) != 0) { + flags |= NumericValue.F_GCC_ULONGLONG; // UL gcc type + } else if ((flags & NumericValue.F_DOUBLE) != 0) { + flags |= NumericValue.F_GCC_DEC128; // DL gcc type + } else { + warning("Multiple length suffixes after " + text); + } + } else { + warning("Multiple length suffixes after " + text); + } + } text.append((char) d); int e = read(); if (e == d) { // Case must match. Ll is Welsh. @@ -531,14 +546,24 @@ private Token _number_suffix(StringBuilder text, NumericValue value, int d) text.append((char) d); d = read(); } else if (d == 'F' || d == 'f') { - if ((flags & NumericValue.FF_SIZE) != 0) - warning("Multiple length suffixes after " + text); + if ((flags & NumericValue.FF_SIZE) != 0) { + if (gccSuffixes && ((flags & NumericValue.F_DOUBLE) != 0)) { + flags |= NumericValue.F_GCC_DEC32; // GCC DF suffic + } else { + warning("Multiple length suffixes after " + text); + } + } flags |= NumericValue.F_FLOAT; text.append((char) d); d = read(); } else if (d == 'D' || d == 'd') { - if ((flags & NumericValue.FF_SIZE) != 0) - warning("Multiple length suffixes after " + text); + if ((flags & NumericValue.FF_SIZE) != 0) { + if (gccSuffixes && ((flags & NumericValue.F_DOUBLE) != 0)) { + flags |= NumericValue.F_GCC_DEC64; // GCC DD suffic + } else { + warning("Multiple length suffixes after " + text); + } + } flags |= NumericValue.F_DOUBLE; text.append((char) d); d = read(); diff --git a/src/main/java/org/anarres/cpp/NumericValue.java b/src/main/java/org/anarres/cpp/NumericValue.java index b51ca59..4ea2147 100644 --- a/src/main/java/org/anarres/cpp/NumericValue.java +++ b/src/main/java/org/anarres/cpp/NumericValue.java @@ -31,8 +31,13 @@ public class NumericValue extends Number { public static final int F_LONGLONG = 8; public static final int F_FLOAT = 16; public static final int F_DOUBLE = 32; + public static final int F_GCC_DEC64 = 64; // these are out of order, but I like + public static final int F_GCC_DEC128 = 128; // having GCC_DEC128 = 128... + public static final int F_GCC_DEC32 = 256; + public static final int F_GCC_ULONGLONG = 512; public static final int FF_SIZE = F_INT | F_LONG | F_LONGLONG | F_FLOAT | F_DOUBLE; + public static final int FF_GCC_EXTENDED_SIZES = F_GCC_DEC32 | F_GCC_DEC64 | F_GCC_DEC128 | F_GCC_ULONGLONG; private final int base; private final String integer; diff --git a/src/main/java/org/anarres/cpp/Preprocessor.java b/src/main/java/org/anarres/cpp/Preprocessor.java index 5b07824..8716cc1 100644 --- a/src/main/java/org/anarres/cpp/Preprocessor.java +++ b/src/main/java/org/anarres/cpp/Preprocessor.java @@ -142,7 +142,7 @@ public Preprocessor() { this.features = EnumSet.noneOf(Feature.class); this.warnings = EnumSet.noneOf(Warning.class); this.filesystem = new JavaFileSystem(); - this.listener = null; + this.listener = new DefaultPreprocessorListener(); } public Preprocessor(@Nonnull Source initial) { @@ -188,6 +188,12 @@ public void setListener(@Nonnull PreprocessorListener listener) { s.init(this); s = s.getParent(); } + + // Make sure that any input sources know about this feature + for (Source source: inputs) { + source.init(this); + } + } /** @@ -214,6 +220,11 @@ public Set getFeatures() { */ public void addFeature(@Nonnull Feature f) { features.add(f); + + // Make sure that any input sources know about this feature + for (Source source: inputs) { + source.init(this); + } } /** @@ -376,6 +387,10 @@ public void addMacro(@Nonnull String name, @Nonnull String value) try { Macro m = new Macro(name); StringLexerSource s = new StringLexerSource(value); + + // In order to make sure that the source honors all the features of this preprocessor, we have to init it + s.init(this); + for (;;) { Token tok = s.token(); if (tok.getType() == EOF) @@ -701,9 +716,9 @@ private boolean macro(Macro m, Token orig) throws IOException, LexerException { Token tok; - List args; + List args = new ArrayList(); - // System.out.println("pp: expanding " + m); + //System.out.println("pp: expanding " + m); if (m.isFunctionLike()) { OPEN: for (;;) { @@ -732,7 +747,6 @@ private boolean macro(Macro m, Token orig) * This deals elegantly with the case that we have * one empty arg. */ if (tok.getType() != ')' || m.getArgs() > 0) { - args = new ArrayList(); Argument arg = new Argument(); int depth = 0; @@ -832,12 +846,10 @@ private boolean macro(Macro m, Token orig) // System.out.println("Macro " + m + " args " + args); } else { /* nargs == 0 and we (correctly) got () */ - args = null; } } else { /* Macro without args. */ - args = null; } if (m == __LINE__) { @@ -1153,13 +1165,22 @@ protected boolean include(@Nonnull VirtualFile file) * * @param path The list of virtual directories to search for the given name. * @param name The name of the file to attempt to include. + * @param next * @return true if the file was successfully included, false otherwise. * @throws IOException if an I/O error occurs. */ - protected boolean include(@Nonnull Iterable path, @Nonnull String name) + protected boolean include(@Nonnull Iterable path, @Nonnull String name, boolean next) throws IOException { for (String dir : path) { VirtualFile file = getFileSystem().getFile(dir, name); + + // Implement the next functionality here. This is actually + // not exactly right because it should be based on the include + // we are currently parsing, but it works _almost_ the same given + // how limited the usage of #include_next is. + if (includes.contains(file) && next) { + continue; + } if (include(file)) return true; } @@ -1198,7 +1219,7 @@ private void include( if (include(ifile)) return; } - if (include(quoteincludepath, name)) + if (include(quoteincludepath, name, next)) return; } else { int idx = name.indexOf('/'); @@ -1206,12 +1227,12 @@ private void include( String frameworkName = name.substring(0, idx); String headerName = name.substring(idx + 1); String headerPath = frameworkName + ".framework/Headers/" + headerName; - if (include(frameworkspath, headerPath)) + if (include(frameworkspath, headerPath, next)) return; } } - if (include(sysincludepath, name)) + if (include(sysincludepath, name, next)) return; StringBuilder buf = new StringBuilder(); @@ -1265,9 +1286,33 @@ private Token include(boolean next) name = (String) tok.getValue(); quoted = false; tok = source_skipline(true); + } else if ((tok.getType() == '"') || (tok.getType() == '<')) { + // Handle the case where the actual include target was a macro that expanded into + // a string. We should have a stream of tokens than terminates in a quote + // Figure out the closing token + int closer = tok.getType() == '<' ? '>' : '"'; + StringBuilder buf = new StringBuilder(); + MACRO: + for (;;) { + tok = token_nonwhite(); + switch (tok.getType()) { + case NL: + case EOF: + break MACRO; + default: + if (tok.getType() == closer) { + tok = token_nonwhite(); + break MACRO; + } else { + buf.append(tok.getText()); + } + } + } + name = buf.toString(); + quoted = closer == '"'; } else { error(tok, - "Expected string or header, not " + tok.getText()); + "Expected string or header, not " + tok.getText() + " of type " + tok.getType() + " at " + tok.getLine() + "," + tok.getColumn()); switch (tok.getType()) { case NL: case EOF: @@ -2165,7 +2210,6 @@ public String toString() { return buf.toString(); } - @Override public void close() throws IOException { {