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_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;

View File

@ -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 {

View File

@ -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);
};

View File

@ -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;

View File

@ -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 },
};

View File

@ -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