File:  [MW Coherent from dump] / coherent / b / bin / as / lex.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:36 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * This is the controlling loop in the assembler.
 *
 */
#include <utype.h>
#include <asm.h>
#include <asflags.h>
#include <y_tab.h>
#include <symtab.h>

/* states */
#define INITIAL	0
#define INSYM   1
#define INCHAR	2	/* in char constant */
#define LTS	3
#define GTS	4
#define BSLP	5	/* back slash while reading parms */
#define WHITE	6	/* in white space */
#define ENDLINE 7
#define CSTATE	8	/* Pick up parms in macro expansion */
#define INTOKEN 9

#define OPONLY1	10	/* search for operator only */
#define OPONLY2 11
#define OPONLY3	12
#define OPONLY4	13

#define INSTR	14	/* string detected */
#define BSL	15	/* back slash */
#define BSLDIG  16	/* digit after back slash */

#define CMSTATE 17	/* pick up names in macro definition */
#define INNAME	18

#define LZERO	19	/* lead zero */
#define XNUM	20	/* hex number */
#define DNUM	21	/* decimal number */
#define ONUM	22	/* octal number */
#define BNUM	23	/* binary number */

#define BANGS	 24	/* ! seen */
#define EQUS	 25	/* = seen */

#define DSTATE	 26	/* eat whole line for S_EQUS */

/* positions */
#define LABEL	0
#define OPCODE	1
#define OPERAND	2
#define COMMENT 3

/* comparisons */
#define LT 1
#define GT 2
#define EQ 4

#define RET(toYacc) return(lastToken = (toYacc))
#define RSTATE(toYacc, newstate) { state = newstate; RET(toYacc); }
#define NEWS(newstate) { state = newstate; continue; }

static unsigned short state = INITIAL;
static unsigned short pstate;	/* previous state when \ detected */
static unsigned short pos = LABEL;

static unsigned short ctype;	/* current logic type */

static char buf[1024], *bp = buf;
static char *backOff;	/* start of decimal number */
static char fromMac = ' ';		/* ' ' or '+' */
static short opIx;	/* index of current opcode */
static psw = 0;
static long number = 0;
static char token[1024], *tp;

static int lastChar;	/* last Character in */
static short vctr, scnt, dcnt;
static symt *stype;
static short ytype;

/*
 * Invalid character message.
 */
static void
invChar(c, s)
register short c;
char *s;
{
	unsigned short p;

	p = bp - lastL;
	if (isprint(c))
		yyerror("Invalid character '%c' %s at position %d", c, s, p);
		/**/
	else
		yyerror("Invalid character 0x%02x %s at position %d",
			c & 255, s, p); /**/
}

/*
 * Expand parms in macro line.
 * # as first char of line foils replacment.
 */
static char *
expand(s, recurs)
register char *s;
{
	register char c;
	char *tp, *rep, *newl, *start;
	macro *mac;
	short sav, pb;
	unsigned short point;

	start = s;
	pb = 0;
	for(state = WHITE; ; ) {
		switch(state) {
		case WHITE:
			if (isalpha(c = *s++)) {
				state = INSYM;
				tp = token;
				*tp++ = c;
				break;
			}
			pb = 0;
			break;
		case INSYM:
			if (isalnum(c = *s++)) {
				*tp++ = c;
				break;
			}
			mac = NULL;
			*tp = '\0';
			if ((!recurs && (NULL != trueMac) &&
			    (NULL != (rep = lookList(token)))) ||
			   (NULL != (mac = macLookUp(token, MACSTR)))) {
				tp = --s - (strlen(token) + pb);
				sav = *tp;	/* stomp parm name */
				*tp = '\0';
				if (NULL == mac)	/* parm match */
					rep = expand(rep, 1);
				else {	/* equs match */
					rep = mac->names->str;
					mac->type = MACSCAN;
					rep = expand(rep, 1);
					mac->type = MACSTR;
				}
				point = strlen(start) + strlen(rep);
				newl = galloc(point + strlen(s) + 1);
				sprintf(newl, "%s%s%s", start, rep, s);
				*tp = sav;	/* Un stomp parm name */
				start = newl;
				s = start + point; /* don't rescan */
			}
			pb = (c == '\\');
			state = WHITE;
		}
		if (!c)
			break;
	}
	return(start);
}

