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

📄 c.y

📁 一个c语言写做的编译器的源码
💻 Y
📖 第 1 页 / 共 3 页
字号:
/*@A (C) 1992 Allen I. Holub                                                */




   /* ANSI C, more or less.
    *
    * Note that I've restricted myself to yacc-compatible constructions here.
    * Negative attributes would be very handy in places and it's difficult
    * not to use them.
    */

%{
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <tools/debug.h>	/* Misc. macros. (see Appendix A)	 */
#include <tools/hash.h>		/* Hash-table support. (see Appendix A)	 */
#include <tools/compiler.h> 	/* Prototypes for comp.lib functions.	 */
#include <tools/l.h>	    	/* Prototypes for l.lib functions.	 */
#include <tools/occs.h>	    	/* Prototypes for LeX/occs-generated stuff   */
#include <tools/c-code.h>    	/* Virtual-machine definitions.		 */

#ifdef __TURBOC__		/* Borland			*/
#include <dir.h>		/* for mktemp() prototype	*/
#endif
#ifdef MSDOS			/* Microsoft.			*/
#include <io.h>			/* for mktemp() prototype	*/
#endif

#ifdef YYACTION
#define ALLOC		/* Define ALLOC to create symbol table in symtab.h.  */
#endif

#include "symtab.h"	/* Definitions for the symbol-table.	     	     */
#include "value.h"	/* Definitions used for expression processing.	     */
#include "label.h"	/* Prefixes used for compiler-generated labels.	     */
#include "switch.h"	/* Definitions used for switch processing.	     */
#include "proto.h"	/* Function prototypes for all .c files used by the  */
			/* parser. It is not printed anywhere in the book,   */
			/* but is included on the distribution disk.	     */

PRIVATE void clean_up P((void));
%}
/*----------------------------------------------------------------------*/

%union {
    char	*p_char;
    symbol	*p_sym;
    link	*p_link;
    structdef	*p_sdef;
    specifier	*p_spec;
    value	*p_val;
    int		num;		/* Make short if sizeof(int) > sizeof(int*) */
    int		ascii;
}

/*----------------------------------------------------------------------*/

%term	STRING		/* String constant.				 */
%term	ICON		/* Integer or long constant including '\t', etc. */
%term	FCON		/* Floating-point constant.			 */

%term	TYPE	    	/* int char long float double signed unsigned short */
			/* const volatile void				    */
%term	<ascii> STRUCT	/* struct union			     		    */
%term	ENUM		/* enum				     		    */

%term	RETURN GOTO
%term	IF ELSE
%term	SWITCH CASE DEFAULT
%term	BREAK CONTINUE
%term	WHILE DO FOR
%term	LC RC		/* 	{ }	*/
%term	SEMI		/* 	 ;	*/
%term	ELLIPSIS	/*	...	*/

/* The attributes used below tend to be the sensible thing. For example, the
 * ASSIGNOP attribute is the operator component of the lexeme; most other
 * attributes are the first character of the lexeme. Exceptions are as follows:
 *	token	  attribute
 *	RELOP >	    '>'
 *	RELOP <     '<'
 *	RELOP >=    'G'
 *	RELOP <=    'L'
 */

%left	COMMA			     /*	,			     	    */
%right	EQUAL <ascii> ASSIGNOP 	     /* =   *= /= %= += -= <<= >>= &= |= ^= */
%right	QUEST COLON		     /* 	? :			    */
%left	OROR			     /*	||				    */
%left	ANDAND			     /*	&&				    */
%left	OR			     /*	|				    */
%left   XOR			     /*	^				    */
%left	AND			     /*	&				    */
%left	<ascii> EQUOP		     /*	==  !=				    */
%left	<ascii> RELOP		     /*	<=  >= <  >			    */
%left	<ascii> SHIFTOP		     /*	>> <<				    */
%left	PLUS  MINUS		     /*	+ -				    */
%left	STAR  <ascii> DIVOP	     /*	*  /   %			    */
%right	SIZEOF <ascii> UNOP INCOP    /*        sizeof     ! ~     ++ --     */
%left	LB RB LP RP <ascii> STRUCTOP /*	[ ] ( )  . ->			    */


			/* These attributes are shifted by the scanner.   */
%term <p_sym> TTYPE	/* Name of a type created with a previous typedef.*/
			/* Attribute is a pointer to the symbol table     */
			/* entry for that typedef.			  */
%nonassoc <ascii> CLASS	/* extern register auto static typedef. Attribute */
			/* is the first character of the lexeme.	  */
%nonassoc <p_sym> NAME	/* Identifier or typedef name. Attribute is NULL  */
			/* if the symbol doesn't exist, a pointer to the  */
			/* associated "symbol" structure, otherwise.	  */

