From 30ee2227daf95d51b602b77eb45e352d3b8e666d Mon Sep 17 00:00:00 2001 From: "ben.franksen" <ben.franksen@online.de> Date: Mon, 22 Aug 2011 10:37:06 +0000 Subject: [PATCH] added support for the C comma operator As turned out, the 2.0.x branch supported this, so it is added for compatibility. --- documentation/Reference.txt | 43 ++++++++++++++++++++++------------ src/snc/snl.lem | 42 +++++++++++++++++++-------------- test/validate/Makefile | 1 + test/validate/commaOperator.st | 30 ++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 33 deletions(-) create mode 100644 test/validate/commaOperator.st diff --git a/documentation/Reference.txt b/documentation/Reference.txt index 1aa97e44..bfcb11b3 100644 --- a/documentation/Reference.txt +++ b/documentation/Reference.txt @@ -799,12 +799,12 @@ Statements statement: "state" `identifier` ";" statement: `c_code` statement: `block` - statement: "if" "(" `expr` ")" `statement` - statement: "if" "(" `expr` ")" `statement` "else" `statement` - statement: "while" "(" `expr` ")" `statement` + statement: "if" "(" `comma_expr` ")" `statement` + statement: "if" "(" `comma_expr` ")" `statement` "else" `statement` + statement: "while" "(" `comma_expr` ")" `statement` statement: `for_statement` statement: `opt_expr` ";" - for_statement: "for" "(" `exprs` ";" `opt_expr` ";" `exprs` ")" `statement` + for_statement: "for" "(" `opt_expr` ";" `opt_expr` ";" `opt_expr` ")" `statement` As can be seen, most C statements are supported. Not supported are the switch/case statement and the return statement. @@ -836,14 +836,14 @@ Parenthesized Expression ~~~~~~~~~~~~~~~~~~~~~~~~ .. productionlist:: - expr: "(" `expr` ")" + expr: "(" `comma_expr` ")" Primary Expression Operators ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. productionlist:: - expr: `identifier` "(" `exprs` ")" - expr: "exit" "(" `exprs` ")" + expr: `identifier` "(" `args` ")" + expr: "exit" "(" `args` ")" expr: `expr` "[" `expr` "]" expr: `expr` "." `expr` expr: `expr` "->" `expr` @@ -924,17 +924,30 @@ Assignment Operators These operators are right-associative. -Expression List -~~~~~~~~~~~~~~~ +Comma Operator +~~~~~~~~~~~~~~ + +.. productionlist:: + comma_expr: `comma_expr` "," `expr` + comma_expr: `expr` + opt_expr: `comma_expr` + opt_expr: + +The comma operator is left associative. An :token:`opt_expr` is +an optional :token:`comma_expr`; it appears, for instance, inside +a :token:`for_statement`. + +Argument List +~~~~~~~~~~~~~ .. productionlist:: - exprs: `exprs` "," `expr` - exprs: `expr` - exprs: + args: `args` "," `expr` + args: `expr` + args: -Comma separated expression lists are not expressions (in SNL), since -SNL does not support the comma operator. However, they appear as parts -of expressions and statements, and then have the same meaning as in C. +Function argument lists look exactly like chained application of the +comma operator, which is why application of the comma operator in an +argument list must be grouped by parentheses. .. _BuiltinFunctions: diff --git a/src/snc/snl.lem b/src/snc/snl.lem index e183e1b6..a489e9b4 100644 --- a/src/snc/snl.lem +++ b/src/snc/snl.lem @@ -55,12 +55,10 @@ in the file LICENSE that is included with this distribution. // PRE and POST are pseudo tokens, they only for the // precedence declaration. -// We do not support the comma operator, except -// in for(;;), where it is built-in. +// The comma operator is implemented as an extra production, +// so we need no explicit precedence for it. // %left COMMA. - -%right EQUAL ADDEQ SUBEQ ANDEQ OREQ - DIVEQ MULEQ MODEQ LSHEQ RSHEQ XOREQ. +%right EQUAL ADDEQ SUBEQ ANDEQ OREQ DIVEQ MULEQ MODEQ LSHEQ RSHEQ XOREQ. %right QUESTION COLON. %left OROR. %left ANDAND. @@ -182,6 +180,7 @@ direct_declarator(p) ::= direct_declarator(x) subscript(s). { p = decl_postfix_array(x, s.str); } // Initializer +// Note: comma operator not allowed in 'expr'. init_expr(p) ::= LBRACE(t) init_exprs(x) RBRACE.{ p = expr(E_INIT, t, x); } init_expr(p) ::= expr(x). { p = x; } @@ -303,22 +302,26 @@ statement(p) ::= STATE NAME(t) SEMICOLON. { p = expr(S_CHANGE, t); } statement(p) ::= c_code(x). { p = x; } statement(p) ::= LBRACE(t) block_defns(ds) statements(xs) RBRACE. { p = expr(S_CMPND, t, ds, xs); } -statement(p) ::= IF(t) LPAREN expr(c) RPAREN statement(th). +statement(p) ::= IF(t) LPAREN comma_expr(c) RPAREN statement(th). { p = expr(S_IF, t, c, th, 0); } -statement(p) ::= IF(t) LPAREN expr(c) RPAREN statement(th) ELSE statement(el). +statement(p) ::= IF(t) LPAREN comma_expr(c) RPAREN statement(th) ELSE statement(el). { p = expr(S_IF, t, c, th, el); } -statement(p) ::= WHILE(t) LPAREN expr(c) RPAREN statement(x). +statement(p) ::= WHILE(t) LPAREN comma_expr(c) RPAREN statement(x). { p = expr(S_WHILE, t, c, x); } statement(p) ::= for_statement(x). { p = x; } statement(p) ::= opt_expr(x) SEMICOLON(t). { p = expr(S_STMT, t, x); } for_statement(p) ::= FOR(for) LPAREN - exprs(init) SEMICOLON opt_expr(cond) SEMICOLON exprs(iter) + opt_expr(init) SEMICOLON opt_expr(cond) SEMICOLON opt_expr(iter) RPAREN statement(st). { p = expr(S_FOR, for, init, cond, iter, st); } // Expressions +// Note: the non-terminal 'expr' does not include application of the comma operator. +// Comma separated lists of 'expr' can be: function arguments (non-terminal +// 'args')and applications of the comma operator (non-terminal 'comma_expr'). + // Atomic expr(p) ::= INTCON(x). { p = expr(E_CONST, x); } expr(p) ::= FPCON(x). { p = expr(E_CONST, x); } @@ -326,11 +329,11 @@ expr(p) ::= string(x). { p = x; } expr(p) ::= variable(v). { p = expr(E_VAR, v); } // Parenthesized -expr(p) ::= LPAREN(t) expr(x) RPAREN. { p = expr(E_PAREN, t, x); } +expr(p) ::= LPAREN(t) comma_expr(x) RPAREN. { p = expr(E_PAREN, t, x); } // Primary Expression and Unary Postfix Operators -expr(p) ::= NAME(t) LPAREN exprs(xs) RPAREN. [POST] { p = expr(E_FUNC, t, xs); } -expr(p) ::= EXIT(t) LPAREN exprs(xs) RPAREN. [POST] { p = expr(E_FUNC, t, xs); } +expr(p) ::= NAME(t) LPAREN args(xs) RPAREN. [POST] { p = expr(E_FUNC, t, xs); } +expr(p) ::= EXIT(t) LPAREN args(xs) RPAREN. [POST] { p = expr(E_FUNC, t, xs); } expr(p) ::= expr(x) LBRACKET(t) expr(y) RBRACKET.[POST] { p = expr(E_SUBSCR, t, x, y); } expr(p) ::= expr(x) PERIOD(t) expr(y). [POST] { p = expr(E_BINOP, t, x, y); } expr(p) ::= expr(x) POINTER(t) expr(y). [POST] { p = expr(E_BINOP, t, x, y); } @@ -384,15 +387,18 @@ expr(p) ::= expr(x) LSHEQ(t) expr(y). { p = expr(E_BINOP, t, x, y); } expr(p) ::= expr(x) RSHEQ(t) expr(y). { p = expr(E_BINOP, t, x, y); } expr(p) ::= expr(x) XOREQ(t) expr(y). { p = expr(E_BINOP, t, x, y); } -// Comma, left-to-right, not supported -// expr(p) ::= expr(x) COMMA(t) expr(y). { p = expr(E_BINOP, t, x, y); } +// Comma, left-to-right +comma_expr(p) ::= comma_expr(xs) COMMA(t) expr(x). { p = expr(E_BINOP, t, xs, x); } +comma_expr(p) ::= expr(x). { p = x; } -opt_expr(p) ::= expr(x). { p = x; } +opt_expr(p) ::= comma_expr(x). { p = x; } opt_expr(p) ::= . { p = 0; } -exprs(p) ::= exprs(xs) COMMA expr(x). { p = link_expr(xs, x); } -exprs(p) ::= expr(x). { p = x; } -exprs(p) ::= . { p = 0; } +// Function arguments +// Ssyntactically the same as opt_expr but interpreted differently. +args(p) ::= args(xs) COMMA expr(x). { p = link_expr(xs, x); } +args(p) ::= expr(x). { p = x; } +args(p) ::= . { p = 0; } string(p) ::= STRCON(t). { p = expr(E_STRING, t); } diff --git a/test/validate/Makefile b/test/validate/Makefile index 2e2f88cc..e7044a34 100644 --- a/test/validate/Makefile +++ b/test/validate/Makefile @@ -37,6 +37,7 @@ REGRESSION_TESTS_WITH_DB += norace REGRESSION_TESTS_WITHOUT_DB += array REGRESSION_TESTS_WITHOUT_DB += assign REGRESSION_TESTS_WITHOUT_DB += change +REGRESSION_TESTS_WITHOUT_DB += commaOperator REGRESSION_TESTS_WITHOUT_DB += local REGRESSION_TESTS_WITHOUT_DB += pvSync REGRESSION_TESTS_WITHOUT_DB += safeMonitor diff --git a/test/validate/commaOperator.st b/test/validate/commaOperator.st new file mode 100644 index 00000000..09439b1e --- /dev/null +++ b/test/validate/commaOperator.st @@ -0,0 +1,30 @@ +/*************************************************************************\ +Copyright (c) 2010-2011 Helmholtz-Zentrum Berlin f. Materialien + und Energie GmbH, Germany (HZB) +This file is distributed subject to a Software License Agreement found +in the file LICENSE that is included with this distribution. +\*************************************************************************/ +program commaOperatorTest + +%%#include "../testSupport.h" + +entry { + testPlan(4); +} + +ss myss { + state doit { + when () { + int i = 0; + /* check associativity (evaluation order) and result */ + testOk1(((i = 1), testOk1(i==1), (i = 2), testOk1(i==2), + (i = 3)) == 3); + testOk1(i == 3); + } exit + } +} + +exit { + testDone(); + seq_test_done(); +} -- GitLab