/* * PARSE3.C - The expression parser * * (c)Copyright 1993-2014, Matthew Dillon, All Rights Reserved. See the * COPYRIGHT file at the base of the distribution. */ #include "defs.h" static Exp *pushOper(Parse *p, Exp **op, Exp **val, int t, string_t id, int flags); static Exp *pushValue(Parse *p, Exp **op, Exp **val, int t, string_t id); static void pushValueExp(Exp **op, Exp **val, Exp *exp); static int popExp(Exp **op, Exp **val); int ParseExp(Parse *p, int t, Exp **pexp) { Exp *opStack = NULL; Exp *valStack = NULL; Exp *tmp; int save; int mode = 1; /* start in unary mode */ int done = 0; int t2; while ((t & TOKF_ERROR) == 0 && !done) { if (mode == 1) { /* * UNARY */ switch(t) { case TOK_ASS: /* syntax error */ case TOK_ANDAND: /* syntax error */ case TOK_OROR: /* syntax error */ case TOK_DOT: /* syntax error */ case TOK_STRIND: /* syntax error */ t = LexError(&p->p_Token, TOK_ERR_EXP_SYNTAX); break; case TOK_OPER: /* unary operator */ /* * We have to deal with pointer indirection. * Regenerate the token using only the first * character if it is a '*' */ switch(p->p_Token.t_Ptr[0]) { case '*': t = LexRedactToken(&p->p_Token, 1); t = TOK_PTRIND; break; case '&': t = LexRedactToken(&p->p_Token, 1); t = TOK_ADDR; break; default: break; } pushOper(p, &opStack, &valStack, t, StrTableToken(&p->p_Token), EXF_UNARY); t = LexToken(&p->p_Token); break; case TOK_OBRACKET: /* * Bracketed array. This is similar to a * compound expression except it represents * elements of an array. */ t = ParseBracketedExp(p, t, &tmp); pushValueExp(&opStack, &valStack, tmp); mode = 2; break; case TOK_CBRACKET: /* syntax error */ t = LexError(&p->p_Token, TOK_ERR_EXP_SYNTAX); break; case TOK_OPAREN: /* ( [id:]exp[, [id:]exp]* ) */ /* * Parenthesized expression: Either a compound * expression (which might degenerate back * into a normal expression in the resolver), * or a cast. * * (typeof(blah)) is supported as a cast. * We may have to save (blah) for the resolver, * store it in ex_Rhs as a special case. */ t2 = LexPeekToken(&p->p_Token); if (t2 == TOK_TYPEOF) { Exp *save2; t = LexSkipToken(&p->p_Token, TOK_OPAREN); assert(t == TOK_TYPEOF); t = ParseExp(p, t, &save2); t = LexSkipToken(&p->p_Token, TOK_CPAREN); /* * This is nasty, but easy to parse * so... allow selection on a cast * as if it were a type. */ if (t == TOK_DOT) { tmp = pushValue(p, &opStack, &valStack, TOK_TYPE, NULL); mode = 2; } else { tmp = pushOper(p, &opStack, &valStack, TOK_CAST, NULL, EXF_UNARY); } tmp->ex_Type = save2->ex_Type; tmp->ex_Flags |= save2->ex_Flags & (EXF_PARSE_TYPE | EXF_REQ_TYPE); if (save2->ex_Flags & EXF_PARSE_TYPE) FreeExp(save2); else tmp->ex_Rhs = save2; } else if ((t2 & (TOKF_SCOPE_QUAL | TOKF_STOR_QUAL)) || t2 == TOK_CLASSID) { Type *type; Scope scope; int sqflags; int rqflags; string_t id = NULL; t = LexSkipToken(&p->p_Token, TOK_OPAREN); /* ignore scope */ t = ParseScopeQual(p, t, &scope); t = ParseStorageQual(p, t, &sqflags); if (scope.s_Flags & SCOPE_LVALUE) rqflags = SF_LVALUE; else rqflags = 0; t = ParseType(p, t, &type, sqflags); t = ParseDeclType(p, t, &type, NULL, scope.s_Flags & SCOPE_CLANG, rqflags, &id, 0); t = LexSkipToken(&p->p_Token, TOK_CPAREN); /* * This is nasty, but easy to parse * so... allow selection on a cast * as if it were a type. */ if (t == TOK_DOT) { tmp = pushValue(p, &opStack, &valStack, TOK_TYPE, NULL); mode = 2; } else { tmp = pushOper(p, &opStack, &valStack, TOK_CAST, NULL, EXF_UNARY); } tmp->ex_Type = type; tmp->ex_Flags |= EXF_PARSE_TYPE; } else { t = ParseParenthesizedExp(p, t, &tmp, 1); pushValueExp(&opStack, &valStack, tmp); mode = 2; } break; case TOK_DSTRING: /* value */ case TOK_SSTRING: /* value */ case TOK_BSTRING: /* value */ case TOK_INTEGER: /* value */ case TOK_FLOAT: /* value */ pushValue(p, &opStack, &valStack, t, StrTableToken(&p->p_Token)); t = LexToken(&p->p_Token); mode = 2; break; case TOK_SIZEOF: case TOK_ARYSIZE: case TOK_TYPEOF: /* * We can distinguish between expressions and * types by identifying a scope or storage * qualifier or a type-flagged identifier. */ save = t; t = LexToken(&p->p_Token); if (t == TOK_OPAREN) t2 = LexPeekToken(&p->p_Token); else t2 = 0; if (t == TOK_OPAREN && ((t2 & (TOKF_SCOPE_QUAL | TOKF_STOR_QUAL)) || t2 == TOK_CLASSID) ) { Scope scope; int sqflags; int rqflags; string_t id = NULL; Type *type; t = LexSkipToken(&p->p_Token, TOK_OPAREN); /* ignore scope */ t = ParseScopeQual(p, t, &scope); t = ParseStorageQual(p, t, &sqflags); if (scope.s_Flags & SCOPE_LVALUE) rqflags = SF_LVALUE; else rqflags = 0; tmp = WrapExp(&p->p_Token, NULL, save); t = ParseType(p, t, &type, sqflags); t = ParseDeclType(p, t, &type, NULL, scope.s_Flags & SCOPE_CLANG, rqflags, &id, 0); tmp->ex_Type = type; tmp->ex_Flags |= EXF_PARSE_TYPE | EXF_RET_TYPE; } else { t = LexSkipToken(&p->p_Token, TOK_OPAREN); t = ParseExp(p, t, &tmp); /* XXX why was this here? if (tmp->ex_Lhs) tmp->ex_Flags |= EXF_UNARY; */ tmp = WrapExp(&p->p_Token, tmp, save); } #if 0 /* * XXX removed because this can cause dynamic * type resolution at run-time to occur. */ if (t == TOK_COMMA) { /* * remove storage qualifiers */ t = LexToken(&p->p_Token); t = ParseStorageQual(p, t, &tmp->ex_AuxFlags[0]); } if (t == TOK_COMMA) { /* * add storage qualifiers */ t = LexToken(&p->p_Token); t = ParseStorageQual(p, t, &tmp->ex_AuxFlags[1]); } #endif /* XXX why was this here? if (tmp->ex_Lhs) tmp->ex_Flags |= EXF_UNARY; */ pushValueExp(&opStack, &valStack, tmp); t = LexSkipToken(&p->p_Token, TOK_CPAREN); mode = 2; break; case TOK_ID: /* value: semantic id */ case TOK_CLASSID: /* value: semantic id */ pushValue(p, &opStack, &valStack, t, StrTableToken(&p->p_Token)); t = LexToken(&p->p_Token); mode = 2; break; case TOK_SELF: /* * Identifies the procedure's argument space. */ pushValue(p, &opStack, &valStack, t, NULL); t = LexToken(&p->p_Token); mode = 2; break; case TOK_DOLLAR: /* * Identifies the procedure's return storage. */ pushValue(p, &opStack, &valStack, t, NULL); t = LexToken(&p->p_Token); mode = 2; break; case TOK_CPAREN: /* syntax error */ case TOK_CBRACE: /* syntax error */ case TOK_COMMA: /* syntax error */ case TOK_SEMI: /* syntax error */ case TOK_COLON: /* syntax error */ default: t = LexError(&p->p_Token, TOK_ERR_EXP_SYNTAX); break; } } else { /* * BINARY */ switch(t) { case TOK_ASS: case TOK_ANDAND: /* binary operator */ case TOK_OROR: /* binary operator */ case TOK_DOT: /* binary operator */ case TOK_STRIND: /* binary operator */ case TOK_OPER: /* binary operator */ pushOper(p, &opStack, &valStack, t, StrTableToken(&p->p_Token), EXF_BINARY); t = LexToken(&p->p_Token); mode = 1; break; case TOK_OBRACKET: /* '[' array operator */ t = LexToken(&p->p_Token); tmp = NULL; t = ParseExp(p, t, &tmp); t = LexSkipToken(&p->p_Token, TOK_CBRACKET); pushOper(p, &opStack, &valStack, TOK_OBRACKET, NULL, EXF_BINARY); pushValueExp(&opStack, &valStack, tmp); break; case TOK_CBRACKET: /* ']' terminator */ done = 1; break; case TOK_OPAREN: /* * Procedure call. In order to avoid * fubar((x, y)) confusion we do not allow * ParseParenthesizedExp() to generate a * compound exp encapsulation for comma * delimited case. Instead we do it ourselves. */ t = ParseParenthesizedExp(p, t, &tmp, 0); tmp = ExpToCompoundExp(tmp, TOK_COMPOUND); pushOper(p, &opStack, &valStack, TOK_CALL, NULL, EXF_BINARY); pushValueExp(&opStack, &valStack, tmp); break; case TOK_ID: /* syntax error */ case TOK_CLASSID: /* syntax error */ t = LexError(&p->p_Token, TOK_ERR_EXP_SYNTAX_MAYTYPE); break; case TOK_DSTRING: /* syntax error */ case TOK_SSTRING: /* syntax error */ case TOK_BSTRING: /* syntax error */ case TOK_INTEGER: /* syntax error */ case TOK_FLOAT: /* syntax error */ case TOK_SIZEOF: /* syntax error */ case TOK_ARYSIZE: /* syntax error */ case TOK_TYPEOF: /* syntax error */ case TOK_SELF: /* syntax error */ t = LexError(&p->p_Token, TOK_ERR_EXP_SYNTAX); break; case TOK_CPAREN: /* terminator */ case TOK_CBRACE: /* terminator */ case TOK_COMMA: /* terminator */ case TOK_SEMI: /* terminator */ case TOK_COLON: /* terminator */ done = 1; break; default: t = LexError(&p->p_Token, TOK_ERR_EXP_SYNTAX); break; } } } while (opStack) { if (popExp(&opStack, &valStack) < 0) { t = LexError(&p->p_Token, TOK_ERR_EXP_SYNTAX); } } if (valStack == NULL) { t = LexError(&p->p_Token, TOK_ERR_EXP_SYNTAX); } else if (valStack->ex_Next != NULL) { t = LexError(&p->p_Token, TOK_ERR_EXP_SYNTAX); FreeExp(valStack->ex_Next); valStack->ex_Next = NULL; } *pexp = valStack; return(t); } /* * ParseParenthesizedExp() - parse a parenthesized expression. * * This will parse a parenthesized, possibly compound expression. docomp * determines whether the returned expression should be collapsed into * TOK_COMPOUND when there is more then one element, or whether this * should be left up to the caller. Note that if you *REQUIRE* the * result to be compound, you should pass docomp as 0 and call * ExpToCompoundExp() unconditionally on the returned expression * to avoid confusion. * * An empty expression returns a TOK_VOIDEXP exp node. * * NOTE: A single expressive element is considered to be compound if it * is named. */ int ParseParenthesizedExp(Parse *p, int t, Exp **pexp, int docomp) { Exp *tmp = NULL; t = LexSkipToken(&p->p_Token, TOK_OPAREN); if (t != TOK_CPAREN) { Exp **pnext = &tmp; for (;;) { string_t argId = NULL; if (t == TOK_ID || t == TOK_CLASSID/* XXX */) { /* lookahead */ token_t t2 = p->p_Token; if (LexToken(&t2) == TOK_COLON) { argId = StrTableToken(&p->p_Token); /* get the colon */ LexToken(&p->p_Token); t = LexSkipToken(&p->p_Token, TOK_COLON); } } t = ParseExp(p, t, pnext); if (*pnext) { (*pnext)->ex_ArgId = argId; pnext = &(*pnext)->ex_Next; } if (t != TOK_COMMA) break; t = LexToken(&p->p_Token); } } t = LexSkipToken(&p->p_Token, TOK_CPAREN); /* * Generate a non-compound expression for unnamed single-element * parenthesized objects. Set EX2F_WASCOMP in case the resolver * wants to know what we need. */ if (tmp) { if (docomp && (tmp->ex_ArgId || tmp->ex_Next)) tmp = ExpToCompoundExp(tmp, TOK_COMPOUND); else if (docomp) tmp->ex_Flags2 |= EX2F_WASCOMP; } else { tmp = AllocExp(&p->p_Token); tmp->ex_Token = TOK_VOIDEXP; } *pexp = tmp; return(t); } /* * ParseBracketedExp() - parse a bracketed expression. * * This parses an expression representing array elements. The returned * expression is collapsed into TOK_BRACKETED. */ int ParseBracketedExp(Parse *p, int t, Exp **pexp) { Exp *tmp = NULL; t = LexSkipToken(&p->p_Token, TOK_OBRACKET); if (t != TOK_CBRACKET) { Exp **pnext = &tmp; for (;;) { t = ParseExp(p, t, pnext); if (*pnext) { /* XXX use (*pnext)->ex_ArgId for index? */ pnext = &(*pnext)->ex_Next; } if (t != TOK_COMMA) break; t = LexToken(&p->p_Token); } } t = LexSkipToken(&p->p_Token, TOK_CBRACKET); /* * Generate a non-compound expression for unnamed single-element * parenthesized objects. Set EX2F_WASCOMP in case the resolver * wants to know what we need. */ if (tmp) { tmp = ExpToBracketedExp(tmp, TOK_BRACKETED); } else { tmp = AllocExp(&p->p_Token); tmp->ex_Token = TOK_BRACKETED; } *pexp = tmp; return(t); } int ParseNotExp(Parse *p, int t, Exp **pexp) { t = ParseExp(p, t, pexp); if ((t & TOKF_ERROR) == 0) *pexp = ExpToNotExp(*pexp); return(t); } static Exp * pushOper(Parse *p, Exp **op, Exp **val, int t, string_t id, int flags) { Exp *exp; int prec; int rtl = 0; /* right-to-left */ if (flags & EXF_BINARY) { prec = EXPREC_USER; switch(t) { case TOK_OPER: /* * EXPREC_PLUS - contains '+', or '-' * EXPREC_SHIFT - begins '<<' or '>>' * EXPREC_COMPARE - not SHIFT and contains '<', '=', * or '>'. * EXPREC_ASS - not COMPARE and ends with '=' * (also make right-to-left) */ if (strpbrk(id, "+-") != NULL) prec = EXPREC_PLUS; if (id[0] == '<' && id[1] == '<') prec = EXPREC_SHIFT; if (id[0] == '>' && id[1] == '>') prec = EXPREC_SHIFT; if (prec != EXPREC_SHIFT && strpbrk(id, "<=>") != NULL) prec = EXPREC_COMPARE; if (prec != EXPREC_COMPARE && id[strlen(id)-1] == '=') { prec = EXPREC_ASS; rtl = 1; } break; case TOK_DOT: case TOK_STRIND: prec = EXPREC_DOT; break; case TOK_OBRACKET: prec = EXPREC_CLOSURE; break; case TOK_CALL: prec = EXPREC_CALL; break; case TOK_ANDAND: prec = EXPREC_ANDAND; break; case TOK_ASS: prec = EXPREC_ASS; rtl = 1; break; case TOK_OROR: prec = EXPREC_OROR; break; default: dassert_parse(p, TOK_ERR_UNKNOWN, 0); } } else { prec = EXPREC_UNARY; rtl = 1; } /* * Construct the expression */ exp = AllocExp(&p->p_Token); exp->ex_Prec = prec; exp->ex_Id = id; exp->ex_Token = t; exp->ex_Flags |= flags; /* * Pop-off any operators with a >= precedence. Handle * special right-to-left ordering for assignments and unary * operators simply by delaying the pop. */ while (*op) { if ((*op)->ex_Prec > prec) { popExp(op, val); continue; } if (rtl == 0 && (*op)->ex_Prec == prec) { popExp(op, val); continue; } break; } exp->ex_Next = *op; *op = exp; return(exp); } static Exp * pushValue(Parse *p, Exp **op __unused, Exp **val, int t, string_t id) { Exp *exp = AllocExp(&p->p_Token); exp->ex_Token = t; exp->ex_Id = id; exp->ex_Next = *val; *val = exp; return(exp); } static void pushValueExp(Exp **op __unused, Exp **val, Exp *exp) { exp->ex_Next = *val; *val = exp; } static int popExp(Exp **op, Exp **val) { Exp *exp; int r = 0; if ((exp = *op) != NULL) { if (exp->ex_Flags & EXF_BINARY) { Exp *rhs = *val; Exp *lhs = (rhs) ? rhs->ex_Next : NULL; /* * The expression parser will generate an error if * this situation occurs so we can just return. */ if (lhs && rhs) { *val = lhs->ex_Next; lhs->ex_Next = NULL; rhs->ex_Next = NULL; exp->ex_Lhs = lhs; exp->ex_Rhs = rhs; /* * Special handling. */ switch(exp->ex_Token) { case TOK_DOT: /* * Lhs may be a type, class, module, * or variable id. * * Rhs must be an identifier which we * convert to TOK_STRUCT_ID. */ dassert_exp(rhs, rhs->ex_Token == TOK_ID || rhs->ex_Token == TOK_CLASSID); rhs->ex_Token = TOK_STRUCT_ID; break; case TOK_STRIND: /* * Lhs must an lvalue or rvalue (not * checked), Rhs must must be an * identifier which we convert to * TOK_STRUCT_ID. */ dassert_exp(rhs, rhs->ex_Token == TOK_ID || rhs->ex_Token == TOK_CLASSID); rhs->ex_Token = TOK_STRUCT_ID; break; case TOK_CALL: /* * The rhs of a procedure call is a * compound expression, denoted by * TOK_COMPOUND. The compound * expression is necessary to govern * the context the arguments will * eventually be stored in, so we do * not collapse this even if its * a void call. */ dassert_exp(rhs, rhs->ex_Token == TOK_COMPOUND); #if 0 exp->ex_Rhs = rhs->ex_Lhs; rhs->ex_Lhs = NULL; FreeExp(rhs); rhs = NULL; #endif break; case TOK_ANDAND: case TOK_OROR: default: break; } } else { r = -1; } } else { Exp *lhs = *val; if (lhs) { exp->ex_Lhs = lhs; *val = lhs->ex_Next; lhs->ex_Next = NULL; } else { r = -1; } } *op = exp->ex_Next; exp->ex_Next = *val; *val = exp; } return(r); }