📄 decl.c
字号:
/*@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 + -