diff --git a/simgear/nasal/code.c b/simgear/nasal/code.c index 5f94217f..2f75220e 100644 --- a/simgear/nasal/code.c +++ b/simgear/nasal/code.c @@ -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; diff --git a/simgear/nasal/code.h b/simgear/nasal/code.h index 4ff27afc..e7cb3f39 100644 --- a/simgear/nasal/code.h +++ b/simgear/nasal/code.h @@ -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 { diff --git a/simgear/nasal/codegen.c b/simgear/nasal/codegen.c index bc36a817..495456a6 100644 --- a/simgear/nasal/codegen.c +++ b/simgear/nasal/codegen.c @@ -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); }; diff --git a/simgear/nasal/lex.c b/simgear/nasal/lex.c index b0dcf5f3..92777ff9 100644 --- a/simgear/nasal/lex.c +++ b/simgear/nasal/lex.c @@ -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; diff --git a/simgear/nasal/parse.c b/simgear/nasal/parse.c index 2e66d8fe..e5b012fa 100644 --- a/simgear/nasal/parse.c +++ b/simgear/nasal/parse.c @@ -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 }, }; diff --git a/simgear/nasal/parse.h b/simgear/nasal/parse.h index 1574ea30..39bfbe05 100644 --- a/simgear/nasal/parse.h +++ b/simgear/nasal/parse.h @@ -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