📄 decl.c
字号:
/*
* C compiler
* ==========
*
* Copyright 1989, 1990, 1991 Christoph van Wuellen.
* Credits to Matthew Brandt.
* All commercial rights reserved.
*
* This compiler may be redistributed as long there is no
* commercial interest. The compiler must not be redistributed
* without its full sources. This notice must stay intact.
*
* History:
*
* 1989 starting an 68000 C compiler, starting with material
* originally by M. Brandt
* 1990 68000 C compiler further bug fixes
* started i386 port (December)
* 1991 i386 port finished (January)
* further corrections in the front end and in the 68000
* code generator.
* The next port will be a SPARC port
*/
/*****************************************************************************/
#include "chdr.h"
#include "expr.h"
#include "cglbdec.h"
#include "proto.h"
#include "outproto.h"
/********************************************************* Macro Definitions */
/* type specifiers */
#define T_VOID ((unsigned) 1)
#define T_CHAR ((unsigned) 2)
#define T_SHORT ((unsigned) 4)
#define T_INT ((unsigned) 8)
#define T_LONG ((unsigned) 16)
#define T_LONGLONG ((unsigned) 32)
#define T_FLOAT ((unsigned) 64)
#define T_DOUBLE ((unsigned) 128)
#define T_SIGNED ((unsigned) 256)
#define T_UNSIGNED ((unsigned) 512)
#define T_BOOL ((unsigned) 1024)
#define T_COMPLEX ((unsigned) 2048)
#define T_IMAGINARY ((unsigned) 4096)
#define T_ALL (T_VOID|T_CHAR|T_SHORT|T_INT|T_LONG|T_FLOAT|T_DOUBLE|T_SIGNED|T_UNSIGNED|T_BOOL|T_COMPLEX|T_IMAGINARY)
#ifdef SYNTAX_CORRECT
#define check_stdarg(x)
#define check_tag(x1,x2)
#define check_function_declaration(x)
#define check_function_definition(x)
#define check_representable(x1,x2)
#define check_parameters(x1,x2)
#endif /* SYNTAX_CORRECT */
/*********************************************** Static Function Definitions */
static BLOCK *get_parameters P_ ((const SYM *));
static BOOL is_typedef_symbol P_ ((const CHAR *));
static QUALIFIER type_qualifier P_ ((QUALIFIER));
static QUALIFIER type_qualifier_list P_ ((void));
static SIZE declaration P_ ((STORAGE, STORAGE, SIZE));
static SIZE struct_declaration_list P_ ((const TYP *));
static STORAGE storage_class_specifier P_ ((STORAGE, BOOL));
static FSPECIFIER function_specifier P_ ((FSPECIFIER));
static SYM *declarator P_ ((STORAGE, TYP *));
static SYM *declare P_ ((SYM *, STORAGE));
static SYM *direct_declarator P_ ((STORAGE, TYP *));
static TYP *declaration_specifiers P_ ((STORAGE *, STORAGE, FSPECIFIER*));
static TYP *direct_declarator_tail P_ ((SYM *, TYP *));
static TYP *enum_specifier P_ ((STORAGE));
static TYP *enumeration_list P_ ((void));
static TYP *struct_or_union_specifier P_ ((STORAGE));
static void identifier_list P_ ((void));
static void parameter_type_list P_ ((void));
#ifndef SYNTAX_CORRECT
static void check_parameters P_ ((const BLOCK *, const SYM *));
static void check_stdarg P_ ((const SYM *));
static void check_tag P_ ((const SYM *, const TYP *));
#endif /* SYNTAX_CORRECT */
static SYM *func_symbol = NULL;
/*****************************************************************************/
/*
* Returns true if the token is one which starts a type
* specifier, otherwise it returns false.
*/
static BOOL is_type_specifier P1 (TOKEN, st)
{
switch (st) {
case tk_id:
return is_typedef_symbol (lastsym);
case kw_void:
case kw_bool:
case kw_char:
case kw_short:
case kw_unsigned:
case kw_signed:
case kw_long:
case kw_struct:
case kw_union:
case kw_enum:
case kw_float:
case kw_double:
case kw_int:
return TRUE;
default:
break;
}
return FALSE;
}
/*
* Returns true if the token is one which starts a storage
* class specifier.
*/
static BOOL is_storage_class P1 (TOKEN, st)
{
switch (st) {
case kw_typedef:
case kw_static:
case kw_auto:
case kw_register:
case kw_extern:
return TRUE;
default:
break;
}
return FALSE;
}
/*
* Returns true if the token is one which starts a type
* qualifier.
*/
static BOOL is_type_qualifier P1 (TOKEN, st)
{
switch (st) {
case kw_const:
case kw_volatile:
#ifdef TOPSPEED
case kw_cdecl:
#endif /* TOPSPEED */
case kw_restrict:
return TRUE;
default:
break;
}
return FALSE;
}
/*
* Return true if the token is one which starts a declaration
* specifier, otherwise it returns false.
*/
BOOL is_declaration_specifier P1 (TOKEN, st)
{
return is_type_specifier (st) ||
is_storage_class (st) || is_type_qualifier (st);
}
/*
* Returns true if the token is one which starts a specifier
* qualifier list, otherwise it returns false.
*/
static BOOL is_specifier_qualifier P1 (TOKEN, st)
{
return is_type_specifier (st) || is_type_qualifier (st);
}
/*
* Returns true if the token is one which starts a type
* name, otherwise it returns false.
*/
BOOL is_type_name P1 (TOKEN, st)
{
return is_specifier_qualifier (st);
}
#ifndef SYNTAX_CORRECT
/*
* Returns true if the integer constant can be represented by
* the specified type, otherwise it returns false.
*/
BOOL is_representable P2 (IVAL, i, const TYP *, tp)
{
switch (tp->type) {
case bt_char:
case bt_schar:
return (i >= -128L && i < 128L);
case bt_uchar:
case bt_charu:
return (i >= 0L && i < 256L);
case bt_short:
case bt_int16:
return (i >= -32768L && i < 32768L);
case bt_ushort:
case bt_uint16:
return (i >= 0L && i < 65536L);
#ifdef LONGLONG_SUPPORT
#ifdef LONGLONG_BOOTSTRAP
case bt_int32:
case bt_long:
return TRUE;
case bt_uint32:
case bt_ulong:
return TRUE;
#else /* */
case bt_int32:
case bt_long:
return (i >= -(IVAL) 2147483648L && i < (IVAL) 2147483647L);
case bt_uint32:
case bt_ulong:
return (i >= 0L && i < (IVAL) 0x100000000L);
#endif /* LONGLONG_BOOTSTRAP */
#else
case bt_int32:
case bt_long:
return TRUE;
case bt_uint32:
case bt_ulong:
return TRUE;
#endif /* LONGLONG_SUPPORT */
case bt_longlong:
return TRUE;
case bt_ulonglong:
return TRUE;
default:
break;
}
return FALSE;
}
#endif /* SYNTAX_CORRECT */
/*
* Returns true if the current token is a typedef name,
* otherwise it returns false.
*/
static BOOL is_typedef_symbol P1 (const CHAR *, str)
{
SYM *sp = sym_search (str);
return ((sp != NIL_SYM) && is_typedef (sp));
}
#ifndef SYNTAX_CORRECT
/*
* If the parameter parmN is declared with the register storage
* class, with a function or array type, or with a type that is not
* compatible with the type that results after application of the
* default promotions, the behaviour is undefined.
*/
static void check_stdarg P1 (const SYM *, sp)
{
TYP *tp = typeof (sp);
if (is_register (sp) || is_array_type (tp)) {
message (WARN_STDARG);
} else if (is_function_type (tp)) {
message (WARN_STDARG2);
} else {
switch (tp->type) {
case bt_char:
case bt_uchar:
case bt_schar:
case bt_charu:
case bt_short:
case bt_ushort:
case bt_float:
message (WARN_STDARG);
break;
default:
break;
}
}
}
static void check_tag P2 (const SYM *, sp, const TYP *, tp)
{
switch (typeof (sp)->type) {
case bt_struct:
case bt_union:
if (is_same_type (typeof (sp), tp)) {
return;
}
break;
case bt_schar:
case bt_uchar:
case bt_short:
case bt_ushort:
case bt_int16:
case bt_uint16:
case bt_int32:
case bt_uint32:
case bt_long:
case bt_ulong:
if (is_same_type (tp_int, tp)) {
return;
}
break;
default:
break;
}
message (ERR_TAG, nameof (sp));
}
static void check_function_declaration P1 (const SYM *, sp)
{
/*
* The storage-specifier, if any, in the declaration specifiers
* shall be either extern or static.
*/
switch (storageof (sp)) {
TYP *tp;
case sc_global: /* no specifier */
case sc_external: /* extern specifier */
case sc_static: /* static specifier */
tp = typeof (sp);
if (tp != NULL) {
tp = returned_type (typeof (sp));
#ifndef SYNTAX_CORRECT
if (tp != NULL && !is_void (tp)) {
check_complete (tp);
}
#endif /* SYNTAX_CORRECT */
}
break;
default:
message (ERR_ILLCLASS);
}
}
static void check_function_definition P1 (const SYM *, sp)
{
/*
* The return type of a function shall be void or an object type
* other than array.
*/
TYP *tp = returned_type (typeof (sp));
switch (tp->type) {
case bt_func:
message (ERR_FUNC);
break;
case bt_pointer16:
case bt_pointer32:
if (is_array_type (tp)) {
message (ERR_ARRAYRETURN);
}
break;
case bt_void:
if (is_qualified_type (tp)) {
message (WARN_QUALIFIER);
}
break;
default:
break;
}
}
/*
* Checks that i has a value representable as a 'tp'
*/
static void check_representable P2 (IVAL, i, const TYP *, tp)
{
if (!is_representable (i, tp)) {
message (ERR_REPRESENT, nameoftype (tp));
}
}
/*
* Checks that the parameters in 'block' match those in any
* function prototype for 'sp'.
*/
static void check_parameters P2 (const BLOCK *, block, const SYM *, sp)
{
SYM *sp1, *sp2 = sym_search (nameof (sp));
if ((sp2 == NIL_SYM) || !is_func (typeof (sp2))) {
return; /* no function definition */
}
sp1 = symbolsof (block);
sp2 = parametersof (typeof (sp2));
if (sp2 == NIL_SYM) {
return; /* no prototype on function definition */
}
if (sp1 == NIL_SYM) {
if (!is_equal_type (tp_void, typeof (sp2))) {
message (ERR_PROTO, nameof (sp));
}
sp2 = nextsym (sp2);
}
while ((sp1 != NIL_SYM) && (sp2 != NIL_SYM)) {
if (!is_equal_type(promote_type (typeof (sp1)), promote_type (typeof (sp2)))) {
message (ERR_PROTO, nameof (sp));
} else if (!is_equal_type (promote_type (typeof (sp1)), typeof (sp2))) {
message (ERR_PROTODEF, nameof (sp));
}
sp1 = nextsym (sp1);
sp2 = nextsym (sp2);
}
if (sp1 != sp2) {
message (ERR_PROTONUM, nameof (sp));
}
}
#endif /* SYNTAX_CORRECT */
/*
* Adds the symbol to the symbol table.
*/
static SYM *declare P2 (SYM *, sp, STORAGE, sc)
{
BOOL func_body;
switch (typeof (sp)->type) {
case bt_func:
func_body = (lastst == tk_begin || lastst == kw_register ||
lastst == kw_auto || is_type_name (lastst));
#ifndef SYNTAX_CORRECT
switch (fspecifierof (sp)) {
case fs_inline:
if (nameof (sp) == main_name) {
message (ERR_INLINEMAIN);
}
break;
case fs_none:
break;
default:
CANNOT_REACH_HERE ();
break;
}
#endif /* SYNTAX_CORRECT */
switch (storageof (sp)) {
case sc_external:
if (func_body) {
set_storage (sp, sc_global);
}
break;
case sc_global:
if (!func_body) {
set_storage (sp, sc_external);
}
break;
case sc_auto:
set_storage (sp, sc_external);
break;
case sc_static:
case sc_typedef:
break;
default:
CANNOT_REACH_HERE ();
break;
}
#ifndef SYNTAX_CORRECT
if (sc == sc_auto) {
switch (storageof (sp)) {
default:
message (ERR_ILLCLASS);
/*lint -fallthrough */
case sc_external:
case sc_typedef:
break;
}
}
#endif /* SYNTAX_CORRECT */
break;
default:
break;
}
sym_append (&sp);
return sp;
}
SYM *identifier P0 (void)
{
SYM *sp = sym_search (lastsym);
if (sp != NIL_SYM) {
#ifndef SYNTAX_CORRECT
if (is_symbol_outscope (sp)) {
message (WARN_OUTSCOPE, nameof (sp));
}
#endif /* SYNTAX_CORRECT */
getsym ();
return sp;
}
if (lastsym == func_name && lang_option >= LANG_C99) {
if (func_symbol) {
sp = mk_sym (lastsym, sc_static, copy_type (tp_conststring));
getsym ();
sym_append (&sp);
initfuncid (sp, func_symbol);
return sp;
#ifndef SYNTAX_CORRECT
} else {
message (ERR_FUNCID);
#endif /* SYNTAX_CORRECT */
}
}
sp = mk_sym (lastsym, sc_external, tp_long);
getsym ();
switch (lastst) {
case tk_openpa:
set_type (sp, tp_func);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -