# include "mfile1.h" # include /* temporarily */ /* character-set translation */ # ifndef CCTRANS # define CCTRANS(x) (x) # endif int flflag = 0; # ifndef FLOATCVT double atof(); # define FLOATCVT(x) atof(x) # endif # ifndef ASMBUF # define ASMBUF 50 # endif char asmbuf[ASMBUF]; char *asmp; int asm_esc = 0; /* asm escaped used in file */ /* lexical actions */ # define A_ERR 0 /* illegal character */ # define A_LET 1 /* saw a letter */ # define A_DIG 2 /* saw a digit */ # define A_1C 3 /* return a single character */ # define A_STR 4 /* string */ # define A_CC 5 /* character constant */ # define A_BCD 6 /* GCOS BCD constant */ # define A_SL 7 /* saw a / */ # define A_DOT 8 /* saw a . */ # define A_PL 9 /* + */ # define A_MI 10 /* - */ # define A_EQ 11 /* = */ # define A_NOT 12 /* ! */ # define A_LT 13 /* < */ # define A_GT 14 /* > */ # define A_AND 16 /* & */ # define A_OR 17 /* | */ # define A_WS 18 /* whitespace (not \n) */ # define A_NL 19 /* \n */ /* character classes */ # define LEXLET 01 # define LEXDIG 02 # define LEXOCT 04 # define LEXHEX 010 # define LEXWS 020 # define LEXDOT 040 /* reserved word actions */ # define AR_TY 0 /* type word */ # define AR_RW 1 /* simple reserved word */ # define AR_CL 2 /* storage class word */ # define AR_S 3 /* struct */ # define AR_U 4 /* union */ # define AR_E 5 /* enum */ # define AR_A 6 /* asm */ /* text buffer */ # define LXTSZ BUFSIZ char yytext[LXTSZ]; char * lxgcp; /* Let -T determine whether symbols are truncated. */ static int truncate_flag = 0; /* truncate based on -T (non-zero to truncate) */ #ifdef STKCK # include # define TRUE 1 extern char *getenv(); int stkckflg; /* global - referenced again in local.c - bfcode() */ #endif #ifdef PROFILE int proflg; /* global - referenced again in local.c - bfcode() */ #endif PROFILE /* ARGSUSED */ mainp1( argc, argv ) int argc; char *argv[]; { /* control multiple files */ register i; register char *cp; #ifdef STKCK register char *strval; #endif extern int idebug, bdebug, tdebug, edebug, ddebug, xdebug, opdebug; #ifndef TWOPASS extern int zflag; #endif extern unsigned long maxoffset; int fdef = 0; unsigned int temp = 1; i = 0; do { temp <<= 1; ++i; } while ( temp != 0 ); /* maxoffset = 1 << (i-1); */ maxoffset = 0x7ffc0L; #ifdef STKCK /* flag indicates if stack checking is req'd */ if( ((strval=getenv("M68000")) != NULL) && (!strcmp(strval,"STACKCHECK")) ) { stkckflg = TRUE; } #endif # ifdef SDB /* check specially for -g as first argument */ if( argc>1 && *(cp=argv[1])=='-' && cp[1]=='g' && !cp[2] ) { extern int gdebug; gdebug = 1; ++argv; --argc; } # endif for( i=1; i', A_GT, RELOP, GT, '=', A_EQ, ASSIGN, ASSIGN, -1, A_1C, 0, 0, }; struct lxdope *lxcp[CSSZ+1]; lxinit() { register struct lxdope *p; register i; register char *cp; /* set up character classes */ lxenter( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_", LEXLET ); lxenter( "0123456789", LEXDIG ); lxenter( "0123456789abcdefABCDEF", LEXHEX ); /* \013 should become \v someday; \013 is OK for ASCII and EBCDIC */ lxenter( " \t\r\b\f\013", LEXWS ); lxenter( "01234567", LEXOCT ); lxmask['.'+1] |= LEXDOT; /* make lxcp point to appropriate lxdope entry for each character */ /* initialize error entries */ for( i= 0; i<=CSSZ; ++i ) lxcp[i] = lxdope; /* make unique entries */ for( p=lxdope; ; ++p ) { lxcp[p->lxch+1] = p; if( p->lxch < 0 ) break; } /* handle letters, digits, and whitespace */ /* by convention, first, second, and third places */ cp = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; while( *cp ) lxcp[*cp++ + 1] = &lxdope[1]; cp = "123456789"; while( *cp ) lxcp[*cp++ + 1] = &lxdope[2]; cp = "\t\b\r\f\013"; while( *cp ) lxcp[*cp++ + 1] = &lxdope[3]; /* first line might have title */ lxtitle(); } int lxmatch; /* character to be matched in char or string constant */ lxstr(ct) register ct; { /* match a string or character constant, up to lxmatch */ register c; register val; register i; i=0; while( (c = getchar()) != lxmatch ) { switch( c ) { case EOF: uerror( "lxstr() unexpected EOF" ); break; case '\n': uerror( "newline in string or char constant" ); ++lineno; break; case '\\': switch( c = getchar() ) { case '\n': ++lineno; continue; default: val = c; goto mkcc; case 'n': val = '\n'; goto mkcc; case 'r': val = '\r'; goto mkcc; case 'b': val = '\b'; goto mkcc; case 't': val = '\t'; goto mkcc; case 'f': val = '\f'; goto mkcc; case 'v': val = '\013'; goto mkcc; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': val = c-'0'; c = getchar(); /* try for 2 */ if( lxmask[c+1] & LEXOCT ) { val = (val<<3) | (c-'0'); c = getchar(); /* try for 3 */ if( lxmask[c+1] & LEXOCT ) { val = (val<<3) | (c-'0'); } else ungetc( c ,stdin); } else ungetc( c ,stdin); goto mkcc1; } default: val =c; mkcc: val = CCTRANS(val); mkcc1: if( lxmatch == '\'' ) { /* it is, after all, a "character" constant */ val = ccast((CONSZ)val,CHAR); if( i==0 ) lastcon = val; else { # ifdef MAKECC MAKECC( val, i ); # else # ifdef RTOLBYTES lastcon <<= SZCHAR; lastcon |= (val&BITMASK(SZCHAR)); # else lastcon &= BITMASK(SZCHAR*i); lastcon |= val << (SZCHAR*i); # endif # endif } } else { /* stash the byte into the string */ if( strflg ) { if( ct==0 || i(SZINT/SZCHAR) || ( (pflag||hflag)&&i>1) ) uerror( "too many characters in character constant" ); } } lxcom() { register c; /* saw a /*: process a comment */ for(;;) { switch( c = getchar() ) { case EOF: uerror( "lxcom() unexpected EOF" ); return; case '\n': ++lineno; default: continue; case '*': if( (c = getchar()) == '/' ) return; else ungetc( c ,stdin); continue; # ifdef LINT case 'V': lxget( c, LEXLET|LEXDIG ); { extern int vaflag; register i; i = yytext[7]?yytext[7]-'0':0; yytext[7] = '\0'; if( strcmp( yytext, "VARARGS" ) ) continue; vaflag = i; continue; } case 'L': lxget( c, LEXLET ); if( strcmp( yytext, "LINTLIBRARY" ) ) continue; { extern int libflag; libflag = 1; } continue; case 'A': lxget( c, LEXLET ); if( strcmp( yytext, "ARGSUSED" ) ) continue; { extern int argflag, vflag; argflag = 1; vflag = 0; } continue; case 'N': lxget( c, LEXLET ); if( strcmp( yytext, "NOTREACHED" ) ) continue; reached = 0; continue; # endif } } } yylex() { for(;;) { register lxchar; register struct lxdope *p; register struct symtab *sp; register char *cp; register id; p = lxcp[(lxchar = getchar())+1]; if(ddebug) printf("yylex with Symbol %d (%c = %x)\n",p->lxact,lxchar,lxchar); switch( p->lxact ) { onechar: ungetc( lxchar ,stdin); case A_1C: /* eat up a single character, and return an opcode */ yylval.intval = p->lxval; return( p->lxtok ); case A_ERR: uerror( "illegal character: %03o (octal)", lxchar ); break; case A_LET: /* collect an identifier, and check for reserved word */ lxget( lxchar, LEXLET|LEXDIG ); /* 0 means some kind of low level error, >0 reserved, ** <0 means id */ if( (lxchar=lxres()) > 0 ) return( lxchar ); if( lxchar== 0 ) continue; if (truncate_flag ) yytext[NCHNAM] = '\0'; /* truncate name */ id = lookup( hash(yytext), /* tag name for struct/union/enum */ (stwart&TAGNAME)? STAG: /* member name for struct/union */ (stwart&(INSTRUCT|INUNION|FUNNYNAME))?SMOS:0 ); sp = &stab[id]; if( sp->sclass == TYPEDEF && !stwart ) { stwart = instruct; yylval.nodep = mkty( sp->stype, sp->dimoff, sp->sizoff ); return( TYPE ); } stwart = (stwart&SEENAME) ? instruct : 0; yylval.intval = id; return( NAME ); case A_DIG: /* collect a digit string, then look at last one... */ lastcon = 0; lxget( lxchar, LEXDIG ); switch( lxchar = getchar() ) { case 'x': case 'X': if( yytext[0] != '0' && !yytext[1] ) uerror( "illegal hex constant" ); lxmore( lxchar, LEXHEX ); /* convert the value */ { for( cp = yytext+2; *cp; ++cp ) { /* this code won't work for all character sets, ** but seems ok for ascii and ebcdic */ lastcon <<= 4; if( isdigit( *cp ) ) lastcon += *cp-'0'; else if( isupper( *cp ) ) lastcon += *cp - 'A'+ 10; else lastcon += *cp - 'a'+ 10; } } hexlong: /* hex and octal constants are long if they ** fit within 0177777 */ if( lastcon & ~0177777L ) yylval.intval = 1; else yylval.intval = 0; goto islong; case '.': lxmore( lxchar, LEXDIG ); getfp: if( (lxchar = getchar()) == 'e' || lxchar == 'E' ) { /* exponent */ case 'e': case 'E': if( (lxchar = getchar()) == '+' || lxchar == '-' ) { *lxgcp++ = 'e'; } else { ungetc(lxchar,stdin); lxchar = 'e'; } lxmore( lxchar, LEXDIG ); /* now have the whole thing... */ } else { /* no exponent */ ungetc( lxchar ,stdin); } # ifdef NOFLOAT if( !flflag ) { flflag = 1; werror( "sorry, no floating point" ); } for( cp = yytext; *cp; ++cp ) { if( *cp == 'e' || *cp == 'E' || *cp == '.' ) { *cp = '\0'; break; } } goto conv10; # else flflag = 1; dcon = FLOATCVT(yytext); return( FCON ); # endif default: ungetc( lxchar ,stdin); if( yytext[0] == '0' ) { /* convert in octal */ for( cp = yytext+1; *cp; ++cp ) { lastcon <<= 3; lastcon += *cp - '0'; } goto hexlong; } else { /* convert in decimal */ # ifdef NOFLOAT conv10: # endif for( cp = yytext; *cp; ++cp ) { lastcon = lastcon*10 + *cp - '0'; } } /* decide if it is long or not (decimal case) */ /* if it is positive and fits in 15 bits, ** or negative and and fits in 15 bits ** with an extended sign, it is int; ** otherwise long */ /* if there is an l or L following, ** all bets are off... */ { register CONSZ v; v = lastcon & ~077777L; if( v == 0 || v == ~077777L ) yylval.intval = 0; else yylval.intval = 1; } islong: /* finally, look for trailing L or l */ if( (lxchar=getchar()) == 'L' || lxchar == 'l' ) yylval.intval = 1; else ungetc( lxchar ,stdin); return( ICON ); } case A_DOT: /* a dot: if followed by a digit, floating point */ lxchar = getchar(); if( lxmask[lxchar+1] & LEXDIG ) { ungetc(lxchar,stdin); lxget( '.', LEXDIG ); goto getfp; } stwart = FUNNYNAME; goto onechar; case A_STR: /* string constant */ lxmatch = '"'; return( STRING ); case A_CC: /* character constant */ lxmatch = '\''; lastcon = 0; lxstr(0); yylval.intval = 0; return( ICON ); case A_BCD: { register i; register j; for( i=0; i6 ) uerror( "BCD constant exceeds 6 characters" ); # ifdef gcos else strtob( yytext, &lastcon, i ); lastcon >>= 6*(6-i); # else if( yytext[0] == 'u' ) { yylval.intval = UOP0 + yytext[1]-'0'; return( UNOP ); } uerror( "gcos BCD constant illegal" ); # endif yylval.intval = 0; /* not long */ return( ICON ); } case A_SL: /* / */ if( (lxchar = getchar()) != '*' ) goto onechar; lxcom(); case A_WS: continue; case A_NL: ++lineno; lxtitle(); continue; case A_NOT: /* ! */ if( (lxchar = getchar()) != '=' ) goto onechar; yylval.intval = NE; return( EQUOP ); case A_MI: /* - */ if( (lxchar = getchar()) == '-' ) { yylval.intval = DECR; return( INCOP ); } if( lxchar != '>' ) goto onechar; stwart = FUNNYNAME; yylval.intval=STREF; return( STROP ); case A_PL: /* + */ if( (lxchar = getchar()) != '+' ) goto onechar; yylval.intval = INCR; return( INCOP ); case A_AND: /* & */ if( (lxchar = getchar()) != '&' ) goto onechar; return( yylval.intval = ANDAND ); case A_OR: /* | */ if( (lxchar = getchar()) != '|' ) goto onechar; return( yylval.intval = OROR ); case A_LT: /* < */ if( (lxchar = getchar()) == '<' ) { yylval.intval = LS; return( SHIFTOP ); } if( lxchar != '=' ) goto onechar; yylval.intval = LE; return( RELOP ); case A_GT: /* > */ if( (lxchar = getchar()) == '>' ) { yylval.intval = RS; return(SHIFTOP ); } if( lxchar != '=' ) goto onechar; yylval.intval = GE; return( RELOP ); case A_EQ: /* = */ switch( lxchar = getchar() ) { case '=': yylval.intval = EQ; return( EQUOP ); default: goto onechar; } default: cerror( "yylex error, character %03o (octal)", lxchar ); } /* ordinarily, repeat here... */ cerror( "out of switch in yylex" ); } } struct lxrdope { /* dope for reserved, in alphabetical order */ char *lxrch; /* name of reserved word */ short lxract; /* reserved word action */ short lxrval; /* value to be returned */ } lxrdope[] = { "asm", AR_A, 0, "auto", AR_CL, AUTO, "break", AR_RW, BREAK, "char", AR_TY, CHAR, "case", AR_RW, CASE, "continue", AR_RW, CONTINUE, "double", AR_TY, DOUBLE, "default", AR_RW, DEFAULT, "do", AR_RW, DO, "extern", AR_CL, EXTERN, "else", AR_RW, ELSE, "enum", AR_E, ENUM, # ifdef ONEFLOAT "float", AR_TY, DOUBLE, # else "float", AR_TY, FLOAT, # endif "for", AR_RW, FOR, "fortran", AR_CL, FORTRAN, "goto", AR_RW, GOTO, "if", AR_RW, IF, "int", AR_TY, INT, "long", AR_TY, LONG, "return", AR_RW, RETURN, "register", AR_CL, REGISTER, "switch", AR_RW, SWITCH, "struct", AR_S, 0, "sizeof", AR_RW, SIZEOF, "short", AR_TY, SHORT, "static", AR_CL, STATIC, "typedef", AR_CL, TYPEDEF, "unsigned", AR_TY, UNSIGNED, "union", AR_U, 0, "void", AR_TY, VOID, "while", AR_RW, WHILE, "", 0, 0, /* to stop the search */ }; lxres() { /* check to see of yytext is reserved; if so, ** do the appropriate action and return */ /* otherwise, return -1 */ register c, ch; register struct lxrdope *p; ch = yytext[0]; if( !islower(ch) ) return( -1 ); switch( ch ) { case 'a': c=0; break; case 'b': c=2; break; case 'c': c=3; break; case 'd': c=6; break; case 'e': c=9; break; case 'f': c=12; break; case 'g': c=15; break; case 'i': c=16; break; case 'l': c=18; break; case 'r': c=19; break; case 's': c=21; break; case 't': c=26; break; case 'u': c=27; break; case 'v': c=29; break; case 'w': c=30; break; default: return( -1 ); } for( p= lxrdope+c; p->lxrch[0] == ch; ++p ) { if( !strcmp( yytext, p->lxrch ) ) { /* match */ switch( p->lxract ) { case AR_TY: /* type word */ stwart = instruct; yylval.nodep = mkty( (TWORD)p->lxrval, 0, p->lxrval ); if( p->lxrval==FLOAT || p->lxrval==DOUBLE ) { # ifdef NOFLOAT if( !flflag ) { flflag = 1; werror( "sorry, no floating point" ); } yylval.nodep->tn.type = LONG; # else flflag = 1; # endif } return( TYPE ); case AR_RW: /* ordinary reserved word */ return( yylval.intval = p->lxrval ); case AR_CL: /* class word */ yylval.intval = p->lxrval; return( CLASS ); case AR_S: /* struct */ stwart = INSTRUCT|SEENAME|TAGNAME; yylval.intval = INSTRUCT; return( STRUCT ); case AR_U: /* union */ stwart = INUNION|SEENAME|TAGNAME; yylval.intval = INUNION; return( STRUCT ); case AR_E: /* enums */ stwart = SEENAME|TAGNAME; return( yylval.intval = ENUM ); case AR_A: /* asm */ asm_esc = 1; /* warn the world! */ lxget( ' ', LEXWS ); if( getchar() != '(' ) goto badasm; lxget( ' ', LEXWS ); if( getchar() != '"' ) goto badasm; asmp = asmbuf; while( (c = getchar()) != '"' ) { if( c=='\n' || c==EOF ) goto badasm; *asmp++ = c; if( asmp >= &asmbuf[ASMBUF-1] ) { uerror( "asm > %d chars", ASMBUF); } } lxget( ' ', LEXWS ); if( getchar() != ')' ) goto badasm; *asmp++ = '\0'; return( ASM ); badasm: uerror( "bad asm construction" ); return( 0 ); default: cerror( "bad AR_?? action" ); } } } return( -1 ); } lxtitle() { /* called after a newline; set linenumber and file name */ register c, val; register char *cp; for(;;) { /* might be several such lines in a row */ #ifdef ASSYCOMMENT if( (c = eatline()) != '#' ) #else if( (c = getchar()) != '#' ) #endif ASSYCOMMENT { if( c != EOF ) ungetc(c,stdin); return; } lxget( ' ', LEXWS ); val = 0; for( c = getchar(); isdigit(c); c = getchar() ) { val = val*10+ c - '0'; } ungetc( c, stdin ); lineno = val; lxget( ' ', LEXWS ); if( (c = getchar()) != '\n' ) { for( cp = ftitle; c != '\n'; c = getchar(),++cp ) { *cp = c; } *cp = '\0'; } } } # ifndef MYASMOUT asmout() { printf( "%s\n", asmbuf ); } # endif #define NSAVETAB 4096 char *savetab; unsigned int saveleft; char * savestr( cp ) /* place string into permanent string storage */ register char *cp; { register int len = strlen( cp ) + 1; extern char * malloc(); extern char * strncpy(); if ( len > saveleft ) { saveleft = NSAVETAB; if ( len > saveleft ) saveleft = len; if ( ( savetab = (char *) malloc( saveleft ) ) == 0 ) cerror( "out of memory [savestr()]" ); } strncpy( savetab, cp, len ); cp = savetab; savetab += len; saveleft -= len; return ( cp ); } #ifdef LINT # define LNCHNAM 8 /* length of symbols to check for pflag */ #endif /* * The segmented hash tables. */ #define MAXHASH 20 #define HASHINC 1013 struct ht { char **ht_low; char **ht_high; int ht_used; } htab[MAXHASH]; char * hash( s ) /* look for s in seg. hash tables. Not found, make new entry */ char *s; { register char **h; register int i; register char *cp; struct ht *htp; int sh; extern char * calloc(); #ifdef LINT char *found = 0; /* set once LNCHNAM chars. matched for name */ #endif /* * Hash on the correct number of characters. Lint needs to be able * to limit this so that it can note length of names for portablility * concerns. */ cp = s; i = 0; #ifdef LINT while ( *cp && ( ( cp - s ) < LNCHNAM ) ) #else while ( *cp ) #endif { i = ( i << 1 ) + *cp++; } sh = ( i & 077777 ) % HASHINC; cp = s; /* * Look through each table for name. If not found in the current * table, skip to the next one. */ for ( htp = htab; htp < &htab[MAXHASH]; htp++ ) { if ( htp->ht_low == 0 ) { register char **hp = (char **) calloc( sizeof (char **), HASHINC ); if ( hp == 0 ) cerror( "out of memory [hash()]" ); htp->ht_low = hp; htp->ht_high = hp + HASHINC; } h = htp->ht_low + sh; /* * Use quadratic re-hash */ i = 1; do { if ( *h == 0 ) { if ( htp->ht_used > ( HASHINC * 3 ) / 4 ) break; htp->ht_used++; *h = savestr( cp ); #ifdef LINT if ( pflag && found ) { /* * If pflag set, then warn of greater * than LNCHNAM character names which * differ past the LNCHNAM'th character. */ werror( "`%s' may be indistinguishable from `%s' due to internal name truncation", *h, found ); } #endif return ( *h ); } #ifdef LINT if ( pflag ) { if ( **h == *cp && strncmp( *h, cp, LNCHNAM ) == 0 ) { /* * We have matched on LNCHNAM chars. * Now, look for the ``total'' name. */ found = *h; if ( strcmp( *h, cp ) == 0 ) { /* * This entry really is * the name we want. */ return ( *h ); } } } else /* No pflag - use entire name length */ { if ( **h == *cp && strcmp( *h, cp ) == 0 ) return ( *h ); } #else if ( **h == *cp && strcmp( *h, cp ) == 0 ) return ( *h ); #endif h += i; i += 2; if ( h >= htp->ht_high ) h -= HASHINC; } while ( i < HASHINC ); } cerror( "out of hash tables" ); /*NOTREACHED*/ }