First push after merge, split and enhance both zOS and zputa

This commit is contained in:
Philip Smart
2020-04-25 22:48:39 +01:00
commit 25466f1db8
5072 changed files with 2191180 additions and 0 deletions

69
apps/tbasic/Makefile Executable file
View File

@@ -0,0 +1,69 @@
#########################################################################################################
##
## Name: Makefile
## Created: July 2019
## Author(s): Philip Smart
## Description: App Makefile - Build an App for the ZPU Test Application (zputa) or the zOS
## operating system.
## This makefile builds an app which is stored on an SD card and called by ZPUTA/zOS
## The app is for testing some component where the code is not built into ZPUTA or
## a user application for zOS.
##
## Credits:
## Copyright: (c) 2019-20 Philip Smart <philip.smart@net2net.org>
##
## History: July 2019 - Initial Makefile created for template use.
## April 2020 - Added K64F as an additional target and resplit ZPUTA into zOS.
##
## Notes: Optional component enables:
## USELOADB - The Byte write command is implemented in hw#sw so use it.
## USE_BOOT_ROM - The target is ROM so dont use initialised data.
## MINIMUM_FUNTIONALITY - Minimise functionality to limit code size.
##
#########################################################################################################
## This source file is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published
## by the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This source file is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>.
#########################################################################################################
APP_NAME = tbasic
APP_DIR = $(CURDIR)/..
APP_COMMON_DIR = $(CURDIR)/../common
BASEDIR = ../../..
# Override values given by parent make for this application as its memory usage differs from the standard app.
override HEAPADDR = 0x1FFF5000
override HEAPSIZE = 0x00033000
override STACKADDR = 0x20028000
override STACKSIZE = 0x00000000
# Modules making up Kilo.
APP_C_SRC = basic_main.c basic_editor.c basic_exectoks.c basic_expr.c basic_tokens.c basic_utils.c $(APP_COMMON_DIR)/sysutils.c
CFLAGS =
CPPFLAGS = -D__HEAPADDR__=$(HEAPADDR) -D__HEAPSIZE__=$(HEAPSIZE)
LDFLAGS = -nostdlib
# Filter out the standard HEAP address and size, replacing with the ones required for this application.
# Useful for sub-makes
FILTER1 = $(filter-out $(filter HEAPADDR=%,$(MAKEFLAGS)), $(MAKEFLAGS))
FILTER2 = $(filter-out $(filter HEAPSIZE=%,$(FILTER1)), $(FILTER1))
NEWMAKEFLAGS = $(FILTER2) HEAPADDR=$(HEADADDR) HEAPSIZE=$(HEAPSIZE)
# Modules making up BASIC.
CFLAGS =
CPPFLAGS =
ifeq ($(__K64F__),1)
include $(APP_DIR)/Makefile.k64f
else
include $(APP_DIR)/Makefile.zpu
endif

133
apps/tbasic/basic_editor.c Normal file
View File

@@ -0,0 +1,133 @@
#include "mystdlib.h"
#include "basic_editor.h"
#include "basic_utils.h"
#include "basic_tokens.h"
#include "basic_extern.h"
#include "basic_textual.h"
extern token* toksBody;
char* prgStore;
short prgSize;
static short maxProgSize;
static unsigned char lineSpacePos;
char lastInput;
void resetEditor(void) {
((prgline*)prgStore)->num = 0;
prgSize = 2;
lineSpacePos = 0;
}
void initEditor(char* prgBody, short progSpaceSize) {
maxProgSize = progSpaceSize;
prgStore = prgBody;
resetEditor();
}
char readLine() {
if (lastInput == '\r' || lastInput == '\n') {
trim(lineSpace);
lineSpace[lineSpacePos] = 0;
lineSpacePos = 0;
sysEcho('\n');
return 1;
} else if (lastInput == '\b' || lastInput == 127) {
if (lineSpacePos > 0) {
lastInput = '\b';
lineSpacePos -= 1;
}
} else if (lastInput >= ' ') {
lineSpace[lineSpacePos++] = lastInput;
}
sysEcho(lastInput);
return 0;
}
short lineSize(prgline* p) {
return p->str.len + 3;
}
prgline* nextLine(prgline* p) {
return (prgline*)(void*)((char*)(void*)p + lineSize(p));
}
prgline* findLine(short num) {
prgline* p = (prgline*)(void*)prgStore;
while (p->num != 0 && p->num < num) {
p = nextLine(p);
}
return p;
}
void injectLine(char* s, short num) {
unsigned char len;
prgline* p = findLine(num);
if (p->num == num) {
len = (char*)(void*)nextLine(p) - (char*)(void*)p;
memmove(p, nextLine(p), prgStore + prgSize - (char*)(void*)nextLine(p));
prgSize -= len;
}
len = strlen(s);
if (prgSize + len + 3 >= maxProgSize) {
outputCr();
outputConstStr(ID_COMMON_STRINGS, 13, NULL);
outputCr();
return;
}
if (len > 0) {
memmove((char*)(void*)p + len + 3, p, prgStore + prgSize - (char*)(void*)p);
prgSize += len + 3;
p->num = num;
p->str.len = len;
memcpy(p->str.text, s, len);
}
}
char editorSave(void) {
if (!storageOperation(NULL, 1)) {
return 0;
}
storageOperation(&prgSize, sizeof(prgSize));
storageOperation(prgStore, prgSize);
storageOperation(NULL, 0);
return 1;
}
char editorLoad(void) {
if (!storageOperation(NULL, -1)) {
return 0;
}
storageOperation(&prgSize, (short) -sizeof(prgSize));
storageOperation(prgStore, -prgSize);
storageOperation(NULL, 0);
return 1;
}
char editorLoadParsed() {
void* p = prgStore;
unsigned char len;
if (!storageOperation(NULL, -1)) {
return 0;
}
storageOperation(lineSpace, -2);
while (1) {
storageOperation(p, (short) -sizeof(short));
if (*((short*)p) == 0) {
break;
}
parseLine(lineSpace, toksBody);
p = (char*)p + sizeof(short);
storageOperation(&len, (short) -sizeof(len));
storageOperation(lineSpace, -len);
lineSpace[len] = 0;
parseLine(lineSpace, toksBody);
len = tokenChainSize(toksBody);
*((char*)p) = len;
memcpy((char*)p + 1, toksBody, len);
p = (char*)p + len + 1;
}
storageOperation(NULL, 0);
prgSize = ((char*)p - (char*)(void*)prgStore) + sizeof(short);
return 1;
}

View File

@@ -0,0 +1,19 @@
#ifndef __EDITOR_H_
#define __EDITOR_H_
#include "basic_utils.h"
extern char* prgStore;
extern short prgSize;
void resetEditor(void);
void initEditor(char* prgBody, short progSpaceSize);
char readLine();
prgline* findLine(short num);
void injectLine(char* s, short num);
char editorSave(void);
char editorLoad(void);
char editorLoadParsed(void);
#endif

View File