%nonassoc ELSE		/* This gives a high precedence to ELSE to suppress
			 * the shift/reduce conflict error message in:
			 *   s -> IF LP expr RP expr | IF LP expr RP s ELSE s
			 * The precedence of the first production is the same
			 * as RP. Making ELSE higher precedence forces
			 * resolution in favor of the shift.
			 */

  			/* Abbreviations used in nonterminal names:
  			 *
  			 * abs    == abstract
  			 * arg(s) == argument(s)
  			 * const  == constant
  			 * decl   == declarator
  			 * def    == definition
  			 * expr   == expression
  			 * ext    == external
  			 * opt    == optional
  			 * param  == parameter
  			 * struct == structure
  			 */
%type <num> args const_expr test

%type <p_sym>   ext_decl_list ext_decl def_list def decl_list decl
%type <p_sym>   var_decl funct_decl local_defs new_name name enumerator
%type <p_sym>	name_list var_list param_declaration abs_decl abstract_decl
%type <p_val>	expr binary non_comma_expr unary initializer initializer_list
%type <p_val>	or_expr and_expr or_list and_list

%type <p_link>	type specifiers opt_specifiers type_or_class type_specifier
%type <p_sdef>	opt_tag tag struct_specifier
%type <p_char>	string_const target

/*----------------------------------------------------------------------
 * Global and external variables. Initialization to zero for all globals is
 * assumed. Since occs -a and -p is used, these variables may not be private.
 * The ifdef assures that space is allocated only once (this, header, section
 * will be placed in both yyact.c and yyout.c, YYACTION is defined only in
 * yyact.c, however.
 */

%{
#ifdef YYACTION
%}

/*@A -------------------------------------------------------------          */





/*@A -------------------------------------------------------------          */








%{
int     Nest_lev;	 /* Current block-nesting level.		*/
%}






%{
int	Enum_val;	 /* Current enumeration constant value	*/
%}


/*@A -------------------------------------------------------------          */



%{
char	Vspace[16];
char	Tspace[16];	 /* The compiler doesn't know the stack-frame size
			  * when it creates a link() directive, so it outputs
			  * a link(VSPACE+TSPACE). Later on, it #defines VSPACE
			  * to the size of the local-variable space and TSPACE
			  * to the size of the temporary-variable space. Vspace
			  * holds the actual name of the VSPACE macro, and
			  * Tspace the TSPACE macro. (There's a different name
			  * for each subroutine.)
			  */

char	Funct_name[ NAME_MAX+1 ];	/* Name of the current function */
%}





%{
#define STR_MAX 512	  	/* Maximum size of a string constant.   */
char	Str_buf[STR_MAX]; 	/* Place to assemble string constants.  */
%}


/*@A -------------------------------------------------------------          */




				/* Stacks. The stack macros are all in	*/
				/* <tools/stack.h>, included earlier	*/
%{
#include <tools/stack.h>    	/* Stack macros. (see Appendix A)	 */

int stk_err( o )	/* declared as int to keep the compiler happy */
int o;
{
    yyerror( o ? "Loop/switch nesting too deep or logical expr. too complex.\n"
	       : "INTERNAL, label stack underflow.\n"  );
    exit( 1 );
    BCC( return 0 );	/* keep the compiler happy */
}
#undef  stack_err
#define stack_err(o)	 stk_err(o)

stack_dcl (S_andor, int, 32);	/* This stack wouldn't be necessary if I were */
				/* willing to put a structure onto the value  */
				/* stack--or_list and and_list must both      */
				/* return 2 attributes; this stack will hold  */
				/* one of them.				      */
%}

/*@A -------------------------------------------------------------          */




%{
/* These stacks are necessary because there's no syntactic connection break,
 * continue, case, default and the affected loop-control statement.
 */

stack_dcl (S_brk,       int,    32); /* number part of current break target  */
stack_dcl (S_brk_label, char *, 32); /* string part of current break target  */

stack_dcl (S_con,  	int,    32); /* number part of current continue targ. */
stack_dcl (S_con_label, char *, 32); /* string part of current continue targ. */
%}


/*@A -------------------------------------------------------------          */





%{
int	Case_label = 0;		  /* Label used to process case statements. */

stack_dcl (S_switch, stab *, 32); /* Switch table for current switch.	    */
%}


/*@A -------------------------------------------------------------          */


%{
#endif /* ifdef YYACTION */
%}


%%
program : ext_def_list { clean_up(); }
	;

ext_def_list
	: ext_def_list ext_def
	| /* epsilon */
	  {
		yydata(   "#include <tools/virtual.h>\n" );
		yydata(   "#define  T(x)\n" 		 );
		yydata(   "SEG(data)\n" 	 	 );
		yycode( "\nSEG(code)\n" 	 	 );
		yybss ( "\nSEG(bss)\n"  	 	 );
	  }
	;

opt_specifiers
	: CLASS TTYPE {   set_class_bit(  0, $2->etype ); /* Reset class.   */
			  set_class_bit( $1, $2->etype ); /* Add new class. */
			  $$ = $2->type ;
		      }
	| TTYPE	      {   set_class_bit(0, $1->etype);  /* Reset class bits.*/
			  $$ = $1->type ;
		      }
	| specifiers
	| /* empty */						%prec COMMA
	  	      {
			  $$	    = new_link();
			  $$->class = SPECIFIER;
			  $$->NOUN  = INT;
		      }
	;
