Beispiel #1
0
static int CPPdefine(yystypepp * yylvalpp)
{
    int token, name, args[MAX_MACRO_ARGS], argc;
    const char *message;
    MacroSymbol mac;
    Symbol *symb;
    SourceLoc dummyLoc;
    memset(&mac, 0, sizeof(mac));
    token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
    if (token != CPP_IDENTIFIER) {
        CPPErrorToInfoLog("#define");
        return token;
    }
    name = yylvalpp->sc_ident;
    token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
    if (token == '(' && !yylvalpp->sc_int) {
        // gather arguments
        argc = 0;
        do {
            token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
            if (argc == 0 && token == ')') break;
            if (token != CPP_IDENTIFIER) {
				CPPErrorToInfoLog("#define");
                return token;
            }
            if (argc < MAX_MACRO_ARGS)
                args[argc++] = yylvalpp->sc_ident;
            token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
        } while (token == ',');
        if (token != ')') {
            CPPErrorToInfoLog("#define");
            return token;
        }
        mac.argc = argc;
        mac.args = mem_Alloc(macros->pool, argc * sizeof(int));
        memcpy(mac.args, args, argc * sizeof(int));
        token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
	}
    mac.body = NewTokenStream(GetAtomString(atable, name), macros->pool);
    while (token != '\n') {
        if (token == '\\') {
            CPPErrorToInfoLog("The line continuation character (\\) is not part of the OpenGL ES Shading Language");
            return token;
        }
        RecordToken(mac.body, token, yylvalpp);
        token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
    };

    symb = LookUpSymbol(macros, name);
    if (symb) {
        if (!symb->details.mac.undef) {
            // already defined -- need to make sure they are identical
            if (symb->details.mac.argc != mac.argc) goto error;
            for (argc=0; argc < mac.argc; argc++)
                if (symb->details.mac.args[argc] != mac.args[argc])
                    goto error;
            RewindTokenStream(symb->details.mac.body);
            RewindTokenStream(mac.body);
            do {
                int old_lval, old_token;
                old_token = ReadToken(symb->details.mac.body, yylvalpp);
                old_lval = yylvalpp->sc_int;
                token = ReadToken(mac.body, yylvalpp);
                if (token != old_token || yylvalpp->sc_int != old_lval) { 
                error:
                    StoreStr("Macro Redefined");
                    StoreStr(GetStringOfAtom(atable,name));
                    message=GetStrfromTStr();
                    DecLineNumber();
                    CPPShInfoLogMsg(message);
                    IncLineNumber();
                    ResetTString();
                    break; }
            } while (token > 0);
        }
        //FreeMacro(&symb->details.mac);
    } else {
        dummyLoc.file = 0;
        dummyLoc.line = 0;
        symb = AddSymbol(&dummyLoc, macros, name, MACRO_S);
    }
    symb->details.mac = mac;
    return '\n';
} // CPPdefine
Beispiel #2
0
int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
{
    TSourceLoc loc = ppToken->loc;  // because we sometimes read the newline before reporting the error
    if (token == PpAtomIdentifier) {
        if (ppToken->atom == PpAtomDefined) {
            bool needclose = 0;
            token = scanToken(ppToken);
            if (token == '(') {
                needclose = true;
                token = scanToken(ppToken);
            }
            if (token != PpAtomIdentifier) {
                parseContext.ppError(loc, "incorrect directive, expected identifier", "preprocessor evaluation", "");
                err = true;
                res = 0;

                return token;
            }
            Symbol* s = LookUpSymbol(ppToken->atom);
            res = s ? ! s->mac.undef : 0;
            token = scanToken(ppToken);
            if (needclose) {
                if (token != ')') {
                    parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", "");
                    err = true;
                    res = 0;

                    return token;
                }
                token = scanToken(ppToken);
            }
        } else {
            token = evalToToken(token, shortCircuit, res, err, ppToken);
            return eval(token, precedence, shortCircuit, res, err, ppToken);
        }
    } else if (token == PpAtomConstInt) {
        res = ppToken->ival;
        token = scanToken(ppToken);
    } else if (token == '(') {
        token = scanToken(ppToken);
        token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken);
        if (! err) {
            if (token != ')') {
                parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", "");
                err = true;
                res = 0;

                return token;
            }
            token = scanToken(ppToken);
        }
    } else {
        int op = NUM_ELEMENTS(unop) - 1;
        for (; op >= 0; op--) {
            if (unop[op].token == token)
                break;
        }
        if (op >= 0) {
            token = scanToken(ppToken);
            token = eval(token, UNARY, shortCircuit, res, err, ppToken);
            res = unop[op].op(res);
        } else {
            parseContext.ppError(loc, "bad expression", "preprocessor evaluation", "");
            err = true;
            res = 0;

            return token;
        }
    }

    token = evalToToken(token, shortCircuit, res, err, ppToken);

    // Perform evaluation of binary operation, if there is one, otherwise we are done.
    while (! err) {
        if (token == ')' || token == '\n') 
            break;
        int op;
        for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) {
            if (binop[op].token == token)
                break;
        }
        if (op < 0 || binop[op].precedence <= precedence)
            break;
        int leftSide = res;
        
        // Setup short-circuiting, needed for ES, unless already in a short circuit.
        // (Once in a short-circuit, can't turn off again, until that whole subexpression is done.
        if (! shortCircuit) {
            if ((token == PpAtomOr  && leftSide == 1) ||
                (token == PpAtomAnd && leftSide == 0))
                shortCircuit = true;
        }

        token = scanToken(ppToken);
        token = eval(token, binop[op].precedence, shortCircuit, res, err, ppToken);

        if (binop[op].op == op_div || binop[op].op == op_mod) {
            if (res == 0) {
                parseContext.ppError(loc, "division by 0", "preprocessor evaluation", "");
                res = 1;
            }
        }
        res = binop[op].op(leftSide, res);
    }

    return token;
}
Beispiel #3
0
// Handle #define
int TPpContext::CPPdefine(TPpToken* ppToken)
{
    MacroSymbol mac;
    Symbol *symb;

    // get macro name
    int token = scanToken(ppToken);
    if (token != PpAtomIdentifier) {
        parseContext.ppError(ppToken->loc, "must be followed by macro name", "#define", "");
        return token;
    }
    if (ppToken->loc.string >= 0) {
        // We are in user code; check for reserved name use:
        parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#define");
    }

    // save the original atom
    const int defAtom = ppToken->atom;

    // gather parameters to the macro, between (...)
    token = scanToken(ppToken);
    if (token == '(' && ! ppToken->space) {
        int argc = 0;
        int args[maxMacroArgs];
        do {
            token = scanToken(ppToken);
            if (argc == 0 && token == ')') 
                break;
            if (token != PpAtomIdentifier) {
                parseContext.ppError(ppToken->loc, "bad argument", "#define", "");

                return token;
            }
            // check for duplication of parameter name
            bool duplicate = false;
            for (int a = 0; a < argc; ++a) {
                if (args[a] == ppToken->atom) {
                    parseContext.ppError(ppToken->loc, "duplicate macro parameter", "#define", "");
                    duplicate = true;
                    break;
                }
            }
            if (! duplicate) {
                if (argc < maxMacroArgs)
                    args[argc++] = ppToken->atom;
                else
                    parseContext.ppError(ppToken->loc, "too many macro parameters", "#define", "");
            }
            token = scanToken(ppToken);
        } while (token == ',');
        if (token != ')') {
            parseContext.ppError(ppToken->loc, "missing parenthesis", "#define", "");

            return token;
        }
        mac.argc = argc;
        mac.args = (int*)mem_Alloc(pool, argc * sizeof(int));
        memcpy(mac.args, args, argc * sizeof(int));
        token = scanToken(ppToken);
    }

    // record the definition of the macro
    TSourceLoc defineLoc = ppToken->loc; // because ppToken is going to go to the next line before we report errors
    mac.body = new TokenStream;
    while (token != '\n' && token != EndOfInput) {
        RecordToken(mac.body, token, ppToken);
        token = scanToken(ppToken);
        if (token != '\n' && ppToken->space)
            RecordToken(mac.body, ' ', ppToken);
    }

    // check for duplicate definition
    symb = LookUpSymbol(defAtom);
    if (symb) {
        if (! symb->mac.undef) {
            // Already defined -- need to make sure they are identical:
            // "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number,
            // ordering, spelling, and white-space separation, where all white-space separations are considered identical."
            if (symb->mac.argc != mac.argc)
                parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", GetAtomString(defAtom));
            else {
                for (int argc = 0; argc < mac.argc; argc++) {
                    if (symb->mac.args[argc] != mac.args[argc])
                        parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", GetAtomString(defAtom));
                }
                RewindTokenStream(symb->mac.body);
                RewindTokenStream(mac.body);
                int newToken;
                do {
                    int oldToken;
                    TPpToken oldPpToken;
                    TPpToken newPpToken;                    
                    oldToken = ReadToken(symb->mac.body, &oldPpToken);
                    newToken = ReadToken(mac.body, &newPpToken);
                    if (oldToken != newToken || oldPpToken != newPpToken) {
                        parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", GetAtomString(defAtom));
                        break; 
                    }
                } while (newToken > 0);
            }
        }
    } else
        symb = AddSymbol(defAtom);

    delete symb->mac.body;
    symb->mac = mac;

    return '\n';
}
Beispiel #4
0
//
// Check an identifier (atom) to see if it is a macro that should be expanded.
// If it is, and defined, push a tInput that will produce the appropriate expansion
// and return 1.
// If it is, but undefined, and expandUndef is requested, push a tInput that will 
// expand to 0 and return -1.
// Otherwise, return 0 to indicate no expansion, which is not necessarily an error.
//
int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay)
{
    ppToken->space = false;
    switch (atom) {
    case PpAtomLineMacro:
        ppToken->ival = parseContext.getCurrentLoc().line;
        snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
        UngetToken(PpAtomConstInt, ppToken);
        return 1;

    case PpAtomFileMacro: {
        if (parseContext.getCurrentLoc().name)
            parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__");
        ppToken->ival = parseContext.getCurrentLoc().string;
        snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str());
        UngetToken(PpAtomConstInt, ppToken);
        return 1;
    }

    case PpAtomVersionMacro:
        ppToken->ival = parseContext.version;
        snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
        UngetToken(PpAtomConstInt, ppToken);
        return 1;

    default:
        break;
    }

    Symbol *sym = LookUpSymbol(atom);
    int token;
    int depth = 0;

    // no recursive expansions
    if (sym && sym->mac.busy)
        return 0;

    // not expanding undefined macros
    if ((! sym || sym->mac.undef) && ! expandUndef)
        return 0;

    // 0 is the value of an undefined macro
    if ((! sym || sym->mac.undef) && expandUndef) {
        pushInput(new tZeroInput(this));
        return -1;
    }

    tMacroInput *in = new tMacroInput(this);

    TSourceLoc loc = ppToken->loc;  // in case we go to the next line before discovering the error
    in->mac = &sym->mac;
    if (sym->mac.args) {
        token = scanToken(ppToken);
        if (newLineOkay) {
            while (token == '\n')                
                token = scanToken(ppToken);
        }
        if (token != '(') {
            parseContext.ppError(loc, "expected '(' following", "macro expansion", GetAtomString(atom));
            UngetToken(token, ppToken);
            ppToken->atom = atom;

            delete in;
            return 0;
        }
        in->args.resize(in->mac->argc);
        for (int i = 0; i < in->mac->argc; i++)
            in->args[i] = new TokenStream;
        int arg = 0;
        bool tokenRecorded = false;
        do {
            depth = 0;
            while (1) {
                token = scanToken(ppToken);
                if (token == EndOfInput) {
                    parseContext.ppError(loc, "End of input in macro", "macro expansion", GetAtomString(atom));
                    delete in;
                    return 0;
                }
                if (token == '\n') {
                    if (! newLineOkay) {
                        parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", GetAtomString(atom));
                        delete in;
                        return 0;
                    }
                    continue;
                }
                if (token == '#') {
                    parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", GetAtomString(atom));
                    delete in;
                    return 0;
                }
                if (in->mac->argc == 0 && token != ')')
                    break;
                if (depth == 0 && (token == ',' || token == ')'))
                    break;
                if (token == '(')
                    depth++;
                if (token == ')')
                    depth--;
                RecordToken(in->args[arg], token, ppToken);
                tokenRecorded = true;
            }
            if (token == ')') {
                if (in->mac->argc == 1 && tokenRecorded == 0)
                    break;
                arg++;
                break;
            }
            arg++;
        } while (arg < in->mac->argc);

        if (arg < in->mac->argc)
            parseContext.ppError(loc, "Too few args in Macro", "macro expansion", GetAtomString(atom));
        else if (token != ')') {
            depth=0;
            while (token != EndOfInput && (depth > 0 || token != ')')) {
                if (token == ')')
                    depth--;
                token = scanToken(ppToken);
                if (token == '(')
                    depth++;
            }

            if (token == EndOfInput) {
                parseContext.ppError(loc, "End of input in macro", "macro expansion", GetAtomString(atom));
                delete in;
                return 0;
            }
            parseContext.ppError(loc, "Too many args in macro", "macro expansion", GetAtomString(atom));
        }
        for (int i = 0; i < in->mac->argc; i++)
            in->args[i] = PrescanMacroArg(in->args[i], ppToken, newLineOkay);
    }

    pushInput(in);
    sym->mac.busy = 1;
    RewindTokenStream(sym->mac.body);

    return 1;
}
Beispiel #5
0
int MacroExpand(int atom, yystypepp * yylvalpp)
{
    Symbol              *sym = LookUpSymbol(macros, atom);
    MacroInputSrc       *in;
    int i,j, token, depth=0;
    const char *message;
	if (atom == __LINE__Atom) {
        yylvalpp->sc_int = GetLineNumber();
        sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
        UngetToken(CPP_INTCONSTANT, yylvalpp);
        return 1;
    }
    if (atom == __FILE__Atom) {
        yylvalpp->sc_int = GetStringNumber();
        sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
        UngetToken(CPP_INTCONSTANT, yylvalpp);
        return 1;
    }
	if (atom == __VERSION__Atom) {
        strcpy(yylvalpp->symbol_name,ESSL_VERSION_STRING);
        yylvalpp->sc_int = atoi(yylvalpp->symbol_name);
        UngetToken(CPP_INTCONSTANT, yylvalpp);
        return 1;
    }
    if (!sym || sym->details.mac.undef) return 0;
    if (sym->details.mac.busy) return 0;        // no recursive expansions
    in = malloc(sizeof(*in));
    memset(in, 0, sizeof(*in));
    in->base.scan = (void *)macro_scan;
    in->base.line = cpp->currentInput->line;
    in->base.name = cpp->currentInput->name;
    in->mac = &sym->details.mac;
    if (sym->details.mac.args) {
        token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
		if (token != '(') {
            UngetToken(token, yylvalpp);
            yylvalpp->sc_ident = atom;
            return 0;
        }
        in->args = malloc(in->mac->argc * sizeof(TokenStream *));
        for (i=0; i<in->mac->argc; i++)
            in->args[i] = NewTokenStream("macro arg", 0);
		i=0;j=0;
        do{
            depth = 0;
			while(1) {
                token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
                if (token <= 0) {
                    StoreStr("EOF in Macro ");
                    StoreStr(GetStringOfAtom(atable,atom));
                    message=GetStrfromTStr();
                    CPPShInfoLogMsg(message);
                    ResetTString();
                    return 1;
                }
                if((in->mac->argc==0) && (token!=')')) break;
                if (depth == 0 && (token == ',' || token == ')')) break;
                if (token == '(') depth++;
                if (token == ')') depth--;
                RecordToken(in->args[i], token, yylvalpp);
                j=1;
			}
            if (token == ')') {
                if((in->mac->argc==1) &&j==0)
                    break;
                i++;
                break;
            }
            i++;
		}while(i < in->mac->argc);

        if (i < in->mac->argc) {
            StoreStr("Too few args in Macro ");
            StoreStr(GetStringOfAtom(atable,atom));
            message=GetStrfromTStr();
            CPPShInfoLogMsg(message);
            ResetTString();
        } else if (token != ')') {
            depth=0;
			while (token >= 0 && (depth > 0 || token != ')')) {
                if (token == ')') depth--;
                token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
                if (token == '(') depth++;
            }
			
            if (token <= 0) {
                StoreStr("EOF in Macro ");
                StoreStr(GetStringOfAtom(atable,atom));
                message=GetStrfromTStr();
                CPPShInfoLogMsg(message);
                ResetTString();
                return 1;
            }
            StoreStr("Too many args in Macro ");
            StoreStr(GetStringOfAtom(atable,atom));
            message=GetStrfromTStr();
            CPPShInfoLogMsg(message);
            ResetTString();
		}
		for (i=0; i<in->mac->argc; i++) {
            in->args[i] = PrescanMacroArg(in->args[i], yylvalpp);
        }
    }
#if 0
    printf("  <%s:%d>found macro %s\n", GetAtomString(atable, loc.file),
           loc.line, GetAtomString(atable, atom));
    for (i=0; i<in->mac->argc; i++) {
        printf("\targ %s = '", GetAtomString(atable, in->mac->args[i]));
        DumpTokenStream(stdout, in->args[i]);
        printf("'\n");
    }
#endif
	/*retain the input source*/
    in->base.prev = cpp->currentInput;
    sym->details.mac.busy = 1;
    RewindTokenStream(sym->details.mac.body);
    cpp->currentInput = &in->base;
    return 1;
} // MacroExpand
Beispiel #6
0
static int eval(int token, int prec, int *res, int *err, yystypepp * yylvalpp)
{
    int         i, val;
    Symbol      *s;
    if (token == CPP_IDENTIFIER) {
        if (yylvalpp->sc_ident == definedAtom) {
            int needclose = 0;
            token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
            if (token == '(') {
                needclose = 1;
                token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
            }
            if (token != CPP_IDENTIFIER)
                goto error;
            *res = (s = LookUpSymbol(macros, yylvalpp->sc_ident))
                        ? !s->details.mac.undef : 0;
            token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
            if (needclose) {
                if (token != ')')
                    goto error;
                token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
            }
		} else if (MacroExpand(yylvalpp->sc_ident, yylvalpp)) {
			token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
            return eval(token, prec, res, err, yylvalpp);
        } else {
            goto error;
        }
	} else if (token == CPP_INTCONSTANT) {
        *res = yylvalpp->sc_int;
        token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
    } else if (token == '(') {
        token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
        token = eval(token, MIN_PREC, res, err, yylvalpp);
        if (!*err) {
            if (token != ')')
                goto error;
            token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
        }
    } else {
        for (i = ALEN(unop) - 1; i >= 0; i--) {
            if (unop[i].token == token)
                break;
        }
        if (i >= 0) {
            token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
            token = eval(token, UNARY, res, err, yylvalpp);
            *res = unop[i].op(*res);
        } else {
            goto error;
        }
    }
    while (!*err) {
        if (token == ')' || token == '\n') break;
        for (i = ALEN(binop) - 1; i >= 0; i--) {
            if (binop[i].token == token)
                break;
        }
        if (i < 0 || binop[i].prec <= prec)
            break;
        val = *res;
        token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
        token = eval(token, binop[i].prec, res, err, yylvalpp);
        
        if (binop[i].op == op_div || binop[i].op == op_mod)
        {
            if (*res == 0)
            {
                CPPErrorToInfoLog("preprocessor divide or modulo by zero");
                *err = 1;
                return token;
            }
        }

        *res = binop[i].op(val, *res);
    }
    return token;
error:
    CPPErrorToInfoLog("incorrect preprocessor directive");
    *err = 1;
    *res = 0;
    return token;
} // eval