@@ -0,0 +1,593 @@
#include "mystdlib.h"
#include "mytypes.h"
#include "basic_tokens.h"
#include "basic_tokenint.h"
#include "basic_editor.h"
#include "basic_utils.h"
#include "basic_extern.h"
#include "basic_textual.h"
extern char mainState;
extern token* toksBody;
numeric* calcStack;
short nextLineNum = 1;
static prgline* progLine;
short sp, spInit;
varHolder* vars;
char numVars;
short arrayBytes;
labelCacheElem* labelCache;
short labelsCached;
numeric lastDim;
static numeric execStepsCount;
static numeric delayT0, delayLimit;
void execRem(void);
void execPrint(void);
void execInput(void);
void execIf(void);
void execGoto(void);
void execGosub(void);
void execReturn(void);
void execEnd(void);
void execLet(void);
void execLeta(void);
void execDim(void);
void execDelay(void);
void execData(void);
void execEmit(void);
void (*executors[])(void) = {
execRem,
execPrint,
execInput,
execIf,
execGoto,
execGosub,
execReturn,
execEnd,
execLet,
execLeta,
execDim,
execDelay,
execData,
execEmit,
};
void resetTokenExecutor(void) {
numVars = 0;
arrayBytes = 0;
sp = spInit;
vars[0].name = 0;
}
short varSize(void) {
return numVars * sizeof(varHolder) + arrayBytes;
}
void initTokenExecutor(char* space, short size) {
spInit = (size / sizeof(*calcStack));
vars = (varHolder*)(void*)space;
calcStack = (numeric*)(void*)space;
resetTokenExecutor();
}
short shortVarName(nstring* name) {
short n = name->text[0];
if (name->len > 1) {
n += name->text[1] * 127;
}
return n;
}
short shortArrayName(char letter) {
return 0x7F00 | letter;
}
unsigned char findVar(short name) {
short hi = numVars;
short lo = 0;
short mid;
while (hi > lo) {
mid = (hi + lo) / 2;
if (vars[mid].name < name) {
lo = mid + 1;
} else {
hi = mid;
}
}
return lo;
}
numeric getVar(short name) {
unsigned char i = findVar(name);
return (vars[i].name == name) ? vars[i].value : 0;
}
short getArrayOffset(char letter) {
short name = shortArrayName(letter);
unsigned char i = findVar(name);
return (vars[i].name == name) ? vars[i].value : -1;
}
char checkLowVarsMemory(short toAddBytes) {
if (((char*)(vars + numVars)) + arrayBytes + toAddBytes >= (char*)(calcStack + spInit - 5)) {
outputCr();
outputConstStr(ID_COMMON_STRINGS, 12, NULL);
outputCr();
return 1;
}
return 0;
}
void setVar(short name, numeric value) {
unsigned char i = findVar(name);
if (vars[i].name != name) {
if (checkLowVarsMemory(sizeof(varHolder))) {
return;
}
if (i < numVars) {
memmove(vars + i + 1, vars + i, sizeof(varHolder) * (numVars - i) + arrayBytes);
}
vars[i].name = name;
numVars += 1;
}
vars[i].value = value;
}
short findLabel(short num) {
short hi = labelsCached;
short lo = 0;
short mid;
while (hi > lo) {
mid = (hi + lo) / 2;
if (labelCache[mid].num < num) {
lo = mid + 1;
} else {
hi = mid;
}
}
return lo;
}
prgline* getCachedLabel(short num) {
short i = findLabel(num);
return labelCache[i].num == num ? (prgline*)(void*)(prgStore + labelCache[i].offset) : NULL;
}
void addCachedLabel(short num, short offset) {
short idx = findLabel(num);
if (idx < labelsCached) {
memmove(labelCache + idx + 1, labelCache + idx, sizeof(labelCacheElem) * (labelsCached - idx));
}
labelCache[idx].num = num;
labelCache[idx].offset = offset;
labelsCached += 1;
}
static void advance(void) {
if (curTok->type != TT_NONE) {
curTok = nextToken(curTok);
}
}
void calcOperation(char op) {
numeric top = calcStack[sp++];
switch (op) {
case '+':
calcStack[sp] += top;
break;
case '-':
calcStack[sp] -= top;
break;
case '*':
calcStack[sp] *= top;
break;
case '/':
calcStack[sp] /= top;
break;
case '%':
calcStack[sp] %= top;
break;
case '~':
calcStack[--sp] = -top;
break;
case '!':
calcStack[--sp] = !top;
break;
case '<':
calcStack[sp] = calcStack[sp] < top;
break;
case '>':
calcStack[sp] = calcStack[sp] > top;
break;
case '=':
calcStack[sp] = calcStack[sp] == top;
break;
case '{':
calcStack[sp] = calcStack[sp] <= top;
break;
case '}':
calcStack[sp] = calcStack[sp] >= top;
break;
case '#':
calcStack[sp] = calcStack[sp] != top;
break;
case '&':
calcStack[sp] = calcStack[sp] && top;
break;
case '|':
calcStack[sp] = calcStack[sp] || top;
break;
case '^':
calcStack[sp] = calcStack[sp] ^ top;
break;
}
}
void calcFunction(nstring* name) {
short i;
numeric r;
numeric h = hashOfNStr(name);
if (h == 0x1FF) { // KEY
i = calcStack[sp];
calcStack[sp] = lastInput;
if (i != 0) {
lastInput = 0;
}
return;
}
if (h == 0xC9) { // MS
calcStack[sp] = sysMillis(calcStack[sp]);
return;
}
if (h == 0x1D3) { // ABS
if (calcStack[sp] < 0) {
calcStack[sp] = -calcStack[sp];
}
return;
}
i = extraFunctionByHash(h);
if (i >= 0) {
// arguments will appear in reverse order
r = extraFunction(i, calcStack + sp);
sp += extraFuncArgCnt[i] - 1;
calcStack[sp] = r;
return;
}
calcStack[sp] = 0;
}
void calcArray(char letter) {
short offset = getArrayOffset(letter);
if (offset == -1) {
calcStack[sp] = 0;
return;
}
char b = (offset & 0x8000) ? 1 : sizeof(numeric);
offset = (offset & 0x7FFF) + b * calcStack[sp];
char* p = ((char*)(void*)vars) + sizeof(varHolder) * numVars + offset;
if (b > 1) {
calcStack[sp] = *((numeric*)(void*)p);
} else {
calcStack[sp] = *((unsigned char*)(void*)p);
}
}
numeric calcExpression(void) {
while (1) {
switch (curTok->type) {
case TT_NONE:
case TT_SEPARATOR:
return calcStack[sp++];
case TT_NUMBER:
calcStack[--sp] = curTok->body.integer;
break;
case TT_VARIABLE:
calcStack[--sp] = getVar(shortVarName(&(curTok->body.str)));
break;
case TT_SYMBOL:
calcOperation(curTok->body.symbol);
break;
case TT_FUNCTION:
calcFunction(&(curTok->body.str));
break;
case TT_ARRAY:
calcArray(curTok->body.symbol);
break;
}
advance();
}
}
void execLet(void) {
short varname = shortVarName(&(curTok->body.str));
advance();
setVar(varname, calcExpression());
}
void setArray(char symbol, short idx, numeric value) {
short offset = getArrayOffset(symbol);
if (offset == -1) {
return;
}
char b = (offset & 0x8000) ? 1 : sizeof(numeric);
offset = (offset & 0x7FFF) + b * idx;
char* p = ((char*)(void*)vars) + sizeof(varHolder) * numVars + offset;
if (b > 1) {
*((numeric*)(void*)p) = value;
} else {
*((unsigned char*)(void*)p) = (value & 0xFF);
}
}
void execLeta(void) {
char a = curTok->body.symbol;
advance();
short idx = calcExpression();
advance();
setArray(a, idx, calcExpression());
}
void execDim(void) {
short name = shortArrayName(curTok->body.symbol);
lastDim = curTok->body.symbol & 0x1F;
advance();
short len = curTok->body.integer;
advance();
char itemSize;
if (curTok->type == TT_NONE) {
itemSize = sizeof(numeric);
} else {
advance();
itemSize = 1;
}
unsigned char pos = findVar(name);
if (vars[pos].name == name) {
return;
}
if (checkLowVarsMemory(sizeof(varHolder) + len * itemSize)) {
return;
}
setVar(name, arrayBytes | (itemSize == 1 ? 0x8000 : 0));
arrayBytes += len * itemSize;
}
void execData(void) {
char a = (lastDim & 0x1F) | 0x40; // capital letter
unsigned char i;
if (a < 'A' || a > 'Z') {
return;
}
do {
if (curTok->type == TT_NUMBER) {
setArray(a, lastDim >> 5, curTok->body.integer);
lastDim += (1 << 5);
} else {
for (i = 0; i < curTok->body.str.len; i += 1) {
setArray(a, lastDim >> 5, curTok->body.str.text[i]);
lastDim += (1 << 5);
}
}
advance();
} while (curTok->type != TT_NONE);
}
void setDelay(numeric millis) {
delayT0 = sysMillis(1);
delayLimit = millis;
}
void execDelay(void) {
setDelay(calcExpression());
mainState |= STATE_DELAY;
}
char checkDelay() {
return sysMillis(1) - delayT0 > delayLimit;
}
void dispatchDelay() {
if (checkDelay()) {
mainState &= ~STATE_DELAY;
}
}
void execRem(void) {
while (curTok->type != TT_NONE) {
advance();
}
}
void execPrint(void) {
while (1) {
switch (curTok->type) {
case TT_NONE:
outputCr();
return;
case TT_SEPARATOR:
break;
case TT_LITERAL:
outputNStr(&(curTok->body.str));
break;
default:
outputInt(calcExpression());
break;
}
advance();
}
}
void execInput(void) {
mainState |= STATE_INPUT;
outputChar('?');
outputChar(curTok->body.str.text[0]);
outputChar('=');
}
void dispatchInput() {
if (lastInput == 0) {
return;
}
if (!readLine()) {
return;
}
setVar(shortVarName(&(curTok->body.str)), decFromStr(lineSpace));
advance();
mainState &= ~STATE_INPUT;
}
void execEmit(void) {
while (1) {
switch (curTok->type) {
case TT_NONE:
return;
case TT_SEPARATOR:
break;
default:
outputChar(calcExpression() & 0xFF);
break;
}
advance();
}
}
void execIf(void) {
if (calcExpression() == 0) {
while (curTok->type != TT_NONE) {
advance();
}
} else {
advance();
}
}
void execGoto(void) {
nextLineNum = curTok->body.integer;
advance();
}
void execGosub(void) {
calcStack[--sp] = nextLineNum;
nextLineNum = curTok->body.integer;
advance();
}
void execReturn(void) {
nextLineNum = calcStack[sp++];
}
void execEnd(void) {
nextLineNum = 32767;
}
void execExtra(unsigned char cmd) {
unsigned char n = extraCmdArgCnt[cmd];
char i;
sp -= n;
for (i = 0; i < n; i++) {
calcStack[sp + i] = calcExpression();
advance();
}
extraCommand(cmd, calcStack + sp);
sp += n;
}
void executeTokens(token* t) {
curTok = t;
while (t->type != TT_NONE) {
advance();
if (t->body.command < CMD_EXTRA) {
executors[t->body.command]();
if (t->body.command == CMD_INPUT) {
break;
}
} else {
execExtra(t->body.command - CMD_EXTRA);
}
t = curTok;
}
}
void signalEndOfCode(void) {
outputConstStr(ID_COMMON_STRINGS, 5, NULL);
outputCr();
}
void stopExecution() {
if ((mainState & STATE_RUN) != 0) {
editorLoad();
}
mainState &= ~(STATE_RUN | STATE_STEPS | STATE_BREAK);
}
char executeStep() {
prgline* p = findLine(nextLineNum);
if (p->num == 0) {
stopExecution();
signalEndOfCode();
return 1;
}
nextLineNum = p->num + 1;
memcpy(lineSpace, p->str.text, p->str.len);
lineSpace[p->str.len] = 0;
parseLine(lineSpace, toksBody);
executeTokens(toksBody);
return 0;
}
void dispatchBreak() {
stopExecution();
execStepsCount = 0;
sp = spInit;
outputConstStr(ID_COMMON_STRINGS, 4, NULL); // BREAK
outputCr();
}
void executeNonParsed(numeric count) {
if (count != 0) {
execStepsCount = count;
return;
}
if (execStepsCount != -1) {
execStepsCount -= 1;
}
if (executeStep()) {
execStepsCount = 0;
}
if (execStepsCount == 0) {
stopExecution();
}
}
void initParsedRun(void) {
nextLineNum = 1;
progLine = findLine(nextLineNum);
labelsCached = 0;
labelCache = (labelCacheElem*)(void*)(prgStore + prgSize);
mainState |= STATE_RUN;
}
void executeParsedRun(void) {
prgline* next;
if (progLine->num == 0 || nextLineNum == 0) {
stopExecution();
signalEndOfCode();
return;
}
next = (prgline*)(void*)((char*)(void*)progLine
+ sizeof(progLine->num) + sizeof(progLine->str.len) + progLine->str.len);
nextLineNum = next->num;
executeTokens((token*)(void*)(progLine->str.text));
if (next->num != nextLineNum) {
progLine = getCachedLabel(nextLineNum);
if (progLine == NULL) {
progLine = findLine(nextLineNum);
addCachedLabel(nextLineNum, (short)((char*)(void*)progLine - (char*)(void*)prgStore));
}
} else {
progLine = next;
}
}

