예제 #1
0
        /* processes a #define directive */
        private Token define()
        {
            Token	tok = source_token_nonwhite();
            if (tok.getType() != Token.IDENTIFIER) {
            error(tok, "Expected Token.IDENTIFIER");
            return source_skipline(false);
            }
            /* if predefined */

            String			name = tok.getText();
            if ("defined" == name) {
            error(tok, "Cannot redefine name 'defined'");
            return source_skipline(false);
            }

            Macro			m = new Macro(getSource(), name);
            List<String>	args;

            tok = source_token();
            if (tok.getType() == '(') {
            tok = source_token_nonwhite();
            if (tok.getType() != ')') {
                args = new List<String>();
                for (;;) {
                    switch (tok.getType()) {
                        case Token.IDENTIFIER:
                            if(m.isVariadic()) {
                                throw new Exception();
                            }
                            args.Add(tok.getText());
                            break;
                        case Token.ELLIPSIS:
                            m.setVariadic(true);
                            args.Add("__VA_ARGS__");
                            break;
                        case Token.NL:
                        case Token.EOF:
                            error(tok,
                                "Unterminated macro parameter list");
                            return tok;
                        default:
                            error(tok,
                                "error in macro parameters: " +
                                tok.getText());
                            return source_skipline(false);
                    }
                    tok = source_token_nonwhite();
                    switch (tok.getType()) {
                        case ',':
                            break;
                        case Token.ELLIPSIS:
                            tok = source_token_nonwhite();
                            if (tok.getType() != ')')
                                error(tok,
                                    "ellipsis must be on last argument");
                            m.setVariadic(true);
                            goto BREAK_ARGS;
                        case ')':
                            goto BREAK_ARGS;

                        case Token.NL:
                        case Token.EOF:
                            /* Do not skip line. */
                            error(tok,
                                "Unterminated macro parameters");
                            return tok;
                        default:
                            error(tok,
                                "Bad token in macro parameters: " +
                                tok.getText());
                            return source_skipline(false);
                    }
                    tok = source_token_nonwhite();
                }
            BREAK_ARGS:;
            }
            else {
                System.Diagnostics.Debug.Assert(tok.getType() == ')', "Expected ')'");
                args = new List<string>();
            }

            m.setArgs(args);
            }
            else {
            /* For searching. */
            args = new List<string>();
            source_untoken(tok);
            }

            /* Get an expansion for the macro, using IndexOf. */
            bool	space = false;
            bool	paste = false;
            int		idx;

            /* Ensure no space at start. */
            tok = source_token_nonwhite();
            for (;;) {
            switch (tok.getType()) {
                case Token.EOF:
                    goto BREAK_EXPANSION;
                case Token.NL:
                    goto BREAK_EXPANSION;

                case Token.CCOMMENT:
                case Token.CPPCOMMENT:
                    /* XXX This is where we implement GNU's cpp -CC. */
                    // break;
                case Token.WHITESPACE:
                    if (!paste)
                        space = true;
                    break;

                /* Paste. */
                case Token.PASTE:
                    space = false;
                    paste = true;
                    m.addPaste(new Token(Token.M_PASTE,
                            tok.getLine(), tok.getColumn(),
                            "#" + "#", null));
                    break;

                /* Stringify. */
                case '#':
                    if (space)
                        m.addToken(Token.space);
                    space = false;
                    Token	la = source_token_nonwhite();
                    if(la.getType() == Token.IDENTIFIER &&
                        ((idx = args.IndexOf(la.getText())) != -1)) {
                            m.addToken(new Token(Token.M_STRING,
                                la.getLine(), la.getColumn(),
                                "#" + la.getText(),
                                idx));
                    }
                    else {
                        m.addToken(tok);
                        /* Allow for special processing. */
                        source_untoken(la);
                    }
                    break;

                case Token.IDENTIFIER:
                    if (space)
                        m.addToken(Token.space);
                    space = false;
                    paste = false;
                    idx = args.IndexOf(tok.getText());
                    if (idx == -1)
                        m.addToken(tok);
                    else
                        m.addToken(new Token(Token.M_ARG,
                                tok.getLine(), tok.getColumn(),
                                tok.getText(),
                                idx));
                    break;

                default:
                    if (space)
                        m.addToken(Token.space);
                    space = false;
                    paste = false;
                    m.addToken(tok);
                    break;
            }
            tok = source_token();
            }
            BREAK_EXPANSION:

            if (getFeature(Feature.DEBUG))
            System.Console.Error.WriteLine("Defined macro " + m);
            addMacro(m);

            return tok;	/* Token.NL or Token.EOF. */
        }
예제 #2
0
        /* 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;
        }