shithub: rgbds

ref: 7e4104cabe8d995e40e552da2078fea87ff4ada6
dir: /src/asm/lexer.c/

View raw version
#include "asm/asm.h"
#include "asm/lexer.h"
#include "asm/types.h"
#include "asm/main.h"
#include "asm/rpn.h"
#include "asm/fstack.h"

#include "asmy.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

struct sLexString {
	char *tzName;
	ULONG nToken;
	ULONG nNameLength;
	struct sLexString *pNext;
};
#define pLexBuffer		(pCurrentBuffer->pBuffer)
#define nLexBufferLeng	(pCurrentBuffer->nBufferSize)

#define SAFETYMARGIN	1024

extern ULONG symvaluetostring(char *dest, char *s);

struct sLexFloat tLexFloat[32];
struct sLexString *tLexHash[LEXHASHSIZE];
YY_BUFFER_STATE pCurrentBuffer;
ULONG yyleng;
ULONG nLexMaxLeng;

ULONG tFloatingSecondChar[256];
ULONG tFloatingFirstChar[256];
ULONG tFloatingChars[256];
ULONG nFloating;
enum eLexerState lexerstate = LEX_STATE_NORMAL;

#define AtLineStart	pCurrentBuffer->oAtLineStart

#ifdef __GNUC__
void 
strupr(char *s)
{
	while (*s) {
		*s = toupper(*s);
		s += 1;
	}
}

void 
strlwr(char *s)
{
	while (*s) {
		*s = tolower(*s);
		s += 1;
	}
}
#endif
void 
yyskipbytes(ULONG count)
{
	pLexBuffer += count;
}

void 
yyunputbytes(ULONG count)
{
	pLexBuffer -= count;
}

void 
yyunput(char c)
{
	*(--pLexBuffer) = c;
}

void 
yyunputstr(char *s)
{
	SLONG i;

	i = strlen(s) - 1;

	while (i >= 0)
		yyunput(s[i--]);
}

void 
yy_switch_to_buffer(YY_BUFFER_STATE buf)
{
	pCurrentBuffer = buf;
}

void 
yy_set_state(enum eLexerState i)
{
	lexerstate = i;
}

void 
yy_delete_buffer(YY_BUFFER_STATE buf)
{
	free(buf->pBufferStart - SAFETYMARGIN);
	free(buf);
}

YY_BUFFER_STATE 
yy_scan_bytes(char *mem, ULONG size)
{
	YY_BUFFER_STATE pBuffer;

	if ((pBuffer =
		(YY_BUFFER_STATE) malloc(sizeof(struct yy_buffer_state))) !=
	    NULL) {
		if ((pBuffer->pBuffer = pBuffer->pBufferStart =
			(char *) malloc(size + 1 + SAFETYMARGIN)) != NULL) {
			pBuffer->pBuffer += SAFETYMARGIN;
			pBuffer->pBufferStart += SAFETYMARGIN;
			memcpy(pBuffer->pBuffer, mem, size);
			pBuffer->nBufferSize = size;
			pBuffer->oAtLineStart = 1;
			pBuffer->pBuffer[size] = 0;
			return (pBuffer);
		}
	}
	fatalerror("Out of memory!");
	return (NULL);
}

YY_BUFFER_STATE 
yy_create_buffer(FILE * f)
{
	YY_BUFFER_STATE pBuffer;

	if ((pBuffer =
		(YY_BUFFER_STATE) malloc(sizeof(struct yy_buffer_state))) !=
	    NULL) {
		ULONG size;

		fseek(f, 0, SEEK_END);
		size = ftell(f);
		fseek(f, 0, SEEK_SET);

		if ((pBuffer->pBuffer = pBuffer->pBufferStart =
			(char *) malloc(size + 2 + SAFETYMARGIN)) != NULL) {
			char *mem;
			ULONG instring = 0;

			pBuffer->pBuffer += SAFETYMARGIN;
			pBuffer->pBufferStart += SAFETYMARGIN;

			size = fread(pBuffer->pBuffer, sizeof(UBYTE), size, f);

			pBuffer->pBuffer[size] = '\n';
			pBuffer->pBuffer[size + 1] = 0;
			pBuffer->nBufferSize = size + 1;

			mem = pBuffer->pBuffer;

			while (*mem) {
				if (*mem == '\"')
					instring = 1 - instring;

				if (instring) {
					mem += 1;
				} else {
					if ((mem[0] == 10 && mem[1] == 13)
					    || (mem[0] == 13 && mem[1] == 10)) {
						mem[0] = ' ';
						mem[1] = '\n';
						mem += 2;
					} else if (mem[0] == 10 || mem[0] == 13) {
						mem[0] = '\n';
						mem += 1;
					} else if (mem[0] == '\n'
					    && mem[1] == '*') {
						mem += 1;
						while (!
						    (*mem == '\n'
							|| *mem == '\0'))
							*mem++ = ' ';
					} else if (*mem == ';') {
						while (!
						    (*mem == '\n'
							|| *mem == '\0'))
							*mem++ = ' ';
					} else
						mem += 1;
				}
			}

			pBuffer->oAtLineStart = 1;
			return (pBuffer);
		}
	}
	fatalerror("Out of memory!");
	return (NULL);
}

ULONG 
lex_FloatAlloc(struct sLexFloat * tok)
{
	tLexFloat[nFloating] = (*tok);

	return (1 << (nFloating++));
}

void 
lex_FloatDeleteRange(ULONG id, UWORD start, UWORD end)
{
	while (start <= end) {
		tFloatingChars[start] &= ~id;
		start += 1;
	}
}

void 
lex_FloatAddRange(ULONG id, UWORD start, UWORD end)
{
	while (start <= end) {
		tFloatingChars[start] |= id;
		start += 1;
	}
}

void 
lex_FloatDeleteFirstRange(ULONG id, UWORD start, UWORD end)
{
	while (start <= end) {
		tFloatingFirstChar[start] &= ~id;
		start += 1;
	}
}

void 
lex_FloatAddFirstRange(ULONG id, UWORD start, UWORD end)
{
	while (start <= end) {
		tFloatingFirstChar[start] |= id;
		start += 1;
	}
}

void 
lex_FloatDeleteSecondRange(ULONG id, UWORD start, UWORD end)
{
	while (start <= end) {
		tFloatingSecondChar[start] &= ~id;
		start += 1;
	}
}

void 
lex_FloatAddSecondRange(ULONG id, UWORD start, UWORD end)
{
	while (start <= end) {
		tFloatingSecondChar[start] |= id;
		start += 1;
	}
}

struct sLexFloat *
lexgetfloat(ULONG id)
{
	ULONG r = 0, mask = 1;

	if (id == 0)
		return (NULL);

	while ((id & mask) == 0) {
		mask <<= 1;
		r += 1;
	}

	return (&tLexFloat[r]);
}

ULONG 
lexcalchash(char *s)
{
	ULONG r = 0;

	while (*s) {
		r = ((r << 1) + (toupper(*s))) % LEXHASHSIZE;
		s += 1;
	}

	return (r);
}

void 
lex_Init(void)
{
	ULONG i;

	for (i = 0; i < LEXHASHSIZE; i += 1) {
		tLexHash[i] = NULL;
	}

	for (i = 0; i < 256; i += 1) {
		tFloatingFirstChar[i] = 0;
		tFloatingSecondChar[i] = 0;
		tFloatingChars[i] = 0;
	}

	nLexMaxLeng = 0;
	nFloating = 0;
}

void 
lex_AddStrings(struct sLexInitString * lex)
{
	while (lex->tzName) {
		struct sLexString **ppHash;
		ULONG hash;

		ppHash = &tLexHash[hash = lexcalchash(lex->tzName)];
		while (*ppHash)
			ppHash = &((*ppHash)->pNext);

		//printf("%s has hashvalue %d\n", lex->tzName, hash);

		if (((*ppHash) =
			(struct sLexString *) malloc(sizeof(struct sLexString))) !=
		    NULL) {
			if (((*ppHash)->tzName =
				(char *) strdup(lex->tzName)) != NULL) {
				(*ppHash)->nNameLength = strlen(lex->tzName);
				(*ppHash)->nToken = lex->nToken;
				(*ppHash)->pNext = NULL;

				strupr((*ppHash)->tzName);

				if ((*ppHash)->nNameLength > nLexMaxLeng)
					nLexMaxLeng = (*ppHash)->nNameLength;

			} else
				fatalerror("Out of memory!");
		} else
			fatalerror("Out of memory!");

		lex += 1;
	}
}