View File

@@ -0,0 +1,25 @@
#ifndef __EXECTOKS_H_
#define __EXECTOKS_H_
#include "basic_tokens.h"
extern short nextLineNum;
void resetTokenExecutor(void);
void initTokenExecutor(char* space, short size);
short varSize(void);
void executeTokens(token* t);
char executeStep(char* lineBuf, token* tokenBuf);
void execBreak(void);
void executeNonParsed(numeric count);
void initParsedRun(void);
void executeParsedRun(void);
void setLastInput(short c);
void dispatchInput(void);
void dispatchDelay(void);
void setDelay(numeric millis);
char checkDelay();
void dispatchBreak(void);
#endif

232
apps/tbasic/basic_expr.c Normal file
View File

@@ -0,0 +1,232 @@
#include "mystdlib.h"
#include "basic_tokens.h"
#include "basic_tokenint.h"
#include "basic_expr.h"
char parseExprUnary() {
char c = *getCurTokPos();
if (c != '-' && c != '!') {
return 0;
}
parseSymbol();
if (prevTok->body.symbol == '-') {
prevTok->body.symbol = '~';
}
return 1;
}
char parseExprVal(void) {
if (parseNumber()) {
if (*getCurTokPos() == '(') {
setTokenError(getCurTokPos(), 9);
return 'e';
}
return '+';
}
if (parseName(0)) {
if (*getCurTokPos() == '(') {
prevTok->type = TT_FUNCTION;
skipTokenInInput(1);
return 'f';
}
prevTok->type = TT_VARIABLE;
return '+';
}
if (*getCurTokPos() == '(') {
parseSymbol();
return '(';
}
if (parseExprUnary()) {
return '1';
}
setTokenError(getCurTokPos(), 9);
return 'e';
}
char parseExprBop(void) {
char c = *getCurTokPos();
if (c == 0 || c == ';') {
return 's';
}
if (c == ')') {
return ')';
}
if (c == ',') {
return ',';
}
if (c == '+' || c == '-' || c == '*' || c == '^' || c == '/' || c == '%'
|| c == '<' || c == '>' || c == '=' || c == '&' || c == '|') {
parseSymbol();
return '1';
}
setTokenError(getCurTokPos(), 9);
return 'e';
}
char parseExprRbr(char brCount, char argCount) {
if (brCount < 1) {
setTokenError(getCurTokPos(), 9);
return 'e';
} else {
parseSymbol();
if (argCount > 0) {
prevTok->type = TT_FUNC_END;
prevTok->body.symbol = argCount;
}
return '+';
}
}
char parseExprComma(char inFunc) {
if (inFunc == 0) {
setTokenError(getCurTokPos(), 9);
return 'e';
} else {
parseSymbol();
return '1';
}
}
schar operatorPriority(char op) {
switch (op) {
case '&':
case '|':
return 5;
case '<':
case '>':
case '=':
case '#':
case '{':
case '}':
return 10;
case '+':
case '-':
return 15;
case '*':
case '/':
case '%':
return 20;
case '!':
case '~':
return 25;
case '(':
return 0;
}
return -1;
}
char isUnary(char op) {
return op == '!' || op == '~';
}
char convertRpnPop(char op) {
if (op == '(') {
return 0;
}
curTok->type = TT_SYMBOL;
curTok->body.symbol = op;
curTok = nextToken(curTok);
return 1;
}
void shuntingYard(token* next) {
char opstack[16];
schar sp = -1;
char prio;
char op;
char* start = (char*)(void*)next;
while (next->type != TT_ERROR) {
if (next->type == TT_VARIABLE || next->type == TT_NUMBER) {
copyToken(curTok, next);
curTok = nextToken(curTok);
} else if (next->type == TT_SYMBOL) {
op = next->body.symbol;
if (op == '(') {
opstack[++sp] = '(';
} else if (op == ')' || op == ',') {
while (convertRpnPop(opstack[sp--]));
if (op == ',') {
sp++;
}
} else {
prio = operatorPriority(op);
if (isUnary(op)) {
prio += 1;
}
while (sp >= 0 && operatorPriority(opstack[sp]) >= prio) {
convertRpnPop(opstack[sp--]);
}
opstack[++sp] = op;
}
} else if (next->type == TT_FUNCTION) {
opstack[++sp] = (char)(((char*)(void*)next) - start);
opstack[++sp] = '(';
} else if (next->type == TT_FUNC_END) {
while (convertRpnPop(opstack[sp--]));
copyToken(curTok, (token*)(void*)(start + opstack[sp--]));
if (curTok->body.str.len == 1) {
curTok->type = TT_ARRAY;
curTok->body.symbol = curTok->body.str.text[0];
}
curTok = nextToken(curTok);
}
next = nextToken(next);
}
while (sp >= 0) {
convertRpnPop(opstack[sp--]);
}
}
void convertToRpn(token* next) {
char buf[MAX_LINE_LEN * 2];
curTok->type = TT_ERROR;
memcpy(buf, next, ((char*)(void*)curTok) - ((char*)(void*)next) + 1);
curTok = next;
next = (token*)(void*) buf;
shuntingYard(next);
curTok->type = TT_ERROR;
prevTok = NULL;
}
char parseExpression(void) {
token* startTok = curTok;
char funcBrackets[16];
unsigned char iFuncBr = 0;
char state = '1';
funcBrackets[iFuncBr] = 0;
if (*getCurTokPos() == 0) {
setTokenError(getCurTokPos(), 10);
return 0;
}
while (state != 's') {
switch (state) {
case '1':
state = parseExprVal();
break;
case 'f':
funcBrackets[++iFuncBr] = 1;
state = '1';
break;
case '(':
funcBrackets[++iFuncBr] = 0;
state = '1';
break;
case '+':
state = parseExprBop();
break;
case ')':
state = parseExprRbr(iFuncBr, funcBrackets[iFuncBr]);
iFuncBr -= 1;
break;
case ',':
state = parseExprComma(funcBrackets[iFuncBr]++);
break;
case 'e':
return 0;
}
}
convertToRpn(startTok);
return 1;
}

