/* At this point, we have consumed the first M_PASTE. * @see Macro#addPaste(Token) */ private void paste(Token ptok) { StringBuilder buf = new StringBuilder(); Token err = null; /* We know here that arg is null or expired, * since we cannot paste an expanded arg. */ int count = 2; for (int i = 0; i < count; i++) { if (!tokens.hasNext()) { /* XXX This one really should throw. */ error(ptok.getLine(), ptok.getColumn(), "Paste at end of expansion"); buf.append(' ').append(ptok.getText()); break; } Token tok = tokens.next(); // System.out.println("Paste " + tok); switch (tok.getType()) { case Token.M_PASTE: /* One extra to paste, plus one because the * paste token didn't count. */ count += 2; ptok = tok; break; case Token.M_ARG: int idx = (int)tok.getValue(); concat(buf, args.get(idx)); break; /* XXX Test this. */ case Token.CCOMMENT: case Token.CPPCOMMENT: break; default: buf.append(tok.getText()); break; } } /* Push and re-lex. */ /* * StringBuilder src = new StringBuilder(); * escape(src, buf); * StringLexerSource sl = new StringLexerSource(src.toString()); */ StringLexerSource sl = new StringLexerSource(buf.toString()); /* XXX Check that concatenation produces a valid token. */ arg = new SourceIterator(sl); }
private Token stringify(Token pos, Argument arg) { StringBuilder buf = new StringBuilder(); concat(buf, arg); // System.out.println("Concat: " + arg + " -> " + buf); StringBuilder str = new StringBuilder("\""); escape(str, buf.ToString()); str.append("\""); // System.out.println("Escape: " + buf + " -> " + str); return(new Token(Token.STRING, pos.getLine(), pos.getColumn(), str.toString(), buf.toString())); }
/** * Handles a warning. * * If a PreprocessorListener is installed, it receives the * warning. Otherwise, an exception is thrown. * * @see #warning(int, int, String) */ protected void warning(Token tok, String msg) { warning(tok.getLine(), tok.getColumn(), msg); }
/** * Handles an error. * * If a PreprocessorListener is installed, it receives the * error. Otherwise, an exception is thrown. * * @see #error(int, int, String) */ protected void error(Token tok, String msg) { error(tok.getLine(), tok.getColumn(), msg); }
private Token toWhitespace(Token tok) { String text = tok.getText(); int len = text.Length; bool cr = false; int nls = 0; for (int i = 0; i < len; i++) { char c = text[i]; switch (c) { case '\r': cr = true; nls++; break; case '\n': if (cr) { cr = false; break; } goto case '\u2028'; /* fallthrough */ case '\u2028': case '\u2029': case '\u000B': case '\u000C': case '\u0085': cr = false; nls++; break; } } char[] cbuf = new char[nls]; for(int i = 0; i < nls; i++) { cbuf[i] = '\n'; } return new Token(Token.WHITESPACE, tok.getLine(), tok.getColumn(), new String(cbuf)); }
/* processes and expands a macro. */ private bool macro(Macro m, Token orig) { Token tok; List<Argument> args; // System.out.println("pp: expanding " + m); if (m.isFunctionLike()) { for (;;) { tok = source_token(); // System.out.println("pp: open: token is " + tok); switch (tok.getType()) { case Token.WHITESPACE: /* XXX Really? */ case Token.CCOMMENT: case Token.CPPCOMMENT: case Token.NL: break; /* continue */ case '(': goto BREAK_OPEN; default: source_untoken(tok); return false; } } BREAK_OPEN: // tok = expanded_token_nonwhite(); tok = source_token_nonwhite(); /* We either have, or we should have args. * This deals elegantly with the case that we have * one empty arg. */ if (tok.getType() != ')' || m.getArgs() > 0) { args = new List<Argument>(); Argument arg = new Argument(); int depth = 0; bool space = false; ARGS: for (;;) { // System.out.println("pp: arg: token is " + tok); switch (tok.getType()) { case Token.EOF: error(tok, "EOF in macro args"); return false; case ',': if (depth == 0) { if (m.isVariadic() && /* We are building the last arg. */ args.Count == m.getArgs() - 1) { /* Just add the comma. */ arg.addToken(tok); } else { args.Add(arg); arg = new Argument(); } } else { arg.addToken(tok); } space = false; break; case ')': if (depth == 0) { args.Add(arg); goto BREAK_ARGS; } else { depth--; arg.addToken(tok); } space = false; break; case '(': depth++; arg.addToken(tok); space = false; break; case Token.WHITESPACE: case Token.CCOMMENT: case Token.CPPCOMMENT: /* Avoid duplicating spaces. */ space = true; break; default: /* Do not put space on the beginning of * an argument token. */ if (space && arg.Count != 0) arg.addToken(Token.space); arg.addToken(tok); space = false; break; } // tok = expanded_token(); tok = source_token(); } BREAK_ARGS: if(m.isVariadic() && args.Count < m.getArgs()) { args.Add(new Argument()); } /* space may still be true here, thus trailing space * is stripped from arguments. */ if (args.Count != m.getArgs()) { error(tok, "macro " + m.getName() + " has " + m.getArgs() + " parameters " + "but given " + args.Count + " args"); /* We could replay the arg tokens, but I * note that GNU cpp does exactly what we do, * i.e. output the macro name and chew the args. */ return false; } /* for (Argument a : args) a.expand(this); */ for (int i = 0; i < args.Count; i++) { args[i].expand(this); } // 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__) { push_source(new FixedTokenSource( new Token[] { new Token(Token.INTEGER, orig.getLine(), orig.getColumn(), orig.getLine().ToString(), orig.getLine()) } ), true); } else if (m == __FILE__) { StringBuilder buf = new StringBuilder("\""); String name = getSource().getName(); if (name == null) name = "<no file>"; for (int i = 0; i < name.Length; i++) { char c = name[i]; switch (c) { case '\\': buf.Append("\\\\"); break; case '"': buf.Append("\\\""); break; default: buf.Append(c); break; } } buf.Append("\""); String text = buf.ToString(); push_source(new FixedTokenSource( new Token[] { new Token(Token.STRING, orig.getLine(), orig.getColumn(), text, text) } ), true); } else if (m == __COUNTER__) { /* This could equivalently have been done by adding * a special Macro subclass which overrides getTokens(). */ int value = this.counter++; push_source(new FixedTokenSource( new Token[] { new Token(Token.INTEGER, orig.getLine(), orig.getColumn(), value.ToString(), value) } ), true); } else { push_source(new MacroTokenSource(m, args), true); } return true; }
/* At this point, we have consumed the first M_PASTE. * @see Macro#addPaste(Token) */ private void paste(Token ptok) { StringBuilder buf = new StringBuilder(); Token err = null; /* We know here that arg is null or expired, * since we cannot paste an expanded arg. */ int count = 2; for (int i = 0; i < count; i++) { if (!tokens.hasNext()) { /* XXX This one really should throw. */ error(ptok.getLine(), ptok.getColumn(), "Paste at end of expansion"); buf.append(' ').append(ptok.getText()); break; } Token tok = tokens.next(); // System.out.println("Paste " + tok); switch (tok.getType()) { case Token.M_PASTE: /* One extra to paste, plus one because the * paste token didn't count. */ count += 2; ptok = tok; break; case Token.M_ARG: int idx = (int)tok.getValue(); concat(buf, args.get(idx)); break; /* XXX Test this. */ case Token.CCOMMENT: case Token.CPPCOMMENT: break; default: buf.append(tok.getText()); break; } } /* Push and re-lex. */ /* StringBuilder src = new StringBuilder(); escape(src, buf); StringLexerSource sl = new StringLexerSource(src.toString()); */ StringLexerSource sl = new StringLexerSource(buf.toString()); /* XXX Check that concatenation produces a valid token. */ arg = new SourceIterator(sl); }
private Token stringify(Token pos, Argument arg) { StringBuilder buf = new StringBuilder(); concat(buf, arg); // System.out.println("Concat: " + arg + " -> " + buf); StringBuilder str = new StringBuilder("\""); escape(str, buf.ToString()); str.append("\""); // System.out.println("Escape: " + buf + " -> " + str); return new Token(Token.STRING, pos.getLine(), pos.getColumn(), str.toString(), buf.toString()); }