Nasal: support for standard bitwise operators.
This makes bitwise operations a lot easier^^
This commit is contained in:
parent
2c41c25fcd
commit
9aa5c3b2ae
@ -592,6 +592,9 @@ static naRef run(naContext ctx)
|
||||
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:
|
||||
@ -605,6 +608,9 @@ static naRef run(naContext ctx)
|
||||
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;
|
||||
|
@ -26,7 +26,8 @@ enum {
|
||||
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 {
|
||||
|
@ -166,6 +166,15 @@ static int defArg(struct Parser* p, struct Token* t)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -678,6 +687,21 @@ static void genExpr(struct Parser* p, struct Token* 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)
|
||||
@ -690,10 +714,12 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
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;
|
||||
@ -705,6 +731,9 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
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);
|
||||
};
|
||||
|
@ -8,6 +8,9 @@ static const struct Lexeme {
|
||||
{"and", TOK_AND},
|
||||
{"or", TOK_OR},
|
||||
{"!", TOK_NOT},
|
||||
{"&", TOK_BIT_AND},
|
||||
{"|", TOK_BIT_OR},
|
||||
{"^", TOK_BIT_XOR},
|
||||
{"(", TOK_LPAR},
|
||||
{")", TOK_RPAR},
|
||||
{"[", TOK_LBRA},
|
||||
@ -49,6 +52,9 @@ static const struct Lexeme {
|
||||
{"*=", TOK_MULEQ},
|
||||
{"/=", TOK_DIVEQ},
|
||||
{"~=", TOK_CATEQ},
|
||||
{"&=", TOK_BIT_ANDEQ},
|
||||
{"|=", TOK_BIT_OREQ},
|
||||
{"^=", TOK_BIT_XOREQ},
|
||||
{"forindex", TOK_FORINDEX},
|
||||
};
|
||||
|
||||
@ -136,13 +142,14 @@ static void newToken(struct Parser* p, int pos, int type,
|
||||
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;
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
// 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;
|
||||
@ -14,16 +14,22 @@ static const struct precedence {
|
||||
{ { 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 },
|
||||
};
|
||||
|
@ -8,15 +8,16 @@
|
||||
#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
|
||||
|
Loading…
Reference in New Issue
Block a user