/*
 * Get next line from macro or while.
 */
static char *
nextMac()
{
	macctl *tmp;
	macline *l;
	extern char *strcpy();

	for(;;) {
		if (NULL == macExp) {	/* not in a macro */
			fromMac = ' ';
			return(NULL);
		}
		if (NULL != (l = macExp->curr)) {
			fromMac = '+';
			macExp->curr =  l->next;
			return(strcpy(buf, l->line));
		}

		if ((tmp = macExp) == trueMac) { /* popping macro */
			freeList(macExp->parms);

			while(logic->expno == trueMac->expno) {
				if ((logic->type == INWDEF) ||
				   (logic->type == INPWDEF))
					yyerror("End of macro building .while");
				/* A \fB.macro\fR ended while reading in a
				 * \fB.while\fR loop. */
				freeLevel();
			}

			do {
				trueMac = trueMac->prev;
			} while((NULL != trueMac) &&
			        (trueMac->type != MACTYPE));
		}

		macExp = macExp->prev;		/* pop a level */
		free((char *)tmp);
	}
}

/*
 * Save a line in a macro.
 */
saveLine()
{
	macline *newl;

	newl = (macline *)alloc((unsigned)(sizeof(*newl) + strlen(lastL)));
	strcpy(newl->line, lastL);
	if (NULL == inMacDef->first)
		lastDef = inMacDef->first = newl;
	else {
		lastDef->next = newl;
		lastDef = newl;
	}
}

/*
 * Get a line off a file.
 */
static char *
getLine()
{
	register char *line;

	++statement;		/* increment statement number */
	if (NULL != (line = nextMac()))
		return(line);

	while(NULL == (fgets(line = buf, sizeof(buf), inpc->fp))) {
		if (NULL != inpc->prev) {
			inpctl *tmp;

			fclose(inpc->fp);
			inpc = (tmp = inpc)->prev;
			free((char *)tmp);
		}
		else {	/* end of pass */
			for(;NORMAL != logic->type; freeLevel()) {
				switch(logic->type) {
				case INMACDEF:
				case PMACDEF:
					yyerror("Missing .endm");
				 /* Input ended leaving \fB.macro\fR open. */
					break;
				case INIF0:
				case INIF1:
				case INIFX:
					yyerror("Missing .endi");
				 /* Input ended leaving \fB.if\fR open. */
					break;
				case INWDEF:
				case INPWDEF:
					yyerror("Missing .endw");
				 /* Input ended leaving \fB.while\fR open. */
				}
			}
			if (2 == pass) {
				cleanUp();

				switch (errCt) {
				case 0:
					exit(0);
				case 1:
					fprintf(errdev, "1 Error\n");
					break;
				default:
					fprintf(errdev, "%d Errors\n", errCt);
				}
				unlink(outName);
				exit(1);
			}
			else {	/* avoid close & open */
				rewind(inpc->fp);
				inpc->lineNo = 0;
				statement = 1;

				newPass(outName);

				/* reset compiler switches to initial state */
				alignon = alignonX;
				lswitch = lswitchX;
				nswitch = nswitchX;
				wswitch = wswitchX;
				fswitch = fswitchX;
				bswitch = bswitchX;

				dodefs();
				outLine((char *)NULL, 0);
				continue;
			}
		}
	}
	inpc->lineNo++;
	return(line);
}

/*
 * In OPONLY3 we found an op process it.
 * separated to keep from crashing Coherent compiler in cc2.
 */
static unsigned short
procOp()
{
	register opc *op;

	*tp = '\0';
	bp--;
	if (-1 == (opIx = opLookUp(token)))
		return(OPONLY4);

	if (INIF1 <= ctype)
		fatal("Logic error in macro def '%s' %d", token, ctype); /* TECH */

	op = prefTab + opIx;
	switch(op->kind) {	/* switch on function type */	
	case S_MACRO:
		if (ctype < INIF0)
			newLevel(PMACDEF);
		break;
	case S_ENDM:
		switch(ctype) {
		case INMACDEF:
			inMacDef = (macro *)NULL;
			lastDef = (macline *)NULL;
			freeLevel();
			return(INITIAL);
		case PMACDEF:
			freeLevel();
		}
		break;
	case S_WHILE:
		switch(ctype) {
		case INWDEF:
		case INPWDEF:
			newLevel(INPWDEF);
		}
		break;
	case S_ENDW:
		switch(ctype) {
		case INWDEF: {
			macctl *tmp;
				saveLine();
			logic = (tmp = logic)->prev;
			tmp->type  = WHILETYPE;
			tmp->curr = tmp->first = inMacDef->first;
			tmp->parms = tmp->names = NULL;
			tmp->prev = macExp;
			macExp = tmp;
			free((char *)inMacDef);
			lastDef  = (macline *)NULL;
			inMacDef = (macro *)NULL;
			return(INITIAL);
		}
		case INPWDEF:
			freeLevel();
			break;
		}
		break;
	case S_IF:
		switch(ctype) {
		case INIF0:
		case INIFX:
			newLevel(INIFX);
		}
		break;
	case S_ELSE:
		switch(ctype) {
		case INIF0:
			logic->type = INIF1;
			return(INITIAL);
		}
		break;
	case S_ENDI:
		switch(ctype) {
		case INIF0:
		case INIFX:
			freeLevel();
		}
		break;
	}
	return(OPONLY4);
}

/*
 * Read line and start processing.
 * separated from yylex() to keep from crashing compiler in cc2.
 */
static unsigned short
startLine()
{
	register short c;

	do {	/* GNU outputs # line numbers */
		if (';' != lastChar) {
			outLine(lastL, fromMac);
			bp = lastL = getLine();
		}
		if (COMMA != lastToken)
			freel();	/* trash free space from last line */
	} while ('#' == *bp);

	ctype = logic->type;

	if (('#' != *bp) &&
	   (';' != lastChar) &&
	   (defCt || (NULL != trueMac)) &&
	   ((ctype > INPWDEF) || (ctype < INWDEF))) {
		bp = lastL = expand(bp, 0);

		if ((lastL != buf) && (fromMac != '+')) {
			outLine(buf, fromMac);
			fromMac = '@';
		}
	}

	if ('#' == *bp)	/* don't lex noexpand */
		bp++;

	if (COMMA == lastToken)	/* continuation line ? */
		return(psw);

	lastChar = c = *bp;	/* get a char */
	if (ctype < INIF1) {
		if ((' ' == c) || ('\t' == c))
			return(OPONLY1);
		else if (isalpha(c))
			return(OPONLY2);
		else
			return(OPONLY4);
	}
	if ((' ' == c) || ('\t' == c)) {
		pos = OPCODE;
		return(WHITE);
	}
	if (isalpha(c)) {
		pos = LABEL;
		tp = token;
		*tp++ = c;
		return(INSYM);
	}
	switch(c) {
	case '/': case '\n': case 0: case ';':
		break;
	default:
		invChar(c, "");
	}
	return(INITIAL);
}

/*
 * Got an opcode, set it up.
 */
static
doOp(opIx)
{
	register opc *op;

	lflags = 0;
	stype = typTab + (kind = (op = prefTab + opIx)->kind);
	yylval.o = op;
	pos = OPERAND;
	/* op code determines operand syntax */
	switch(ytype = stype->type) {
	case NCMD:
		RSTATE(ytype, ENDLINE)
	case OP:
		if (stype->bldr & REP_INSTR)
			pos = OPCODE;
	case ICMD:
	case DATA:
		RSTATE(ytype, WHITE)
	case ECMD:
	case ECMDX:
	case CMD:
		if (S_EQUS == kind) {
			tp = token;
			scnt = dcnt = 0;
			RSTATE(ytype, DSTATE)
		}
		RSTATE(ytype, CSTATE)
	case DCMD:
		RSTATE(ytype, CMSTATE)
	default:
		fatal("Optype %d in lex", ytype); /* TECH */
	}
}

/*
 * get tokens
 */
yylex()
{
    register short c;

    for(;;) {
    	/*
	 * Allow Japaneese comments and strings, catch other non ascii
	 * and abort the line.
	 */
 	if ((state != INITIAL) &&
	   !isascii(lastChar = c = *bp++) &&
	   (state != INSTR) &&
	   (state != INCHAR)) {
		invChar(c, "");
		RSTATE(NL, INITIAL)
	}

	switch(state) {
	case INITIAL:		/* start of line */
		bcnt = pcnt = 0;
		psw = startLine();
		lastChar = c = *bp++;
		if (!isascii(c)) {
			invChar(c, "");
			RSTATE(NL, INITIAL)
		}
		NEWS(psw);
		
	case OPONLY1:	/* find start of opcode */
		switch(c) {
		case ' ':
		case '\t':
			continue;
		default:
			if (!islower(c))
				NEWS(OPONLY4)
			tp = token;
			*tp++ = c;
			NEWS(OPONLY3)
		}

	case OPONLY2:			/* bypass label */
		if (isalnum(c))
			continue;
		--bp;
		if ((' ' == c) || ('\t' == c))
			NEWS(OPONLY1)
		NEWS(OPONLY4)
		
	case OPONLY3:
		if (isalnum(c)) {	/* accumulate opcode */
			*tp++ = c;
			continue;
		}
		NEWS(procOp());

	case OPONLY4:	/* default processing */
		if (logic->type < INIF0)
			saveLine();
		NEWS(INITIAL)

	case INSYM:
		if (isalnum(c)) {
			*tp++ = c;
			continue;
		}
		*tp = '\0';
		--bp;
		if (pos == OPERAND) {
			sym *sp;

			sp = symLookUp(token, S_UNDEF, 0L, 0);
			switch(sp->type) {
			case IDENTIFIER:
			case REG:
			case LEN:
				yylval.s = sp;
				break;
			case NUMBER:
				yylval.val = sp->loc;
			}
			RSTATE(sp->type, WHITE)
		}

		/* pos != OPERAND may be opcode or label */
		if (':' != c) {
			if (-1 != (opIx = opLookUp(token)))
				return(doOp(opIx));

			if (NULL != (macFound = macLookUp(token, MACTYPE))) {
				static opc smac = { /* fake opcode */
					0, S_MAC
				};

				yylval.o = &smac; /* macro expansion */
				RSTATE(CMD, CSTATE)
			}

			if (!strcmp(token, ".")) {
				yylval.t = token;
				pos = OPCODE;
				RSTATE(TOKEN, WHITE)
			}
		}

		if ((pos == LABEL) || (':' == c)) {
			yylval.t = token;
			pos = OPCODE;
			RSTATE(TOKEN, WHITE)
		}

		yyerror("Invalid opcode: '%s'", token);
		/* The string in the opcode position is
		 * not one of our opcodes or one of
		 * your macros. */
		RSTATE(NL, INITIAL)

	case DSTATE:	/* eat whole line for define */
		switch(c) {
		case '"':
			if (dcnt)
				dcnt = 0;
			else if (!scnt)
				dcnt = 1;
			break;
		case '\'':
			if (scnt)
				scnt = 0;
			else if (!dcnt)
				scnt = 1;
			break;
		case '\\':
			*tp++ = c;
			psw = state;
			NEWS(BSLP)
		case '/':
			if (scnt | dcnt)
				break;
		case 0:		/* let # define take semicolon */
		case '\n':
			*tp = '\0';
			yylval.t = trim(token);
			RSTATE(TOKEN, ENDLINE)
		}
		*tp++ = c;
		continue;

	case CSTATE: /* pick up parms on macro expansion */
		state = psw = INTOKEN;
		*(tp = token) = '\0';
		scnt = dcnt = pcnt = bcnt = 0;
		vctr = 1;
		switch(c) {
		case 0:
		case ';':
		case '\n':
		case '/':
			if (COMMA == lastToken)
				NEWS(INITIAL)
			RSTATE(NL, INITIAL)
		case ',':
			switch(lastToken) {
			case CMD:
			case COMMA:
				bp--;
				yylval.t = token;
				RSTATE(TOKEN, CSTATE)
			}
			RSTATE(COMMA, CSTATE)
		}

	case INTOKEN:	/* pick up parms on macro expansion */
		switch(c) {
		case '(':
			pcnt += vctr; break;
		case ')':
			if (pcnt)
				pcnt -= vctr;
			break;
		case '[':
			bcnt += vctr; break;
		case ']':
			if (bcnt)
				bcnt -= vctr;
			break;
		case '"':
			if (dcnt)
				dcnt = 0;
			else if (!scnt)
				dcnt = 1;
			vctr = (dcnt | scnt) ^ 1;
			break;
		case '\'':
			if (scnt)
				scnt = 0;
			else if (!dcnt)
				scnt = 1;
			vctr = (dcnt | scnt) ^ 1;
			break;
		case '\\':
			*tp++ = c;
			psw = state;
			NEWS(BSLP)

		case ';':
		case '/':
			if (!vctr)
				break;
		case 0:
		case '\n':
			if (pcnt | bcnt | scnt | dcnt) {
				yyerror("Unmatched bracket in parmeter");
		/* Line ended leaving an open bracket or parenthesis. */
				RSTATE(NL, INITIAL)
			}
			--bp;
			*tp = '\0';
			if (*(yylval.t = trim(token)))
				RSTATE(TOKEN, CSTATE)
			NEWS(CSTATE)
		case ',':
			if (pcnt | bcnt | scnt | dcnt)
				break;
			--bp;
			*tp = '\0';
			yylval.t = trim(token);
			switch(ytype) {
			case ECMD:
			case ECMDX:
				RSTATE(TOKEN, WHITE)
			}
			RSTATE(TOKEN, CSTATE)
		}
		*tp++ = c;
		continue;

	case BSLP:	/* back slash while reading parm */
		switch(c) {
		case 0:
		case '\n':
			--bp;
			yyerror("End of line after backslash reading parm");
		/* Macro parmeters may not be broken up with backslash. */
			break;
		}
		*tp++ = c;
		NEWS(psw)

	case CMSTATE: /* pick up names on macro definition */
		psw = state = INNAME;
		tp = token;
		switch(c) {
		case ',':
			RET(COMMA);
		case 0:
		case ';':
		case '\n':
		case '/':
			if (COMMA == lastToken)
				NEWS(INITIAL)
			RSTATE(NL, INITIAL)
		}
	case INNAME:	/* pick up parms on macro definition */
		switch(c) {
		case 0:
		case ';':
		case '\n':
		case '/':
		case ',':
			--bp;
			*tp = '\0';
			if (*(yylval.t = trim(token)))
				RSTATE(TOKEN, CMSTATE)
			NEWS(CMSTATE)
		default:
			if (ispunct(c)) {
				invChar(c, "in macro name");
				RSTATE(NL, INITIAL)
			}
		}
		*tp++ = c;
		continue;


	case WHITE:
		/*
		 * This piece of code is heavily trafficked.
		 * Force the fastest form of switch statement
		 * by covering many cases.
		 */
		switch(c) {
		case '1':	case '2':	case '3':	case '4':
		case '5':	case '6':	case '7':	case '8':
		case '9':	case '0':
			backOff = bp - 1;
			if (number = c - '0')
				NEWS(DNUM)
			NEWS(LZERO);

		/* % allowed as first char only */
		case 'a':	case 'b':	case 'c':	case 'd':
		case 'e':	case 'f':	case 'g':	case 'h':
		case 'i':	case 'j':	case 'k':	case 'l':
		case 'm':	case 'n':	case 'o':	case 'p':
		case 'q':	case 'r':	case 's':	case 't':
		case 'u':	case 'v':	case 'w':	case 'x':
		case 'y':	case 'z':
		case 'A':	case 'B':	case 'C':	case 'D':
		case 'E':	case 'F':	case 'G':	case 'H':
		case 'I':	case 'J':	case 'K':	case 'L':
		case 'M':	case 'N':	case 'O':	case 'P':
		case 'Q':	case 'R':	case 'S':	case 'T':
		case 'U':	case 'V':	case 'W':	case 'X':
		case 'Y':	case 'Z':	case '?':	case '_':
		case '%':	case '.':
			tp = token;
			*tp++ = c;
			NEWS(INSYM)

		case ' ':
		case '\t':
			continue;
		case 0:
		case ';':
		case '\n':
		case '/':
			if (COMMA == lastToken)
				NEWS(INITIAL)
			RSTATE(NL, INITIAL)
		case '<':
			NEWS(LTS)
		case '>':
			NEWS(GTS)
		case '!':
			NEWS(BANGS)
		case '=':
			NEWS(EQUS)
		case '+':
			RET(PLUS);
		case '-':
			RET(MINUS);
		case '*':
			RET(TIMES);
		case ':':
			if (OPERAND == pos)
				RET(COLON);
			pos = OPCODE;
			RSTATE(NL, WHITE)
	
		case '&':
			RET(AND);
		case '|':
			RET(OR);
		case '^':
			RET(XOR);
		case '#':
			RET(P_SIGN);
		case '$':
			RET(D_SIGN);
		case '~':
			RET(NOT);
		case ',':
			psw = WHITE;
			RET(COMMA);
		/*
		 * This assembler may reverse the normal usage of
		 * brackets and parentheses. That is expressions
		 * are put in []. 5(%eax) is 5 past %eax.
		 * bswitch flips this back. Keeps counts to improve
		 * the syntax error message.
		 */
		case '[':
			bcnt++;
			RET(bswitch ? LBRACK : LPAREN);
		case ']':
			bcnt--;
			RET(bswitch ? RBRACK : RPAREN);
		case '(':
			pcnt++;
			RET(bswitch ? LPAREN : LBRACK);
		case ')':
			pcnt--;
			RET(bswitch ? RPAREN : RBRACK);
		case '@':
			RET(AT);
		case '"':
			psw = WHITE;
			tp = token;
			NEWS(INSTR)
		case '\'':
			psw = WHITE;
			tp = token;
			NEWS(INCHAR)
		default:
			invChar(c, "as token start");
			RSTATE(NL, INITIAL)
		}

	case ONUM:
		if (isdigit(c)) {
			if (c > '7')
				yyerror("Error in octal number"); /**/
			number *= 8;
			number += c - '0';
			continue;
		}
		bp--;
		yylval.val = number;
		RSTATE(NUMBER, WHITE)

	case BNUM:
		if (isdigit(c)) {
			if (c > '1')
				yyerror("Error in binary number"); /**/
			number *= 2;
			number += c - '0';
			continue;
		}
		bp--;
		yylval.val = number;
		RSTATE(NUMBER, WHITE)

	case XNUM:
		if (isxdigit(c)) {
			number *= 16;
			if (isdigit(c))
				number += c - '0';
			else if (islower(c))
				number += c - ('a' - 10);
			else
				number += c - ('A' - 10);
			continue;
		}
		bp--;
		yylval.val = number;
		RSTATE(NUMBER, WHITE)
		
	case DNUM:
		if (isdigit(c)) {
			number *= 10;
			number += c - '0';
			continue;
		}
		if (('.' == c) || ('e' == c) || ('E' == c)) {
			yylval.dbl = strtod(backOff, &bp);
			RSTATE(FNUM, WHITE)
		}
		bp--;
		yylval.val = number;
		RSTATE(NUMBER, WHITE)

	case LZERO:
		switch(c) {
		case '.':
			yylval.dbl = strtod(backOff, &bp);
			RSTATE(FNUM, WHITE)
		case 'x':
		case 'X':
			NEWS(XNUM)
		case 'b':
		case 'B':
			NEWS(BNUM)
		default:
			bp--;
			if (isdigit(c))
				NEWS(ONUM)
			yylval.val = number;
			RSTATE(NUMBER, WHITE)
		}

	case LTS:	/* < seen */
		switch(c) {
		case '<':
			RSTATE(LSHIFT, WHITE)
		case '=':
			yylval.val = (LT|EQ);
			break;
		default:
			--bp;
			yylval.val = LT;
		}
		RSTATE(COMPARISON, WHITE)		

	case GTS:	/* > seen */
		switch(c) {
		case '=':
			yylval.val = (GT|EQ);
			break;
		case '>':
			RSTATE(RSHIFT, WHITE)
		default:
			--bp;
			yylval.val = GT;
		}
		RSTATE(COMPARISON, WHITE)

	case EQUS:	/* = seen take = or == */
		if (OPCODE == pos) {
			--bp;
			opIx = opLookUp(".equ");
			return(doOp(opIx));
		}
		if ('=' != c)	
			--bp;
		yylval.val = EQ;
		RSTATE(COMPARISON, WHITE)

	case BANGS:	/* ! seen */
		if ('=' == c) {
			yylval.val = (GT|LT);
			RSTATE(COMPARISON, WHITE)
		}
		--bp;
		RSTATE(BANG, WHITE)

	case INSTR:
	case INCHAR:
		switch(c) {
		case 0:
		case '\n':
			--bp;
			if (state == INSTR) {
				yyerror("End of line detected in string"); /**/
				*tp = '\0';
				yylval.t = token;
				RSTATE(TOKEN, psw)
			}
			yyerror("End of line detected in character constant");
			/**/
		case '\'':
			if (state != INCHAR)
				break;
			*tp = '\0';
			if (strlen(token) != 1)
				yyerror("Character constant %d long",
					strlen(token));
				/* Character constants must be one byte long. */
			yylval.val = token[0];
			RSTATE(NUMBER, psw)
		case '"':
			if (state != INSTR)
				break;
			*tp = '\0';
			yylval.t = token;
			RSTATE(TOKEN, psw)
		case '\\':
			pstate = state;
			NEWS(BSL)
		}
		*tp++ = c;
		continue;

	case BSL:	/* back slash */
		switch(c) {
		case 0:
		case '\n':
			--bp;
			yyerror("End of line after backslash");
			/**/
			break;
		case 'n':
			*tp++ = '\n'; break;
		case 'r':
			*tp++ = '\r'; break;
		case 't':
			*tp++ = '\t'; break;
		case 'b':
			*tp++ = '\b'; break;
		case 'f':
			*tp++ = '\f'; break;
		default:
			if ((c >= '0') && (c <= '7')) {
				number = 0;
				bp--;
				NEWS(BSLDIG)
			}
			*tp++ = c;
		}
		NEWS(pstate)

	case BSLDIG:	/* accumulate octal number */
		if ((c >= '0') && (c <= '7')) {
			number *= 8;
			number += c - '0';
			continue;
		}
		if (number > 255) {
			yyerror("Octal number %ld truncated to char", number);
			/* An octal number in a string was too big. */
			number &= 255;
		}
		if (!number) {
			yyerror("Cannot insert \\0 in string");
			/* NUL (\e0) terminates strings.
			 * Instead of
			 * .DM
			 *	.byte	"hello\en\e0"
			 * .DE
			 * use:
			 * .DM
			 *	.byte	"hello\en", 0
			 * .DE */
		}
		*tp++ = number;
		bp--;
		NEWS(pstate)

	case ENDLINE:
		RSTATE(NL, INITIAL)
	}
    }
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.