From fb420cde5ce1699d689790ffad8493e009a1d13b Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Wed, 15 Oct 2008 23:32:54 +0200 Subject: [PATCH] ternary operator extension make the ?: operator right assoc, so that it behaves like C implement the GNU C extension a?:b B.W. --- Patch: !ternary-operator.patch Patch: +ternary-operator-GNU.patch --- series | 1 + ternary-operator-GNU.patch | 148 +++++++++++++++++++++++++++++++++++++++++++++ ternary-operator.patch | 6 +- 3 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 ternary-operator-GNU.patch diff --git a/series b/series index 025986d..caabfc3 100644 --- a/series +++ b/series @@ -128,3 +128,4 @@ MultipleAssignment-redux.patch MultipleAssignment-selector.patch key-grammar.patch ternary-operator.patch +ternary-operator-GNU.patch diff --git a/ternary-operator-GNU.patch b/ternary-operator-GNU.patch new file mode 100644 index 0000000..278792f --- /dev/null +++ b/ternary-operator-GNU.patch @@ -0,0 +1,148 @@ +--- + + source/interpret.c | 23 +++++++++++++++++++++++ + source/ops.h | 1 + + source/parse.y | 38 ++++++++++++++++++++++++++++++++++++-- + 3 files changed, 60 insertions(+), 2 deletions(-) + +diff --quilt old/source/parse.y new/source/parse.y +--- old/source/parse.y ++++ new/source/parse.y +@@ -96,6 +96,7 @@ static int follow2(char expect1, int yes + static int follow_non_whitespace(char expect, int yes, int no); + static int eq_look_ahead(void); + static int comma_look_ahead(void); ++static int te_look_ahead(void); + static Symbol *matchesActionRoutine(char **inPtr); + static int scanString(void); + +@@ -134,7 +135,7 @@ static int nextSymIsField = 0; + %type lvlist + %type lventry + %token ARGSEP +-%type thenx elsex ++%type thenx elsex thenelsex + + %nonassoc IF_NO_ELSE + %nonassoc ELSE +@@ -142,7 +143,7 @@ static int nextSymIsField = 0; + %nonassoc ';' + %nonassoc SYMBOL ARG_LOOKUP + %right '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ +-%right '?' ':' ++%right '?' ':' TE + %left CONCAT + %left OR + %left AND +@@ -676,6 +677,9 @@ numexpr: '(' blank expr blank ')' + SET_BR_OFF($2, $5 + 1); /* thenx limb ends at $5+1 */ + SET_BR_OFF($5, GetPC()); /* elsex limb ends here */ + } ++ | numexpr thenelsex mark blank numexpr %prec '?' { ++ SET_BR_OFF($2, GetPC()); ++ } + | incrdecr blank SYMBOL %prec INCR { + ADD_OP(OP_PUSH_SYM); ADD_SYM($3); ADD_OP($1); + ADD_OP(OP_DUP); ADD_OP(OP_ASSIGN); ADD_SYM($3); +@@ -738,13 +742,24 @@ or: OR { + ; + + thenx: '?' { ++ ADD_OP(OP_BOOLEANIZE); + ADD_OP(OP_BRANCH_FALSE); $$ = GetPC(); + ADD_BR_OFF(0); + } ++ ; + elsex: ':' { + ADD_OP(OP_BRANCH); $$ = GetPC(); + ADD_BR_OFF(0); + } ++ ; ++thenelsex: TE { ++ ADD_OP(OP_DUP); ++ ADD_OP(OP_BOOLEANIZE); ++ ADD_OP(OP_BRANCH_TRUE); $$ = GetPC(); ++ ADD_BR_OFF(0); ++ ADD_OP(OP_POP); ++ } ++ ; + + dot: '.' %prec '.' { + nextSymIsField = 1; +@@ -936,6 +951,7 @@ static int yylex(void) + return result; /* but return what we started with */ + } + case ',': return comma_look_ahead(); ++ case '?': return te_look_ahead(); + default: return *(InPtr-1); + } + } +@@ -1037,6 +1053,24 @@ static int comma_look_ahead(void) + return ','; + } + ++/* look ahead fo ternary operator without second operand, ie ?: */ ++static int te_look_ahead(void) ++{ ++ char *savedInPtr = InPtr; ++ ++ /* skip any whitespace */ ++ skipWhitespace(); ++ ++ if (*InPtr == ':') { ++ /* eat this */ ++ InPtr++; ++ return TE; ++ } ++ ++ InPtr = savedInPtr; ++ return '?'; ++} ++ + /* + ** Look (way) ahead for hyphenated routine names which begin at inPtr. A + ** hyphenated name is allowed if it is pre-defined in the global symbol +diff --quilt old/source/interpret.c new/source/interpret.c +--- old/source/interpret.c ++++ new/source/interpret.c +@@ -2462,6 +2462,29 @@ static int power(void) + return errCheck("exponentiation"); + } + ++static int booleanize(void) ++{ ++ DataValue dv; ++ int res; ++ ++ DISASM_RT(); ++ STACKDUMP(1, 3); ++ ++ POP(dv); ++ ++ switch (dv.tag) { ++ case INT_TAG: res = !!dv.val.n; break; ++ case STRING_TAG: res = !!dv.val.str.len; break; ++ case ARRAY_TAG: res = !!ArraySize(&dv); break; ++ default: EXEC_ERROR("incompatible type in booleanize context: <%s>", ++ tagToStr(dv.tag)); ++ } ++ ++ PUSH_INT(res); ++ ++ return STAT_OK; ++} ++ + /* + ** A helper routine used in concat(), and makeArrayKeyFromArgs(). Concatenate a + ** number of values from the stack and return the result as a character pointer +diff --quilt old/source/ops.h new/source/ops.h +--- old/source/ops.h ++++ new/source/ops.h +@@ -30,6 +30,7 @@ OP(BIT_OR, bitOr) + OP(AND, and) /* pop(v2,v1), push(v1 && v2) */ + OP(OR, or) /* pop(v2,v1), push(v1 || v2) */ + OP(NOT, not) /* pop(v), push(!v) */ ++OP(BOOLEANIZE, booleanize) /* pop(v), push(!!v) */ + OP(POWER, power) /* pop(v2,v1), push(v1 ** v2) */ + OP(CONCAT, concat) /* pop(s2,s1), push(s1 s2) */ + OP(ASSIGN, assign) /* sym */ /* pop(v), sym.v = v */ diff --git a/ternary-operator.patch b/ternary-operator.patch index 69791a6..91a0fb5 100644 --- a/ternary-operator.patch +++ b/ternary-operator.patch @@ -18,7 +18,7 @@ diff --quilt old/source/parse.y new/source/parse.y %nonassoc ';' %nonassoc SYMBOL ARG_LOOKUP %right '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ -+%left '?' ':' ++%right '?' ':' %left CONCAT %left OR %left AND @@ -26,8 +26,8 @@ diff --quilt old/source/parse.y new/source/parse.y | numexpr or blank numexpr %prec OR { ADD_OP(OP_OR); SET_BR_OFF($2, GetPC()); } -+ | numexpr thenx blank numexpr elsex blank numexpr %prec '?' { -+ SET_BR_OFF($2, $5 + 1); /* thenx limb ends at $5.v+1 */ ++ | numexpr thenx blank expr elsex blank expr %prec '?' { ++ SET_BR_OFF($2, $5 + 1); /* thenx limb ends at $5+1 */ + SET_BR_OFF($5, GetPC()); /* elsex limb ends here */ + } | incrdecr blank SYMBOL %prec INCR { -- 2.11.4.GIT