Files
zSoft/apps/tbasic/basic_tokens.c

511 lines
11 KiB
C

#include "mystdlib.h"
#include "basic_tokens.h"
#include "basic_expr.h"
#include "basic_utils.h"
#include "basic_extern.h"
#include "basic_textual.h"
char* cur;
token* curTok;
token* prevTok;
char* parseError;
char parseErrorCode;
static short cmdCodeByHash(numeric h) {
// replaced array with switch to save RAM
switch (h) {
case 0x018F: // REM
return CMD_REM;
case 0x067C: // PRINT
return CMD_PRINT;
case 0x075E: // INPUT
return CMD_INPUT;
case 0x00D4: // IF
return CMD_IF;
case 0x03E3: // GOTO
return CMD_GOTO;
case 0x07AC: // GOSUB
return CMD_GOSUB;
case 0x0D0E: // RETURN
return CMD_RETURN;
case 0x01CC: // END
return CMD_END;
case 0x01CF: // DIM
return CMD_DIM;
case 0x0783: // DELAY
return CMD_DELAY;
case 0x03CD: // DATA
return CMD_DATA;
case 0x03DA: // EMIT
return CMD_EMIT;
default:
return extraCommandByHash(h);
}
}
char* getCurTokPos() {
return cur;
}
short tokenSize(token* t) {
switch (t->type) {
case TT_NUMBER:
return 1 + sizeof(t->body.integer);
case TT_NAME:
case TT_COMMENT:
case TT_LITERAL:
case TT_FUNCTION:
case TT_VARIABLE:
return 2 + t->body.str.len;
case TT_FUNC_END:
case TT_SYMBOL:
case TT_ARRAY:
case TT_COMMAND:
return 1 + sizeof(t->body.symbol);
case TT_NONE:
case TT_ERROR:
case TT_SEPARATOR:
return 1;
}
return 0;
}
short tokenChainSize(token* src) {
token* t = src;
while (t->type != TT_NONE) {
t = nextToken(t);
}
return (short)((char*)(void*)t - (char*)(void*)src) + 1;
}
void copyToken(token* dst, token* src) {
memcpy(dst, src, tokenSize(src));
}
void setTokenError(char* pos, char code) {
parseErrorCode = code;
parseError = pos;
curTok->type = TT_ERROR;
}
token* nextToken(token* t) {
return (token*)(void*) ((char*)(void*)t + tokenSize(t));
}
void skipTokenInInput(char offset) {
cur = skipSpaces(cur + offset);
}
static void advance(char* s) {
cur = skipSpaces(s);
prevTok = curTok;
curTok = nextToken(curTok);
}
static void substCommandFound(char code) {
curTok->type = TT_COMMAND;
curTok->body.command = code;
nextToken(curTok)->type = TT_ERROR;
}
void trySubstCmd(void) {
short i;
numeric cmdHash = tokenHash(curTok);
i = cmdCodeByHash(cmdHash);
if (i >= 0) {
substCommandFound(i);
return;
}
}
char parseName(char checkCmd) {
short i = 0;
if (!isAlpha(*cur)) {
return 0;
}
curTok->type = TT_NAME;
while (isAlNum(cur[i])) {
curTok->body.str.text[i] = toUpper(cur[i]);
i++;
}
curTok->body.str.len = i;
if (checkCmd) {
trySubstCmd();
}
advance(cur + i);
return 1;
}
char parseChar(void) {
if (cur[0] != '\'') {
return 0;
}
curTok->type = TT_NUMBER;
curTok->body.integer = ((unsigned char*) cur)[1];
cur += 2;
advance(cur);
return 1;
}
char parseNumber(void) {
char base = 10;
if (!isDigit(*cur)) {
return parseChar();
}
curTok->type = TT_NUMBER;
curTok->body.integer = 0;
if (cur[0] == '0') {
if (toUpper(cur[1]) == 'X') {
base = 16;
cur += 2;
} else if (toUpper(cur[1]) == 'B') {
base = 2;
cur += 2;
} else {
base = 8;
}
}
while (isDigitBased(*cur, base)) {
curTok->body.integer = curTok->body.integer * base + makeDigit(*cur, base);
cur++;
}
advance(cur);
return 1;
}
char parseNone(void) {
if (*cur != 0) {
setTokenError(cur, 5);
return 0;
}
curTok->type = TT_NONE;
return 1;
}
char parseComment(void) {
unsigned char len = strlen(cur);
curTok->type = TT_COMMENT;
curTok->body.str.len = len;
memcpy(&(curTok->body.str.text), cur, len);
advance(cur + len);
return parseNone();
}
char parseLiteral() {
if (*cur != '"') {
return 0;
}
short i = 1;
curTok->type = TT_LITERAL;
while (cur[i] != 0 && cur[i] != '"') {
curTok->body.str.text[i - 1] = cur[i];
i++;
}
curTok->body.str.len = i - 1;
advance(cur + i + (cur[i] == '"' ? 1 : 0));
return 1;
}
char parseSymbol() {
curTok->type = TT_SYMBOL;
char c = 0;
if (cur[0] == '<') {
if (cur[1] == '>') {
c = '#';
} else if (cur[1] == '=') {
c = '{';
}
} else if (cur[0] == '>' && cur[1] == '=') {
c = '}';
}
if (c != 0) {
cur++;
} else {
c = cur[0];
}
curTok->body.symbol = toUpper(c);
advance(cur + 1);
return 1;
}
char parseLineNumber(void) {
char* start = cur;
if (!parseNumber()) {
return 1;
}
if (prevTok->body.integer < 1 || prevTok->body.integer > MAX_LINE_NUMBER) {
setTokenError(start, 7);
return 0;
}
return 1;
}
char parseSemicolon(void) {
if (*cur != ';') {
setTokenError(cur, 4);
return 0;
}
curTok->type = TT_SEPARATOR;
advance(cur + 1);
return 1;
}
char* skipSubscripts() {
char* p = cur;
char br = 0;
while (*p != 0) {
if (*p == '(') {
br += 1;
} else if (*p == ')') {
br -= 1;
if (br == 0) {
break;
}
}
p++;
}
return p;
}
char assignmentSyntax(void) {
char* p;
if (*cur == '=') {
return CMD_LET;
} else if (*cur != '(') {
setTokenError(cur, 2);
return 0;
}
p = skipSubscripts();
if (*p == 0) {
setTokenError(p, 10);
return 0;
}
p = skipSpaces(p + 1);
if (*p != '=') {
setTokenError(cur, 2);
return 0;
}
return CMD_LETA;
}
char parseSubscripts(void) {
char* p = skipSubscripts();
*p = ';';
cur++;
if (!parseExpression()) {
return 0;
}
parseSemicolon();
*p = ')';
return 1;
}
char parseAssignment(void) {
char synt = assignmentSyntax();
if (!synt) {
return 0;
}
curTok->type = TT_COMMAND;
memmove((char*)(void*)prevTok + tokenSize(curTok), prevTok, tokenSize(prevTok));
prevTok->type = TT_COMMAND;
prevTok->body.command = synt;
curTok = nextToken(prevTok);
if (synt == CMD_LETA) {
curTok->type = TT_ARRAY;
curTok->body.symbol = curTok->body.str.text[0];
}
prevTok = curTok;
curTok = nextToken(curTok);
if (synt == CMD_LETA) {
if (!parseSubscripts()) {
return 0;
}
}
cur = skipSpaces(cur + 1);
return parseExpression() && parseNone();
}
char parseExprOrLiteral(void) {
if (parseLiteral()) {
return 1;
}
return parseExpression();
}
char parseVar(void) {
if (!parseName(0)) {
setTokenError(cur, 3);
return 0;
}
prevTok->type = TT_VARIABLE;
return 1;
}
char parseExprList(void) {
if (!parseExpression()) {
return 0;
}
while (*cur != 0) {
if (!parseSemicolon() || !parseExpression()) {
return 0;
}
}
return parseNone();
}
char parsePrintList(void) {
if (!parseExprOrLiteral()) {
return 0;
}
while (*cur != 0) {
if (!parseSemicolon() || !parseExprOrLiteral()) {
return 0;
}
}
return parseNone();
}
char parseDataList(void) {
do {
if (!parseNumber() && !parseLiteral()) {
setTokenError(cur, 8);
return 0;
}
} while (*cur != 0);
return parseNone();
}
char parseNExpressions(char cnt) {
if (cnt > 0) {
if (!parseExpression()) {
return 0;
}
while (--cnt > 0) {
if (!parseSemicolon() || !parseExpression()) {
return 0;
}
}
}
return parseNone();
}
char parseLabel(void) {
if (parseNumber()) {
return parseNone();
}
setTokenError(cur, 8);
return 0;
}
char parseStatement(void);
char parseConditional(void) {
if (!parseExpression()) {
return 0;
}
return parseSemicolon() && parseStatement();
}
char parseAllocate() {
if (!parseName(0)) {
setTokenError(cur, 3);
return 0;
}
prevTok->type = TT_ARRAY;
prevTok->body.symbol = prevTok->body.str.text[0];
curTok = nextToken(prevTok);
if (!parseNumber()) {
setTokenError(cur, 8);
return 0;
}
if (*cur != 0) {
if (!parseSymbol() || prevTok->body.symbol != 'B') {
setTokenError(cur, 9);
return 0;
}
}
return parseNone();
}
void parseSpecialWithError() {
curTok = nextToken(curTok);
while (parseName(0) || parseNumber() || parseLiteral()) {
}
curTok->type = TT_ERROR;
}
char parseStatement(void) {
char cmd;
if (!parseName(1)) {
setTokenError(cur, 1);
return 0;
} else if (prevTok->type != TT_COMMAND) {
if (parseAssignment()) {
return 1;
} else {
parseSpecialWithError();
return 0;
}
}
cmd = prevTok->body.command;
if (cmd == CMD_REM) {
return parseComment();
} else if (cmd == CMD_GOTO || cmd == CMD_GOSUB) {
return parseLabel();
} else if (cmd == CMD_RETURN || cmd == CMD_END) {
return parseNone();
} else if (cmd == CMD_PRINT) {
return parsePrintList();
} else if (cmd == CMD_INPUT) {
return parseVar() && parseNone();
} else if (cmd == CMD_IF) {
return parseConditional();
} else if (cmd == CMD_DIM) {
return parseAllocate();
} else if (cmd == CMD_DELAY) {
return parseNExpressions(1);
} else if (cmd == CMD_DATA) {
return parseDataList();
} else if (cmd == CMD_EMIT) {
return parseExprList();
} else if (cmd >= CMD_EXTRA) {
return parseNExpressions(extraCmdArgCnt[cmd - CMD_EXTRA]);
}
setTokenError(cur, 6);
return 0;
}
void parseLine(char* line, token* tokens) {
cur = line;
curTok = tokens;
prevTok = NULL;
setTokenError(NULL, 0);
if (parseLineNumber()) {
if (*cur != 0) {
parseStatement();
} else {
parseNone();
}
}
}
char tokenClass(token* t) {
return t->type & 0xF0;
}
numeric tokenHash(token* t) {
if (tokenClass(t) != TT_NAME) {
return 0;
}
return hashOfNStr(&(t->body.str));
}
char* getParseErrorPos(void) {
return parseError;
}
void getParseErrorMsg(char* s) {
outputConstStr(ID_PARSING_ERRORS, parseErrorCode, s);
}