📄 c.y
字号:
| unary INCOP { $$ = incop( 0, $2, $1 ); }
| INCOP unary { $$ = incop( 1, $1, $2 ); }
| AND unary { $$ = addr_of ( $2 ); } %prec UNOP
| STAR unary { $$ = indirect( NULL, $2 ); } %prec UNOP
| unary LB expr RB { $$ = indirect( $3, $1 ); } %prec UNOP
| unary STRUCTOP NAME { $$ = do_struct($1, $2, yytext); } %prec STRUCTOP
| unary LP args RP { $$ = call ( $1, $3 ); }
| unary LP RP { $$ = call ( $1, 0 ); }
;
args : non_comma_expr %prec COMMA { gen( "push", rvalue( $1 ) );
release_value( $1 );
$$ = 1;
}
| non_comma_expr COMMA args { gen( "push", rvalue( $1 ) );
release_value( $1 );
$$ = $3 + 1;
}
;
expr : expr COMMA {release_value($1);} non_comma_expr { $$=$4; }
| non_comma_expr
;
non_comma_expr
: non_comma_expr QUEST { static int label = 0;
if( !IS_INT($1->type) )
yyerror("Test in ?: must be integral\n");
gen( "EQ", rvalue( $1 ), "0" );
gen( "goto%s%d", L_COND_FALSE,
$<num>$ = ++label );
release_value( $1 );
}
non_comma_expr COLON { $<p_val>$ = $4->is_tmp
? $4
: tmp_gen($4->type, $4)
;
gen( "goto%s%d", L_COND_END, $<num>3 );
gen( ":%s%d", L_COND_FALSE, $<num>3 );
}
non_comma_expr { $$ = $<p_val>6;
if( !the_same_type($$->type, $7->type, 1) )
yyerror(
"Types on two sides of : must agree\n");
gen( "=", $$->name, rvalue($7) );
gen( ":%s%d", L_COND_END, $<num>3 );
release_value( $7 );
}
| non_comma_expr ASSIGNOP non_comma_expr {$$ = assignment($2, $1, $3);}
| non_comma_expr EQUAL non_comma_expr {$$ = assignment( 0, $1, $3);}
| or_expr
;
or_expr : or_list { int label;
if( label = pop( S_andor ) )
$$ = gen_false_true( label, NULL );
}
;
or_list : or_list OROR { if( $1 )
or( $1, stack_item(S_andor,0) = tf_label());
}
and_expr { or( $4, stack_item(S_andor,0) );
$$ = NULL;
}
| and_expr { push( S_andor, 0 );
}
;
and_expr: and_list { int label;
if( label = pop( S_andor ) )
{
gen( "goto%s%d", L_TRUE, label );
$$ = gen_false_true( label, NULL );
}
}
;
and_list: and_list ANDAND { if( $1 )
and($1, stack_item(S_andor,0) = tf_label());
}
binary { and( $4, stack_item(S_andor,0) );
$$ = NULL;
}
| binary { push( S_andor, 0 );
}
;
binary
: binary RELOP binary { $$ = relop( $1, $2, $3 ); }
| binary EQUOP binary { $$ = relop( $1, $2, $3 ); }
| binary STAR binary { $$ = binary_op( $1, '*', $3 ); }
| binary DIVOP binary { $$ = binary_op( $1, $2, $3 ); }
| binary SHIFTOP binary { $$ = binary_op( $1, $2, $3 ); }
| binary AND binary { $$ = binary_op( $1, '&', $3 ); }
| binary XOR binary { $$ = binary_op( $1, '^', $3 ); }
| binary OR binary { $$ = binary_op( $1, '|', $3 ); }
| binary PLUS binary { $$ = plus_minus( $1, '+', $3 ); }
| binary MINUS binary { $$ = plus_minus( $1, '-', $3 ); }
| unary
;
opt_expr
: expr { release_value( $1 ); tmp_freeall(); }
| /* epsilon */
;
const_expr
: expr %prec COMMA
{
$$ = -1 ;
if( !IS_CONSTANT( $1->type ) )
yyerror("Constant required.");
else if( !IS_INT( $1->type ) )
yyerror("Constant expression must be int.");
else
$$ = $1->type->V_INT ;
release_value($1);
tmp_freeall();
}
;
initializer : expr %prec COMMA
| LC initializer_list RC { $$ = $2; }
;
initializer_list
: initializer
| initializer_list COMMA initializer
{
yyerror("Aggregate initializers are not supported\n");
release_value( $3 );
}
;
string_const
: STRING
{
$$ = Str_buf;
*Str_buf = '\0';
yytext[ strlen(yytext) - 1 ] = '\0' ; /* Remove trailing " */
if( concat(STR_MAX, Str_buf, Str_buf, yytext+1, NULL) < 0 )
yyerror("String truncated at %d characters\n", STR_MAX );
}
| string_const STRING
{
yytext[ strlen(yytext) - 1 ] = '\0' ; /* Remove trailing " */
if( concat(STR_MAX, Str_buf, Str_buf, yytext+1, NULL) < 0 )
yyerror("String truncated at %d characters\n", STR_MAX );
}
;
%%
#define OFILE_NAME "output.c" /* Output file name. */
char *Bss ; /* Name of BSS temporary file. */
char *Code; /* Name of Code temporary file. */
char *Data; /* Name of Data temporary file. */
static void init_output_streams P((char **p_code,char **p_data, char **p_bss));
static void sigint_handler P((void ));
/*----------------------------------------------------------------------*/
PRIVATE void init_output_streams( p_code, p_data, p_bss)
char **p_code, **p_data, **p_bss;
{
/* Initialize the output streams, making temporary files as necessary.
* Note that the ANSI tmpfile() or the UNIX mkstmp() functions are both
* better choices than the mktemp()/fopen() used here because another
* process could, at least in theory, sneak in between the two calls.
* Since mktemp uses the process id as part of the file name, this
* is not much of a problem, and the current method is more portable
* than tmpfile() or mkstmp(). Be careful in a network environment.
*/
if( !(*p_code = mktemp("ccXXXXXX")) || !(*p_data = mktemp("cdXXXXXX")) ||
!(*p_bss = mktemp("cbXXXXXX"))
)
{
yyerror("Can't create temporary-file names");
exit( 1 );
}
if( !(yycodeout=fopen(*p_code, "w")) || !(yydataout=fopen(*p_data, "w")) ||
!(yybssout =fopen( *p_bss, "w"))
)
{
perror("Can't open temporary files");
exit( 1 );
}
}
/*----------------------------------------------------------------------*/
#ifdef __TURBOC__
void _Cdecl (* _Cdecl Osig) (int);
#else
void (*Osig) P((int)); /* Previous SIGINT handler.Initialized in */
/* yy_init_occs(). */
#endif
PRIVATE void sigint_handler()
{
/* Ctrl-C handler. Note that the debugger raises SIGINT on a 'q' command,
* so this routine is executed when you exit the debugger. Also, the
* debugger's own SIGINT handler, which cleans up windows and so forth, is
* installed before yy_init_occs() is called. It's called here to clean up
* the environment if necessary. If the debugger isn't installed, the call
* is harmless.
*/
signal ( SIGINT, SIG_IGN );
clean_up ( );
unlink ( OFILE_NAME );
(*Osig)(0);
exit(1); /* Needed only if old signal handler returns. */
}
/*----------------------------------------------------------------------*/
sym_cmp (s1, s2) symbol *s1, *s2; { return strcmp (s1->name, s2->name);}
struct_cmp (s1, s2) structdef *s1, *s2; { return strcmp (s1->tag, s2->tag );}
unsigned sym_hash (s1) symbol *s1; { return hash_pjw(s1->name ); }
unsigned struct_hash (s1) structdef *s1; { return hash_pjw(s1->tag ); }
PUBLIC void yy_init_occs( val )
void *val; /* void* to match function prototype. */
{ /* Exact match reqired by Borland C. */
Osig = signal( SIGINT, SIG_IGN );
init_output_streams( &Code, &Data, &Bss );
signal( SIGINT, BCC( (void _Cdecl (*)( )) )
MSC( (void (__cdecl *)(int)) ) sigint_handler );
((yystype *)val)->p_char = "---"; /* Attribute for the start symbol. */
Symbol_tab = maketab( 257, sym_hash, sym_cmp );
Struct_tab = maketab( 127, struct_hash, struct_cmp );
}
/*----------------------------------------------------------------------*/
PRIVATE void clean_up()
{
/* Cleanup actions. Mark the ends of the various segments, then merge the
* three temporary files used for the code, data, and bss segments into a
* single file called output.c. Delete the temporaries. Since some compilers
* don't delete an existing file with a rename(), it's best to assume the
* worst. It can't hurt to delete a nonexistent file, you'll just get an
* error back from the operating system.
*/
extern FILE *yycodeout, *yydataout, *yybssout;
signal ( SIGINT, SIG_IGN );
fclose ( yycodeout );
fclose ( yydataout );
fclose ( yybssout );
unlink ( OFILE_NAME ); /* delete old output file (ignore EEXIST) */
if( rename( Data, OFILE_NAME ) )
yyerror("Can't rename temporary (%s) to %s\n", Data, OFILE_NAME );
else
{ /* Append the other temporary */
movefile( OFILE_NAME, Bss , "a" ); /* files to the end of the */
movefile( OFILE_NAME, Code, "a" ); /* output file and delete the */
} /* temporary files. movefile() */
} /* is in appendix A. */
enum union_fields { NONE, P_SYM, P_LINK, P_SDEF, P_FIELD, P_SPEC,
P_CHAR, P_VALUE, SYM_CHAIN, ASCII, NUM };
typedef struct tabtype
{
char *sym;
enum union_fields case_val;
} tabtype;
static int tcmp P(( tabtype *p1, tabtype *p2 )); /* declared below */
tabtype Tab[] =
{
/* nonterminal field */
/* name in %union */
{ "ASSIGNOP", ASCII },
{ "CLASS", ASCII },
{ "DIVOP", ASCII },
{ "EQUOP", ASCII },
{ "INCOP", ASCII },
{ "NAME", P_SYM },
{ "RELOP", ASCII },
{ "SHIFTOP", ASCII },
{ "STRUCT", ASCII },
{ "STRUCTOP", ASCII },
{ "TTYPE", P_SYM },
{ "UNOP", ASCII },
{ "abs_decl", P_SYM },
{ "abstract_decl", P_SYM },
{ "and_expr", P_VALUE },
{ "and_list", P_VALUE },
{ "args", NUM },
{ "binary", P_VALUE },
{ "const_expr", NUM },
{ "decl", P_SYM },
{ "decl_list", SYM_CHAIN },
{ "def", SYM_CHAIN },
{ "def_list", SYM_CHAIN },
{ "enumerator", P_SYM },
{ "expr", P_VALUE },
{ "ext_decl", P_SYM },
{ "ext_decl_list", SYM_CHAIN },
{ "funct_decl", P_SYM },
{ "initializer", P_VALUE },
{ "initializer_list", P_VALUE },
{ "local_defs", SYM_CHAIN },
{ "name", P_SYM },
{ "name_list", SYM_CHAIN },
{ "new_name", P_SYM },
{ "non_comma_expr", P_VALUE },
{ "opt_specifiers", P_LINK },
{ "opt_tag", P_SDEF },
{ "or_expr", P_VALUE },
{ "or_list", P_VALUE },
{ "param_declaration", SYM_CHAIN },
{ "specifiers", P_LINK },
{ "string_const", P_CHAR },
{ "struct_specifier", P_SDEF },
{ "tag", P_SDEF },
{ "test", NUM },
{ "type", P_LINK },
{ "type_or_class", P_LINK },
{ "type_specifier", P_LINK },
{ "unary", P_VALUE },
{ "var_decl", P_SYM },
{ "var_list", SYM_CHAIN },
{ "{72}", NUM },
{ "{73}", P_VALUE }
};
static int tcmp( p1, p2 )
tabtype *p1, *p2;
{
return( strcmp(p1->sym, p2->sym) );
}
char *yypstk( val, name )
void *val; /* Ptr. to value-stack item. void* to match prototype */
char *name; /* Ptr. to debug-stack item. */
{
static char buf[128];
char *text;
tabtype *tp, template;
yystype *v = (yystype *)val; /* avoid casts all over the place */
template.sym = name;
tp = (tabtype *) bsearch( &template, Tab, sizeof(Tab)/sizeof(*Tab),
sizeof(*Tab),
BCC( (int _Cdecl( *)(const void _FAR *, const void _FAR *)) )
MSC( (int (__cdecl *)(const void *, const void *)) ) tcmp);
sprintf( buf, "%04x ", v->num ); /* The first four characters in the */
text = buf + 5; /* string are the numeric value of */
/* the current stack element. */
/* Other text is written at "text". */
switch( tp ? tp->case_val : NONE )
{
case SYM_CHAIN:
sprintf( text, "sym chain: %s",
v->p_sym ? sym_chain_str(v->p_sym) : "NULL" );
break;
case P_SYM:
if( ! v->p_sym )
sprintf( text, "symbol: NULL" );
else if( IS_FUNCT(v->p_sym->type) )
sprintf( text, "symbol: %s(%s)=%s %1.40s",
v->p_sym->name,
sym_chain_str( v->p_sym->args ),
v->p_sym->type && *(v->p_sym->rname) ?
v->p_sym->rname : "",
type_str(v->p_sym->type) );
else
sprintf( text, "symbol: %s=%s %1.40s",
v->p_sym->name,
v->p_sym->type && *(v->p_sym->rname) ?
v->p_sym->rname : "",
type_str(v->p_sym->type) );
break;
case P_SPEC:
if( !v->p_spec )
sprintf( text, "specifier: NULL" );
else
sprintf( text, "specifier: %s %s", attr_str( v->p_spec ),
noun_str( v->p_spec->noun ) );
break;
case P_LINK:
if( !v->p_link )
sprintf( text, "specifier: NULL" );
else
sprintf( text, "link: %1.50s", type_str(v->p_link) );
break;
case P_VALUE:
if( !v->p_val )
sprintf( text, "_value: NULL" );
else
{
sprintf( text, "%cvalue: %s %c/%u %1.40s",
v->p_val->lvalue ? 'l' : 'r' ,
*(v->p_val->name) ? v->p_val->name : "--",
v->p_val->is_tmp ? 't' : 'v' ,
v->p_val->offset,
type_str( v->p_val->type ) );
}
break;
case P_SDEF:
if( !v->p_sdef )
sprintf( text, "structdef: NULL" );
else
sprintf( text, "structdef: %s lev %d, size %d",
v->p_sdef->tag,
v->p_sdef->level,
v->p_sdef->size);
break;
case P_CHAR:
if( !v->p_sdef )
sprintf( text, "string: NULL" );
else
sprintf( text, "<%s>", v->p_char );
break;
case NUM:
sprintf( text, "num: %d", v->num );
break;
case ASCII:
sprintf( text, "ascii: `%s`", bin_to_ascii(v->ascii, 1) );
break;
}
return buf;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -