%{
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "parseproto.h"
#include <assert.h>
static decl_spec_t *declspec_Construct(void);
static void declspec_Destroy(decl_spec_t *);
decl_spec_t *, const char **);
static char *declspec_GetTag(decl_spec_t *);
static type_t *type_Construct(void);
static void type_Destroy(type_t *);
static const char *type_Verify(type_t *);
static decl_t *decl_Construct(void);
static int decl_IsVoid(decl_t *);
static int decl_IsVoidArray(decl_t *);
static const char *decl_VerifyArgs(decl_t *);
#if defined(DEBUG)
static void type_PrintType(type_t *, int);
static void decl_PrintDecl(decl_t *, int);
static void decl_PrintTraceInfo(decl_t *);
static char *de_const(char *);
#endif
static int yylex(void);
static void yyerror(const char *);
static int yyparse(void);
#if defined(MEM_DEBUG)
static int declspec_Construct_calls;
static int type_Construct_calls;
static int decl_Construct_calls;
#endif
#if defined(DEBUG)
static char *de_const(char *);
#endif
%}
%union {
char *s_val;
int i_val;
}
%%
/*
*/
{
protop = $$ = $2;
/* only one declaration allowed */
const char *sp;
}
declspec_Destroy($1);
}
| error ';'
{
errstr = "function prototype syntax error";
}
/*
* XXX - Does not support a "stand-alone" declaration specifier. It is
* essentially a type declaration, for example:
*
* typedef enum { FALSE = 0, TRUE = 1 } boolean_t;
* or
* struct _name { char *first; char *last };
*/
/* XXX | declaration_specifiers */
;
{
char const *ep;
declspec_Destroy($1);
}
{
const char *ep;
declspec_Destroy($1);
}
{
const char *ep;
declspec_Destroy($1);
}
;
: REGISTER
{
}
/*
* XXX - Does not support any storage class specifier other than
* register, and then only for function arguments.
*
| TYPEDEF
{
$$ = declspec_Init(SCS_TYPEDEF, NULL);
}
| EXTERN
{
$$ = declspec_Init(SCS_EXTERN, NULL);
}
| STATIC
{
$$ = declspec_Init(SCS_STATIC, NULL);
}
| AUTO
{
$$ = declspec_Init(SCS_AUTO, NULL);
}
*/
;
: VOID
{
atIDENT = 1;
}
| CHAR
{
atIDENT = 1;
}
| SHORT
{
atIDENT = 1;
}
| INT
{
atIDENT = 1;
}
| LONG
{
atIDENT = 1;
}
| FLOAT
{
atIDENT = 1;
}
| DOUBLE
{
atIDENT = 1;
}
| SIGNED
{
atIDENT = 1;
}
| UNSIGNED
{
atIDENT = 1;
}
;
{
atIDENT = 1;
free($1);
}
;
/*
* The "restrict" keyword is new in the C99 standard.
* It is type qualifier like const and volatile.
* We are using "_RESTRICT_KYWD" in headers and source code so
* it is easily turned on and off by various macros at compile time.
* In order for the "restrict" keyword to be recognized you must
* be using a C99 compliant compiler in its native mode.
*/
: CONST
{
}
| VOLATILE
{
}
| RESTRICT
{
}
{
}
;
{
free($3);
}
/*
* XXX - struct or union definitions are not supported. It is generally
* not done within the context of a function declaration (prototype) or
* variable definition.
| struct_or_union IDENTIFIER '{' struct_declaration_list '}'
| struct_or_union '{' struct_declaration_list '}'
*/
;
: STRUCT
{
$$ = TS_STRUCT;
}
| UNION
{
$$ = TS_UNION;
}
;
{
$$ = $1;
atIDENT = 1;
}
/*
* XXX - Does not support a comma separated list of declarations or
* definitions. Function prototypes or variable definitions must be
* given as one per C statement.
| init_declarator_list ',' init_declarator
{
$$ = decl_AddArg($1, $3);
atIDENT = 1;
}
*/
;
/*
* XXX - Initialization is not supported.
| declarator '=' initializer
*/
;
{
free($3);
}
/*
* XXX - enumerator definition is not supported for the same reasons
* struct|union definition is not supported.
| ENUM IDENTIFIER '{' enumerator_list '}'
| ENUM '{' enumerator_list '}'
*/
;
{
}
;
{
atIDENT = 0;
free($1);
}
{
$$ = $2;
}
{
free($3);
}
| direct_declarator '[' ']'
{
}
{
}
| direct_declarator '(' ')'
{
}
;
: '*' type_qualifier_list
{
declspec_Destroy($2);
}
| '*'
{
}
{
declspec_Destroy($2);
}
| '*' pointer
{
}
;
{
const char *ep;
/* XXX - ignore any error */
declspec_Destroy($2);
}
;
{
$$ = decl_addellipsis($1);
}
;
{
if (sp)
$$ = $1;
atIDENT = 0;
}
{
if (sp)
atIDENT = 0;
}
;
{
const char *ep;
declspec_Destroy($1);
}
{
const char *ep;
declspec_Destroy($1);
}
{
const char *ep;
declspec_Destroy($1);
}
;
: pointer
{
}
{
}
;
{
$$ = $2;
}
{
free($3);
}
{
free($2);
}
| direct_abstract_declarator '[' ']'
{
}
| '[' ']'
{
}
{
}
{
}
| direct_abstract_declarator '(' ')'
{
}
| '(' ')'
{
}
;
/*
* XXX - General case constant expressions are not supported. It would
* be easy to implement (for the most part), but there are no cases to
* date that require such a facility. The grammar does allow an
* identifier (or typedef name) to be used since the prototype is not
* processed by CPP. The only integer constant that is supported is
* decimal.
*/
: INTEGER
;
%%
/* Data Declarations */
typedef struct {
char *name;
int token;
} keyword_t;
typedef struct {
char *s_str;
} sttpair_t;
/* External Declarations */
static const keyword_t *lookup_keyword(const char *);
static const char *lookup_sttpair(stt_t);
static int getch(void);
static void ungetch(int);
static void skipwhitespace(void);
static int lookahead(int);
static void skipcomment(void);
/* External Definitions */
/* at point in stream were identifier is expected */
static int atIDENT = 0;
/*
* lookup_keyword - Given a string, return the keyword_t or NULL.
*/
static const keyword_t *
lookup_keyword(const char *name) {
#if UNSUPPORTED
#endif /* UNSUPPORTED */
};
int i;
for (i = 0; i < NKEYWORD; ++i) {
return (&keytbl[i]);
}
return (NULL);
}
/*
* lookup_sttpair - Given an stt_t return a string or NULL.
*
*/
static const char *
lookup_sttpair(stt_t s) {
/* valid type specifier combinations */
{ TS_VOID, "void" },
{ TS_CHAR, "char" },
{ TS_SHORT, "short" },
"signed short int" },
{ TS_UNSIGNED | TS_SHORT,
"unsigned short" },
"unsigned short int" },
{ TS_INT, "int" },
{ TS_SIGNED, "signed" },
{ TS_NO_TS, "" },
{ TS_UNSIGNED, "unsigned" },
{ TS_LONG, "long" },
"signed long int" },
"unsigned long int" },
{ TS_FLOAT, "float" },
{ TS_DOUBLE, "double" },
{ TS_STRUCT, "struct" },
{ TS_UNION, "union" },
{ TS_ENUM, "enum" },
{ TS_TYPEDEF, "" },
/* non-ANSI type: long long */
{ TS_LONGLONG, "long long" },
{ TS_SIGNED | TS_LONGLONG,
"signed long long" },
{ TS_UNSIGNED | TS_LONGLONG,
"unsigned long long" },
"signed long long int" },
"unsigned long long int" },
};
int i;
for (i = 0; i < NDECLSPEC; ++i)
return (NULL);
}
/*
* yylex - return next token from the the input stream.
*
* The lexical analyzer does not recognize all possible C lexical
* elements. It only recognizes those associated with function
* declarations (read: prototypes) and data definitions.
*/
static int
yylex(void) {
int c;
int i = 0;
switch (c = getch()) {
case '/':
if (lookahead('*')) {
skipcomment();
goto restart;
}
case '.':
if (lookahead('.')) {
if (lookahead('.'))
return (ELLIPSIS);
}
case EOF:
case '(':
case ')':
case ',':
case '[':
case ']':
case ';':
case '*':
return (c);
default:
if ((c == '_') || isalpha(c)) {
do {
buf[i++] = c;
c = getch();
} while ((c == '_') || isalnum(c));
ungetch(c);
buf[i] = '\0';
} else {
}
} else if (isdigit(c)) {
do {
buf[i++] = c;
ungetch(c);
buf[i] = '\0';
return (INTEGER);
} else
return (c);
}
/* NOTREACHED */
}
/* getch - return the next character from the input stream. */
static int
getch(void) {
int c;
if ((c = *input) == '\0')
c = EOF;
else /* only advance on non-NULL */
input++;
return (c);
}
/* ungetch - return a character to the input stream. */
static void
ungetch(int c) {
*(--input) = c;
}
/* skipwhitespace - skip over whitespace in the input stream. */
static void
skipwhitespace(void) {
int c;
;
ungetch(c);
}
/* skipcomment - scan ahead to the next end of comment. */
static void
skipcomment(void) {
loop {
int c;
switch (c = getch()) {
case EOF:
return;
case '*':
if (lookahead('/'))
return;
}
}
/* NOTREACHED */
}
/* lookahead - does next character match 'c'? */
static int
lookahead(int c) {
int match;
return (match);
}
/* putNtabs - write N '\t' to standard output. */
#if defined(DEBUG)
static void
putNTabs(int n) {
int i;
for (i = 0; i < n; ++i)
putchar('\t');
}
#endif /* DEBUG */
/* D E C L A R A T I O N S P E C I F I E R S */
/*
* Declaration specifiers encode storage class, type specifier and type
* qualifier information. This includes any identifiers associated with
* struct, union or enum declarations. Typedef names are also encoded
* in declaration specifiers.
*/
/* declspec_Construct - allocate and initialize a declspec_t. */
static decl_spec_t *
declspec_Construct(void) {
#if defined(MEM_DEBUG)
#endif
return (dsp);
}
/* declspec_Destroy - free a declspec_t. */
static void
#if defined(MEM_DEBUG)
#endif
}
/*
* declspec_Init - allocate and initialize a declspec_t given an
* stt_t and identifier.
*
* Note:
* 1) identifier can be NULL.
* 2) errors resulting in the stt_t and identifier are ignored.
*/
static decl_spec_t *
const char *p;
return (dsp);
}
/*
* declspec_VerifySTT - verify that the two given stt_t can be combined.
*
* Note:
* 1) The return value is a const char *, non-NULL to indicate an error.
*/
static char *
return ("attempt to add declaration specifier "
"that is already present");
return ("attempt to combine basic and "
"derived types");
if (STT_isvoid(result) &&
return ("attempt to combine void with "
"other type specifiers");
return ("attempt to combine floating and "
"integer type specifiers");
return ("attempt to combine character and "
"integer type specifiers");
if (STT_has_explicit_sign(result) &&
return ("attempt to combine signed or "
"unsigned with float or derived type");
return ("invalid declaration specifier");
}
return (NULL);
}
/*
* declspec_AddSTT - add an stt_t to a decl_spec_t.
*
* Note:
* 1) The "long long" type is handled here.
* If both stt_t include TS_LONG then this is an attempt to use
* "long long". The TS_LONG is cleared from the s1 and s2 and
* then TS_LONGLONG is added to s2. The resulting s1 and s2 are
* passed to declspec_VerifySTT to determine if the result is valid.
*
* 2) This method of handling "long long" does detect the case of
* "long double long" and all it's variant forms.
*/
static decl_spec_t *
/* non-ANSI type: long long */
s2 |= TS_LONGLONG;
}
return (dsp);
}
/*
* declpec_AddDS - add a decl_spec_t to an existing decl_spec_t.
*/
static decl_spec_t *
}
return (dsp);
}
/*
* declspec_GetSTT - return the stt_t within a decl_spec_t.
*/
static stt_t
}
/*
* declspec_GetTag - return the identifier within a decl_spec_t.
*/
static char *
}
/*
* declspec_ToString - convert a decl_spec_t into a string.
*
* Note:
* 1) The form of the resulting string is always the same, i.e.
*
* [register] [type_specifier] [const] [volatile]
*
* dsp must be correct
*
*/
char *
const char *s;
int something = 0;
*bufp = '\0';
/* storage class specifier */
case SCS_REGISTER:
something = 1;
break;
}
/* type specifier */
case TS_STRUCT:
case TS_UNION:
case TS_ENUM:
if (something)
break;
case TS_TYPEDEF:
if (something)
break;
default:
if (something)
break;
}
if (s)
something = 1;
}
/*
* It currently acknowledges and ignores restrict or _RESTRICT_KYWD
* in code generation because of the uncertain behavior of "restrict".
*/
return (bufp);
}
/* T Y P E M O D I F I E R S */
/*
* Type modifiers encode the "array of...", "pointer to ..." and
* "function returning ..." aspects of C types. The modifiers are kept
* as a linked list in precedence order. The grammar encodes the
* precedence order described by the standard.
*
* Type modifiers are always added at the end of list and the list is
* always traversed from head to tail.
*/
/* type_Construct - allocate and initialize a type_t. */
static type_t *
type_Construct(void) {
tp->t_ellipsis = 0;
/* DD_PTR */
#if defined(MEM_DEBUG)
#endif
return (tp);
}
/* type_Destroy - free a type_t list. */
static void
while (tp) {
case DD_FUN:
break;
case DD_PTR:
break;
case DD_ARY:
break;
}
#if defined(MEM_DEBUG)
#endif
}
}
/*
* type_SetPtr - make a type_t into a "pointer to ..." variant.
*
* Note:
* 1) The stt_t will encode any type qualifiers (const, volatile).
*/
static type_t *
return (tp);
}
/*
* type_SetAry - make a type_t into an "array of ...", variant.
*
* Note:
* 1) The array dimension can be NULL to indicate undefined, i.e. [].
*/
static type_t *
if (dim) {
} else
return (tp);
}
/*
* type_SetFun - make a type_t into a "function returning ..." variant.
*
* Note:
* 1) The argument list can be NULL to indicate undefined, i.e. ().
*/
static type_t *
if (arglist) {
}
return (tp);
}
/*
* type_AddTail - add a type_t to the end of an existing type_t list.
*
* Note:
* 1) The type_t *tp is added to the end of the type_t *dp list.
*/
static type_t *
type_t *p;
lastp = p;
return (dp);
}
#if defined(DEBUG)
/* type_PrintType - print a type_t list onto standard output. */
static void
while (tp) {
case DD_PTR:
break;
case DD_FUN:
printf("fun [%d%c] %s\n",
"undefined arguments");
if (tp->t_ellipsis) {
printf("...\n");
}
}
break;
case DD_ARY:
printf("ary [%s] of\n",
break;
}
}
}
#endif /* DEBUG */
/*
* type_Verify - verify a type_t list for semantic correctness.
*
* Note:
* 1) C supports most combinations of type modifiers.
* It does not support three combinations, they are:
*
* function returning array
* array of functions
* function returning function
*
* 2) The enum values associated with type modifiers (i.e. DD_*)
* cannot be modified without changing the table included within the
* function.
*
* 3) The function returns NULL to indicate that the type modifier
* list is valid and non-NULL to indicate an error.
*
* 4) A type_t of NULL is permitted to indicate an empty type_t list.
*/
static const char *
/* NONE ARY FUN PTR */
"function returning function", NULL},
};
if (tp) {
do {
const char *p;
return (p);
}
return (NULL);
}
/* type_GetNext - return the next type_t in the list. */
type_t *
}
/*
* The following group of functions return and or
* test various aspects of type modifiers.
*
* 1) The three functions: type_IsPtrTo, type_IsFunction and
* type_IsArray will accept an argument of NULL.
*
* 2) All other functions require one of the above three to be true.
* Various asserts are in place to verify correct usage.
*/
int
}
char *
}
int
}
}
int
}
int
}
int
return (tp->t_ellipsis);
}
decl_t *
}
/*
* type_IsPtrFun - determine if the type_t results in a call-able function.
*
* Note:
* 1) The argument can be NULL.
*
* 2) The test is true if the type_t list is number of DD_PTR followed
* by a DD_FUN.
*/
int
return (0);
}
/* D E C L A R A T O R */
/*
* A decl_t encodes the name,
* declaration specifiers and type modifiers of an object.
*/
/* decl_Construct - allocate a decl_t. */
static decl_t *
decl_Construct(void) {
dp->d_ellipsis = 0;
#if defined(MEM_DEBUG)
#endif
return (dp);
}
/* decl_Destroy - free a decl_t list. */
void
while (dp) {
#if defined(MEM_DEBUG)
#endif
}
}
/*
* decl_GetArgLength - return the length of a decl_t list.
*
* Note:
* 1) The argument may be NULL to indicate an empty list, len == 0.
*/
int
int len;
++len;
return (len);
}
/*
* The following group of functions get or test various aspects of a decl_t.
*/
decl_t *
}
}
char *
}
type_t *
}
int
return (dp->d_ellipsis);
}
int
}
char *
}
/*
* decl_AddArg - add a decl_t to the end of an decl_t list.
*/
static decl_t *
decl_t *p;
lastp = p;
return (dp);
}
/*
* decl_IsVoid - return true if the decl_t is a "pure" void declaration.
*/
static int
}
/*
* decl_IsVoidArray - return true if the decl_t includes "void []".
*/
static int
int retval = 0;
if (tp) {
}
return (retval);
}
/*
* decl_Verify - verify a decl_t.
*/
static const char *
if (decl_IsVoid(dp))
ep = "type is void";
else if (decl_IsVoidArray(dp))
ep = "type is void []";
else
return (ep);
}
/*
* decl_VerifyArgs - verify a decl_t list.
*/
static const char *
if (dp) {
int nv = 0;
if (decl_IsVoid(dp)) {
++nv;
if (decl_GetName(dp))
ep = "argument list includes "
"void with identifier";
} else if (decl_IsVoidArray(dp))
ep = "argument list includes void []";
if (nv) { /* there was some void */
if (nargs > 1)
ep = "argument list includes void";
if (tp->d_ellipsis)
ep = "argument list includes void and \"...\"";
}
}
return (ep);
}
/* decl_AddDS - add a decl_spec_t to a decl_t. */
static decl_t *
return (dp);
}
/*
* decl_SetName - set the name associated with a decl_t.
*
* Note:
* 1) Any previously known name is free'd.
*/
decl_t *
return (dp);
}
/*
* decl_AddTypeTail - add a type_t to the end of a decl_t type_t list.
*/
static decl_t *
else
return (dp);
}
/*
* decl_addptr - add a DD_PTR type_t to the end of a decl_t type_t list.
*/
static decl_t *
return (dp);
}
/*
* decl_addary - allocate and add a DD_ARY type_t to the end of
* a decl_t type_t list.
*/
static decl_t *
return (dp);
}
/*
* decl_addfun - allocate and add a DD_FUN type_t to the end of a
* decl_t type_t list.
*/
static decl_t *
const char *sp;
return (dp);
}
/*
* decl_addellipsis - set the ellipsis state in a decl_t.
*
* Note:
* 1) This function is only used in the grammar in the
* parameter list parsing.
*/
static decl_t *
return (dp);
}
#if defined(DEBUG)
static void
while (dp) {
printf("name = %s, ds = %s\n",
}
}
#endif /* DEBUG */
static char *
char_getend(char *s) {
while (*s != '\0')
++s;
return (s);
}
char *
const char *altname) {
const char *namep;
int ffun = 1;
switch (out) {
default:
/* FALLTHRU */
case DTS_DECL:
} else {
}
break;
case DTS_CAST:
namep = "(*)";
break;
case DTS_RET:
namep = "_return";
} else {
}
break;
}
*bufp = '\0';
while (tp) {
case DD_PTR:
} else {
}
/*
* It currently acknowledges and ignores restrict
* or _RESTRICT_KYWD in code generation because
* of the uncertain behavior of "restrict".
*/
} else {
}
break;
case DD_ARY:
break;
case DD_FUN:
ffun = 0;
} else {
NULL);
}
}
if (tp->t_ellipsis) {
}
}
break;
}
}
} else {
}
return (bufp);
}
decl_t *
int argno = 0;
if (decl_IsFunction(dp)) {
int argno = 0;
while (p) {
char *s = decl_GetName(p);
if ((s == NULL) && !decl_IsVoid(p)) {
decl_SetName(p, s);
}
p = p->d_next;
++argno;
}
}
return (dp);
}
const char *
atIDENT = 0;
yyparse(); /* parse the prototype */
} else { /* failure */
}
return (errstr);
}
static void
}
#if defined(DEBUG)
/* main */
static int yydebug = 1;
int
int i;
yydebug = 1;
for (i = 1; i < argc; ++i) {
const char *es;
else {
#if GR_DEBUG
decl_PrintDecl(pp, 0);
#endif
printf("---\n%s;\n",
printf("%s\n",
printf("%s;\n",
#ifdef TRACE
printf("\n\nTrace Info\n");
#endif
}
#if defined(MEM_DEBUG)
#endif
}
return (0);
}
#ifdef TRACE
void
int isptrfun;
return;
else
return;
if (isptrfun)
while (funargs) {
while (tp) {
}
}
} else {
}
}
}
#endif /* TRACE */
#endif /* DEBUG */
static char *
{
return (str);
}
void
{
return;
while (tp) {
}
}
if (type_IsPtrFun(tp)) {
} else {
}
}
char *
{
char *bend;
tmp[0] = 0;
bufp[0] = 0;
while (tp) {
case DD_ARY:
break;
case DD_FUN:
NULL);
}
}
if (tp->t_ellipsis) {
}
}
break;
}
}
return (bufp);
}