⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c.y

📁 一个c语言写做的编译器的源码
💻 Y
📖 第 1 页 / 共 3 页
字号:



	| 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 + -