2025-05-19 14:50:19 +08:00

340 lines
20 KiB
C

/*
* @cond
* The following section will be excluded from the documentation.
*/
/* *********************************************************************************************************************
PicoMite MMBasic
MMBasic.h
<COPYRIGHT HOLDERS> Geoff Graham, Peter Mather
Copyright (c) 2021, <COPYRIGHT HOLDERS> All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution.
3. The name MMBasic be used when referring to the interpreter in any documentation and promotional material and the original copyright message be displayed
on the console at startup (additional copyright messages may be added).
4. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed
by the <copyright holder>.
5. Neither the name of the <copyright holder> nor the names of its contributors may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDERS> AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDERS> BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
************************************************************************************************************************/
#ifndef __MMBASIC_H
#define __MMBASIC_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <stdint.h>
#include <stdbool.h>
#if defined(MAXIMITE) || defined(UBW32) || defined(DUINOMITE) || defined(COLOUR)
#define MMFAMILY
#endif
#include "configuration.h" // memory configuration defines for the particular hardware this is running on
// Types used to define an item of data. Often they are ORed together.
// Used in tokens, variables and arguments to functions
#define T_NOTYPE 0 // type not set or discovered
#define T_NBR 0x01 // number (or float) type
#define T_STR 0x02 // string type
#define T_INT 0x04 // 64 bit integer type
#define T_PTR 0x08 // the variable points to another variable's data
#define T_IMPLIED 0x10 // the variables type does not have to be specified with a suffix
#define T_CONST 0x20 // the contents of this variable cannot be changed
#define T_BLOCKED 0x40 // Hash table entry blocked after ERASE
#define T_EXPLICIT 0x80 // Was the variable specified with a type suffix
#define TypeMask(a) ((a) & (T_NBR | T_INT | T_STR)) // macro to isolate the variable type bits
// types of tokens. These are or'ed with the data types above to fully define a token
#define T_INV 0 // an invalid token
#define T_NA 0 // an invalid token
#define T_CMD 0x10 // a command
#define T_OPER 0x20 // an operator
#define T_FUN 0x40 // a function (also used for a function that can operate as a command)
#define T_FNA 0x80 // a function that has no arguments
#define C_BASETOKEN 0x80 // the base of the token numbers
// flags used in the program lines
#define T_CMDEND 0 // end of a command
#define T_NEWLINE 1 // Single byte indicating the start of a new line
#define T_LINENBR 2 // three bytes for a line number
#define T_LABEL 3 // variable length indicating a label
#define E_END 255 // dummy last operator in an expression
// these constants are used in the second argument of the findvar() function, they should be or'd together
#define V_FIND 0x0000 // a straight forward find, if the variable is not found it is created and set to zero
#define V_NOFIND_ERR 0x0200 // throw an error if not found
#define V_NOFIND_NULL 0x0400 // return a null pointer if not found
#define V_DIM_VAR 0x0800 // dimension an array
#define V_LOCAL 0x1000 // create a local variable
#define V_EMPTY_OK 0x2000 // allow an empty array variable. ie, var()
#define V_FUNCT 0x4000 // we are defining the name of a function
// these flags are used in the last argument in expression()
#define E_NOERROR true
#define E_ERROR 0
#define E_DONE_GETVAL 0b10
extern struct s_vartbl s_vartbl_val;
struct s_funtbl {
char name[MAXVARLEN]; // variable's name
uint32_t index;
};
extern struct s_funtbl funtbl[MAXSUBFUN];
typedef struct s_vartbl { // structure of the variable table
unsigned char name[MAXVARLEN]; // variable's name
unsigned char type; // its type (T_NUM, T_INT or T_STR)
unsigned char level; // its subroutine or function level (used to track local variables)
unsigned char size; // the number of chars to allocate for each element in a string array
unsigned char namelen;
#ifdef rp2350
int __attribute__ ((aligned (4))) dims[MAXDIM]; // the dimensions. it is an array if the first dimension is NOT zero
#else
short __attribute__ ((aligned (4))) dims[MAXDIM]; // the dimensions. it is an array if the first dimension is NOT zero
#endif
union u_val{
MMFLOAT f; // the value if it is a float
long long int i; // the value if it is an integer
MMFLOAT *fa; // pointer to the allocated memory if it is an array of floats
long long int *ia; // pointer to the allocated memory if it is an array of integers
unsigned char *s; // pointer to the allocated memory if it is a string
} val;
} vartbl_val;
typedef struct s_hash {
short hash;
short level;
} hash_val;
extern struct s_vartbl g_vartbl[];
extern int g_varcnt; // number of variables defined (eg, largest index into the variable table)
//extern int g_Localvarcnt; // number of LOCAL variables defined (eg, largest index into the variable table)
extern int g_Globalvarcnt; // number of GLOBAL variables defined (eg, largest index into the variable table)
extern int g_Localvarcnt; // number of GLOBAL variables defined (eg, largest index into the variable table)
extern int g_VarIndex; // index of the current variable. set after the findvar() function has found/created a variable
extern int g_LocalIndex; // used to track the level of local variables
extern int g_OptionBase; // value of OPTION BASE
extern unsigned char OptionExplicit, OptionEscape, OptionConsole; // true if OPTION EXPLICIT has been used
extern bool OptionNoCheck;
extern unsigned char DefaultType; // the default type if a variable is not specifically typed
#if !defined(BOOL_ALREADY_DEFINED)
#define BOOL_ALREADY_DEFINED
typedef enum _BOOL { FALSE = 0, TRUE } BOOL; // Undefined size
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#define MAXLINENBR 65001 // maximim acceptable line number
#define NOLINENBR MAXLINENBR+1
// skip whitespace
// finishes with x pointing to the next non space char
#define skipspace(x) while(*x == ' ') x++
// skip to the next element
// finishes pointing to the zero unsigned char that preceeds an element
#define skipelement(x) while(*x) x++
// skip to the next line
// skips text and and element separators until it is pointing to the zero char marking the start of a new line.
// the next byte will be either the newline token or zero char if end of program
#define skipline(x) while(!(x[-1] == 0 && (x[0] == T_NEWLINE || x[0] == 0)))x++
// find a token
// finishes pointing to the token or zero unsigned char if not found in the line
#define findtoken(x) while(*x != (tkn) && *x)x++
#define IsDigitinline(a) ( a >= '0' && a <= '9' )
//extern const char namestart[256];
//extern const char namein[256];
//extern const char nameend[256];
//extern const char upper[256];
//#define mytoupper(a) upper[(unsigned int)a]
#define mytoupper(a) toupper(a)
//#define isnamestart(c) (namestart[(uint8_t)c]) // true if valid start of a variable name
//#define isnamechar(c) (namein[(uint8_t)c]) // true if valid part of a variable name
//#define isnameend(c) (nameend[(uint8_t)c]) // true if valid at the end of a variable name
#define isnamestart(c) (isalpha((unsigned char)c) || c == '_') // true if valid start of a variable name
#define isnamechar(c) (isalnum((unsigned char)c) || c == '_' || c == '.') // true if valid part of a variable name
#define isnameend(c) (isalnum((unsigned char)c) || c == '_' || c == '.' || c == '$' || c == '!' || c == '%') // true if valid at the end of a variable name
#define tokentype(i) ((i >= C_BASETOKEN && i < TokenTableSize - 1 + C_BASETOKEN) ? (tokentbl[i - C_BASETOKEN].type) : 0) // get the type of a token
#define tokenfunction(i)((i >= C_BASETOKEN && i < TokenTableSize - 1 + C_BASETOKEN) ? (tokentbl[i - C_BASETOKEN].fptr) : (tokentbl[0].fptr)) // get the function pointer of a token
#define tokenname(i) ((i >= C_BASETOKEN && i < TokenTableSize - 1 + C_BASETOKEN) ? (tokentbl[i - C_BASETOKEN].name) : (unsigned char *)"") // get the name of a token
#define commandfunction(i)((i < CommandTableSize - 1) ? (commandtbl[i].fptr) : (commandtbl[0].fptr)) // get the function pointer of a token
#define commandname(i) ((i < CommandTableSize - 1 ) ? (commandtbl[i].name) : (unsigned char *)"") // get the name of a command
// this macro will allocate temporary memory space and build an argument table in it
// x = pointer to the basic text to be split up (unsigned char *)
// y = maximum number of args (will throw an error if exceeded) (int)
// s = a string of characters to be used in detecting where to split the text (unsigned char *)
#define getargs(x, y, s) unsigned char argbuf[STRINGSIZE + STRINGSIZE/2]; unsigned char *argv[y]; int argc; makeargs(x, y, argbuf, argv, &argc, s)
extern int CommandTableSize, TokenTableSize;
extern volatile int MMAbort;
extern jmp_buf mark; // longjump to recover from an error
extern unsigned char BreakKey; // console break key (defaults to CTRL-C)
extern jmp_buf jmprun;
extern int ProgMemSize;
extern int NextData; // used to track the next item to read in DATA & READ stmts
extern unsigned char *NextDataLine; // used to track the next line to read in DATA & READ stmts
extern unsigned char *CurrentLinePtr,*SaveCurrentLinePtr; // pointer to the current line being executed
extern unsigned char *ContinuePoint; // Where to continue from if using the continue statement
extern int ProgramChanged; // true if the program in memory has been changed and not saved
extern unsigned char inpbuf[]; // used to store user keystrokes until we have a line
extern unsigned char tknbuf[]; // used to store the tokenised representation of the users input line
extern unsigned char lastcmd[]; // used to store the command history in case the user uses the up arrow at the command prompt
extern MMFLOAT farg1, farg2, fret; // Global floating point variables used by operators
extern long long int iarg1, iarg2, iret; // Global integer variables used by operators
extern unsigned char *sarg1, *sarg2, *sret; // Global string pointers used by operators
extern int targ; // Global type of argument (string or float) returned by an operator
extern int cmdtoken; // Token number of the command
extern unsigned char *cmdline; // Command line terminated with a zero unsigned char and trimmed of spaces
extern unsigned char *nextstmt; // Pointer to the next statement to be executed.
extern unsigned char *ep; // Pointer to the argument to a function
extern int OptionErrorSkip; // value of OPTION ERROR
extern int MMerrno;
extern char MMErrMsg[MAXERRMSG]; // array holding the error msg
extern unsigned char *subfun[]; // Table of subroutines and functions built when the program starts running
extern char CurrentSubFunName[MAXVARLEN + 1]; // the name of the current sub or fun
extern char CurrentInterruptName[MAXVARLEN + 1];// the name of the current interrupt function
struct s_tokentbl { // structure of the token table
unsigned char *name; // the string (eg, PRINT, FOR, ASC(, etc)
unsigned char type; // the type returned (T_NBR, T_STR, T_INT)
unsigned char precedence; // precedence used by operators only. operators with equal precedence are processed left to right.
void (*fptr)(void); // pointer to the function that will interpret that token
};
extern const struct s_tokentbl tokentbl[];
extern const struct s_tokentbl commandtbl[];
extern unsigned char tokenTHEN, tokenELSE, tokenGOTO, tokenEQUAL, tokenTO, tokenSTEP, tokenWHILE, tokenUNTIL, tokenGOSUB, tokenAS, tokenFOR;
extern unsigned short cmdIF, cmdENDIF, cmdEND_IF, cmdELSEIF, cmdELSE_IF, cmdELSE, cmdSELECT_CASE, cmdFOR, cmdNEXT, cmdWHILE, cmdENDSUB, cmdENDFUNCTION, cmdLOCAL, cmdSTATIC, cmdCASE, cmdDO, cmdLOOP, cmdCASE_ELSE, cmdEND_SELECT;
extern unsigned short cmdSUB, cmdFUN, cmdCSUB, cmdIRET, cmdComment, cmdEndComment;
extern unsigned char *GetIntAddress(unsigned char *p);
extern void MMPrintString(char *s);
// void error(unsigned char *msg) ;
void error(char *msg, ...);
void InitBasic(void);
int FloatToInt32(MMFLOAT);
long long int FloatToInt64(MMFLOAT x);
void makeargs(unsigned char **tp, int maxargs, unsigned char *argbuf, unsigned char *argv[], int *argc, unsigned char *delim);
void *findvar(unsigned char *, int);
void erasearray(unsigned char *n);
void ClearVars(int level, bool all);
void ClearStack(void);
void ClearRuntime(bool all);
void ClearProgram(bool psram);
void *DoExpression(unsigned char *p, int *t);
unsigned char *GetNextCommand(unsigned char *p, unsigned char **CLine, unsigned char *EOFMsg) ;
int CheckEmpty(char *p);
unsigned char *evaluate(unsigned char *p, MMFLOAT *fa, long long int *ia, unsigned char **sa, int *ta, int noerror);
unsigned char *doexpr(unsigned char *p, MMFLOAT *fa, long long int *ia, unsigned char **sa, int *oo, int *t);
void DefinedSubFun(int iscmd, unsigned char *cmd, int index, MMFLOAT *fa, long long int *i64, unsigned char **sa, int *t);
MMFLOAT getnumber(unsigned char *p);
long long int getinteger(unsigned char *p);
long long int getint(unsigned char *p, long long int min, long long int max);
unsigned char *getstring(unsigned char *p);
void tokenise(int console);
void ExecuteProgram(unsigned char *);
void AddProgramLine(int append);
unsigned char *findline(int, int);
unsigned char *findlabel(unsigned char *labelptr);
unsigned char *skipvar(unsigned char *p, int noerror);
unsigned char *skipexpression(unsigned char *p);
int FunctionType(unsigned char *p);
unsigned char *getclosebracket(unsigned char *p);
void makeupper(unsigned char *p);
void checkend(unsigned char *p);
char *fstrstr (const char *s1, const char *s2);
int GetCommandValue(unsigned char *n);
int GetTokenValue(unsigned char *n);
unsigned char *checkstring(unsigned char *p, unsigned char *tkn);
int GetLineLength(unsigned char *p);
unsigned char *MtoC(unsigned char *p);
unsigned char *CtoM(unsigned char *p);
void Mstrcpy(unsigned char *dest, unsigned char *src);
void Mstrcat(unsigned char *dest, unsigned char *src);
int Mstrcmp(unsigned char *s1, unsigned char *s2);
unsigned char *getCstring(unsigned char *p);
unsigned char *getFstring(unsigned char *p);
int IsValidLine(int line);
void InsertLastcmd(unsigned char *s);
int CountLines(unsigned char *target);
extern jmp_buf ErrNext;
int FindSubFun(unsigned char *p, int type);
void PrepareProgram(int ErrAbort);
void MMfputs(unsigned char *p, int filenbr);
extern int TempStringClearStart; // used to prevent clearing of space in an expression that called a FUNCTION
extern unsigned char *LibMemory; // library memory
extern unsigned char *ProgMemory; // program memory
extern int PSize; // size of the program in program memory
extern unsigned char *cmdline; // Command line terminated with a zero unsigned char and trimmed of spaces
extern unsigned char *nextstmt; // Pointer to the next statement to be executed.
extern unsigned char PromptString[MAXPROMPTLEN]; // the prompt for input, an empty string means use the default
extern int multi;
extern void str_replace(char *target, const char *needle, const char *replacement, uint8_t ignore);
extern void MIPS16 STR_REPLACE(char *target, const char *needle, const char *replacement, uint8_t ignore);
#if defined(MMFAMILY)
extern unsigned char FunKey[NBRPROGKEYS][MAXKEYLEN + 1]; // used by the programmable function keys
#endif
#if defined(MMFAMILY) || defined(DOS)
extern unsigned char *ModuleTable[MAXMODULES]; // list of pointers to library modules loaded in memory;
extern int NbrModules; // the number of library modules currently loaded
#endif
#if defined(__PIC32MX__)
inline int str_equal(const unsigned char *s1, const unsigned char *s2);
#else
void IntToStrPad(char *p, long long int nbr, signed char padch, int maxch, int radix);
void IntToStr(char *strr, long long int nbr, unsigned int base);
void FloatToStr(char *p, MMFLOAT f, int m, int n, unsigned char ch);
int str_equal(const unsigned char *s1, const unsigned char *s2);
#endif
int mystrncasecmp (const unsigned char *s1, const unsigned char *s2, size_t n);
int mem_equal(unsigned char *s1, unsigned char *s2, int i);
extern int emptyarray;
typedef uint16_t CommandToken;
#ifdef __cplusplus
}
#endif
#endif /* __MMBASIC_H */
/* @endcond */