specifiers
	: type_or_class
	| specifiers type_or_class { spec_cpy( $$, $2 );
				     discard_link_chain( $2 ); }
	;
type
	: type_specifier
	| type type_specifier	{  spec_cpy( $$, $2 );
				   discard_link_chain( $2 ); }
	;
type_or_class
	: type_specifier
	| CLASS 	   	{  $$ = new_class_spec( $1 );  }
	;
type_specifier
	: TYPE		   	{ $$ = new_type_spec( yytext );	 }

	| enum_specifier   	{ $$ = new_type_spec( "int"  );	 }
	| struct_specifier 	{ $$ = new_link();
			     	  $$->class    = SPECIFIER;
				  $$->NOUN     = STRUCTURE;
				  $$->V_STRUCT = $1;
				}
	;


var_decl
	: new_name	     %prec COMMA  /* This production is done first. */

	| var_decl LP RP	    {	add_declarator( $$, FUNCTION ); }
	| var_decl LP var_list RP   {   add_declarator( $$, FUNCTION );
					discard_symbol_chain( $3 );
				    }
	| var_decl LB RB
	  {
		/* At the global level, this must be treated as an array of
		 * indeterminate size; at the local level this is equivalent to
		 * a pointer. The latter case is patched after the declaration
		 * is assembled.
		 */

		add_declarator( $$, ARRAY );
		$$->etype->NUM_ELE = 0;

		YYD( yycomment("Add POINTER specifier\n"); )
	  }

	| var_decl LB const_expr RB
	  {
		add_declarator( $$, ARRAY );
		$$->etype->NUM_ELE = $3;

		YYD(yycomment("Add array[%d] spec.\n", $$->etype->NUM_ELE);)
	  }
	| STAR var_decl			%prec UNOP
	  {
		add_declarator( $$ = $2, POINTER );
		YYD( yycomment("Add POINTER specifier\n"); )
	  }

	| LP var_decl RP { $$ = $2; }
	;

/*----------------------------------------------------------------------
 * Name productions. new_name always creates a new symbol, initialized with the
 * current lexeme. Name returns a preexisting symbol with the associated name
 * (if there is one); otherwise, the symbol is allocated. The NAME token itself
 * has a NULL attribute if the symbol doesn't exist, otherwise it returns a
 * pointer to a "symbol" for the name.
 */

new_name: NAME	{  $$ = new_symbol( yytext, Nest_lev );   }
	;

name	: NAME	{  if( !$1 || $1->level != Nest_lev )
		       $$ = new_symbol( yytext, Nest_lev );
		}
	;

/*----------------------------------------------------------------------
 * Global declarations: take care of the declarator part of the declaration.
 * (The specifiers are handled by specifiers).
 * Assemble the declarators into a chain, using the cross links.
 */

ext_decl_list
	:  ext_decl
	   {
		$$->next = NULL;		/* First link in chain. */
	   }
	|  ext_decl_list COMMA ext_decl
	   {
		/* Initially, $1 and $$ point at the head of the chain.
		 * $3 is a pointer to the new declarator.
		 */

		$3->next = $1;
		$$       = $3;
	   }
	;

ext_decl
	: var_decl
	| var_decl EQUAL initializer { $$->args = (symbol *)$3; }
	| funct_decl
	;



funct_decl
	: STAR funct_decl	      {   add_declarator( $$ = $2 , POINTER ); }
	| funct_decl LB RB	      {   add_declarator( $$, ARRAY );
					  $$->etype->NUM_ELE = 0;
				      }
	| funct_decl LB const_expr RB {   add_declarator( $$, ARRAY );
					  $$->etype->NUM_ELE = $3;
				      }
	| LP funct_decl RP	      {   $$ = $2; 			  }
	| funct_decl LP RP	      {   add_declarator( $$, FUNCTION ); }
	| new_name LP RP	      {   add_declarator( $$, FUNCTION ); }

	| new_name LP { ++Nest_lev; } name_list { --Nest_lev; } RP
	  {
		add_declarator( $$, FUNCTION );

		$4       = reverse_links( $4 );
		$$->args = $4;
	  }
	| new_name LP { ++Nest_lev; } var_list { --Nest_lev; } RP
	  {
		add_declarator( $$, FUNCTION );
		$$->args = $4;
	  }
	;
name_list
	: new_name		   {
					$$->next	 = NULL;
					$$->type	 = new_link();
					$$->type->class  = SPECIFIER;
					$$->type->SCLASS = AUTO;
				   }
	| name_list COMMA new_name {
					$$       	 = $3;
					$$->next 	 = $1;
					$$->type	 = new_link();
					$$->type->class  = SPECIFIER;
					$$->type->SCLASS = AUTO;
				    }
	;
var_list
	: param_declaration			{ if($1) $$->next = NULL; }
	| var_list COMMA param_declaration	{ if($3)
						  {
						      $$       = $3;
						      $3->next = $1;
						  }
						}
	;
param_declaration
	: type  var_decl    	{ add_spec_to_decl($1,  $$ = $2  ); }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -