forked from KolibriOS/kolibrios
1967c25fac
git-svn-id: svn://kolibrios.org@718 a494cfbc-eb01-0410-851d-a64ba20cac60
558 lines
11 KiB
C
558 lines
11 KiB
C
/*
|
|
** Small-C Compiler -- Part 2 -- Front End and Miscellaneous.
|
|
** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix
|
|
** Copyright 1998 H T Walheim
|
|
** All rights reserved.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "cc.h"
|
|
|
|
extern char
|
|
*symtab, *macn, *macq, *pline, *mline, optimize,
|
|
alarm, *glbptr, *line, *lptr, *cptr, *cptr2, *cptr3,
|
|
*locptr, msname[NAMESIZE], pause, quote[2];
|
|
|
|
extern int
|
|
*wq, ccode, ch, csp, eof, errflag, iflevel,
|
|
input, input2, listfp, macptr, nch,
|
|
nxtlab, op[16], opindex, opsize, output, pptr,
|
|
skiplevel, *wqptr;
|
|
|
|
/********************** input functions **********************/
|
|
|
|
preprocess() {
|
|
int k;
|
|
char c;
|
|
if(ccode) {
|
|
line = mline;
|
|
ifline();
|
|
if(eof) return;
|
|
}
|
|
else {
|
|
inline();
|
|
return;
|
|
}
|
|
pptr = -1;
|
|
while(ch != NEWLINE && ch) {
|
|
if(white()) {
|
|
keepch(' ');
|
|
while(white()) gch();
|
|
}
|
|
else if(ch == '"') {
|
|
keepch(ch);
|
|
gch();
|
|
while(ch != '"' || (*(lptr-1) == 92 && *(lptr-2) != 92)) {
|
|
if(ch == NULL) {
|
|
error("no quote");
|
|
break;
|
|
}
|
|
keepch(gch());
|
|
}
|
|
gch();
|
|
keepch('"');
|
|
}
|
|
else if(ch == 39) {
|
|
keepch(39);
|
|
gch();
|
|
while(ch != 39 || (*(lptr-1) == 92 && *(lptr-2) != 92)) {
|
|
if(ch == NULL) {
|
|
error("no apostrophe");
|
|
break;
|
|
}
|
|
keepch(gch());
|
|
}
|
|
gch();
|
|
keepch(39);
|
|
}
|
|
else if(ch == '/' && nch == '*')
|
|
{
|
|
bump(2);
|
|
while((ch == '*' && nch == '/') == 0)
|
|
{
|
|
if(ch)
|
|
bump(1);
|
|
else
|
|
{
|
|
ifline();
|
|
if(eof)
|
|
break;
|
|
}
|
|
}
|
|
bump(2);
|
|
}
|
|
else if(ch == '/' && nch == '/')
|
|
{
|
|
bump(2);
|
|
while(ch != NEWLINE)
|
|
{
|
|
if(ch)
|
|
bump(1);
|
|
else
|
|
{
|
|
if(eof)
|
|
break;
|
|
}
|
|
}
|
|
bump(1);
|
|
}
|
|
else if(an(ch)) {
|
|
k = 0;
|
|
while(an(ch) && k < NAMEMAX) {
|
|
msname[k++] = ch;
|
|
gch();
|
|
}
|
|
msname[k] = NULL;
|
|
if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) {
|
|
k = getint(cptr+NAMESIZE, 2/*INTSIZE*/);
|
|
while(c = macq[k++]) keepch(c);
|
|
while(an(ch)) gch();
|
|
}
|
|
else {
|
|
k = 0;
|
|
while(c = msname[k++]) keepch(c);
|
|
}
|
|
}
|
|
else keepch(gch());
|
|
}
|
|
if(pptr >= LINEMAX) error("line too long");
|
|
keepch(NULL);
|
|
line = pline;
|
|
bump(0);
|
|
}
|
|
|
|
keepch(c) char c; {
|
|
if(pptr < LINEMAX) pline[++pptr] = c;
|
|
}
|
|
|
|
ifline() {
|
|
while(1) {
|
|
inline();
|
|
if(eof) return;
|
|
if(match("#ifdef")) {
|
|
++iflevel;
|
|
if(skiplevel) continue;
|
|
symname(msname);
|
|
if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0) == 0)
|
|
skiplevel = iflevel;
|
|
continue;
|
|
}
|
|
if(match("#ifndef")) {
|
|
++iflevel;
|
|
if(skiplevel) continue;
|
|
symname(msname);
|
|
if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0))
|
|
skiplevel = iflevel;
|
|
continue;
|
|
}
|
|
if(match("#else")) {
|
|
if(iflevel) {
|
|
if(skiplevel == iflevel) skiplevel = 0;
|
|
else if(skiplevel == 0) skiplevel = iflevel;
|
|
}
|
|
else noiferr();
|
|
continue;
|
|
}
|
|
if(match("#endif")) {
|
|
if(iflevel) {
|
|
if(skiplevel == iflevel) skiplevel = 0;
|
|
--iflevel;
|
|
}
|
|
else noiferr();
|
|
continue;
|
|
}
|
|
if(skiplevel) continue;
|
|
if(ch == 0) continue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
inline() { /* numerous revisions */
|
|
int k, unit;
|
|
|
|
if(input == EOF) openfile();
|
|
if(eof) return;
|
|
if((unit = input2) == EOF) unit = input;
|
|
if(fgets(line, LINEMAX, unit) == NULL) {
|
|
fclose(unit);
|
|
if(input2 != EOF)
|
|
input2 = EOF;
|
|
else input = EOF;
|
|
*line = NULL;
|
|
}
|
|
else if(listfp)
|
|
{
|
|
if(listfp == output) fputc(';', output);
|
|
fputs(line, listfp);
|
|
}
|
|
#ifdef _MSC_VER
|
|
else
|
|
{
|
|
fputc(';', output);
|
|
fputs(line, output);
|
|
}
|
|
#endif
|
|
bump(0);
|
|
}
|
|
|
|
inbyte() {
|
|
while(ch == 0) {
|
|
if(eof) return 0;
|
|
preprocess();
|
|
}
|
|
return gch();
|
|
}
|
|
|
|
/********************* scanning functions ********************/
|
|
|
|
/*
|
|
** test if next input string is legal symbol name
|
|
*/
|
|
symname(sname) char *sname; {
|
|
int k;char c;
|
|
blanks();
|
|
if(alpha(ch) == 0) return (*sname = 0);
|
|
k = 0;
|
|
while(an(ch)) {
|
|
sname[k] = gch();
|
|
if(k < NAMEMAX) ++k;
|
|
}
|
|
sname[k] = 0;
|
|
return 1;
|
|
}
|
|
|
|
need(str) char *str; {
|
|
if(match(str) == 0) error("missing token");
|
|
}
|
|
|
|
ns() {
|
|
if(match(";") == 0) error("no semicolon");
|
|
else errflag = 0;
|
|
}
|
|
|
|
match(lit) char *lit; {
|
|
int k;
|
|
blanks();
|
|
if(k = streq(lptr, lit)) {
|
|
bump(k);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
streq(str1, str2) char str1[], str2[]; {
|
|
int k;
|
|
k = 0;
|
|
while (str2[k]) {
|
|
if(str1[k] != str2[k]) return 0;
|
|
++k;
|
|
}
|
|
return k;
|
|
}
|
|
|
|
amatch(lit, len) char *lit; int len; {
|
|
int k;
|
|
blanks();
|
|
if(k = astreq(lptr, lit, len)) {
|
|
bump(k);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
astreq(str1, str2, len) char str1[], str2[]; int len; {
|
|
int k;
|
|
k = 0;
|
|
while (k < len) {
|
|
if(str1[k] != str2[k]) break;
|
|
/*
|
|
** must detect end of symbol table names terminated by
|
|
** symbol length in binary
|
|
*/
|
|
if(str2[k] < ' ') break;
|
|
if(str1[k] < ' ') break;
|
|
++k;
|
|
}
|
|
if(an(str1[k]) || an(str2[k])) return 0;
|
|
return k;
|
|
}
|
|
|
|
nextop(list) char *list; {
|
|
char op[4];
|
|
opindex = 0;
|
|
blanks();
|
|
while(1) {
|
|
opsize = 0;
|
|
while(*list > ' ') op[opsize++] = *list++;
|
|
op[opsize] = 0;
|
|
if(opsize = streq(lptr, op))
|
|
if(*(lptr+opsize) != '=' &&
|
|
*(lptr+opsize) != *(lptr+opsize-1))
|
|
return 1;
|
|
if(*list) {
|
|
++list;
|
|
++opindex;
|
|
}
|
|
else return 0;
|
|
}
|
|
}
|
|
|
|
blanks() {
|
|
while(1) {
|
|
while(ch) {
|
|
if(white()) gch();
|
|
else return;
|
|
}
|
|
if(line == mline) return;
|
|
preprocess();
|
|
if(eof) break;
|
|
}
|
|
}
|
|
|
|
white() {
|
|
return (*lptr <= ' ' && *lptr);
|
|
}
|
|
|
|
gch() {
|
|
int c;
|
|
if(c = ch) bump(1);
|
|
return c;
|
|
}
|
|
|
|
bump(n) int n; {
|
|
if(n) lptr += n;
|
|
else lptr = line;
|
|
if(ch = nch = *lptr) nch = *(lptr+1);
|
|
}
|
|
|
|
kill() {
|
|
*line = 0;
|
|
bump(0);
|
|
}
|
|
|
|
skip() {
|
|
if(an(inbyte()))
|
|
while(an(ch)) gch();
|
|
else while(an(ch) == 0) {
|
|
if(ch == 0) break;
|
|
gch();
|
|
}
|
|
blanks();
|
|
}
|
|
|
|
endst() {
|
|
blanks();
|
|
return (streq(lptr, ";") || ch == 0);
|
|
}
|
|
|
|
/*********** symbol table management functions ***********/
|
|
|
|
addsym(sname, id, type, size, value, lgpp, class)
|
|
char *sname, id, type;
|
|
int size, value, *lgpp, class;
|
|
{
|
|
if(lgpp == &glbptr)
|
|
{
|
|
if(cptr2 = findglb(sname))
|
|
return cptr2;
|
|
if(cptr == 0)
|
|
{
|
|
error("global symbol table overflow");
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(locptr > (ENDLOC-SYMMAX))
|
|
{
|
|
error("local symbol table overflow");
|
|
exit(ERRCODE);
|
|
}
|
|
cptr = *lgpp;
|
|
}
|
|
cptr[IDENT] = id;
|
|
cptr[TYPE] = type;
|
|
cptr[CLASS] = class;
|
|
putint(size, cptr + SIZE, INTSIZE);
|
|
putint(value, cptr + OFFSET, INTSIZE);
|
|
cptr3 = cptr2 = cptr + NAME;
|
|
while(an(*sname))
|
|
*cptr2++ = *sname++;
|
|
|
|
if(lgpp == &locptr)
|
|
{
|
|
*cptr2 = cptr2 - cptr3; /* set length */
|
|
*lgpp = ++cptr2;
|
|
}
|
|
return cptr;
|
|
}
|
|
|
|
/*
|
|
** search for symbol match
|
|
** on return cptr points to slot found or empty slot
|
|
*/
|
|
search(sname, buf, len, end, max, off)
|
|
char *sname, *buf, *end; int len, max, off; {
|
|
cptr =
|
|
cptr2 = buf+((hash(sname)%(max-1))*len);
|
|
while(*cptr != NULL) {
|
|
if(astreq(sname, cptr+off, NAMEMAX)) return 1;
|
|
if((cptr = cptr+len) >= end) cptr = buf;
|
|
if(cptr == cptr2) return (cptr = 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
hash(sname) char *sname; {
|
|
int i, c;
|
|
i = 0;
|
|
while(c = *sname++) i = (i << 1) + c;
|
|
return i;
|
|
}
|
|
|
|
findglb(sname) char *sname; {
|
|
if(search(sname, STARTGLB, SYMMAX, ENDGLB, NUMGLBS, NAME))
|
|
return cptr;
|
|
return 0;
|
|
}
|
|
|
|
findloc(sname) char *sname; {
|
|
cptr = locptr - 1; /* search backward for block locals */
|
|
while(cptr > STARTLOC) {
|
|
cptr = cptr - *cptr;
|
|
if(astreq(sname, cptr, NAMEMAX)) return (cptr - NAME);
|
|
cptr = cptr - NAME - 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
nextsym(entry) char *entry; {
|
|
entry = entry + NAME;
|
|
while(*entry++ >= ' '); /* find length byte */
|
|
return entry;
|
|
}
|
|
|
|
/******** while queue management functions *********/
|
|
|
|
addwhile(ptr) int ptr[]; {
|
|
int k;
|
|
ptr[WQSP] = csp; /* and stk ptr */
|
|
ptr[WQLOOP] = getlabel(); /* and looping label */
|
|
ptr[WQEXIT] = getlabel(); /* and exit label */
|
|
if(wqptr == WQMAX) {
|
|
error("control statement nesting limit");
|
|
exit(ERRCODE);
|
|
}
|
|
k = 0;
|
|
while (k < WQSIZ) *wqptr++ = ptr[k++];
|
|
}
|
|
|
|
readwhile(ptr) int *ptr; {
|
|
if(ptr <= wq) {
|
|
error("out of context");
|
|
return 0;
|
|
}
|
|
else return (ptr - WQSIZ);
|
|
}
|
|
|
|
delwhile() {
|
|
if(wqptr > wq) wqptr -= WQSIZ;
|
|
}
|
|
|
|
/****************** utility functions ********************/
|
|
|
|
/*
|
|
** test if c is alphabetic
|
|
*/
|
|
alpha(c) char c; {
|
|
return (isalpha(c) || c == '_');
|
|
}
|
|
|
|
/*
|
|
** test if given character is alphanumeric
|
|
*/
|
|
an(c) char c; {
|
|
return (alpha(c) || isdigit(c));
|
|
}
|
|
|
|
/*
|
|
** return next avail internal label number
|
|
*/
|
|
getlabel() {
|
|
return(++nxtlab);
|
|
}
|
|
|
|
/*
|
|
** get integer of length len from address addr
|
|
** (byte sequence set by "putint")
|
|
*/
|
|
getint(addr, len) char *addr; int len; {
|
|
int i;
|
|
i = *(addr + --len); /* high order byte sign extended */
|
|
while(len--) i = (i << 8) | *(addr + len) & 255;
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
** put integer i of length len into address addr
|
|
** (low byte first)
|
|
*/
|
|
putint(i, addr, len) char *addr; int i, len; {
|
|
while(len--) {
|
|
*addr++ = i;
|
|
i = i >> 8;
|
|
}
|
|
}
|
|
|
|
lout(line, fd) char *line; int fd; {
|
|
fputs(line, fd);
|
|
fputc(NEWLINE, fd);
|
|
}
|
|
|
|
/******************* error functions *********************/
|
|
|
|
illname() {
|
|
error("illegal symbol");
|
|
skip();
|
|
}
|
|
|
|
multidef(sname) char *sname; {
|
|
error("already defined");
|
|
}
|
|
|
|
needlval() {
|
|
error("must be lvalue");
|
|
}
|
|
|
|
noiferr() {
|
|
error("no matching #if...");
|
|
errflag = 0;
|
|
}
|
|
|
|
error(msg)
|
|
char msg[];
|
|
{
|
|
if(errflag)
|
|
return;
|
|
else
|
|
errflag = 1;
|
|
|
|
lout(line, stderr);
|
|
errout(msg, stderr);
|
|
if(alarm)
|
|
fputc(7, stderr);
|
|
if(pause)
|
|
while(fgetc(stderr) != NEWLINE);
|
|
if(listfp > 0)
|
|
errout(msg, listfp);
|
|
}
|
|
|
|
errout(msg, fp) char msg[]; int fp; {
|
|
int k;
|
|
k = line+2;
|
|
while(k++ <= lptr) fputc(' ', fp);
|
|
lout("/\\", fp);
|
|
fputs("**** ", fp); lout(msg, fp);
|
|
}
|
|
|