Mercurial > hg > index.cgi
diff lwcc/cc-parse.c @ 502:14a40f8bb4eb
Add various operators to lwcc
Add various binary and ternary operators to lwcc, but only those which can
work with constant operands. Seems like variables are probably required
next.
author | William Astle <lost@l-w.ca> |
---|---|
date | Wed, 25 Sep 2019 20:23:49 -0600 |
parents | f3e9732973f1 |
children | 7e8298f7bc0a |
line wrap: on
line diff
--- a/lwcc/cc-parse.c Tue Sep 24 22:07:56 2019 -0600 +++ b/lwcc/cc-parse.c Wed Sep 25 20:23:49 2019 -0600 @@ -169,6 +169,8 @@ } +node_t *parse_expr_real(struct parser_state *ps, int prec); + node_t *parse_term_real(struct parser_state *ps) { node_t *rv; @@ -185,13 +187,125 @@ return NULL; } +node_t *parse_expr_fncall(struct parser_state *ps, node_t *term1) +{ + if (ps -> curtok -> ttype != TOK_CPAREN) + { + node_destroy(term1); + parse_generr(ps, "missing )"); + return NULL; + } + parse_next(ps); + return node_create(NODE_OPER_FNCALL, term1, NULL); +} + +node_t *parse_expr_postinc(struct parser_state *ps, node_t *term1) +{ + return node_create(NODE_OPER_POSTINC, term1); +} + +node_t *parse_expr_postdec(struct parser_state *ps, node_t *term1) +{ + return node_create(NODE_OPER_POSTDEC, term1); +} + +node_t *parse_expr_subscript(struct parser_state *ps, node_t *term1) +{ + node_t *term2; + term2 = parse_expr_real(ps, 0); + if (!term2) + { + node_destroy(term1); + return NULL; + } + if (ps -> curtok -> ttype != TOK_CSQUARE) + { + node_destroy(term2); + node_destroy(term1); + parse_generr(ps, "missing ]"); + return NULL; + } + parse_next(ps); + return node_create(NODE_OPER_SUBSCRIPT, term1, term2); +} + +node_t *parse_expr_cond(struct parser_state *ps, node_t *term1) +{ + node_t *term2, *term3; + // conditional operator + // NOTE: the middle operand is evaluated as though it is its own + // independent expression because the : must appear. The third + // operand is evaluated at the ternary operator precedence so that + // subsequent operand binding behaves correctly (if surprisingly). This + // would be less confusing if the ternary operator was fully bracketed + // (that is, had a terminator) + term2 = parse_expr_real(ps, 0); + if (!term2) + { + node_destroy(term1); + return NULL; + } + if (ps -> curtok -> ttype == TOK_COLON) + { + parse_next(ps); + term3 = parse_expr_real(ps, 25); + if (!term3) + { + node_destroy(term1); + node_destroy(term2); + return NULL; + } + return node_create(NODE_OPER_COND, term1, term2, term3); + } + else + { + node_destroy(term1); + node_destroy(term2); + parse_generr(ps, "missing :"); + return NULL; + } +} + node_t *parse_expr_real(struct parser_state *ps, int prec) { - static struct { int tok; int nodetype; int prec; } operlist[] = { + static struct { int tok; int nodetype; int prec; int ra; node_t *(*spec)(struct parser_state *, node_t *); } operlist[] = { +// { TOK_OPAREN, NODE_OPER_FNCALL, 200, 0, parse_expr_fncall }, +// { TOK_OSQUARE, NODE_OPER_SUBSCRIPT, 200, 0, parse_expr_subscript }, +// { TOK_ARROW, NODE_OPER_PTRMEM, 200, 0 }, +// { TOK_DOT, NODE_OPER_OBJMEM, 200, 0 }, +// { TOK_DBLADD, NODE_OPER_POSTINC, 200, 0, parse_expr_postinc }, +// { TOK_DBLSUB, NODE_OPER_POSTDEC, 200, 0, parse_expr_postdec }, { TOK_STAR, NODE_OPER_TIMES, 150 }, { TOK_DIV, NODE_OPER_DIVIDE, 150 }, + { TOK_MOD, NODE_OPER_MOD, 150 }, { TOK_ADD, NODE_OPER_PLUS, 100 }, { TOK_SUB, NODE_OPER_MINUS, 100 }, + { TOK_LSH, NODE_OPER_LSH, 90 }, + { TOK_RSH, NODE_OPER_RSH, 90 }, + { TOK_LT, NODE_OPER_LT, 80 }, + { TOK_LE, NODE_OPER_LE, 80 }, + { TOK_GT, NODE_OPER_GT, 80 }, + { TOK_GE, NODE_OPER_GE, 80 }, + { TOK_EQ, NODE_OPER_EQ, 70 }, + { TOK_NE, NODE_OPER_NE, 70 }, + { TOK_BWAND, NODE_OPER_BWAND, 60}, + { TOK_XOR, NODE_OPER_BWXOR, 55 }, + { TOK_BWOR, NODE_OPER_BWOR, 50 }, + { TOK_BAND, NODE_OPER_BAND, 40 }, + { TOK_BOR, NODE_OPER_BOR, 35 }, + { TOK_QMARK, NODE_OPER_COND, 25, 1, parse_expr_cond }, +// { TOK_ASS, NODE_OPER_ASS, 20, 1 }, +// { TOK_ADDASS, NODE_OPER_ADDASS, 20, 1 }, +// { TOK_SUBASS, NODE_OPER_SUBASS, 20, 1 }, +// { TOK_MULASS, NODE_OPER_MULASS, 20, 1 }, +// { TOK_DIVASS, NODE_OPER_DIVASS, 20, 1 }, +// { TOK_MODASS, NODE_OPER_MODASS, 20, 1 }, +// { TOK_LSHASS, NODE_OPER_LSHASS, 20, 1 }, +// { TOK_RSHASS, NODE_OPER_RSHASS, 20, 1 }, +// { TOK_BWANDASS, NODE_OPER_BWANDASS, 20, 1}, +// { TOK_BWORASS, NODE_OPER_BWORASS, 20, 1 }, +// { TOK_XORASS, NODE_OPER_BWXORASS, 20, 1 }, + { TOK_COMMA, NODE_OPER_COMMA, 1 }, { 0, 0, 0 } }; node_t *term1, *term2; @@ -210,16 +324,35 @@ if (operlist[i].tok == 0) return term1; - // is the next operator less or same precedence? - if (operlist[i].prec <= prec) + // is previous operation higher precedence? If so, just return the first term + if (operlist[i].prec < prec) + return term1; + + // is this operator left associative and previous operation is same precedence? + // if so, just return the first term + if (operlist[i].ra == 0 && operlist[i].prec == prec) return term1; + // consume the operator parse_next(ps); + + // special handling + if (operlist[i].spec) + { + term2 = (operlist[i].spec)(ps, term1); + if (!term2) + { + node_destroy(term1); + return NULL; + } + term1 = term2; + goto nextoper; + } term2 = parse_expr_real(ps, operlist[i].prec); if (!term2) { parse_generr(ps, "expr"); - node_destroy(term2); + node_destroy(term1); } term1 = node_create(operlist[i].nodetype, term1, term2);