/* lexer.c */

#include "picasm.h"

int lexgetchar()
{
	return fgetc(lexstack[last_lexlevel].file);
}

void lexungetc(int ch)
{
	ungetc(ch,lexstack[last_lexlevel].file);
}

void lexan_file()	/* lexical analyzer */
{
	int t;
	char tmp_str[5];

	do
	{
		t = lexgetchar();		

		if (t == '\n')
			lexstack[last_lexlevel].lineno++;

	} while (isspace(t));

	if (isdigit(t))
	{			/* t is a digit */
		lexungetc(t);
		donumber();
	}
	else
	if (isalpha(t) || (t=='_'))
	{			/* t is a letter or underscore */
		lexungetc(t);
		doidentifier();
	}
	else
	{
		switch(t)
		{
			case EOF:	current_symbol.token = DONE;
					break;
			case '.':	current_symbol.token = PERIOD;
					break;
			case ',':	current_symbol.token = COMMA;
					break;
			case ';':	current_symbol.token = SEMICOLON;
					break;
			case ':':	current_symbol.token = COLON;
					break;
			case '(':	current_symbol.token = LPAREN;
					break;
			case ')':	current_symbol.token = RPAREN;
					break;
			case '[':	current_symbol.token = LBLOCK;
					break;
			case ']':	current_symbol.token = RBLOCK;
					break;
			case '{':	current_symbol.token = LBRACE;
					break;
			case '}':	current_symbol.token = RBRACE;
					break;
			case '*':	current_symbol.token = MUL;
					break;
			case '%':	current_symbol.token = MOD;
					break;
			case '#':	current_symbol.token = HASH;
					break;
			case '/':	current_symbol.token = DIV;
					break;
			case '~':	current_symbol.token = COMP;
					break;
			case '^':	current_symbol.token = BXOR;
					break;
			case '$':	current_symbol.token = DOLLAR;
					break;

			case '+':	t = lexgetchar();
					if (t == '+')
						current_symbol.token = INCSY;
					else
					{
						lexungetc(t);
						current_symbol.token = PLUS;
					}
					break;

			case '-':	t = lexgetchar();
					if (t == '-')
						current_symbol.token = DECSY;
					else
					{
						lexungetc(t);
						current_symbol.token = MINUS;
					}
					break;

			case '=':	t = lexgetchar();
					if (t == '=')
						current_symbol.token = SAME;
					else
					{
						lexungetc(t);
						current_symbol.token = ASSIGN;
					}
					break;

			case '>':	t = lexgetchar();
					if (t == '>')
						current_symbol.token = SHR;
					else
					if (t == '=')
						current_symbol.token = GTREQ;
					else
					{
						lexungetc(t);
						current_symbol.token = GTR;
					}
					break;

			case '<':	t = lexgetchar();
					if (t == '<')
						current_symbol.token = SHL;
					else
					if (t == '=')
						current_symbol.token = LESSEQ;
					else
					{
						lexungetc(t);
						current_symbol.token = LESS;
					}
					break;

			case '!':	t = lexgetchar();
					if (t == '=')
						current_symbol.token = NOTEQ;
					else
					{
						lexungetc(t);
						current_symbol.token = NOT;
					}
					break;

			case '&':	t = lexgetchar();
					if (t == '&')
						current_symbol.token = ANDSY;
					else
					{
						lexungetc(t);
						current_symbol.token = BAND;
					}
					break;

			case '|':	t = lexgetchar();
					if (t == '|')
						current_symbol.token = ORSY;
					else
					{
						lexungetc(t);
						current_symbol.token = BOR;
					}
					break;

			case '\"':	dostring();
					break;

			default:	sprintf(tmp_str," \'%c\' ", t);
					error("Unknown symbol",tmp_str,"","");
		}
	}
}

void strip_comment()
{
	int t;

	do
	{
		t = lexgetchar();
	} while((t != '\n') && (t != EOF));

	lexstack[last_lexlevel].lineno++;
}

void lexan_macro()
{
	if(lexstack[last_lexlevel].symsleft)
	{
		cpsym(&current_symbol, &macrostore[lexstack[last_lexlevel].whereupto]);
		lexstack[last_lexlevel].whereupto++;
		lexstack[last_lexlevel].symsleft--;
	}
	else
		current_symbol.token  = DONE;
}

void lexan()
{
	switch(lexstack[last_lexlevel].type)
	{
		case LEXFILE:	lexan_file();
				break;

		case LEXMACRO:	lexan_macro();
				break;

		default:	error("eh!!!","","","");
	}

	if (current_symbol.token == DONE)
	{
		if(lexstack[last_lexlevel].type == LEXFILE)
			fclose(lexstack[last_lexlevel].file);
					
		if(last_lexlevel)
			last_lexlevel--;
	}
}

void getanother()
{
	int cont;

	cont = 1;

	while(cont)
	{
		lexan();
		cont = 0;	/* leave unless we get a comment */

		if (current_symbol.token == SEMICOLON)
		{
			strip_comment();
			cont = 1;
		}
	}
}

/* ... The End ... */
