GCC上古版本(3.4)还有yacc,学习GCC如何实现if else 嵌套的问题。即:
else后面的if到底是else if语义
if (xxx)
a=1
else if (xxx) a=2
还是 else (语法块中的if else)。
if (xxx)
a=1
else
if (xxx) a = 2 else a=2;
PostgreSQL中因为没有else if语法,只有elif,所以语法规则实现比较简单,没有dangling else的问题。
stmt_if : K_IF expr_until_then proc_sect stmt_elsifs stmt_else K_END K_IF ';'
{
PLpgSQL_stmt_if *new;
new = palloc0(sizeof(PLpgSQL_stmt_if));
new->cmd_type = PLPGSQL_STMT_IF;
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->cond = $2;
new->then_body = $3;
new->elsif_list = $4;
new->else_body = $5;
$$ = (PLpgSQL_stmt *)new;
}
;
stmt_elsifs :
{
$$ = NIL;
}
| stmt_elsifs K_ELSIF expr_until_then proc_sect
{
PLpgSQL_if_elsif *new;
new = palloc0(sizeof(PLpgSQL_if_elsif));
new->lineno = plpgsql_location_to_lineno(@2);
new->cond = $3;
new->stmts = $4;
$$ = lappend($1, new);
}
;
stmt_else :
{
$$ = NIL;
}
| K_ELSE proc_sect
{
$$ = $2;
}
;
那么C语言中支持else if的语法: c-parse
%token IF ELSE
%nonassoc IF
%nonassoc ELSE
select_or_iter_stmt:
simple_if ELSE
{
c_expand_start_else ();
$<itype>1 = stmt_count;
}
c99_block_lineno_labeled_stmt
{
c_finish_else ();
c_expand_end_cond ();
if (extra_warnings && stmt_count == $<itype>1)
warning ("empty body in an else-statement");
}
| simple_if %prec IF
{
c_expand_end_cond ();
if (extra_warnings && stmt_count++ == $<itype>1)
warning ("%Hempty body in an if-statement",&if_stmt_locus);
}
| simple_if ELSE error
{ c_expand_end_cond (); }
注意递归部分是simple_if:
《使用优先级解决shift/reduce冲突的经典例子(%prec UMINUS)》
https://www.gnu.org/software/bison/manual/bison.html#Shift_002fReduce