9
apps/tbasic/basic_expr.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef __EXPR_H_
#define __EXPR_H_
#include "basic_tokens.h"
char parseExpression(void);
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __EXTERN_H_
#define __EXTERN_H_
extern char extraCmdArgCnt[];
extern char extraFuncArgCnt[];
short extraCommandByHash(numeric h);
short extraFunctionByHash(numeric h);
extern char dataSpace[];
extern char lineSpace[];
extern char lastInput;
void sysPutc(char c);
void sysEcho(char c);
numeric sysMillis(numeric div);
void extraCommand(char cmd, numeric args[]);
numeric extraFunction(char cmd, numeric args[]);
void outputConstStr(char strId, char index, char* s);
/* data=NULL for open/close, size > 0 for write,
size < 0 for read, size=0 for close,
abs(size) can be fileId */
char storageOperation(void* data, short size);
#endif

284
apps/tbasic/basic_main.c Normal file
View File

@@ -0,0 +1,284 @@
#include "mystdlib.h"
#include "basic_tokens.h"
#include "basic_editor.h"
#include "basic_exectoks.h"
#include "basic_utils.h"
#include "basic_extern.h"
#include "basic_textual.h"
static short listLine, listPage;
token* toksBody;
char mainState;
#if 0
void printToken(token* t) {
switch (t->type) {
case TT_NUMBER:
outputStr("INT=");
outputInt(t->body.integer);
break;
case TT_NAME:
outputStr("NAME=");
outputNStr(&(t->body.str));
break;
case TT_VARIABLE:
outputStr("VAR=");
outputNStr(&(t->body.str));
break;
case TT_FUNCTION:
outputStr("FN=");
outputNStr(&(t->body.str));
break;
case TT_COMMAND:
outputStr("CMD=");
outputInt(t->body.command);
break;
case TT_LITERAL:
outputStr("STR=\"");
outputNStr(&(t->body.str));
outputStr("\"");
break;
case TT_COMMENT:
outputStr("REM=\"");
outputNStr(&(t->body.str));
outputStr("\"");
break;
case TT_SYMBOL:
outputStr("SYM=");
outputChar(t->body.symbol);
break;
case TT_ARRAY:
outputStr("ARR=");
outputChar(t->body.symbol);
break;
case TT_FUNC_END:
outputStr("FE=%d");
outputInt(t->body.symbol);
break;
case TT_NONE:
outputChar('N');
break;
case TT_SEPARATOR:
outputChar(';');
break;
default:
outputChar('E');
break;
}
}
void printTokens(token* t) {
while (1) {
printToken(t);
outputChar(' ');
if (tokenClass(t) == TT_NONE) {
break;
}
t = nextToken(t);
}
outputCr();
}
#else
void printTokens(token* t) {
}
#endif
void printProgram(void) {
prgline* p = findLine(listLine);
if (p->num == 0 && listLine > 1) {
p = findLine(1);
}
short lineCount = 0;
while (p->num != 0 && lineCount < listPage) {
listLine = p->num + 1;
outputInt(p->num);
outputChar(' ');
outputNStr(&(p->str));
outputCr();
p = findLine(p->num + 1);
lineCount += 1;
}
}
void listProgram(token* t) {
t = nextToken(nextToken(t));
if (t->type == TT_NUMBER) {
listLine = t->body.integer;
t = nextToken(t);
if (t->type == TT_NUMBER) {
listPage = t->body.integer;
}
}
printProgram();
}
void executeSteps() {
token* t = nextToken(nextToken(toksBody));
mainState |= STATE_STEPS;
executeNonParsed(t->type == TT_NUMBER ? t->body.integer : 1);
}
void executeRun() {
if (editorSave()) {
editorLoadParsed();
initParsedRun();
} else {
executeNonParsed(-1);
}
}
void manualSave(void) {
editorSave();
outputConstStr(ID_COMMON_STRINGS, 6, NULL); // Saved
outputChar(' ');
outputInt(prgSize > 2 ? prgSize + 2 : 0);
outputChar(' ');
outputConstStr(ID_COMMON_STRINGS, 8, NULL); // bytes
outputCr();
}
void manualLoad(void) {
if (editorLoad()) {
outputConstStr(ID_COMMON_STRINGS, 7, NULL); // Loaded
outputChar(' ');
outputInt(prgSize + 2);
outputChar(' ');
outputConstStr(ID_COMMON_STRINGS, 8, NULL); // bytes
outputCr();
} else {
outputConstStr(ID_COMMON_STRINGS, 9, NULL); // bytes
outputCr();
}
}
void prgReset(void) {
resetEditor();
resetTokenExecutor();
}
void showInfo(void) {
outputConstStr(ID_COMMON_STRINGS, 1, NULL); // code:
outputInt(prgSize);
outputCr();
outputConstStr(ID_COMMON_STRINGS, 2, NULL); // vars:
outputInt(varSize());
outputCr();
outputConstStr(ID_COMMON_STRINGS, 3, NULL); // next:
outputInt(nextLineNum);
outputCr();
}
void metaOrError() {
numeric h = tokenHash(toksBody);
if (h == 0x3B6) { // LIST
listProgram(toksBody);
} else if (h == 0x312) { // STEP
executeSteps();
} else if (h == 0x1AC) { // RUN
executeRun();
} else if (h == 0x375) { // SAVE
manualSave();
} else if (h == 0x39A) { // LOAD
manualLoad();
} else if (h == 0x69A) { // RESET
prgReset();
} else if (h == 0x3B3) { // INFO
showInfo();
} else {
getParseErrorMsg(lineSpace);
outputStr(lineSpace);
outputChar(' ');
outputInt((long)(getParseErrorPos() - lineSpace) + 1);
outputCr();
}
}
void processLine() {
if (lineSpace[0] == 0) {
return;
}
parseLine(lineSpace, toksBody);
printTokens(toksBody);
if (getParseErrorPos() != NULL) {
metaOrError();
return;
}
if (toksBody->type != TT_NUMBER) {
executeTokens(toksBody);
} else {
injectLine(skipSpaces(skipDigits(lineSpace)), toksBody->body.integer);
}
}
void preload(char* line, token* t) {
if (editorLoadParsed()) {
outputConstStr(ID_COMMON_STRINGS, 10, NULL); // code found, autorun message
outputCr();
setDelay(1000);
mainState = STATE_PRELOAD;
} else {
prgReset();
}
}
void init(short dataSize, short lineSize, short progSize) {
outputCr();
outputConstStr(ID_COMMON_STRINGS, 0, NULL); // TBASIC vX.X
outputCr();
initEditor(dataSpace + dataSize, progSize);
initTokenExecutor(dataSpace, dataSize);
listLine = 1;
listPage = 10;
mainState = STATE_INTERACTIVE;
toksBody = (token*)(void*) (lineSpace + lineSize);
preload(lineSpace, toksBody);
}
void waitPreloadRunDelay() {
if (lastInput > 0) {
mainState &= ~STATE_PRELOAD;
outputConstStr(ID_COMMON_STRINGS, 11, NULL); // canceled
outputCr();
editorLoad();
} else if (checkDelay()) {
mainState &= ~STATE_PRELOAD;
initParsedRun();
}
}
void dispatch() {
if (lastInput == 3) {
mainState |= STATE_BREAK;
}
if ((mainState & (STATE_RUN | STATE_SLOWED)) == STATE_RUN) {
executeParsedRun();
return;
}
switch (mainState & STATE_SLOWED) {
case STATE_DELAY:
dispatchDelay();
return;
case STATE_INPUT:
dispatchInput();
lastInput = 0;
return;
case STATE_BREAK:
dispatchBreak();
lastInput = 0;
return;
}
if ((mainState & STATE_STEPS) != 0) {
executeNonParsed(0);
} else if ((mainState & STATE_PRELOAD) != 0) {
waitPreloadRunDelay();
} else {
if (lastInput > 0) {
if (readLine()) {
processLine();
}
lastInput = 0;
}
}
return;
}

