Nasal: support for standard bitwise operators.

This makes bitwise operations a lot easier^^
This commit is contained in:
Thomas Geymayer 2014-06-17 16:13:53 +02:00
parent 2c41c25fcd
commit 9aa5c3b2ae
6 changed files with 62 additions and 12 deletions

View File

@ -592,6 +592,9 @@ static naRef run(naContext ctx)
case OP_LTE: BINOP(l <= r ? 1 : 0); break; case OP_LTE: BINOP(l <= r ? 1 : 0); break;
case OP_GT: 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_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 #undef BINOP
case OP_EQ: case OP_NEQ: case OP_EQ: case OP_NEQ:
@ -605,6 +608,9 @@ static naRef run(naContext ctx)
case OP_NEG: case OP_NEG:
STK(1) = naNum(-numify(ctx, STK(1))); STK(1) = naNum(-numify(ctx, STK(1)));
break; break;
case OP_BIT_NEG:
STK(1) = naNum(~(int)numify(ctx, STK(1)));
break;
case OP_NOT: case OP_NOT:
STK(1) = naNum(boolify(ctx, STK(1)) ? 0 : 1); STK(1) = naNum(boolify(ctx, STK(1)) ? 0 : 1);
break; break;

View File

@ -26,7 +26,8 @@ enum {
OP_MEMBER, OP_SETMEMBER, OP_LOCAL, OP_SETLOCAL, OP_NEWVEC, OP_VAPPEND, 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_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_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 { struct Frame {

View File

@ -166,6 +166,15 @@ static int defArg(struct Parser* p, struct Token* t)
RIGHT(t)->num *= -1; RIGHT(t)->num *= -1;
return defArg(p, RIGHT(t)); 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); 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!) genExpr(p, RIGHT(t)); // unary negation (see also TOK_MINUS!)
emit(p, OP_NEG); emit(p, OP_NEG);
break; 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: case TOK_DOT:
genExpr(p, LEFT(t)); genExpr(p, LEFT(t));
if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL) 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: case TOK_AND: case TOK_OR:
genShortCircuit(p, t); genShortCircuit(p, t);
break; 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_MUL: genBinOp(OP_MUL, p, t); break;
case TOK_PLUS: genBinOp(OP_PLUS, p, t); break; case TOK_PLUS: genBinOp(OP_PLUS, p, t); break;
case TOK_DIV: genBinOp(OP_DIV, 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_LT: genBinOp(OP_LT, p, t); break;
case TOK_LTE: genBinOp(OP_LTE, p, t); break; case TOK_LTE: genBinOp(OP_LTE, p, t); break;
case TOK_EQ: genBinOp(OP_EQ, 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_MULEQ: genEqOp(OP_MUL, p, t); break;
case TOK_DIVEQ: genEqOp(OP_DIV, p, t); break; case TOK_DIVEQ: genEqOp(OP_DIV, p, t); break;
case TOK_CATEQ: genEqOp(OP_CAT, 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: default:
naParseError(p, "parse error", t->line); naParseError(p, "parse error", t->line);
}; };

View File

@ -8,6 +8,9 @@ static const struct Lexeme {
{"and", TOK_AND}, {"and", TOK_AND},
{"or", TOK_OR}, {"or", TOK_OR},
{"!", TOK_NOT}, {"!", TOK_NOT},
{"&", TOK_BIT_AND},
{"|", TOK_BIT_OR},
{"^", TOK_BIT_XOR},
{"(", TOK_LPAR}, {"(", TOK_LPAR},
{")", TOK_RPAR}, {")", TOK_RPAR},
{"[", TOK_LBRA}, {"[", TOK_LBRA},
@ -49,6 +52,9 @@ static const struct Lexeme {
{"*=", TOK_MULEQ}, {"*=", TOK_MULEQ},
{"/=", TOK_DIVEQ}, {"/=", TOK_DIVEQ},
{"~=", TOK_CATEQ}, {"~=", TOK_CATEQ},
{"&=", TOK_BIT_ANDEQ},
{"|=", TOK_BIT_OREQ},
{"^=", TOK_BIT_XOREQ},
{"forindex", TOK_FORINDEX}, {"forindex", TOK_FORINDEX},
}; };
@ -136,13 +142,14 @@ static void newToken(struct Parser* p, int pos, int type,
tok->lastChild = 0; tok->lastChild = 0;
tok->rule = 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 // equal or higher precedence must be a unary negation. Needed to
// get precedence right in the parser for expressiong like "a * -2" // 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; int pt = tok->prev->type;
if(pt==TOK_PLUS||pt==TOK_MINUS||pt==TOK_CAT||pt==TOK_MUL||pt==TOK_DIV) if( pt==TOK_PLUS||pt==TOK_MINUS||pt==TOK_CAT||pt==TOK_MUL||pt==TOK_DIV
tok->type = type = TOK_NEG; || 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; if(!p->tree.children) p->tree.children = tok;

View File

@ -5,7 +5,7 @@
// Static precedence table, from low (loose binding, do first) to high // Static precedence table, from low (loose binding, do first) to high
// (tight binding, do last). // (tight binding, do last).
#define MAX_PREC_TOKS 6 #define MAX_PREC_TOKS 9
static const struct precedence { static const struct precedence {
int toks[MAX_PREC_TOKS]; int toks[MAX_PREC_TOKS];
int rule; int rule;
@ -14,16 +14,22 @@ static const struct precedence {
{ { TOK_ELLIPSIS }, PREC_SUFFIX }, { { TOK_ELLIPSIS }, PREC_SUFFIX },
{ { TOK_RETURN, TOK_BREAK, TOK_CONTINUE }, PREC_PREFIX }, { { TOK_RETURN, TOK_BREAK, TOK_CONTINUE }, PREC_PREFIX },
{ { TOK_ASSIGN, TOK_PLUSEQ, TOK_MINUSEQ, { { 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_COLON, TOK_QUESTION }, PREC_REVERSE },
{ { TOK_VAR }, PREC_PREFIX }, { { TOK_VAR }, PREC_PREFIX },
{ { TOK_BIT_OR }, PREC_BINARY },
{ { TOK_BIT_XOR }, PREC_BINARY },
{ { TOK_BIT_AND }, PREC_BINARY },
{ { TOK_OR }, PREC_BINARY }, { { TOK_OR }, PREC_BINARY },
{ { TOK_AND }, PREC_BINARY }, { { TOK_AND }, PREC_BINARY },
{ { TOK_EQ, TOK_NEQ }, PREC_BINARY }, { { TOK_EQ, TOK_NEQ }, PREC_BINARY },
{ { TOK_LT, TOK_LTE, TOK_GT, TOK_GTE }, PREC_BINARY }, { { TOK_LT, TOK_LTE, TOK_GT, TOK_GTE }, PREC_BINARY },
{ { TOK_PLUS, TOK_MINUS, TOK_CAT }, PREC_BINARY }, { { TOK_PLUS, TOK_MINUS, TOK_CAT }, PREC_BINARY },
{ { TOK_MUL, TOK_DIV }, 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_LPAR, TOK_LBRA }, PREC_SUFFIX },
{ { TOK_DOT }, PREC_BINARY }, { { TOK_DOT }, PREC_BINARY },
}; };

View File

@ -8,15 +8,16 @@
#include "code.h" #include "code.h"
enum tok { 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_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_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_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_IF, TOK_ELSIF, TOK_ELSE, TOK_FOR, TOK_FOREACH, TOK_WHILE,
TOK_RETURN, TOK_BREAK, TOK_CONTINUE, TOK_FUNC, TOK_SYMBOL, TOK_RETURN, TOK_BREAK, TOK_CONTINUE, TOK_FUNC, TOK_SYMBOL,
TOK_LITERAL, TOK_EMPTY, TOK_NIL, TOK_ELLIPSIS, TOK_QUESTION, TOK_VAR, TOK_LITERAL, TOK_EMPTY, TOK_NIL, TOK_ELLIPSIS, TOK_QUESTION, TOK_VAR,
TOK_PLUSEQ, TOK_MINUSEQ, TOK_MULEQ, TOK_DIVEQ, TOK_CATEQ, TOK_PLUSEQ, TOK_MINUSEQ, TOK_MULEQ, TOK_DIVEQ, TOK_CATEQ, TOK_BIT_ANDEQ,
TOK_FORINDEX TOK_BIT_OREQ, TOK_BIT_XOREQ, TOK_FORINDEX
}; };
// Precedence rules // Precedence rules