First push after merge, split and enhance both zOS and zputa
This commit is contained in:
510
apps/tbasic/basic_tokens.c
Normal file
510
apps/tbasic/basic_tokens.c
Normal file
@@ -0,0 +1,510 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user