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

📄 decl.c

📁 一个c语言写做的编译器的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*@A (C) 1992 Allen I. Holub                                                */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tools/debug.h>
#include <tools/hash.h>
#include <tools/l.h>
#include <tools/compiler.h>
#include <tools/c-code.h>
#include <tools/occs.h>

#include "symtab.h"
#include "value.h"
#include "proto.h"

/* DECL.C	This file contains support subroutines for those actions in c.y
 *		that deal with declarations.
 *----------------------------------------------------------------------
 */

PUBLIC	link	  *new_class_spec( first_char_of_lexeme )
int	first_char_of_lexeme;
{
    /* Return a new specifier link with the sclass field initialized to hold
     * a storage class, the first character of which is passed in as an argument
     * ('e' for extern, 's' for static, and so forth).
     */

    link *p  = new_link();
    p->class = SPECIFIER;
    set_class_bit( first_char_of_lexeme, p );
    return p;
}

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

PUBLIC	void	set_class_bit( first_char_of_lexeme, p )
int	first_char_of_lexeme;
link	*p;
{
      /* Change the class of the specifier pointed to by p as indicated by the
       * first character in the lexeme. If it's 0, then the defaults are
       * restored (fixed, nonstatic, nonexternal). Note that the TYPEDEF
       * class is used here only to remember that the input storage class
       * was a typedef, the tdef field in the link is set true (and the storage
       * class is cleared) before the entry is added to the symbol table.
       */

      switch( first_char_of_lexeme )
      {
      case 0:	p->SCLASS = FIXED;
		p->STATIC = 0;
		p->EXTERN = 0;
		break;

      case 't': p->SCLASS  = TYPEDEF  ;	break;
      case 'r': p->SCLASS  = REGISTER ;	break;
      case 's': p->STATIC  = 1        ;	break;
      case 'e': p->EXTERN  = 1        ;	break;

      default : yyerror("INTERNAL, set_class_bit: bad storage class '%c'\n",
							  first_char_of_lexeme);
		exit( 1 );
		break;
      }
}

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

PUBLIC	link	*new_type_spec( lexeme )
char	*lexeme;
{
    /* Create a new specifier and initialize the type according to the indicated
     * lexeme. Input lexemes are: char const double float int long short
     *				  signed unsigned void volatile
     */

    link *p  = new_link();
    p->class = SPECIFIER;

    switch( lexeme[0] )
    {
    case 'c': 	if( lexeme[1]=='h' )			/* char | const	   */
		    p->NOUN = CHAR ;			/* (Ignore const.) */
		break;
    case 'd':						/* double	 */
    case 'f':	yyerror("No floating point\n");		/* float	 */
		break;

    case 'i':	p->NOUN	    = INT;	break;		/* int		 */
    case 'l':	p->LONG	    = 1;	break;		/* long		 */
    case 'u': 	p->UNSIGNED = 1;	break;		/* unsigned	 */

    case 'v':	if( lexeme[2] == 'i' )			/* void | volatile */
		    p->NOUN = VOID;			/* ignore volatile */
		break;
    case 's': 	break;					/* short | signed */
    }							/* ignore both 	  */

    return p;
}
void	add_spec_to_decl( p_spec, decl_chain )
link	*p_spec;
symbol	*decl_chain;
{
    /* p_spec is a pointer either to a specifier/declarator chain created
     * by a previous typedef or to a single specifier. It is cloned and then
     * tacked onto the end of every declaration chain in the list pointed to by
     * decl_chain. Note that the memory used for a single specifier, as compared
     * to a typedef, may be freed after making this call because a COPY is put
     * into the symbol's type chain.
     *
     * In theory, you could save space by modifying all declarators to point
     * at a single specifier. This makes deletions much more difficult, because
     * you can no longer just free every node in the chain as it's used. The
     * problem is complicated further by typedefs, which may be declared at an
     * outer level, but can't be deleted when an inner-level symbol is
     * discarded. It's easiest to just make a copy.
     *
     * Typedefs are handled like this: If the incoming storage class is TYPEDEF,
     * then the typedef appeared in the current declaration and the tdef bit is
     * set at the head of the cloned type chain and the storage class in the
     * clone is cleared; otherwise, the clone's tdef bit is cleared (it's just
     * not copied by clone_type()).
     */

    link *clone_start, *clone_end ;

    for( ; decl_chain ; decl_chain = decl_chain->next )
    {
	if( !(clone_start = clone_type(p_spec, &clone_end)) )
	{
	    yyerror("INTERNAL, add_typedef_: Malformed chain (no specifier)\n");
	    exit( 1 );
	}
	else
	{
	    if( !decl_chain->type )			  /* No declarators. */
		decl_chain->type = clone_start ;
	    else
		decl_chain->etype->next = clone_start;

	    decl_chain->etype = clone_end;

	    if( IS_TYPEDEF(clone_end) )
	    {
		set_class_bit( 0, clone_end );
		decl_chain->type->tdef = 1;
	    }
	}
    }
}
void	add_symbols_to_table( sym )
symbol	*sym;
{
    /* Add declarations to the symbol table.
     *
     * Serious redefinitions (two publics, for example) generate an error
     * message. Harmless redefinitions are processed silently. Bad code is
     * generated when an error message is printed. The symbol table is modified
     * in the case of a harmless duplicate to reflect the higher precedence
     * storage class: (public == private) > common > extern.
     *
     * The sym->rname field is modified as if this were a global variable (an
     * underscore is inserted in front of the name). You should add the symbol
     * chains to the table before modifying this field to hold stack offsets
     * in the case of local variables.
     */

    symbol *exists;		/* Existing symbol if there's a conflict.    */
    int    harmless;
    symbol *new;

    for(new = sym; new ; new = new->next )
    {
	exists = (symbol *) findsym(Symbol_tab, new->name);

	if( !exists || exists->level != new->level )
	{
	    sprintf ( new->rname, "_%1.*s", sizeof(new->rname)-2, new->name);
	    addsym  ( Symbol_tab, new );
	}
	else
	{
	    harmless	   = 0;
	    new->duplicate = 1;

	    if( the_same_type( exists->type, new->type, 0) )
	    {
		if( exists->etype->OCLASS==EXT || exists->etype->OCLASS==COM )
		{
		    harmless = 1;

		    if( new->etype->OCLASS != EXT )
		    {
		    	exists->etype->OCLASS = new->etype->OCLASS;
		    	exists->etype->SCLASS = new->etype->SCLASS;
		    	exists->etype->EXTERN = new->etype->EXTERN;
		    	exists->etype->STATIC = new->etype->STATIC;
		    }
		}
	    }
	    if( !harmless )
		yyerror("Duplicate declaration of %s\n", new->name );
	}
    }
}

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

