📄 parser.y
字号:
tr_stmt(yylineno, yytext, yes); tr_vars(0, yyleng); reset(); } | error ';' { puttext(yyleng); } | error '}' { puttext(yyleng); } ;flow_control_stmt : if_stmt | for_stmt | while_stmt | do_stmt | switch_stmt ;flow_break_stmt : break_cont_goto { tr_stmt(yylineno, yytext, yes); puttext(yyleng); } | RETURN opt_exp ';' { tr_stmt(yylineno, yytext, yes); tr_vars(0, yyleng); reset(); }break_cont_goto : BREAK_CONT ';' | GOTO ident ';' ;label : ident ':' | CASE exp ':' | DEFAULT ':' ;pp_if_stmt : PP_IF { putpp(); } stmt_list pp_else_part PP_ENDIF { putpp(); } ;pp_else_part : /* no #else */ | PP_ELSE { putpp(); } stmt_list ;if_stmt : IF '(' exp ')' { tr_stmt(yylineno, yytext, yes); tr_vars(0, yyleng); reset(); putchar('{'); } stmt { putchar('}'); } else_part ;else_part : /* no else */ | ELSE { puttext(yyleng); putchar('{'); tr_stmt(yylineno, yytext, yes); } stmt { putchar('}'); } ;for_stmt : FOR '(' opt_exp ';' opt_exp ';' opt_exp ')' { /* put the stmt trace before the first and last exp because they may cause an execution error */ tr_stmt(yylineno, yytext, yes); tr_vars(0, $6.end); tr_stmt(yylineno, yytext, no); if ($7.start != $7.end && trace && !too_long) /* check for a non-null exp */ putchar(','); tr_vars($7.start, yyleng); reset(); putchar('{'); } stmt { putchar('}'); } ;while_stmt : WHILE '(' exp ')' { /* insert the statement trace after the "while(" */ tr_vars(0, $2.end); tr_stmt(yylineno, yytext, no); if (trace && !too_long) putchar(','); tr_vars($3.start, yyleng); reset(); putchar('{'); } stmt { putchar('}'); } ;do_stmt : DO { puttext(yyleng); putchar('{'); tr_stmt(yylineno, yytext, yes); } stmt WHILE '(' exp ')' ';' { tr_stmt(yylineno, yytext, yes); putchar('}'); tr_vars(0, yyleng); reset(); } ;switch_stmt : SWITCH '(' exp ')' { tr_stmt(yylineno, yytext, yes); tr_vars(0, yyleng); reset(); flow_break = yes; /* don't trace the '{' before the first case */ } stmt ;/* expressions */opt_exp : /* no exp */ { $$.start = $$.end = $<symbol>0.end; } | exp ;exp : exp ',' exp { bop: symbol_info($$, $1, $3, max3($1.type, $3.type, repeatable)); } | exp '=' exp { symbol_info($$, $1, $3, max3($1.type, $3.type, repeatable)); if ($1.type != side_effect) { /* keep inner expressions lower on the stack so *a++ = *b++ is traced properly */ rm_trace($1); /* don't trace a=b=1 */ if (suppress && $3.type == constant) $$.type = constant; else { /* trace only a in a=b */ /* note: (p = p->next) cannot be traced as one variable */ /* don't set to variable because "(a=b)" will expand to a term and then to a normal trace */ if (suppress && $3.type == variable) rm_trace($3); /* trace the assigned variable */ add_trace($1, $1, $3, assign); } } } | exp ASSIGNOP exp { symbol_info($$, $1, $3, max3($1.type, $3.type, repeatable)); if ($1.type != side_effect) rm_trace($1); /* keep inner expressions lower on the trace stack */ add_trace($1, $1, $3, assign); } | exp '?' exp ':' exp { symbol_info($$, $1, $5, max4($1.type, $3.type, $5.type, repeatable)); } | exp OROR exp { goto bop; } | exp ANDAND exp { goto bop; } | exp '|' exp { goto bop; } | exp '^' exp { goto bop; } | exp '&' exp { goto bop; } | exp EQUOP exp { goto bop; } | exp RELOP exp { goto bop; } | exp SHIFTOP exp { goto bop; } | exp '+' exp { goto bop; } | exp '-' exp { goto bop; } | exp '*' exp { goto bop; } | exp DIVOP exp { goto bop; } | term { if ($1.type == variable) add_trace($1, $1, $1, normal); } ;term : '*' term { symbol_info($$, $1, $2, $2.type); if ($2.type == variable) /* don't expand ++a to *++a */ expand_trace($2, $1, $2); } | '&' term { goto const_op; } | SIZEOF term { const_op: symbol_info($$, $1, $2, constant); if ($2.type == side_effect) $$.type = side_effect; /* don't trace sizeof(a) or &(a) */ rm_trace($2); } | SIZEOF cast %prec SIZEOF { symbol_info($$, $1, $2, constant); } | '-' term { goto unop; } | NOTCOMPL term { unop: symbol_info($$, $1, $2, max($2.type, repeatable)); if ($2.type == variable) add_trace($2, $2, $2, normal); } | INCOP term { symbol_info($$, $1, $2, max($2.type, repeatable)); if ($2.type != side_effect) add_trace($2, $1, $2, prefix); } | term INCOP { symbol_info($$, $1, $2, max($1.type, repeatable)); if ($1.type != side_effect) add_trace($1, $1, $2, postfix); } | cast term %prec INCOP { symbol_info($$, $1, $2, $2.type); } | term '[' exp ']' { symbol_info($$, $1, $4, max($1.type, $3.type)); if ($$.type != side_effect) $$.type = variable; } | term '(' opt_exp ')' { symbol_info($$, $1, $4, side_effect); /* prevent pcc sizeof function compiler error */ rm_trace($1); } | MACRO '(' opt_exp ')' { rm_all_trace($3); symbol_info($$, $1, $4, side_effect); } | MACRO { symbol_info($$, $1, $1, side_effect); } | strfcn | term DOTARROW ident { symbol_info($$, $1, $3, $1.type); expand_trace($1, $1, $3); } | IDENT { $$.type = variable; } | FUNCTION { $$.type = constant; } | strfcn_name { $$.type = constant; } | CONSTANT { $$.type = constant; } | '(' exp ')' { symbol_info($$, $1, $3, $2.type); if ($2.type == variable) /* don't expand ++a to (++a) */ expand_trace($2, $1, $3); } ;strfcn_name : STRRES | STRCAT | STRNCAT | STRCPY | STRCMP | STRNCMP | STRLEN ;strfcn : STRRES '(' arg opt_args ')' { symbol_info($$, $1, $5, side_effect); if ($3.type != side_effect) add_trace($3, $1, $5, strres); /* result */ } | STRCAT '(' arg ',' arg ')' { symbol_info($$, $1, $6, side_effect); if ($3.type != side_effect) /* $5 is evaluated only once so it can have side effects */ add_trace($3, $1, $6, string); /* result */ if ($5.type != side_effect && $5.type != constant) add_trace($5, $5, $5, string); /* arg 2 */ } | STRNCAT '(' arg ',' arg ',' arg ')' { symbol_info($$, $1, $8, side_effect); if ($3.type != side_effect) add_trace($3, $1, $8, string); /* result */ } | STRCPY '(' arg ',' arg ')' { symbol_info($$, $1, $6, side_effect); if ($3.type != side_effect) { /* don't trace strcpy(a, "b") */ if (suppress && $5.type == constant) { $$.type = constant; rm_trace($3); } else { /* don't trace b in strcpy(a, b); */ if (suppress && $5.type == variable) { $$.type = repeatable; /* prevent term rule trace */ rm_trace($5); } else if ($5.type != side_effect && $5.type != constant) add_trace($5, $5, $5, string); /* arg 2 */ /* trace the assigned variable */ add_trace($3, $1, $6, string); /* result */ } } } | int_strfcn { /* trace a repeatable string function result */ if ($1.type != side_effect) add_trace($1, $1, $1, normal); /* result */ } ;int_strfcn : STRCMP '(' arg ',' arg ')' { symbol_info($$, $1, $6, max($3.type, $5.type)); if ($3.type != side_effect && $3.type != constant) add_trace($3, $3, $3, string); /* arg 1 */ if ($5.type != side_effect && $5.type != constant) add_trace($5, $5, $5, string); /* arg 2 */ } | STRNCMP '(' arg ',' arg ',' arg ')' { symbol_info($$, $1, $8, max3($3.type, $5.type, $7.type)); } | STRLEN '(' arg ')' { symbol_info($$, $1, $4, $3.type); if ($3.type != side_effect && $3.type != constant) add_trace($3, $3, $3, string); /* arg 1 */ } ;arg : exp %prec ',' ;opt_args : /* none */ | ',' exp ;cast : '(' type null_dcl ')' { symbol_info($$, $1, $4, constant); } ;null_dcl : /* empty */ | '*' null_dcl | null_dcl '[' opt_exp ']' /* these two rules: */ | '(' ')' | '(' null_dcl ')' '(' ')' /* are needed in place of: *//* | null_dcl '(' ')' *//* to prevent 2 out of 3 shift/reduce conflicts */ | '(' null_dcl ')' ;ident : IDENT | FUNCTION ;%%staticyyerror(s)char *s;{ if (last_yychar == MACRO || yychar == MACRO || last_yychar == PP_IF || yychar == PP_IF || last_yychar == PP_ELSE || yychar == PP_ELSE || last_yychar == PP_ENDIF || yychar == PP_ENDIF) { fatal("cannot handle preprocessor code, use -P option"); } else if (strcmp(s, "yacc stack overflow") == 0) { fatal("'if ... else if' sequence too long"); } else if (strcmp(s, "syntax error") == 0) { error("possible syntax error, try -P option"); } else { /* no other known yacc errors, but better be safe than sorry */ fatal(s); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -