|
|
researchv10 Norman
/* -*- Mode:C++ -*- */
/*ident "@(#)ctrans:src/lalex.c 1.6.3.21" */
/*
$Source: /var/lib/cvsd/repos/research/researchv10no/cmd/cfront/ooptcfront/lalex.c,v $ $RCSfile: lalex.c,v $
$Revision: 1.1.1.1 $ $Date: 2018/04/24 17:21:35 $
$Author: root $ $Locker: $
$State: Exp $
*/
/**************************************************************************
C++ source for cfront, the C++ compiler front-end
written in the computer science research center of Bell Labs
Copyright (c) 1984 AT&T, Inc. All Rights Reserved
THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T, INC.
lalex.c:
lookahead
*****************************************************************************/
#include <stdio.h>
#include "cfront.h"
#include "yystype.h"
#include "tqueue.h"
#include "template.h"
// external functions
extern void la_backup( TOK, YYSTYPE );
extern int la_decl();
extern int la_cast();
extern TOK lalex();
extern TOK la_look();
static int laexpr( TOK );
static int latype( TOK );
/* make this a toknode! */
static int lasttk = 0; // one token history
static YYSTYPE lastval; // yylval lasttk value
int must_be_expr = 0; // handle redundant parentheses
int must_be_id = 0; // !0, TNAME => ID, i.e., int X
extern int in_mem_fct;
extern int in_class_decl;
extern int in_arg_list;
extern int DECL_TYPE;
toknode* latok; // current lookahead token
toknode* front = 0;
toknode* rear = 0;
static toknode* free_toks = 0;
const TQCHUNK = 16;
toknode::toknode(TOK t, YYSTYPE r)
{
if (free_toks == 0) {
// extern char* calloc(unsigned,unsigned);
register toknode* q;
int sz = sizeof( toknode );
free_toks = q = (toknode*)calloc( TQCHUNK, sz );
for (; q != &free_toks[TQCHUNK-1]; q->next = q+1, ++q);
}
this = free_toks; free_toks = free_toks->next;
tok = t;
retval = r;
next = last = 0;
}
toknode::~toknode()
{
next = free_toks;
free_toks = this;
this = 0;
}
void addtok(TOK t, YYSTYPE r)
{
toknode* T = new toknode(t,r);
if (front == 0)
front = rear = T;
else {
rear->next = T;
T->last = rear;
rear = T;
}
}
extern TOK
deltok( int noset = 0 )
{
register toknode* T = front;
register TOK tk = T->tok;
if ( !noset ) yylval = T->retval;
if (front = front->next)
front->last = 0;
else
latok = rear = 0;
delete T;
return tk;
}
static void
add_tokens()
/*
extend lookahead token queue when depleted
*/
{
TOK tk = tlex();
if ( tk != ID )
return;
while (tk == ID || tk == MEM || tk == DOT )
tk = tlex();
}
extern TOK
la_look()
/*
peek at head of token queue
*/
{
if ( front == 0 )
add_tokens();
latok = front;
return latok->tok;
}
static int
latype( TOK t )
{
switch ( t ) {
default: // includes friend, typedef, storage classes, etc.
return 0;
case CHAR: case SHORT: case INT: case LONG:
case FLOAT: case DOUBLE:
case UNSIGNED:
return 1;
}
}
static int
laexpr( TOK t )
{
switch ( t ) {
default:
return 0;
case RETURN: case NEW: case AND: case ANDAND: case OR: case OROR:
case SIZEOF: case NOT: case COMPL: case MUL: case PLUS: case MINUS:
case ER: case ASSIGN: case ASOP: case RELOP: case EQUOP: case DIVOP:
case SHIFTOP: case ICOP:
return 1;
}
}
static toknode *get_next_token(toknode *t)
{
if (! t->next)
add_tokens() ;
return t->next ;
}
// provide the looakhead for determining TSCOPE tokens when the name is a
// parametrized type name; the lookahead here is non-trivial, because it
// involves stepping over the template arguments.
static int template_tscope(Pname tn, toknode *lt) {
int nest = 0 ; // the LT has been fetched
if (lt->tok != LT) error ('i', "a LT token was expected") ;
// assume the worst, ensure that name strings are consed in the heap
templp->parameters_in_progress++ ;
for (toknode *t = lt;; t = get_next_token(t))
switch (t->tok) {
case LT:
nest ++ ;
continue ;
case GT:
if (--nest == 0) {
t = get_next_token(t) ;
if (t->tok == MEM) {
// determine whether it is a memptr
if (t->next == 0)
add_tokens() ;
if (t->next->tok == MUL) {
t->tok = MEMPTR ;
t->next = t->next->next ;
}else t->tok = TSCOPE ;
t->retval.pn = tn ;
templp->parameters_in_progress-- ;
return 1 ;
} else return 0 ;
}
continue ;
case SM: case LC: case RC: // a quick exit in case of error
case EOFTOK:
templp->parameters_in_progress-- ;
return 0 ;
default:
continue ;
}
}
static TOK
lookahead()
/*
advance lookahead pointer, lexing at end of Q
handle occurrences of TNAME and TSCOPE
(should be kept up to date with lalex())
*/
{
TOK tk;
TOK prev_tk = 0;
YYSTYPE lastval;
if ( latok == rear ) {
add_tokens();
if ( latok )
latok = latok->next;
else
latok = front;
}
else
latok = latok->next;
if ( latok->last ) {
prev_tk = latok->last->tok;
lastval = latok->last->retval;
}
nexttok:
tk = latok->tok;
if ( tk == ID || tk == TNAME )
{
if (latok->next == 0) add_tokens();
TOK tk2 = latok->next->tok;
if ( tk == TNAME ) {
if (tk2 == LT) {
// a parametrized type name
if (template_tscope(latok->retval.pn, latok->next))
// differentiate it from a TNAME, so that it can be dealt with
// in the grammar.
tk = PTNAME ;
}else if ( tk2 == MEM || tk2 == DOT ) {
tk = TSCOPE;
latok = latok->next;
if (latok->next == 0) add_tokens();
tk2 = latok->next->tok;
if ( tk2 == MUL )
{
tk = MEMPTR;
latok = latok->next;
}
}
else if (( prev_tk == MUL && tk2 != RP )
|| prev_tk == AND )
{
tk = ID;
latok->retval.pn->hide();
latok->tok = ID;
latok->retval.s = latok->retval.pn->string;
}
}
else if ( tk2 == MEM ) {
// ID ::
latok = latok->next->next;
goto nexttok;
}
if ( tk == ID &&
( tk2 == ID ||
( prev_tk == ID && ( tk2 == COLON || tk2 == LC )))) {
// ID ID
latok = latok->next;
goto nexttok;
}
}
return tk;
}
extern Ptype in_typedef;
extern Pname statStat;
static Pname mem_sel = 0;
extern TOK
lalex()
/* return next token to grammar */
{
register TOK tk;
if ( front == 0 )
add_tokens(); // extend lookahead queue
gettok:
tk = deltok();
if ( tk == ID || tk == TNAME )
{
TOK tk2 = la_look();
extern int bl_level;
int lex_level = bl_level - in_class_decl - (tk2 == LC );
if ( tk == TNAME )
{
// error('d', "lalex %n lasttk: %k tk2: %k must_be_id: %d", yylval.pn, lasttk, tk2, must_be_id );
if ( tk2 == LP
&& (bl_level == 0 || in_class_decl )
&& ( laexpr(lasttk) == 0 )
&& must_be_expr == 0
&& DECL_TYPE == 0 ) {
if (la_decl()) {
must_be_id = 0;
DECL_TYPE = tk;
tk = DECL_MARKER;
goto ret;
}
}
if ( lasttk == AGGR || lasttk == ENUM ) {
if ( in_typedef == 0 ) {
TOK type_tk = yylval.pn->tp->base==COBJ
? AGGR
: (yylval.pn->tp->base==EOBJ?ENUM:TYPEDEF);
if ( lasttk != type_tk )
error( "%nredefined: %k and %k", yylval.pn, type_tk, lasttk );
}
if ( lex_level && (tk2 == LC || tk2 == COLON)
// temporary
&& lasttk != ENUM ) {
Pname bn = Pbase(yylval.pn->tp)->b_name;
Pclass cl = Pclass(bn->tp);
if ( yylval.pn->lex_level != lex_level || cl->lcl ) {
extern void local_hide( Pname ); // place in cfront.h
extern Plist local_blk; // place in cfront.h
local_hide( yylval.pn );
Pname n = new name( yylval.pn->string );
n->lex_level = lex_level>=0?lex_level:0;
n = n->tname( lastval.t );
modified_tn = modified_tn->l;
n->n_key = LOCAL;
local_class = new name_list( n, local_class );
local_blk = new name_list( n, local_blk );
yylval.pn = n;
}
// catch redefinition of local classes
else if ( lex_level == yylval.pn->lex_level && cl->defined )
error( "localC%nredefined", yylval.pn );
}
} // end: if (lasttk == AGGR or ENUM )
if (tk2 == LT) {
// a parametrized type name
if (template_tscope(yylval.pn,latok))
// differentiate it from a TNAME, so that it can be dealt with
// in the grammar.
tk = PTNAME ;
}else if ( tk2 == MEM || (tk2 == DOT && mem_sel == 0 )) {
if (tk2==DOT)
error('w',"``.'' used for qualification, please use ``::''");
tk = TSCOPE;
tk2 = deltok(1);
tk2 = la_look();
if ( tk2 == MUL ) {
tk = MEMPTR;
tk2 = deltok(1);
}
}
// Have a TNAME. Check to be sure.
else if ( must_be_id ){
if ( in_class_decl
&& lasttk == TYPE
&& tk2 == LP
&& strcmp(yylval.pn->string,ccl->string) == 0 )
error("%nK with returnT", yylval.pn);
else if ( lasttk == TYPE && lastval.t == OVERLOAD
&& ( tk2 == SM || tk2 == LP ) )
{
tk = ID;
yylval.pn->hide();
yylval.pn = new name( yylval.pn->string );
yylval.pn->n_oper = TNAME;
}
else if ( lasttk == OPERATOR )
must_be_id = 0;
else
// watch out for X::X
if ( lasttk != TSCOPE
|| lastval.pn != yylval.pn
|| ( in_typedef && in_typedef->check( yylval.pn->tp,0) == 0 ))
{
tk = ID;
extern int defer_check;
extern Pname in_tag;
if ( in_typedef && (lasttk == MUL || lasttk == REF)) {
defer_check = 1;
in_tag = yylval.pn;
}
if ( lasttk == MEM && yylval.pn->lex_level ) {
Pname nn = gtbl->look( yylval.pn->string, 0 );
if (nn == 0 )
error( "%k%s undeclared", lasttk, yylval.pn->string);
else
yylval.pn = nn;
}
else {
// error('d',"lalex: else: lasttk: %k", lasttk );
if (lasttk!=DOT && lasttk!=REF && lasttk!=TSCOPE && lasttk !=GOTO) yylval.pn->hide();
yylval.pn = new name (yylval.pn->string);
if (lasttk!=DOT && lasttk!=REF && lasttk!=TSCOPE && lasttk !=GOTO) yylval.pn->n_oper = TNAME;
}
if ( defer_check ) defer_check = 0;
}
} // must_be_id
if ((lasttk == SM || lasttk == RC || lasttk == LC)
&& tk2 == COLON ) { // label
tk = ID;
yylval.pn = new name (yylval.pn->string);
}
if ( in_class_decl &&
ccl->lex_level &&
yylval.pn->lex_level != 0 &&
yylval.pn->tp &&
(yylval.pn->tp->base != COBJ && yylval.pn->tp->base != EOBJ))
{
Pname n = gtbl->look( yylval.pn->string,0);
// error( 'd', "bl_level: %d in_mem_fct: %d", bl_level, in_mem_fct );
if ( in_mem_fct ) {
if (n && n->base == TNAME ) {
error('w', "local typedef %n(%t) is not in scope of local class %s members; using global (%t)", yylval.pn, yylval.pn->tp, ccl->string, n->tp );
yylval.pn = n;
}
else
error( "local typedef %sis not in scope of inline member function of local class %s", yylval.pn->string, ccl->string);
}
}
}
else
{ // tk == ID
char *s = yylval.s;
Pname n = ktbl->look( s, HIDDEN );
//error( 'd', "n: %n, beenhid: %n, in_arg_list: %d", n, beenHid,in_ arg_list );
if (tk2 == MEM) {
// ID ::
if (n) {
tk = TSCOPE;
tk2 = deltok(1);
yylval.pn = n;
tk2 = la_look();
if ( tk2 == MUL ) {
tk = MEMPTR;
tk2 = deltok(1);
}
}
else {
error( "%s is not aTN", s);
tk2 = deltok(1);
goto gettok;
}
}
// Have an ID. Check last token to be sure.
else if (lasttk==ENUM ||
(lasttk==AGGR &&
// template <class id, class id>
(tk2 != GT) && tk2 != CM)) {
tk = TNAME;
if ((n==0) ||
(n->n_template_arg == name::template_type_formal))
{ // new tag, define it
n = new name( s );
n->lex_level = lex_level>=0?lex_level:0;
n = n->tname( lastval.t );
modified_tn = modified_tn->l;
if (lex_level == 0 ) {
if (gtbl->look(n->string,0))
// don't know yet if n has ctor(): defer
statStat = n;
}
else if ( lex_level > 0
// temporary
&& lasttk != ENUM ) {
n->n_key = LOCAL;
local_class = new name_list( n, local_class );
extern Plist local_blk; // place in cfront.h
local_blk = new name_list( n, local_blk );
}
}
else {
if (n->tp->base!=COBJ && n->tp->base!=EOBJ) {
error( 'i', "hidden%n:%t",n,n->tp );
goto gettok;
}
if ( tk2 == LC || tk2 == COLON ) {
// class declared and hidden but not yet defined
// may have ctor defined which invalidates hiding
statStat = n;
n->n_key = 0; // inside class definition it cannot be hidden
}
}
yylval.pn = n;
}
else {
tk = ID;
yylval.pn = new name( s );
}
if ( tk == ID )
{
if ( tk2 == ID ) {
Pname n = ktbl->look( s, HIDDEN );
if ( n ) {
// add handling of enum
if ( n->tp->base == COBJ )
error("%sis hidden: use struct %s%s", s,s,front->retval.s);
else if ( n->tp->base == EOBJ )
error("%sis hidden: use enum %s%s", s,s,front->retval.s);
else error("typedef %sis not visible in this scope", s );
}
else
error("%s%s: %sis not aTN", s,front->retval.s,s);
}
else
if ( tk2 == DOT || tk2 == REF )
mem_sel = yylval.pn;
else
if ( lasttk == TNAME && tk2 == LC )
{
error("T%s %k: %s is unexpected", s, tk2, s );
goto gettok;
}
}
}
}
if ( tk == TNAME || ( tk == TYPE && latype(yylval.t) )
|| tk == TSCOPE || tk == MEM
|| tk == REF || tk == DOT || tk == GOTO
|| tk == MEMPTR )
// TNAME cannot immediately follow a type name,
// scope operator, right curly, selection, or goto
must_be_id = 1;
else
must_be_id = 0;
if( tk == SM) mem_sel = 0;
ret:
lasttk = tk ;
lastval = yylval;
return tk;
}
extern void
la_backup( TOK t, YYSTYPE r )
/*
called by parser to push token back on front of queue
*/
{
if ( t == ID ) r.s = r.pn->string;
register toknode* T = new toknode(t,r);
if (front) {
front->last = T;
T->next = front;
T->last = 0;
front = T;
} else
front = rear = T;
}
extern int
la_sctype( TOK t ) {
if ( t != latok->tok && t != TSCOPE ) error( 'i', "la_sctype, lalex.c" );
switch( latok->retval.t ) {
case TYPEDEF:
case EXTERN:
case STATIC:
case AUTO:
case REGISTER:
case OVERLOAD:
case INLINE:
case FRIEND:
case CONST:
case VOLATILE:
return 1;
default:
return 0;
}
}
extern int
la_cast()
/*
called in reduction of term_lp to check for ambiguous prefix-style cast
if result is 1, caller inserts DECL_MARKER to force reduction of cast
*/
{
// yychar already designates TYPE or TNAME
// LP must start the lookahead queue!
int tk, tk2 = latok->tok;
for ( ; ; ) {
tk = tk2;
tk2 = lookahead();
switch( tk ) {
case LP:
if ( tk2 == MUL || tk2 == AND ||
tk2 == TSCOPE || tk2 == MEMPTR )
// T ( * ...
// T ( C ::* ...
continue;
else
// T ( exp )
return 0;
case MUL: case AND:
//if ( tk2 == SCTYPE )
if ( la_sctype( tk2 ) )
// T ( * const ...
// T ( * volatile ...
tk2 = lookahead();
continue;
case TSCOPE:
if ( tk2 == MUL )
// T ( C :: * ...
continue;
else
// T ( exp )
return 0;
case RP: case LB:
// T (*)()
// T (*[])()
return 1;
case MEMPTR:
if ( tk2 == RP )
continue;
}
return 0;
}
}
extern int
la_decl()
/*
handles ambiguities
type (*x) ()
type (*x) []
at start of arg list / statement
return val == 1 if lookahead finds a declaration
(used for error messages only)
if declaration is "ambiguous" (i.e., can't be recognized with
1-symbol lookahead), insert DECL_MARKER to force reduction
of "type"
*/
{
// LP must start the lookahead queue!
int tk, tk2 = latok->tok;
int paren = 0;
int ptr = 0;
for ( ; ; ) {
tk = tk2;
tk2 = lookahead();
// fprintf(stderr,"\nla_decl:tk:%d %s tk2: %d %s", tk, keys[tk], tk2, keys[tk2]);
switch( tk ) {
case LP:
if ( tk2 == MUL || tk2 == AND || tk2 == TSCOPE ) {
// T ( * ...
++paren;
ptr = 1;
continue;
} else
if ( tk2 == MEMPTR ) {
// T ( C ::* ...
return 1;
} else
// possible redundant parens
if ( tk2 == ID && lookahead() == RP ) {
TOK tp = lookahead();
// error( 'd', "tp %k tk: %k tk2: %k", tp, tk, tk2 );
// error( 'd', "bl_level: %d, in_class_decl: %d", bl_level,in_class_decl );
if ( tp == SM || tp == CM || tp == ASSIGN )
{
// member initialization list
if ( tp != SM && in_arg_list == 0 ) return 1;
}
else
if ( tp == RP && (bl_level-in_class_decl==0))
return 1;
if ( tp != LP )
return 0;
latok=latok->last; // restore lookahead
++paren;
continue;
}
else
// T ( exp )
return 0;
case MUL: case AND:
//if ( tk2 == SCTYPE )
if ( la_sctype( tk2 ))
// T ( * const ...
// T ( * volatile ...
return 1;
else {
ptr = 0;
continue;
}
case TSCOPE:
if ( tk2 == MUL )
// T ( C :: * ...
return 1;
else if ( ptr )
// T ( exp )
return 0;
else if ( tk2 == ID || tk2 == OPERATOR )
// T ( * C :: id ...
continue;
else
// error
return 0;
}
break;
}
if ( tk == RP || tk == LB )
// T (*)()
// T (*[])()
return 1;
if ( tk != ID && tk != OPERATOR )
// T ( exp )
return 0;
if ( tk == OPERATOR )
switch ( tk2 ) {
case PLUS: case MINUS: case MUL: case REFMUL:
case AND: case OR: case ER: case SHIFTOP: case EQUOP:
case DIVOP: case RELOP: case ANDAND: case OROR:
case NOT: case COMPL: case ICOP: case ASSIGN:
case ASOP: case NEW: case GNEW: case DELETE:
// OPERATOR oper
tk2 = lookahead();
break;
case LP:
// OPERATOR ()
tk2 = lookahead();
if ( tk2 == RP ) {
tk2 = lookahead();
break;
} else
return 0;
case LB:
// OPERATOR []
tk2 = lookahead();
if ( tk2 == LB ) {
tk2 = lookahead();
break;
} else
return 0;
default: // illegal operator
return 0;
}
int allow_lp = 1;
int allow_rp = 1;
for ( ; ; ) {
tk = tk2;
tk2 = lookahead();
// fprintf(stderr,"\nla_decl2:tk:%d %s tk2: %d %s", tk, keys[tk], tk2, keys[tk2]);
switch( tk ) {
case LP:
if ( !allow_lp )
// T ( * id [ exp ] ( ...
return 0;
// Current lookahead will be a decl if
// the next lookahead is an arg decl
if ( tk2 == RP || tk2 == ENUM || tk2==AGGR
|| tk2==ELLIPSIS || la_sctype( tk2 ))
// T ( * id ()
// T ( * id ) ()
return 1;
if ( tk2 == TYPE || tk2 == TNAME ) {
// T ( * id ) ( T2 ...
if ( lookahead() == LP && !la_decl() )
return 0;
return 1;
}
return 0;
case LB:
if ( tk2 == RB || lookahead() == RB )
// T ( * id [] ...
return 1;
else {
// T ( * id [ exp ] ...
allow_lp = 0;
allow_rp = 1;
while ( lookahead() != RB );
tk2 = lookahead();
continue;
}
case RP:
// error ('d', "rp: allow_rp: %d paren: %d", allow_rp, paren );
if ( !allow_rp || !paren )
// T ( * id ) )
return 0;
// permit redundant parentheses
else
if ( tk2 == SM || tk2 == CM || tk2 == ASSIGN )
return 1;
else
if ( tk2 == RP && (bl_level-in_class_decl == 0))
return 1;
else
{
// T ( * id ) ...
allow_lp = 1;
allow_rp = 0;
--paren;
continue;
}
default:
return 0;
}
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.