case OP_LTE: BINOP(l <= r ? 1 : 0); break;
case OP_GT: BINOP(l > r ? 1 : 0); break;
case OP_GTE: BINOP(l >= r ? 1 : 0); break;
+ case OP_BIT_AND: BINOP((int)l & (int)r); break;
+ case OP_BIT_OR: BINOP((int)l | (int)r); break;
+ case OP_BIT_XOR: BINOP((int)l ^ (int)r); break;
#undef BINOP
case OP_EQ: case OP_NEQ:
case OP_NEG:
STK(1) = naNum(-numify(ctx, STK(1)));
break;
+ case OP_BIT_NEG:
+ STK(1) = naNum(~(int)numify(ctx, STK(1)));
+ break;
case OP_NOT:
STK(1) = naNum(boolify(ctx, STK(1)) ? 0 : 1);
break;
OP_MEMBER, OP_SETMEMBER, OP_LOCAL, OP_SETLOCAL, OP_NEWVEC, OP_VAPPEND,
OP_NEWHASH, OP_HAPPEND, OP_MARK, OP_UNMARK, OP_BREAK, OP_SETSYM, OP_DUP2,
OP_INDEX, OP_BREAK2, OP_PUSHEND, OP_JIFTRUE, OP_JIFNOT, OP_FCALLH,
- OP_MCALLH, OP_XCHG2, OP_UNPACK, OP_SLICE, OP_SLICE2
+ OP_MCALLH, OP_XCHG2, OP_UNPACK, OP_SLICE, OP_SLICE2, OP_BIT_AND, OP_BIT_OR,
+ OP_BIT_XOR, OP_BIT_NEG
};
struct Frame {
RIGHT(t)->num *= -1;
return defArg(p, RIGHT(t));
}
+ if(t->type == TOK_CAT && RIGHT(t) &&
+ RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str)
+ {
+ /* default arguments are constants, but "~1" parses as two
+ * tokens, so we have to subset the expression generator for that
+ * case */
+ RIGHT(t)->num = ~(int)RIGHT(t)->num;
+ return defArg(p, RIGHT(t));
+ }
return findConstantIndex(p, t);
}
genExpr(p, RIGHT(t)); // unary negation (see also TOK_MINUS!)
emit(p, OP_NEG);
break;
+ case TOK_CAT:
+ if(BINARY(t)) {
+ genBinOp(OP_CAT, p, t); // string concatenation
+ } else if(RIGHT(t) && RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
+ RIGHT(t)->num = ~(int)RIGHT(t)->num; // Pre-negate constants
+ genScalarConstant(p, RIGHT(t));
+ } else {
+ genExpr(p, RIGHT(t)); // unary, bitwise negation
+ emit(p, OP_BIT_NEG);
+ }
+ break;
+ case TOK_BIT_NEG:
+ genExpr(p, RIGHT(t)); // unary, bitwise negation (see also TOK_CAT!)
+ emit(p, OP_BIT_NEG);
+ break;
case TOK_DOT:
genExpr(p, LEFT(t));
if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL)
case TOK_AND: case TOK_OR:
genShortCircuit(p, t);
break;
+ case TOK_BIT_AND:genBinOp(OP_BIT_AND, p, t); break;
+ case TOK_BIT_OR: genBinOp(OP_BIT_OR, p, t); break;
+ case TOK_BIT_XOR:genBinOp(OP_BIT_XOR, p, t); break;
case TOK_MUL: genBinOp(OP_MUL, p, t); break;
case TOK_PLUS: genBinOp(OP_PLUS, p, t); break;
case TOK_DIV: genBinOp(OP_DIV, p, t); break;
- case TOK_CAT: genBinOp(OP_CAT, p, t); break;
case TOK_LT: genBinOp(OP_LT, p, t); break;
case TOK_LTE: genBinOp(OP_LTE, p, t); break;
case TOK_EQ: genBinOp(OP_EQ, p, t); break;
case TOK_MULEQ: genEqOp(OP_MUL, p, t); break;
case TOK_DIVEQ: genEqOp(OP_DIV, p, t); break;
case TOK_CATEQ: genEqOp(OP_CAT, p, t); break;
+ case TOK_BIT_ANDEQ: genEqOp(OP_BIT_AND, p, t); break;
+ case TOK_BIT_OREQ: genEqOp(OP_BIT_OR, p, t); break;
+ case TOK_BIT_XOREQ: genEqOp(OP_BIT_XOR, p, t); break;
default:
naParseError(p, "parse error", t->line);
};
{"and", TOK_AND},
{"or", TOK_OR},
{"!", TOK_NOT},
+ {"&", TOK_BIT_AND},
+ {"|", TOK_BIT_OR},
+ {"^", TOK_BIT_XOR},
{"(", TOK_LPAR},
{")", TOK_RPAR},
{"[", TOK_LBRA},
{"*=", TOK_MULEQ},
{"/=", TOK_DIVEQ},
{"~=", TOK_CATEQ},
+ {"&=", TOK_BIT_ANDEQ},
+ {"|=", TOK_BIT_OREQ},
+ {"^=", TOK_BIT_XOREQ},
{"forindex", TOK_FORINDEX},
};
tok->lastChild = 0;
tok->rule = 0;
- // Context sensitivity hack: a "-" following a binary operator of
+ // Context sensitivity hack: a "-" or "~" following a binary operator of
// equal or higher precedence must be a unary negation. Needed to
// get precedence right in the parser for expressiong like "a * -2"
- if(type == TOK_MINUS && tok->prev) {
+ if((type == TOK_MINUS || type == TOK_CAT) && tok->prev) {
int pt = tok->prev->type;
- if(pt==TOK_PLUS||pt==TOK_MINUS||pt==TOK_CAT||pt==TOK_MUL||pt==TOK_DIV)
- tok->type = type = TOK_NEG;
+ if( pt==TOK_PLUS||pt==TOK_MINUS||pt==TOK_CAT||pt==TOK_MUL||pt==TOK_DIV
+ || pt==TOK_BIT_AND||pt==TOK_BIT_OR||pt==TOK_BIT_XOR )
+ tok->type = type = (type == TOK_MINUS ? TOK_NEG : TOK_BIT_NEG);
}
if(!p->tree.children) p->tree.children = tok;
// Static precedence table, from low (loose binding, do first) to high
// (tight binding, do last).
-#define MAX_PREC_TOKS 6
+#define MAX_PREC_TOKS 9
static const struct precedence {
int toks[MAX_PREC_TOKS];
int rule;
{ { TOK_ELLIPSIS }, PREC_SUFFIX },
{ { TOK_RETURN, TOK_BREAK, TOK_CONTINUE }, PREC_PREFIX },
{ { TOK_ASSIGN, TOK_PLUSEQ, TOK_MINUSEQ,
- TOK_MULEQ, TOK_DIVEQ, TOK_CATEQ }, PREC_REVERSE },
+ TOK_MULEQ, TOK_DIVEQ, TOK_CATEQ,
+ TOK_BIT_ANDEQ, TOK_BIT_OREQ,
+ TOK_BIT_XOREQ }, PREC_REVERSE },
{ { TOK_COLON, TOK_QUESTION }, PREC_REVERSE },
{ { TOK_VAR }, PREC_PREFIX },
+ { { TOK_BIT_OR }, PREC_BINARY },
+ { { TOK_BIT_XOR }, PREC_BINARY },
+ { { TOK_BIT_AND }, PREC_BINARY },
{ { TOK_OR }, PREC_BINARY },
{ { TOK_AND }, PREC_BINARY },
{ { TOK_EQ, TOK_NEQ }, PREC_BINARY },
{ { TOK_LT, TOK_LTE, TOK_GT, TOK_GTE }, PREC_BINARY },
{ { TOK_PLUS, TOK_MINUS, TOK_CAT }, PREC_BINARY },
{ { TOK_MUL, TOK_DIV }, PREC_BINARY },
- { { TOK_MINUS, TOK_NEG, TOK_NOT }, PREC_PREFIX },
+ { { TOK_MINUS, TOK_NEG, TOK_NOT,
+ TOK_CAT, TOK_BIT_NEG }, PREC_PREFIX },
{ { TOK_LPAR, TOK_LBRA }, PREC_SUFFIX },
{ { TOK_DOT }, PREC_BINARY },
};
#include "code.h"
enum tok {
- TOK_TOP=1, TOK_AND, TOK_OR, TOK_NOT, TOK_LPAR, TOK_RPAR, TOK_LBRA,
+ TOK_TOP=1, TOK_AND, TOK_OR, TOK_NOT, TOK_BIT_AND, TOK_BIT_OR, TOK_BIT_XOR,
+ TOK_BIT_NEG, TOK_LPAR, TOK_RPAR, TOK_LBRA,
TOK_RBRA, TOK_LCURL, TOK_RCURL, TOK_MUL, TOK_PLUS, TOK_MINUS, TOK_NEG,
TOK_DIV, TOK_CAT, TOK_COLON, TOK_DOT, TOK_COMMA, TOK_SEMI,
TOK_ASSIGN, TOK_LT, TOK_LTE, TOK_EQ, TOK_NEQ, TOK_GT, TOK_GTE,
TOK_IF, TOK_ELSIF, TOK_ELSE, TOK_FOR, TOK_FOREACH, TOK_WHILE,
TOK_RETURN, TOK_BREAK, TOK_CONTINUE, TOK_FUNC, TOK_SYMBOL,
TOK_LITERAL, TOK_EMPTY, TOK_NIL, TOK_ELLIPSIS, TOK_QUESTION, TOK_VAR,
- TOK_PLUSEQ, TOK_MINUSEQ, TOK_MULEQ, TOK_DIVEQ, TOK_CATEQ,
- TOK_FORINDEX
+ TOK_PLUSEQ, TOK_MINUSEQ, TOK_MULEQ, TOK_DIVEQ, TOK_CATEQ, TOK_BIT_ANDEQ,
+ TOK_BIT_OREQ, TOK_BIT_XOREQ, TOK_FORINDEX
};
// Precedence rules