11
apps/tbasic/basic_main.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef __MAIN_H_
#define __MAIN_H_
#include "mytypes.h"
void init(short dataSize, short lineSize, short progSize);
void dispatch();
void processLine(char* line, token* t);
#endif

View File

@@ -0,0 +1,16 @@
#ifndef __TEXTUAL_H_
#define __TEXTUAL_H_
#define CONST_COMMON_STRINGS "TBASIC 1.7\ncode: \nvars: \nnext: \n"\
"BREAK\nEnd of code\nSaved\nLoaded\nbytes\nLoad failed\n"\
"Autorun in 1 sec\nCanceled!\nLow VARS mem\nLow PROG mem\n"
#define CONST_PARSING_ERRORS "\nCmd or Var expectedd\nSymbol '=' expected\nName expected\n"\
"Symbol ';' expected\nExtra chars at end\nUnexpected error\nNumber out of range\n"\
"Number expected\nUnexpected symbol\nUnexpected line end\n"
#define ID_COMMON_STRINGS 0
#define ID_PARSING_ERRORS 1
#endif

View File

@@ -0,0 +1,15 @@
#ifndef __TOKENINT_H_
#define __TOKENINT_H_
extern token* curTok;
extern token* prevTok;
char* getCurTokPos();
void skipTokenInInput(char offset);
char parseName(char checkCmd);
char parseSymbol(void);
char parseNumber(void);
char parseNone();
void setTokenError(char* pos, char code);
#endif

510
apps/tbasic/basic_tokens.c Normal file
View 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);
}

View File

@@ -0,0 +1,49 @@
#ifndef __TOKENS_H_
#define __TOKENS_H_
#define TT_NONE 0x00
#define TT_ERROR 0x01
#define TT_NUMBER 0x10
#define TT_NAME 0x20
#define TT_COMMAND 0x21
#define TT_VARIABLE 0x22
#define TT_FUNCTION 0x23
#define TT_SYMBOL 0x30
#define TT_FUNC_END 0x31
#define TT_SEPARATOR 0x32
#define TT_ARRAY 0x33
#define TT_LITERAL 0x40
#define TT_COMMENT 0x41
#define CMD_REM 0
#define CMD_PRINT 1
#define CMD_INPUT 2
#define CMD_IF 3
#define CMD_GOTO 4
#define CMD_GOSUB 5
#define CMD_RETURN 6
#define CMD_END 7
#define CMD_LET 8
#define CMD_LETA 9
#define CMD_DIM 10
#define CMD_DELAY 11
#define CMD_DATA 12
#define CMD_EMIT 13
#define CMD_EXTRA 0x40
#define MAX_LINE_NUMBER 30000
#include "basic_utils.h"
void parseLine(char* line, token* tokens);
short tokenSize(token* t);
short tokenChainSize(token* t);
token* nextToken(token* t);
void copyToken(token* dst, token* src);
char tokenClass(token* t);
numeric tokenHash(token* t);
char* getParseErrorPos(void);
void getParseErrorMsg(char*);
#endif

183
apps/tbasic/basic_utils.c Normal file
View File

@@ -0,0 +1,183 @@
#include "mystdlib.h"
#include "basic_utils.h"
#include "basic_extern.h"
void trim(char* s) {
short i = 0, k;
while (s[i] != 0 && s[i] <= ' ') {
i++;
}
k = 0;
while (s[i] != 0) {
s[k++] = s[i++];
}
do {
s[k--] = 0;
} while (k >= 0 && s[k] <= ' ');
}
char* skipSpaces(char* s) {
while (isSpace(*s)) {
s++;
}
return s;
}
char* skipDigits(char* s) {
while (isDigit(*s)) {
s++;
}
return s;
}
char charInStr(char c, char* s) {
while (*s != 0) {
if (*s == c) {
return 1;
}
s++;
}
return 0;
}
char cmpNStrToStr(nstring* ns, char* s) {
if (ns->len != strlen(s)) {
return 0;
}
return memcmp(&(ns->text), s, ns->len) == 0;
}
void outputChar(char c) {
sysPutc(c);
}
void outputStr(char* s) {
while (*s) {
sysPutc(*(s++));
}
}
void outputNStr(nstring* t) {
short i;
for (i = 0; i < t->len; i++) {
sysPutc(t->text[i]);
}
};
void outputInt(long n) {
long d = 1000000000;
if (n < 0) {
outputChar('-');
n = -n;
}
if (n == 0) {
sysPutc('0');
return;
}
while (d > n) {
d /= 10;
}
while (d > 0) {
sysPutc(n / d + '0');
n %= d;
d /= 10;
}
}
int decFromStr(char* s) {
schar sign = 1;
char base = 10;
int res = 0;
if (*s == '-') {
sign = -1;
s += 1;
}
if (*s == '0') {
s += 1;
if (toUpper(*s) == 'X') {
base = 16;
s += 1;
} else if (toUpper(*s) == 'B') {
base = 2;
s += 1;
} else {
base = 8;
}
}
while (isDigitBased(*s, base)) {
res = res * base + makeDigit(*s++, base);
}
return res * sign;
}
void outputCr() {
sysPutc('\n');
}
char toUpper(char c) {
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
}
char isAlpha(char c) {
c = toUpper(c);
return c >= 'A' && c <= 'Z';
}
char isDigit(char c) {
return c >= '0' && c <= '9';
}
char isDigitBased(char c, char base) {
if (c < '0') {
return 0;
} else if (c <= '9') {
return base > c - '0';
} else {
c = toUpper(c);
return c >= 'A' && base > c - 'A' + 10;
}
}
char makeDigit(char c, char base) {
if (c < '0') {
return 0;
} else if (c <= '9') {
return c - '0';
} else {
return toUpper(c) - 'A' + 10;
}
}
char isAlNum(char c) {
return isDigit(c) || isAlpha(c);
}
char isSpace(char c) {
switch (c) {
case ' ':
case '\t':
case '\v':
case '\n':
case '\r':
case '\f':
return 1;
}
return 0;
}
numeric hashOfNStr(nstring* t) {
unsigned char i = 0, n = t->len;
numeric res = 0;
while (i < n) {
res = (res << 1) ^ t->text[i];
i++;
}
return res;
}
void pause(numeric millis) {
numeric t0 = sysMillis(1);
while (sysMillis(1) - t0 < millis) {
}
}

29
apps/tbasic/basic_utils.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef __UTILS_H_
#define __UTILS_H_
#include "mytypes.h"
void trim(char* s);
char* skipSpaces(char* s);
char* skipDigits(char* s);
char charInStr(char c, char* s);
char cmpNStrToStr(nstring* ns, char* s);
int decFromStr(char* s);
char isDigit(char c);
char isDigitBased(char c, char base);
char isAlpha(char c);
char isAlNum(char c);
char isSpace(char c);
char toUpper(char c);
char makeDigit(char c, char base);
numeric hashOfNStr(nstring* t);
void pause(numeric millis);
void outputChar(char c);
void outputStr(char* s);
void outputNStr(nstring* s);
void outputInt(long n);
void outputCr();
#endif

1
apps/tbasic/build.sh Executable file
View File