ULONG 
yylex(void)
{
	ULONG hash, maxlen;
	char *s;
	struct sLexString *pLongestFixed = NULL;
	ULONG nFloatMask, nOldFloatMask, nFloatLen;
	ULONG linestart = AtLineStart;

	switch (lexerstate) {
	case LEX_STATE_NORMAL:
		AtLineStart = 0;

scanagain:

		while (*pLexBuffer == ' ' || *pLexBuffer == '\t') {
			linestart = 0;
			pLexBuffer += 1;
		}

		if (*pLexBuffer == 0) {
			if (yywrap() == 0) {
				linestart = AtLineStart;
				AtLineStart = 0;
				goto scanagain;
			}
		}
		s = pLexBuffer;
		nOldFloatMask = nFloatLen = 0;
		nFloatMask = tFloatingFirstChar[(int) *s++];
		while (nFloatMask && nFloatLen < nLexBufferLeng) {
			nFloatLen += 1;
			nOldFloatMask = nFloatMask;
			if (nFloatLen == 1)
				nFloatMask &= tFloatingSecondChar[(int) *s++];
			else
				nFloatMask &= tFloatingChars[(int) *s++];
		}

		maxlen = nLexBufferLeng;
		if (nLexMaxLeng < maxlen)
			maxlen = nLexMaxLeng;

		yyleng = 0;
		hash = 0;
		s = pLexBuffer;
		while (yyleng < nLexMaxLeng) {
			yyleng += 1;
			hash = ((hash << 1) + (toupper(*s))) % LEXHASHSIZE;
			s += 1;
			if (tLexHash[hash]) {
				struct sLexString *lex;

				lex = tLexHash[hash];
				while (lex) {
					if (lex->nNameLength == yyleng) {
						if (strnicmp
						    (pLexBuffer, lex->tzName,
							yyleng) == 0) {
							pLongestFixed = lex;
						}
					}
					lex = lex->pNext;
				}
			}
		}

		if (nFloatLen == 0 && pLongestFixed == NULL) {
			if (*pLexBuffer == '"') {
				ULONG index = 0;

				pLexBuffer += 1;
				while ((*pLexBuffer != '"')
				    && (*pLexBuffer != '\n')) {
					char ch, *marg;

					if ((ch = *pLexBuffer++) == '\\') {
						switch (ch = (*pLexBuffer++)) {
						case 'n':
							ch = '\n';
							break;
						case 't':
							ch = '\t';
							break;
						case '0':
						case '1':
						case '2':
						case '3':
						case '4':
						case '5':
						case '6':
						case '7':
						case '8':
						case '9':
							if ((marg =
								sym_FindMacroArg(ch
								    -
								    '0'))
							    != NULL) {
								while (*marg)
									yylval.
									    tzString
									    [index++]
									    =
									    *marg++;
								ch = 0;
							}
							break;
						case '@':
							if ((marg =
								sym_FindMacroArg
								(-1)) != NULL) {
								while (*marg)
									yylval.
									    tzString
									    [index++]
									    =
									    *marg++;
								ch = 0;
							}
							break;
						}
					} else if (ch == '{') {
						char sym[MAXSYMLEN];
						int i = 0;

						while ((*pLexBuffer != '}')
						    && (*pLexBuffer != '"')
						    && (*pLexBuffer !=
							'\n')) {
							if ((ch =
								*pLexBuffer++) ==
							    '\\') {
								switch (ch =
								    (*pLexBuffer++)) {
								case '0':
								case '1':
								case '2':
								case '3':
								case '4':
								case '5':
								case '6':
								case '7':
								case '8':
								case '9':
									if ((marg = sym_FindMacroArg(ch - '0')) != NULL) {
										while
										    (*marg)
											sym[i++] = *marg++;
										ch = 0;
									}
									break;
								case '@':
									if ((marg = sym_FindMacroArg(-1)) != NULL) {
										while
										    (*marg)
											sym[i++] = *marg++;
										ch = 0;
									}
									break;
								}
							} else
								sym[i++] = ch;
						}

						sym[i] = 0;
						index +=
						    symvaluetostring(&yylval.
						    tzString
						    [index],
						    sym);
						if (*pLexBuffer == '}')
							pLexBuffer += 1;
						else
							yyerror("Missing }");
						ch = 0;
					}
					if (ch)
						yylval.tzString[index++] = ch;
				}

				yylval.tzString[index++] = 0;

				if (*pLexBuffer == '\n')
					yyerror("Unterminated string");
				else
					pLexBuffer += 1;

				return (T_STRING);
			} else if (*pLexBuffer == '{') {
				char sym[MAXSYMLEN], ch, *marg;
				int i = 0;

				pLexBuffer += 1;

				while ((*pLexBuffer != '}')
				    && (*pLexBuffer != '\n')) {
					if ((ch = *pLexBuffer++) == '\\') {
						switch (ch = (*pLexBuffer++)) {
						case '0':
						case '1':
						case '2':
						case '3':
						case '4':
						case '5':
						case '6':
						case '7':
						case '8':
						case '9':
							if ((marg =
								sym_FindMacroArg(ch
								    -
								    '0'))
							    != NULL) {
								while (*marg)
									sym[i++]
									    =
									    *marg++;
								ch = 0;
							}
							break;
						case '@':
							if ((marg =
								sym_FindMacroArg
								(-1)) != NULL) {
								while (*marg)
									sym[i++]
									    =
									    *marg++;
								ch = 0;
							}
							break;
						}
					} else
						sym[i++] = ch;
				}
				sym[i] = 0;
				symvaluetostring(yylval.tzString, sym);
				if (*pLexBuffer == '}')
					pLexBuffer += 1;
				else
					yyerror("Missing }");

				return (T_STRING);
			} else {
				if (*pLexBuffer == '\n')
					AtLineStart = 1;

				yyleng = 1;
				return (*pLexBuffer++);
			}
		}
		if (nFloatLen == 0) {
			yyleng = pLongestFixed->nNameLength;
			pLexBuffer += yyleng;
			return (pLongestFixed->nToken);
		}
		if (pLongestFixed == NULL) {
			struct sLexFloat *tok;

			tok = lexgetfloat(nOldFloatMask);
			yyleng = nFloatLen;
			if (tok->Callback) {
				if (tok->Callback(pLexBuffer, yyleng) == 0)
					goto scanagain;
			}
			if (tok->nToken == T_ID && linestart) {
				pLexBuffer += yyleng;
				return (T_LABEL);
			} else {
				pLexBuffer += yyleng;
				return (tok->nToken);
			}
		}
		if (nFloatLen > pLongestFixed->nNameLength) {
			struct sLexFloat *tok;

			tok = lexgetfloat(nOldFloatMask);
			yyleng = nFloatLen;
			if (tok->Callback) {
				if (tok->Callback(pLexBuffer, yyleng) == 0)
					goto scanagain;
			}
			if (tok->nToken == T_ID && linestart) {
				pLexBuffer += yyleng;
				return (T_LABEL);
			} else {
				pLexBuffer += yyleng;
				return (tok->nToken);
			}
		} else {
			yyleng = pLongestFixed->nNameLength;
			pLexBuffer += yyleng;
			return (pLongestFixed->nToken);
		}
		break;

	case LEX_STATE_MACROARGS:
		{
			ULONG index = 0;

			while (*pLexBuffer == ' ' || *pLexBuffer == '\t') {
				linestart = 0;
				pLexBuffer += 1;
			}

			while ((*pLexBuffer != ',')
			    && (*pLexBuffer != '\n')) {
				char ch, *marg;

				if ((ch = *pLexBuffer++) == '\\') {
					switch (ch = (*pLexBuffer++)) {
					case 'n':
						ch = '\n';
						break;
					case 't':
						ch = '\t';
						break;
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						if ((marg =
							sym_FindMacroArg(ch -
							    '0')) !=
						    NULL) {
							while (*marg)
								yylval.
								    tzString
								    [index++] =
								    *marg++;
							ch = 0;
						}
						break;
					case '@':
						if ((marg =
							sym_FindMacroArg(-1)) !=
						    NULL) {
							while (*marg)
								yylval.
								    tzString
								    [index++] =
								    *marg++;
							ch = 0;
						}
						break;
					}
				} else if (ch == '{') {
					char sym[MAXSYMLEN];
					int i = 0;

					while ((*pLexBuffer != '}')
					    && (*pLexBuffer != '"')
					    && (*pLexBuffer != '\n')) {
						if ((ch =
							*pLexBuffer++) == '\\') {
							switch (ch =
							    (*pLexBuffer++)) {
							case '0':
							case '1':
							case '2':
							case '3':
							case '4':
							case '5':
							case '6':
							case '7':
							case '8':
							case '9':
								if ((marg =
									sym_FindMacroArg
									(ch -
									    '0')) !=
								    NULL) {
									while
									    (*marg)
										sym[i++] = *marg++;
									ch = 0;
								}
								break;
							case '@':
								if ((marg =
									sym_FindMacroArg
									(-1)) !=
								    NULL) {
									while
									    (*marg)
										sym[i++] = *marg++;
									ch = 0;
								}
								break;
							}
						} else
							sym[i++] = ch;
					}
					sym[i] = 0;
					index +=
					    symvaluetostring(&yylval.
					    tzString[index],
					    sym);
					if (*pLexBuffer == '}')
						pLexBuffer += 1;
					else
						yyerror("Missing }");
					ch = 0;
				}
				if (ch)
					yylval.tzString[index++] = ch;
			}

			if (index) {
				yyleng = index;
				yylval.tzString[index] = 0;
				if (*pLexBuffer == '\n') {
					while (yylval.tzString[--index] == ' ') {
						yylval.tzString[index] = 0;
						yyleng -= 1;
					}
				}
				return (T_STRING);
			} else if (*pLexBuffer == '\n') {
				pLexBuffer += 1;
				AtLineStart = 1;
				yyleng = 1;
				return ('\n');
			} else if (*pLexBuffer == ',') {
				pLexBuffer += 1;
				yyleng = 1;
				return (',');
			} else {
				yyerror("INTERNAL ERROR IN YYLEX");
				return (0);
			}
		}

		break;
	}

	yyerror("INTERNAL ERROR IN YYLEX");
	return (0);
}