void	figure_osclass( sym )
symbol	*sym;
{
    /* Go through the list figuring the output storage class of all variables.
     * Note that if something is a variable, then the args, if any, are a list
     * of initializers. I'm assuming that the sym has been initialized to zeros;
     * at least the OSCLASS field remains unchanged for nonautomatic local
     * variables, and a value of zero there indicates a nonexistent output class.
     */

    for( ; sym ; sym = sym->next )
    {
	if( sym->level == 0 )
	{
	    if( IS_FUNCT( sym->type ) )
	    {
		if	( sym->etype->EXTERN )	sym->etype->OCLASS = EXT;
		else if	( sym->etype->STATIC )	sym->etype->OCLASS = PRI;
		else				sym->etype->OCLASS = PUB;
	    }
	    else
	    {
		if	( sym->etype->STATIC )	sym->etype->OCLASS = PRI;
		if      ( sym->args	     )	sym->etype->OCLASS = PUB;
		else				sym->etype->OCLASS = COM;
	    }
	}
	else if( sym->type->SCLASS == FIXED )
	{
	    if      (  IS_FUNCT ( sym->type ))	sym->etype->OCLASS = EXT;
	    else if (! IS_LABEL ( sym->type ))	sym->etype->OCLASS = PRI;
	}
    }
}

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

void	generate_defs_and_free_args( sym )
symbol	*sym;
{
    /* Generate global-variable definitions, including any necessary
     * initializers. Free the memory used for the initializer (if a variable)
     * or argument list (if a function).
     */

    for( ; sym ; sym = sym->next )
    {
	if( IS_FUNCT(sym->type) )
	{
	    /* Print a definition for the function and discard arguments
	     * (you'd keep them if prototypes were supported).
	     */

	    yydata( "external\t%s();\n", sym->rname );
	    discard_symbol_chain( sym->args );
	    sym->args = NULL;
	}
	else if( IS_CONSTANT(sym->etype) || sym->type->tdef )
	{
	    continue;
	}
	else if( !sym->args )		/* It's an uninitialized variable. */
	{
	    print_bss_dcl( sym );	/* Print the declaration.	  */
	}
	else				/* Deal with an initializer.	  */
	{
	    var_dcl( yydata, sym->etype->OCLASS, sym, "=" );

	    if( IS_AGGREGATE( sym->type ) )
		yyerror("Initialization of aggregate types not supported\n");

	    else if( !IS_CONSTANT( ((value *)sym->args)->etype ) )
		yyerror("Initializer must be a constant expression\n");

	    else if( !the_same_type(sym->type, ((value *) sym->args)->type, 0) )
		yyerror("Initializer: type mismatch\n");

	    else
		yydata( "%s;\n", CONST_STR( (value *) sym->args ) );

	    discard_value( (value *)(sym->args) );
	    sym->args = NULL;
	}
    }
}

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

symbol	*remove_duplicates( sym )
symbol	*sym;
{
    /* Remove all nodes marked as duplicates from the linked list and free the
     * memory. These nodes should not be in the symbol table. Return the new
     * head-of-list pointer (the first symbol may have been deleted).
     */

    symbol *prev  = NULL;
    symbol *first = sym;

    while( sym )
    {
	if( !sym->duplicate )		    /* Not a duplicate, go to the     */
	{				    /* next list element.	      */
	    prev = sym;
	    sym  = sym->next;
	}
	else if( prev == NULL )		    /* Node is at start of the list.  */
	{
	    first = sym->next;

⌨️ 快捷键说明

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