@@ -0,0 +1 @@
g++ -Wall -Wno-write-strings -Wno-char-subscripts -o tinybas.out main_nix.c ../core/*.c

97
apps/tbasic/ctype.h Normal file
View File

@@ -0,0 +1,97 @@
#ifndef _CTYPE_H_
#define _CTYPE_H_
#include "_ansi.h"
_BEGIN_STD_C
int _EXFUN(isalnum, (int __c));
int _EXFUN(isalpha, (int __c));
int _EXFUN(iscntrl, (int __c));
int _EXFUN(isdigit, (int __c));
int _EXFUN(isgraph, (int __c));
int _EXFUN(islower, (int __c));
int _EXFUN(isprint, (int __c));
int _EXFUN(ispunct, (int __c));
int _EXFUN(isspace, (int __c));
int _EXFUN(isupper, (int __c));
int _EXFUN(isxdigit,(int __c));
int _EXFUN(tolower, (int __c));
int _EXFUN(toupper, (int __c));
#if !defined(__STRICT_ANSI__) || defined(__cplusplus) || __STDC_VERSION__ >= 199901L
int _EXFUN(isblank, (int __c));
#endif
#ifndef __STRICT_ANSI__
int _EXFUN(isascii, (int __c));
int _EXFUN(toascii, (int __c));
#define _tolower(__c) ((unsigned char)(__c) - 'A' + 'a')
#define _toupper(__c) ((unsigned char)(__c) - 'a' + 'A')
#endif
#define _U 01
#define _L 02
#define _N 04
#define _S 010
#define _P 020
#define _C 040
#define _X 0100
#define _B 0200
#ifndef _MB_CAPABLE
_CONST
#endif
extern __IMPORT char *__ctype_ptr__;
#ifndef __cplusplus
/* These macros are intentionally written in a manner that will trigger
a gcc -Wall warning if the user mistakenly passes a 'char' instead
of an int containing an 'unsigned char'. Note that the sizeof will
always be 1, which is what we want for mapping EOF to __ctype_ptr__[0];
the use of a raw index inside the sizeof triggers the gcc warning if
__c was of type char, and sizeof masks side effects of the extra __c.
Meanwhile, the real index to __ctype_ptr__+1 must be cast to int,
since isalpha(0x100000001LL) must equal isalpha(1), rather than being
an out-of-bounds reference on a 64-bit machine. */
#define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)])
#define isalpha(__c) (__ctype_lookup(__c)&(_U|_L))
#define isupper(__c) ((__ctype_lookup(__c)&(_U|_L))==_U)
#define islower(__c) ((__ctype_lookup(__c)&(_U|_L))==_L)
#define isdigit(__c) (__ctype_lookup(__c)&_N)
#define isxdigit(__c) (__ctype_lookup(__c)&(_X|_N))
#define isspace(__c) (__ctype_lookup(__c)&_S)
#define ispunct(__c) (__ctype_lookup(__c)&_P)
#define isalnum(__c) (__ctype_lookup(__c)&(_U|_L|_N))
#define isprint(__c) (__ctype_lookup(__c)&(_P|_U|_L|_N|_B))
#define isgraph(__c) (__ctype_lookup(__c)&(_P|_U|_L|_N))
#define iscntrl(__c) (__ctype_lookup(__c)&_C)
#if defined(__GNUC__) && \
(!defined(__STRICT_ANSI__) || __STDC_VERSION__ >= 199901L)
#define isblank(__c) \
__extension__ ({ __typeof__ (__c) __x = (__c); \
(__ctype_lookup(__x)&_B) || (int) (__x) == '\t';})
#endif
/* Non-gcc versions will get the library versions, and will be
slightly slower. These macros are not NLS-aware so they are
disabled if the system supports the extended character sets. */
# if defined(__GNUC__)
# if !defined (_MB_EXTENDED_CHARSETS_ISO) && !defined (_MB_EXTENDED_CHARSETS_WINDOWS)
# define toupper(__c) \
__extension__ ({ __typeof__ (__c) __x = (__c); \
islower (__x) ? (int) __x - 'a' + 'A' : (int) __x;})
# define tolower(__c) \
__extension__ ({ __typeof__ (__c) __x = (__c); \
isupper (__x) ? (int) __x - 'A' + 'a' : (int) __x;})
# else /* _MB_EXTENDED_CHARSETS* */
/* Allow a gcc warning if the user passed 'char', but defer to the
function. */
# define toupper(__c) \
__extension__ ({ __typeof__ (__c) __x = (__c); \
(void) __ctype_ptr__[__x]; (toupper) (__x);})
# define tolower(__c) \
__extension__ ({ __typeof__ (__c) __x = (__c); \
(void) __ctype_ptr__[__x]; (tolower) (__x);})
# endif /* _MB_EXTENDED_CHARSETS* */
# endif /* __GNUC__ */
#endif /* !__cplusplus */
#ifndef __STRICT_ANSI__
#define isascii(__c) ((unsigned)(__c)<=0177)
#define toascii(__c) ((__c)&0177)
#endif
/* For C++ backward-compatibility only. */
extern __IMPORT _CONST char _ctype_[];
_END_STD_C
#endif /* _CTYPE_H_ */

219
apps/tbasic/main_nix.c Normal file
View File

@@ -0,0 +1,219 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <termios.h>
#include <unistd.h>
#include <poll.h>
#include <time.h>
#include "../core/main.h"
#include "../core/utils.h"
#include "../core/textual.h"
#include "../core/tokens.h"
#include "../core/extern.h"
#define VARS_SPACE_SIZE 512
#define DATA_SPACE_SIZE 4096
#define LINE_SIZE 80
char extraCmdArgCnt[] = {2, 2, 0};
char extraFuncArgCnt[] = {1, 2};
static char* commonStrings = CONST_COMMON_STRINGS;
static char * parsingErrors = CONST_PARSING_ERRORS;
char dataSpace[DATA_SPACE_SIZE];
char lineSpace[LINE_SIZE * 3];
static FILE* fCurrent;
static short idCurrent = 0;
static struct termios oldTermSettings;
static void initSystem(void) {
struct termios termSettings;
tcgetattr(STDIN_FILENO, &oldTermSettings);
termSettings = oldTermSettings;
termSettings.c_lflag &= ~(ICANON | ECHO | ISIG);
tcsetattr(STDIN_FILENO, TCSANOW, &termSettings);
setvbuf(stdout, NULL, _IONBF, 0);
}
static void cleanup(void) {
tcsetattr(STDIN_FILENO, TCSANOW, &oldTermSettings);
}
short sysGetc(void) {
struct pollfd fd;
fd.fd = STDIN_FILENO;
fd.events = POLLIN;
if (!poll(&fd, 1, 0)) {
return -1;
}
return getchar();
}
void sysPutc(char c) {
putchar(c);
}
void sysEcho(char c) {
if (c == '\b') {
sysPutc(c);
sysPutc(' ');
}
sysPutc(c);
}
void sysQuit(void) {
cleanup();
exit(0);
}
void sysPoke(unsigned long addr, uchar value) {
dataSpace[addr] = value;
}
uchar sysPeek(unsigned long addr) {
return dataSpace[addr];
}
numeric sysMillis(numeric div) {
struct timespec tp;
long v;
clock_gettime(CLOCK_REALTIME, &tp);
v = (((numeric) tp.tv_sec) * 1000 + tp.tv_nsec / 1000000) & 0x7FFFFFFF;
return div <= 1 ? v : v / div;
}
char translateInput(short c) {
if (c == -1) {
c = 0;
}
return (char) (c & 0xFF);
}
void outputConstStr(char strId, char index, char* w) {
char* s;
switch (strId) {
case ID_COMMON_STRINGS:
s = commonStrings;
break;
case ID_PARSING_ERRORS:
s = parsingErrors;
break;
default:
return;
}
while (index > 0) {
while (*s++ != '\n') {
}
index -= 1;
}
while (*s != '\n') {
if (w) {
*(w++) = (*s++);
} else {
sysPutc(*s++);
}
}
if (w) {
*w = 0;
}
}
static numeric power(numeric base, numeric exp) {
return exp < 1 ? 1 : base * power(base, exp - 1);
}
short extraCommandByHash(numeric h) {
switch (h) {
case 0x036F: // POKE
return CMD_EXTRA + 0;
case 0x019C: // PIN - just prints argument values for test
return CMD_EXTRA + 1;
case 0x031A: // QUIT
return CMD_EXTRA + 2;
default:
return -1;
}
}
short extraFunctionByHash(numeric h) {
switch (h) {
case 0x0355: // PEEK
return 0;
case 0x06FC: // POWER - for test purpose
return 1;
default:
return -1;
}
}
void extraCommand(char cmd, numeric args[]) {
switch (cmd) {
case 0:
sysPoke(args[0], args[1]);
break;
case 1:
printf("PIN: %d,%d\n", args[0], args[1]);
break;
case 2:
sysQuit();
break;
}
}
numeric extraFunction(char cmd, numeric args[]) {
switch (cmd) {
case 0:
return sysPeek(args[0]);
case 1:
return power(args[1], args[0]);
}
return 0;
}
static char openStorage(char id, char op) {
char fname[] = "store0.dat";
char ops[] = "xb";
fname[5] += id;
ops[0] = op;
fCurrent = fopen(fname, ops);
return fCurrent != NULL ? 1 : 0;
}
char storageOperation(void* data, short size) {
if (data == NULL) {
if (idCurrent != 0) {
fclose(fCurrent);
}
idCurrent = 0;
if (size != 0) {
idCurrent = abs(size);
if (!openStorage(idCurrent, size > 0 ? 'w' : 'r')) {
idCurrent = 0;
return 0;
}
}
return 1;
}
if (size > 0) {
fwrite(data, size, 1, fCurrent);
} else {
fread(data, -size, 1, fCurrent);
}
return 1;
}
int main(void) {
initSystem();
init(VARS_SPACE_SIZE, 80, sizeof(dataSpace) - VARS_SPACE_SIZE);
while(1) {
lastInput = translateInput(sysGetc());
dispatch();
}
return 0;
}

21
apps/tbasic/mystdlib.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef __MY_STDLIB_H_
#define __MY_STDLIB_H_
#ifndef NO_STDLIB
#include <stdlib.h>
#include <string.h>
#else
#define NULL ( (void *) 0)
int strlen(const char* s);
void* memcpy(void* dst, const void* src, int sz);
int memcmp(const void* dst, const void* src, int sz);
void* memmove(void* dst, const void* src, int sz);
#endif
#endif

55
apps/tbasic/mytypes.h Normal file
View File

@@ -0,0 +1,55 @@
#ifndef __MYTYPES_H_
#define __MYTYPES_H_
#define MAX_LINE_LEN 80
#define STATE_INTERACTIVE 0x00
#define STATE_DELAY 0x01
#define STATE_INPUT 0x02
#define STATE_BREAK 0x03
#define STATE_SLOWED (STATE_DELAY | STATE_INPUT | STATE_BREAK)
#define STATE_PRELOAD 0x04
#define STATE_RUN 0x10
#define STATE_STEPS 0x20
//16 bit for arduino, 32 on stm32 and linux
typedef signed int numeric;
typedef signed char schar;
typedef unsigned char uchar;
typedef struct nstring {
unsigned char len;
char text[1];
} __attribute__((packed)) nstring;
typedef struct prgline {
short num;
nstring str;
} __attribute__((packed)) prgline;
typedef union tbody {
numeric integer;
char symbol;
unsigned char command;
nstring str;
} tbody;
typedef struct token {
char type;
tbody body;
} __attribute__((packed)) token;
typedef struct varHolder {
short name;
numeric value;
} __attribute__((packed)) varHolder;
typedef struct labelCacheElem {
short num;
short offset;
} __attribute__((packed)) labelCacheElem;
#endif

BIN
apps/tbasic/store1.dat Normal file

Binary file not shown.

143
apps/tbasic/sysutils.c Normal file
View File

@@ -0,0 +1,143 @@
////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: sysutils.c
// Created: January 2019
// Author(s): Philip Smart
// Description: Utilities for C compilation when stdlib is not included in the linker list.
//
// Credits:
// Copyright: (c) 2019 Philip Smart <philip.smart@net2net.org>
//
// History: January 2019 - Initial script written.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__K64F__)
// #include <stdio.h>
// #include <stdlib.h>
// #include <string.h>
#define uint32_t __uint32_t
#define uint16_t __uint16_t
#define uint8_t __uint8_t
#define int32_t __int32_t
#define int16_t __int16_t
#define int8_t __int8_t
#elif defined(__ZPU__)
#include <zstdio.h>
#include <zpu-types.h>
#include <stdlib.h>
#else
#error "Target CPU not defined, use __ZPU__ or __K64F__"
#endif
//#include "interrupts.h"
//#include "ff.h" /* Declarations of FatFs API */
//#include "diskio.h"
//#include <string.h>
//#include <fcntl.h>
//#include <sys/stat.h>
//#include "xprintf.h"
//#include "utils.h"
//#include "basic_main.h"
//#include "basic_utils.h"
//#include "basic_textual.h"
//#include "basic_tokens.h"
//#include "basic_extern.h"
////
//#if defined __ZPUTA__
// #include "zputa_app.h"
//#elif defined __ZOS__
// #include "zOS_app.h"
//#else
// #error OS not defined, use __ZPUTA__ or __ZOS__
//#endif
int strlen(const char* s) {
int i;
for (i = 0; s[i]; i++) {
}
return i;
}
void* memcpy(void* dst, const void* src, int sz) {
char* d = (char*) dst;
char* s = (char*) src;
while (sz-- > 0) {
*(d++) = *(s++);
}
return dst;
}
int memcmp(const void* dst, const void* src, int sz) {
unsigned char* d = (unsigned char*) dst;
unsigned char* s = (unsigned char*) src;
int i, v;
for (i = 0; i < sz; i++) {
v = *(d++) - *(s++);
if (v != 0) {
return v;
}
}
return 0;
}
void* memmove(void* dst, const void* src, int sz) {
unsigned char* d = (unsigned char*) dst;
unsigned char* s = (unsigned char*) src;
int i;
if (d < s) {
for (i = 0; i < sz; i++) {
*(d++) = *(s++);
}
} else {
d += sz;
s += sz;
for (i = 0; i < sz; i++) {
*(--d) = *(--s);
}
}
return dst;
}
int strcmp (const char *p1, const char *p2)
{
const unsigned char *s1 = (const unsigned char *) p1;
const unsigned char *s2 = (const unsigned char *) p2;
unsigned char c1, c2;
do
{
c1 = (unsigned char) *s1++;
c2 = (unsigned char) *s2++;
if (c1 == '\0')
return c1 - c2;
}
while (c1 == c2);
return c1 - c2;
}
__attribute__((weak))
void _exit(int status)
{
while (1);
}
#ifdef __cplusplus
}
#endif

349
apps/tbasic/tbasic.c Executable file
View File

@@ -0,0 +1,349 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: tbasic.c
// Created: April 2029
// Author(s): Miskatino (Miskatino Basic), RodionGork (TinyBasic), Philip Smart (zOS)
// Description: Standalone App for the zOS/ZPU test application to provide a basic interpreter.
// This program implements a loadable appliation which can be loaded from SD card by
// the zOS/ZPUTA application. The idea is that commands or programs can be stored on the
// SD card and executed by zOS/ZPUTA just like an OS such as Linux. The primary purpose
// is to be able to minimise the size of zOS/ZPUTA for applications where minimal ram is
// available.
// Basic is a very useable language to make quick tests and thus I have ported the
// TinyBasic/Miskatino fork to the ZPU/K64F and enhanced accordingly.
//
// Credits:
// Copyright: (C) Miskatino MiskatinoBasic -> 2018, (C) RodionGork TinyBasic-> 2017
// (c) 2019-2020 Philip Smart <philip.smart@net2net.org> zOS/ZPUTA Basic
//
// History: April 2020 - Ported the Miskatino version to work on the ZPU and K64F, updatesdto
// function with the K64F processor and zOS.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__K64F__)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "k64f_soc.h"
#define uint32_t __uint32_t
#define uint16_t __uint16_t
#define uint8_t __uint8_t
#define int32_t __int32_t
#define int16_t __int16_t
#define int8_t __int8_t
#elif defined(__ZPU__)
#include <zstdio.h>
#include <zpu-types.h>
#include "zpu_soc.h"
#include <stdlib.h>
#else
#error "Target CPU not defined, use __ZPU__ or __K64F__"
#endif
#include "interrupts.h"
#include "ff.h" /* Declarations of FatFs API */
#include "diskio.h"
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "xprintf.h"
#include "utils.h"
#include "basic_main.h"
#include "basic_utils.h"
#include "basic_textual.h"
#include "basic_tokens.h"
#include "basic_extern.h"
//
#if defined __ZPUTA__
#include "zputa_app.h"
#elif defined __ZOS__
#include "zOS_app.h"
#else
#error OS not defined, use __ZPUTA__ or __ZOS__
#endif
//
#include "tbasic.h"
//#include <stdio.h>
//#include <stdlib.h>
//#include <signal.h>
//#include <termios.h>
//#include <unistd.h>
//#include <poll.h>
//#include <time.h>
// Utility functions.
#include "tools.c"
// Version info.
#define VERSION "v1.0"
#define VERSION_DATE "10/04/2020"
#define APP_NAME "TBASIC"
#define VARS_SPACE_SIZE 512
#define DATA_SPACE_SIZE 4096
#define LINE_SIZE 80
char extraCmdArgCnt[] = {2, 2, 0};
char extraFuncArgCnt[] = {1, 2};
static char* commonStrings = CONST_COMMON_STRINGS;
static char * parsingErrors = CONST_PARSING_ERRORS;
static short doExit = 0;
char dataSpace[DATA_SPACE_SIZE];
char lineSpace[LINE_SIZE * 3];
static FIL fCurrent;
static short idCurrent = 0;
short sysGetc(void)
{
short keyIn;
#if defined __K64F__
keyIn = (short)usb_serial_getchar();
#elif defined __ZPU__
keyIn = (short)getserial_nonblocking();
#else
#error "Target CPU not defined, use __ZPU__ or __K64F__"
#endif
return keyIn;
}
void sysPutc(char c)
{
xputc(c);
}
void sysEcho(char c)
{
if (c == '\b') {
sysPutc(c);
sysPutc(' ');
}
sysPutc(c);
}
void sysPoke(unsigned long addr, uchar value)
{
dataSpace[addr] = value;
}
uchar sysPeek(unsigned long addr)
{
return dataSpace[addr];
}
numeric sysMillis(numeric div)
{
numeric milliSec;
#if defined __ZPU__
milliSec = (numeric)RTC_MILLISECONDS;
#elif defined __K64F__
milliSec = (numeric)*G->millis;
#else
#error "Target CPU not defined, use __ZPU__ or __K64F__"
#endif
return milliSec;
}
char translateInput(short c)
{
if (c == -1) {
c = 0;
}
return (char) (c & 0xFF);
}
void outputConstStr(char strId, char index, char* w)
{
char* s;
switch (strId)
{
case ID_COMMON_STRINGS:
s = commonStrings;
break;
case ID_PARSING_ERRORS:
s = parsingErrors;
break;
default:
return;
}
while (index > 0)
{
while (*s++ != '\n')
{
}
index -= 1;
}
while (*s != '\n')
{
if (w)
{
*(w++) = (*s++);
} else
{
sysPutc(*s++);
}
}
if (w)
{
*w = 0;
}
}
static numeric power(numeric base, numeric exp)
{
return exp < 1 ? 1 : base * power(base, exp - 1);
}
short extraCommandByHash(numeric h)
{
switch (h)
{
case 0x036F: // POKE
return CMD_EXTRA + 0;
case 0x019C: // PIN - just prints argument values for test
return CMD_EXTRA + 1;
case 0x031A: // QUIT
return CMD_EXTRA + 2;
default:
return -1;
}
}
short extraFunctionByHash(numeric h)
{
switch (h)
{
case 0x0355: // PEEK
return 0;
case 0x06FC: // POWER - for test purpose
return 1;
default:
return -1;
}
}
void extraCommand(char cmd, numeric args[])
{
switch (cmd)
{
case 0:
sysPoke(args[0], args[1]);
break;
case 1:
xprintf("PIN: %d,%d\n", args[0], args[1]);
break;
case 2:
doExit = 1;
break;
}
}
numeric extraFunction(char cmd, numeric args[])
{
switch (cmd)
{
case 0:
return sysPeek(args[0]);
case 1:
return power(args[1], args[0]);
}
return 0;
}
char storageOperation(void* data, short size)
{
UINT bytes;
FRESULT fr;
char fname[] = "TBASIC_0.dat";
fname[7] += idCurrent;
if (data == NULL)
{
if (idCurrent != 0)
{
f_close(&fCurrent);
}
idCurrent = 0;
if (size != 0)
{
idCurrent = abs(size);
if(size > 0)
{
fr = f_open(&fCurrent, fname, FA_CREATE_ALWAYS | FA_WRITE);
xprintf("Writing \"%s\"\n", fname);
} else
{
fr = f_open(&fCurrent, fname, FA_OPEN_EXISTING | FA_READ);
xprintf("Reading \"%s\"\n", fname);
}
if (fr != FR_OK)
{
printFSCode(fr);
idCurrent = 0;
return 0;
}
}
return 1;
}
if (size > 0)
{
fr = f_write(&fCurrent, data, size, &bytes);
} else
{
fr = f_read(&fCurrent, data, -size, &bytes);
}
if(fr) { printFSCode(fr); return 0; } else { return 1; }
}
// Main entry and start point of a zOS/ZPUTA Application. Only 2 parameters are catered for and a 32bit return code, additional parameters can be added by changing the appcrt0.s
// startup code to add them to the stack prior to app() call.
//
// Return code for the ZPU is saved in _memreg by the C compiler, this is transferred to _memreg in zOS/ZPUTA in appcrt0.s prior to return.
// The K64F ARM processor uses the standard register passing conventions, return code is stored in R0.
//
uint32_t app(uint32_t param1, uint32_t param2)
{
// Initialisation.
//
//char *ptr = (char *)param1;
init(VARS_SPACE_SIZE, 80, sizeof(dataSpace) - VARS_SPACE_SIZE);
while(doExit == 0)
{
lastInput = translateInput(sysGetc());
dispatch();
}
return(0);
}
#ifdef __cplusplus
}
#endif

126
apps/tbasic/tbasic.h Executable file
View File

@@ -0,0 +1,126 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: tbasic.h
// Created: April 2029
// Author(s): Miskatino (Miskatino Basic), RodionGork (TinyBasic), Philip Smart (zOS)
// Description: Standalone App for the zOS/ZPU test application to provide a basic interpreter.
// This program implements a loadable appliation which can be loaded from SD card by
// the zOS/ZPUTA application. The idea is that commands or programs can be stored on the
// SD card and executed by zOS/ZPUTA just like an OS such as Linux. The primary purpose
// is to be able to minimise the size of zOS/ZPUTA for applications where minimal ram is
// available.
// Basic is a very useable language to make quick tests and thus I have ported the
// TinyBasic/Miskatino fork to the ZPU/K64F and enhanced accordingly.
//
// Credits:
// Copyright: (C) Miskatino MiskatinoBasic -> 2018, (C) RodionGork TinyBasic-> 2017
// (c) 2019-2020 Philip Smart <philip.smart@net2net.org> zOS/ZPUTA Basic
//
// History: April 2020 - Ported the Miskatino version to work on the ZPU and K64F, updatesdto
// function with the K64F processor and zOS.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef TBASIC_H
#define TBASIC_H
#ifdef __cplusplus
extern "C" {
#endif
// Constants.
// Application execution constants.
//
// Components to be embedded in the program.
//
#define BUILTIN_DEFAULT 1
// Disk low level components to be embedded in the program.
#define BUILTIN_DISK_DUMP 0
#define BUILTIN_DISK_STATUS 0
// Disk buffer components to be embedded in the program.
#define BUILTIN_BUFFER_DUMP 0
#define BUILTIN_BUFFER_EDIT 0
#define BUILTIN_BUFFER_READ 0
#define BUILTIN_BUFFER_WRITE 0
#define BUILTIN_BUFFER_FILL 0
#define BUILTIN_BUFFER_LEN 0
// Memory components to be embedded in the program.
#define BUILTIN_MEM_CLEAR 0
#define BUILTIN_MEM_COPY 0
#define BUILTIN_MEM_DIFF 0
#define BUILTIN_MEM_DUMP 0
#define BUILTIN_MEM_PERF 0
#define BUILTIN_MEM_SRCH 0
#define BUILTIN_MEM_TEST 0
#define BUILTIN_MEM_EDIT_BYTES 0
#define BUILTIN_MEM_EDIT_HWORD 0
#define BUILTIN_MEM_EDIT_WORD 0
// Hardware components to be embedded in the program.
#define BUILTIN_HW_SHOW_REGISTER 0
#define BUILTIN_HW_TEST_TIMERS 0
// Filesystem components to be embedded in the program.
#define BUILTIN_FS_STATUS 0
#define BUILTIN_FS_DIRLIST 1
#define BUILTIN_FS_OPEN 0
#define BUILTIN_FS_CLOSE 0
#define BUILTIN_FS_SEEK 0
#define BUILTIN_FS_READ 0
#define BUILTIN_FS_CAT 0
#define BUILTIN_FS_INSPECT 0
#define BUILTIN_FS_WRITE 0
#define BUILTIN_FS_TRUNC 0
#define BUILTIN_FS_RENAME 0
#define BUILTIN_FS_DELETE 0
#define BUILTIN_FS_CREATEDIR 0
#define BUILTIN_FS_ALLOCBLOCK 0
#define BUILTIN_FS_CHANGEATTRIB 0
#define BUILTIN_FS_CHANGETIME 0
#define BUILTIN_FS_COPY 0
#define BUILTIN_FS_CHANGEDIR 0
#define BUILTIN_FS_CHANGEDRIVE 0
#define BUILTIN_FS_SHOWDIR 0
#define BUILTIN_FS_SETLABEL 0
#define BUILTIN_FS_CREATEFS 0
#define BUILTIN_FS_LOAD 0
#define BUILTIN_FS_DUMP 0
#define BUILTIN_FS_CONCAT 0
#define BUILTIN_FS_XTRACT 0
#define BUILTIN_FS_SAVE 0
#define BUILTIN_FS_EXEC 0
// Test components to be embedded in the program.
#define BUILTIN_TST_DHRYSTONE 0
#define BUILTIN_TST_COREMARK 0
// Miscellaneous components to be embedded in this program.
#define BUILTIN_MISC_HELP 0
#define BUILTIN_MISC_SETTIME 0
// Prototypes.
uint32_t app(uint32_t, uint32_t);
// Global scope variables within the ZPUTA memory space.
GLOBALS *G;
SOC_CONFIG *cfgSoC;
// Global scope variables in the app memory space.
volatile UINT Timer; /* Performance timer (100Hz increment) */
#ifdef __cplusplus
}
#endif
#endif // TBASIC_H