diff --git a/src/BASIC.cpp b/src/BASIC.cpp deleted file mode 100644 index f27e3ea..0000000 --- a/src/BASIC.cpp +++ /dev/null @@ -1,829 +0,0 @@ -/*************************************************************************************************/ -/** - BASIC.cpp - - Contains routines for tokenising/detokenising BBC BASIC programs. - - Modified from code by Thomas Harte. - - Copyright (C) Thomas Harte - - This file is part of BeebAsm. - - BeebAsm 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. - - BeebAsm 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 BeebAsm, as - COPYING.txt. If not, see . -*/ -/*************************************************************************************************/ - -#include "BASIC.h" -#include -#include -#include -#include - -/* - - KeyWord table - used by both the exporter and the importer to convert - between the plain text version of a BASIC program and the format used - internally by the BASIC ROM - - Information taken from pages 41-43 of the BASIC ROM User Guide, - BASIC 2 ROM assumed throughout - -*/ - -struct KeyWord -{ - KeyWord(const char* name, Uint8 flags) - : Name(name), Flags(flags), StrLen(0), Next(NULL) - {} - - const char *Name; - Uint8 Flags; - unsigned int StrLen; - struct KeyWord *Next; -}; - -struct KeyWord KeyWordTable[0x80] = -{ - /* 0x80 */ - KeyWord("AND", 0x00), KeyWord("DIV", 0x00), KeyWord("EOR", 0x00), KeyWord("MOD", 0x00), - KeyWord("OR", 0x00), KeyWord("ERROR",0x04), KeyWord("LINE", 0x00), KeyWord("OFF", 0x00), - - /* 0x88 */ - KeyWord("STEP", 0x00), KeyWord("SPC", 0x00), KeyWord("TAB(", 0x00), KeyWord("ELSE", 0x14), - KeyWord("THEN", 0x14), KeyWord("", 0x00), KeyWord("OPENIN",0x00), KeyWord("PTR", 0x43), - - /* 0x90 */ - KeyWord("PAGE", 0x43), KeyWord("TIME", 0x43), KeyWord("LOMEM",0x43), KeyWord("HIMEM",0x43), - KeyWord("ABS", 0x00), KeyWord("ACS", 0x00), KeyWord("ADVAL",0x00), KeyWord("ASC", 0x00), - - /* 0x98 */ - KeyWord("ASN", 0x00), KeyWord("ATN", 0x00), KeyWord("BGET", 0x01), KeyWord("COS", 0x00), - KeyWord("COUNT",0x01), KeyWord("DEG", 0x00), KeyWord("ERL", 0x01), KeyWord("ERR", 0x01), - - /* 0xa0 */ - KeyWord("EVAL", 0x00), KeyWord("EXP", 0x00), KeyWord("EXT", 0x01), KeyWord("FALSE",0x01), - KeyWord("FN", 0x08), KeyWord("GET", 0x00), KeyWord("INKEY",0x00), KeyWord("INSTR(",0x00), - - /* 0xa8 */ - KeyWord("INT", 0x00), KeyWord("LEN", 0x00), KeyWord("LN", 0x00), KeyWord("LOG", 0x00), - KeyWord("NOT", 0x00), KeyWord("OPENUP",0x00), KeyWord("OPENOUT",0x00), KeyWord("PI", 0x01), - - /* 0xb0 */ - KeyWord("POINT(",0x00), KeyWord("POS", 0x01), KeyWord("RAD", 0x00), KeyWord("RND", 0x01), - KeyWord("SGN", 0x00), KeyWord("SIN", 0x00), KeyWord("SQR", 0x00), KeyWord("TAN", 0x00), - - /* 0xb8 */ - KeyWord("TO", 0x00), KeyWord("TRUE", 0x01), KeyWord("USR", 0x00), KeyWord("VAL", 0x00), - KeyWord("VPOS", 0x01), KeyWord("CHR$", 0x00), KeyWord("GET$", 0x00), KeyWord("INKEY$",0x00), - - /* 0xc0 */ - KeyWord("LEFT$(",0x00), KeyWord("MID$(",0x00), KeyWord("RIGHT$(",0x00), KeyWord("STR$", 0x00), - KeyWord("STRING$(",0x00), KeyWord("EOF", 0x01), KeyWord("AUTO", 0x10), KeyWord("DELETE",0x10), - - /* 0xc8 */ - KeyWord("LOAD", 0x02), KeyWord("LIST", 0x10), KeyWord("NEW", 0x01), KeyWord("OLD", 0x01), - KeyWord("RENUMBER",0x10), KeyWord("SAVE", 0x02), KeyWord("", 0x00), KeyWord("PTR", 0x00), - - /* 0xd0 */ - KeyWord("PAGE", 0x00), KeyWord("TIME", 0x01), KeyWord("LOMEM",0x00), KeyWord("HIMEM",0x00), - KeyWord("SOUND",0x02), KeyWord("BPUT", 0x03), KeyWord("CALL", 0x02), KeyWord("CHAIN",0x02), - - /* 0xd8 */ - KeyWord("CLEAR",0x01), KeyWord("CLOSE",0x03), KeyWord("CLG", 0x01), KeyWord("CLS", 0x01), - KeyWord("DATA", 0x20), KeyWord("DEF", 0x00), KeyWord("DIM", 0x02), KeyWord("DRAW", 0x02), - - /* 0xe0 */ - KeyWord("END", 0x01), KeyWord("ENDPROC",0x01), KeyWord("ENVELOPE",0x02), KeyWord("FOR", 0x02), - KeyWord("GOSUB",0x12), KeyWord("GOTO", 0x12), KeyWord("GCOL", 0x02), KeyWord("IF", 0x02), - - /* 0xe8 */ - KeyWord("INPUT",0x02), KeyWord("LET", 0x04), KeyWord("LOCAL",0x02), KeyWord("MODE", 0x02), - KeyWord("MOVE", 0x02), KeyWord("NEXT", 0x02), KeyWord("ON", 0x02), KeyWord("VDU", 0x02), - - /* 0xf0 */ - KeyWord("PLOT", 0x02), KeyWord("PRINT",0x02), KeyWord("PROC", 0x0a), KeyWord("READ", 0x02), - KeyWord("REM", 0x20), KeyWord("REPEAT",0x00), KeyWord("REPORT",0x01), KeyWord("RESTORE",0x12), - - /* 0xf8 */ - KeyWord("RETURN",0x01), KeyWord("RUN", 0x01), KeyWord("STOP", 0x01), KeyWord("COLOUR",0x02), - KeyWord("TRACE",0x12), KeyWord("UNTIL",0x02), KeyWord("WIDTH",0x02), KeyWord("OSCLI",0x02) -}; - -KeyWord *QuickTable[26*26]; - -/* - - Setup function, to establish contents of QuickTable, store strlens, etc - -*/ - -#define HashCode(str) (str[0] < 'A' || str[0] > 'Z' || str[1] < 'A' || str[1] > 'Z') ? 0 : ((str[0] - 'A')*26 + (str[1] - 'A')) - -void SetupBASICTables() -{ - /* set QuickTable to empty */ - int c = 26*26; - while(c--) - QuickTable[c] = NULL; - - /* go through tokens, store strlens & populate QuickTable */ - for(c = 0; c < 0x80; c++) - { - if((KeyWordTable[c].StrLen = strlen(KeyWordTable[c].Name))) - { - /* reject any symbols that have already appeared 0x40 places earlier in the table */ - if(c < 0x40 || strcmp(KeyWordTable[c].Name, KeyWordTable[c - 0x40].Name)) - { - int Code = HashCode(KeyWordTable[c].Name); - KeyWord **InsertPointer = &QuickTable[Code]; - while(*InsertPointer) - InsertPointer = &(*InsertPointer)->Next; - - *InsertPointer = &KeyWordTable[c]; - } - } - } - - /* - - Go through QuickTable, sorting each branch by string length - - I'm an idiot, so I've used insertion sort! - - */ - c = 26*26; - while(c--) - if(QuickTable[c] && QuickTable[c]->Next) - { - /* sort first by string length */ - KeyWord **Check = &QuickTable[c]; - unsigned int CurLength = (*Check)->StrLen; - Check = &(*Check)->Next; - while(*Check) - { - /* check if out of order */ - if((*Check)->StrLen > CurLength) - { - /* unlink */ - KeyWord *Takeout = *Check; - *Check = (*Check)->Next; - - /* start at top of list, find correct insertion point */ - KeyWord **InsertPoint = &QuickTable[c]; - while((*InsertPoint)->StrLen >= Takeout->StrLen) - InsertPoint = &(*InsertPoint)->Next; - - /* ...and insert */ - Takeout->Next = *InsertPoint; - *InsertPoint = Takeout; - } - else - { - CurLength = (*Check)->StrLen; - Check = &(*Check)->Next; - } - } - } -} - -/* - - Little function to return an error string - -*/ -const char *ErrorTable[] = -{ - "", - "BASIC is not currently active", - "Unable to open file for input", - "Program too large", - "Unable to open file for output", - "Malformed BASIC program or not running BASIC", - "BASIC program appears to run past the end of RAM" -}; -std::ostringstream DynamicErrorText; -std::string DynamicErrorTextString; - -int ErrorNum; - -const char *GetBASICError() -{ - DynamicErrorTextString = DynamicErrorText.str(); - return ErrorNum >= 0 ? ErrorTable[ErrorNum] : DynamicErrorTextString.c_str(); -} - -int GetBASICErrorNum() -{ - return ErrorNum; -} - - -/* - - Functions to export BASIC code, i.e. decode from tokenised form to plain text - -*/ - -bool ExtractLine(FILE *output, Uint8 *Memory, Uint16 Addr, Uint8 LineL) -{ - int LineLength = static_cast(LineL); - - while(LineLength >= 0) - { - Uint8 ThisByte = Memory[Addr]; Addr++; LineLength--; - if(ThisByte >= 0x80) - { - if(ThisByte == 0x8d) // then we're about to see a tokenised line number - { - Uint16 LineNumber; - - // decode weirdo tokenised line number format - LineNumber = Memory[Addr+1]&0x3f; - LineNumber |= (Memory[Addr+2]&0x3f) << 8; - LineNumber |= (Memory[Addr]&0x0c) << 12; - LineNumber |= (Memory[Addr]&0x30) << 2; - LineNumber ^= 0x4040; - - Addr += 3; - LineLength -= 3; - - fprintf(output, "%d", LineNumber); - } - else //ordinary keyword - { - fputs(KeyWordTable[ThisByte - 0x80].Name, output); - - if(KeyWordTable[ThisByte - 0x80].Flags & 0x20) - { - //copy to end of line without interpreting tokens} - while(LineLength >= 0) - { - fputc(Memory[Addr], output); Addr++; LineLength--; - } - return true; - } - } - } - else - { - switch(ThisByte) - { - default: fputc(ThisByte, output); break; - case '"': - /* copy string literal... */ - fputc('"', output); - while(Memory[Addr] != '"' && LineLength >= 0) - { - fputc(Memory[Addr], output); - Addr++; LineLength--; - } - if(Memory[Addr] == '"') - { - fputc(Memory[Addr], output); - Addr++; LineLength--; - } - break; - } - } - } - - return (LineLength == -1) ? true : false; -} - -bool ExportBASIC(const char *Filename, Uint8 *Memory) -{ - ErrorNum = 0; - FILE *output = fopen(Filename, "wt"); - - if(!output) - { - ErrorNum = 4; - return false; - } - - /* get the value of PAGE, start reading BASIC code from there */ - Uint16 Addr = Memory[0x18] << 8; - - if(Addr >= 32768 - 4) - ErrorNum = 6; - - while(!ErrorNum) - { - /* character here should be \r */ - if(Memory[Addr] != 0x0d) - { - ErrorNum = 5; - break; - } - Addr++; - - /* get line number, check if we've hit the end of BASIC */ - Uint16 LineNumber; - LineNumber = (Memory[Addr] << 8) | Memory[Addr+1]; - Addr += 2; - if(LineNumber & 0x8000) // if we've hit the end of the program, exit - break; - - Uint8 LineLength = Memory[Addr]; Addr++; - - if(Addr+LineLength >= 32768 - 4) - { - ErrorNum = 6; - break; - } - - /* print line number */ - fprintf(output, "%5d", LineNumber); - - /* detokenise, etc */ - if(!ExtractLine(output, Memory, Addr, LineLength - 4)) - break; - - /* add a newline */ - fputc('\n', output); - - /* should process line here, but chicken out */ - Addr += LineLength - 4; - } - - fclose(output); - - return ErrorNum ? false : true; -} - -/* - - Functions to import BASIC code, i.e. tokenise from plain text - -*/ - -#define AlphaNumeric(v)\ - (\ - (v >= 'a' && v <= 'z') ||\ - (v >= 'A' && v <= 'Z') ||\ - (v >= '0' && v <= '9')\ - ) - -char IncomingBuffer[9]; -Uint8 Token, NextChar; -unsigned int IncomingPointer; -FILE *inputfile; -bool EndOfFile, NumberStart; -unsigned int NumberValue, NumberLength; -int CurLine; - -Uint8 *Memory; -Uint16 Addr; - -inline bool WriteByte(Uint8 value) -{ - if(Addr == 32768) {ErrorNum = 3; return false;} - Memory[Addr++] = value; - return true; -} - -int my_fgetc(FILE *in) -{ - int r; - do - { - r = fgetc(in); - } - while(r == '\r'); - if(r == '\n') CurLine++; - return r; -} - -void GetCharacter() -{ - if(IncomingPointer == 8) - { - /* shift, load into position [8] */ - int c = 0; - while(c < 8) - { - IncomingBuffer[c] = IncomingBuffer[c+1]; - c++; - } - - IncomingBuffer[8] = my_fgetc(inputfile); - } - else - { - IncomingBuffer[IncomingPointer] = my_fgetc(inputfile); - IncomingPointer++; - } - - if(feof(inputfile)) //if we've hit feof then the last char isn't anything - { - IncomingPointer--; - if(!IncomingPointer) - { - EndOfFile = true; - return; - } - } - - /* check for tokens, set flags accordingly. Be a bit dense about this for now! */ - Token = IncomingBuffer[0]; - int Code = HashCode(IncomingBuffer); - KeyWord *CheckPtr = QuickTable[Code]; - - while(CheckPtr) - { - if(IncomingPointer >= CheckPtr->StrLen && !strncmp(IncomingBuffer, CheckPtr->Name, CheckPtr->StrLen)) - { - Token = (CheckPtr - KeyWordTable) + 0x80; - NextChar = IncomingBuffer[CheckPtr->StrLen]; - break; - } - - CheckPtr = CheckPtr->Next; - } - - /* check if this is a number start */ - NumberStart = false; - if(Token >= '0' && Token <= '9') - { - NumberStart = true; - char *end; - NumberValue = strtol(IncomingBuffer, &end, 10); - NumberLength = end - IncomingBuffer; - } -} - -void EatCharacters(int n) -{ - /* shift left n places, decrease IncomingPointer */ - int c = 0; - while(c < 9-n) - { - IncomingBuffer[c] = IncomingBuffer[c+n]; - c++; - } - IncomingPointer -= n; - IncomingBuffer[IncomingPointer] = '\0'; - while(n--) /* this is a quick fix: it causes lots of unnecessary token searches... */ - GetCharacter(); -} - -bool CopyStringLiteral() -{ - // eat preceeding quote - WriteByte(IncomingBuffer[0]); - EatCharacters(1); - - // don't tokenise anything until another quote is hit, keep eye out for things that may have gone wrong - while(!ErrorNum && !EndOfFile && IncomingBuffer[0] != '"' && IncomingBuffer[0] != '\n') - { - WriteByte(IncomingBuffer[0]); - EatCharacters(1); - } - - if(IncomingBuffer[0] != '"') // stopped going for some reason other than a close quote - { - ErrorNum = -1; - if(IncomingBuffer[0] == '\n') - { - --CurLine; - } - DynamicErrorText << "Malformed string literal on line " << CurLine; - return false; - } - - // eat proceeding quote - WriteByte(IncomingBuffer[0]); - EatCharacters(1); - - return true; -} - -bool DoLineNumberTokeniser() -{ - while(!ErrorNum && !EndOfFile) - { - if(NumberStart) - { - // tokenise line number - Uint16 LineNumber = NumberValue ^ 0x4040; - - WriteByte(0x8d); - - WriteByte(((LineNumber&0xc0) >> 2) | ((LineNumber&0xc000) >> 12) | 0x40); - WriteByte((LineNumber&0x3f) | 0x40); - WriteByte(((LineNumber >> 8)&0x3f) | 0x40); - - EatCharacters(NumberLength); - } - else - switch(Token) - { - // whitespace and commas do not cause this mode to exit - case ' ': - case ',': - WriteByte(Token); - EatCharacters(1); - break; - - // hex numbers get through unscathed too - case '&': - WriteByte(Token); - EatCharacters(1); - - while( - !ErrorNum && - !EndOfFile && - ( - (IncomingBuffer[0] >= '0' && IncomingBuffer[0] <= '9') || - (IncomingBuffer[0] >= 'A' && IncomingBuffer[0] <= 'F') - ) - ) - { - WriteByte(IncomingBuffer[0]); - EatCharacters(1); - } - break; - - /* grab strings without tokenising numbers */ - case '"': - if(!CopyStringLiteral()) - return false; - break; - - /* default action is to turn off line number tokenising and get back to normal */ - default: return true; - } - } - return true; -} - -bool EncodeLine() -{ - bool StartOfStatement = true; - - /* continue until we hit a '\n' or file ends */ - while(!EndOfFile && Token != '\n' && !ErrorNum) - { - /* even if this looks like a keyword, it really isn't if the conditional flag is set & the next char is alphanumeric*/ - if( - Token >= 0x80 && - (KeyWordTable[Token - 0x80].Flags&1) && - AlphaNumeric(NextChar) - ) - Token = IncomingBuffer[0]; - - if(Token < 0x80) //if not a keyword token - { - switch(Token) - { - default: //default is dump character to memory - WriteByte(Token); - - if(Token == ':') // a colon always switches the tokeniser back to "start of statement" mode - StartOfStatement = true; - else if(Token == '=') // an equals sign always switches the tokeniser back to "middle of statement" mode - StartOfStatement = false; - - // grab entire variables rather than allowing bits to be tokenised - if - ( - (Token >= 'a' && Token <= 'z') || - (Token >= 'A' && Token <= 'Z') - ) - { - StartOfStatement = false; - EatCharacters(1); - while(AlphaNumeric(IncomingBuffer[0])) - { - WriteByte(IncomingBuffer[0]); - EatCharacters(1); - } - } - else - EatCharacters(1); - - break; - case '*': - WriteByte(Token); - EatCharacters(1); - - if(StartOfStatement) - { - /* * at start of statement means don't tokenise rest of statement, other than string literals */ - // Bugfix RTW - * commands should not be terminated by colons - while(!EndOfFile && !ErrorNum && /*IncomingBuffer[0] != ':' &&*/ IncomingBuffer[0] != '\n') - { - switch(IncomingBuffer[0]) - { - default: - WriteByte(IncomingBuffer[0]); - EatCharacters(1); - break; - case '"': - if(!CopyStringLiteral()) - return false; - break; - } - } - } - break; - case '"': - if(!CopyStringLiteral()) - return false; - break; - } - } - else - { - Uint8 Flags = KeyWordTable[Token - 0x80].Flags; //make copy of flags, as we're about to throwaway Token - - WriteByte(Token); //write token - EatCharacters(KeyWordTable[Token - 0x80].StrLen); - - /* - - Effect token flags - - */ - if(Flags & 0x08) - { - /* FN or PROC, so duplicate next set of alphanumerics without thought */ - while(!ErrorNum && !EndOfFile && AlphaNumeric(IncomingBuffer[0])) - { - WriteByte(IncomingBuffer[0]); - EatCharacters(1); - } - } - - if(Flags & 0x10) - { - /* tokenise line numbers for a bit */ - if(!DoLineNumberTokeniser()) - return false; - } - - if(Flags & 0x20) - { - /* REM or DATA, so copy rest of line without tokenisation */ - while(!ErrorNum && !EndOfFile && IncomingBuffer[0] != '\n') - { - WriteByte(IncomingBuffer[0]); - EatCharacters(1); - } - } - - if((Flags & 0x40) && StartOfStatement) - { - /* pseudo-variable flag */ - Memory[Addr-1] += 0x40; //adjust just-written token - } - - /* check if we now go into middle of statement */ - if(Flags & 0x02) - StartOfStatement = false; - - /* check if we now go into start of statement */ - if(Flags & 0x04) - StartOfStatement = true; - } - } - - if (!EndOfFile && Token == '\n' && !ErrorNum) - EatCharacters(1); // Eat a '\n' - - return true; -} - -bool ImportBASIC(const char *Filename, Uint8 *Mem, int* Size) -{ - /* store memory target to global var */ - Memory = Mem; - ErrorNum = 0; - Addr = 0; - -#if 0 - /* get the value of PAGE, insert BASIC code starting from there */ - Addr = Memory[0x18] << 8; - - /* validity check: does PAGE currently point to a 0x0d? */ - if(Memory[Addr] != 0x0d) - { - ErrorNum = 1; - return false; - } - - /* validity check: does TOP - 2 point to a 0x0d, 0xff? */ - Uint16 TOPAddr = Memory[0x12] | (Memory[0x13] << 8); - if( - (Memory[TOPAddr-2] != 0x0d) || - (Memory[TOPAddr-1] != 0xff) - ) - { - ErrorNum = 1; - return false; - } -#endif - - /* open file, reset variables */ - inputfile = fopen(Filename, "rt"); - IncomingPointer = 0; - CurLine = 1; - EndOfFile = false; - - if(!inputfile) - { - ErrorNum = 2; - return false; - } - - /* fill input buffer */ - int c = 8; - while(c--) - GetCharacter(); - - /* initialise this to 0 for use with automatic line numbering */ - unsigned int LastLineNumber = 0; - - while(!EndOfFile && !ErrorNum) - { - /* get line number */ - /* skip white space and empty lines */ - while(!EndOfFile && (Token == ' ' || Token == '\t' || Token == '\r' || Token == '\n')) - EatCharacters(1); - - /* end of file? */ - if(EndOfFile) break; - - /* now we may see a line number */ - if(NumberStart) - { - if (NumberValue <= LastLineNumber) - { - ErrorNum = -1; - DynamicErrorText << "Out of sequence line numbers (" << LastLineNumber << " followed by " << NumberValue << ") at line " << CurLine; - break; - } - LastLineNumber = NumberValue; - EatCharacters(NumberLength); - } - else - { - /* auto-number the line instead */ - LastLineNumber += 1; - } - if(LastLineNumber >= 32768) - { - ErrorNum = -1; - DynamicErrorText << "Malformed line number at line " << CurLine; - break; - } - /* inject into memory */ - WriteByte(0x0d); - WriteByte(LastLineNumber>> 8); - WriteByte(LastLineNumber&0xff); - - /* read rest of line, record length */ - Uint16 LengthAddr = Addr; WriteByte(0); - if(!EncodeLine()) - break; - - Uint16 Length = Addr - LengthAddr + 3; - if(Length >= 256) - { - ErrorNum = -1; - /* CurLine - 1 because we've incremented it on seeing '\n' */ - DynamicErrorText << "Overly long line at line " << CurLine - 1; - break; - } - Memory[LengthAddr] = static_cast(Length); - } - - /* write "end of program" */ - WriteByte(0x0d); - WriteByte(0xff); - -#if 0 - /* write TOP */ - Memory[0x12] = Addr&0xff; - Memory[0x13] = Addr >> 8; -#endif - - // Return size of tokenised code - if (Size != NULL) - { - *Size = Addr; - } - - fclose(inputfile); - return ErrorNum ? false : true; -} diff --git a/src/BASIC.h b/src/BASIC.h deleted file mode 100644 index 46fa30e..0000000 --- a/src/BASIC.h +++ /dev/null @@ -1,39 +0,0 @@ -/*************************************************************************************************/ -/** - BASIC.h - - Contains routines for tokenising/detokenising BBC BASIC programs. - - Modified from code by Thomas Harte. - - Copyright (C) Thomas Harte - - This file is part of BeebAsm. - - BeebAsm 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. - - BeebAsm 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 BeebAsm, as - COPYING.txt. If not, see . -*/ -/*************************************************************************************************/ - -#ifndef BASIC_H_ -#define BASIC_H_ - -typedef unsigned char Uint8; -typedef unsigned short Uint16; - -void SetupBASICTables(); -const char *GetBASICError(); -int GetBASICErrorNum(); -bool ExportBASIC(const char *Filename, Uint8 *Memory); -bool ImportBASIC(const char *Filename, Uint8 *Mem, int* Size); - - -#endif // BASIC_H_ diff --git a/src/VS2010/BeebAsm.vcxproj b/src/VS2010/BeebAsm.vcxproj index 60fab5e..e9cfe68 100644 --- a/src/VS2010/BeebAsm.vcxproj +++ b/src/VS2010/BeebAsm.vcxproj @@ -80,7 +80,7 @@ - + @@ -95,10 +95,11 @@ + - + @@ -112,6 +113,7 @@ + diff --git a/src/VS2010/BeebAsm.vcxproj.filters b/src/VS2010/BeebAsm.vcxproj.filters index 47a7342..0b1ff7c 100644 --- a/src/VS2010/BeebAsm.vcxproj.filters +++ b/src/VS2010/BeebAsm.vcxproj.filters @@ -51,9 +51,6 @@ Source Files - - Source Files - Source Files @@ -66,6 +63,12 @@ Source Files + + Source Files + + + Source Files + @@ -95,9 +98,6 @@ Header Files - - Header Files - Header Files @@ -116,5 +116,11 @@ Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/src/basic_tokens.cpp b/src/basic_tokens.cpp new file mode 100644 index 0000000..70aceed --- /dev/null +++ b/src/basic_tokens.cpp @@ -0,0 +1,141 @@ +/************************************************************************************************* + + basic_tokens.cpp - a table of BBC BASIC keywords + +*************************************************************************************************/ + +#include "basic_tokens.h" + +// Return name and length of name +#define NL(N) N, sizeof(N)-1 + +const token token_list[] = { + { NL("AND"), 0x80, 0 }, + { NL("ABS"), 0x94, 0 }, + { NL("ACS"), 0x95, 0 }, + { NL("ADVAL"), 0x96, 0 }, + { NL("ASC"), 0x97, 0 }, + { NL("ASN"), 0x98, 0 }, + { NL("ATN"), 0x99, 0 }, + { NL("AUTO"), 0xC6, token_L_flag }, + { NL("BGET"), 0x9A, token_C_flag }, + { NL("BPUT"), 0xD5, token_M_flag | token_C_flag }, + { NL("COLOUR"), 0xFB, token_M_flag }, + { NL("CALL"), 0xD6, token_M_flag }, + { NL("CHAIN"), 0xD7, token_M_flag }, + { NL("CHR$"), 0xBD, 0 }, + { NL("CLEAR"), 0xD8, token_C_flag }, + { NL("CLOSE"), 0xD9, token_M_flag | token_C_flag }, + { NL("CLG"), 0xDA, token_C_flag }, + { NL("CLS"), 0xDB, token_C_flag }, + { NL("COS"), 0x9B, 0 }, + { NL("COUNT"), 0x9C, token_C_flag }, + { NL("DATA"), 0xDC, token_R_flag }, + { NL("DEG"), 0x9D, 0 }, + { NL("DEF"), 0xDD, 0 }, + { NL("DELETE"), 0xC7, token_L_flag }, + { NL("DIV"), 0x81, 0 }, + { NL("DIM"), 0xDE, token_M_flag }, + { NL("DRAW"), 0xDF, token_M_flag }, + { NL("ENDPROC"), 0xE1, token_C_flag }, + { NL("END"), 0xE0, token_C_flag }, + { NL("ENVELOPE"), 0xE2, token_M_flag }, + { NL("ELSE"), 0x8B, token_L_flag | token_S_flag }, + { NL("EVAL"), 0xA0, 0 }, + { NL("ERL"), 0x9E, token_C_flag }, + { NL("ERROR"), 0x85, token_S_flag }, + { NL("EOF"), 0xC5, token_C_flag }, + { NL("EOR"), 0x82, 0 }, + { NL("ERR"), 0x9F, token_C_flag }, + { NL("EXP"), 0xA1, 0 }, + { NL("EXT"), 0xA2, token_C_flag }, + { NL("FOR"), 0xE3, token_M_flag }, + { NL("FALSE"), 0xA3, token_C_flag }, + { NL("FN"), 0xA4, token_F_flag }, + { NL("GOTO"), 0xE5, token_L_flag | token_M_flag }, + { NL("GET$"), 0xBE, 0 }, + { NL("GET"), 0xA5, 0 }, + { NL("GOSUB"), 0xE4, token_L_flag | token_M_flag }, + { NL("GCOL"), 0xE6, token_M_flag }, + { NL("HIMEM"), 0x93, token_P_flag | token_M_flag | token_C_flag }, + { NL("INPUT"), 0xE8, token_M_flag }, + { NL("IF"), 0xE7, token_M_flag }, + { NL("INKEY$"), 0xBF, 0 }, + { NL("INKEY"), 0xA6, 0 }, + { NL("INT"), 0xA8, 0 }, + { NL("INSTR("), 0xA7, 0 }, + { NL("LIST"), 0xC9, token_L_flag }, + { NL("LINE"), 0x86, 0 }, + { NL("LOAD"), 0xC8, token_M_flag }, + { NL("LOMEM"), 0x92, token_P_flag | token_M_flag | token_C_flag }, + { NL("LOCAL"), 0xEA, token_M_flag }, + { NL("LEFT$("), 0xC0, 0 }, + { NL("LEN"), 0xA9, 0 }, + { NL("LET"), 0xE9, token_S_flag }, + { NL("LOG"), 0xAB, 0 }, + { NL("LN"), 0xAA, 0 }, + { NL("MID$("), 0xC1, 0 }, + { NL("MODE"), 0xEB, token_M_flag }, + { NL("MOD"), 0x83, 0 }, + { NL("MOVE"), 0xEC, token_M_flag }, + { NL("NEXT"), 0xED, token_M_flag }, + { NL("NEW"), 0xCA, token_C_flag }, + { NL("NOT"), 0xAC, 0 }, + { NL("OLD"), 0xCB, token_C_flag }, + { NL("ON"), 0xEE, token_M_flag }, + { NL("OFF"), 0x87, 0 }, + { NL("OR"), 0x84, 0 }, + { NL("OPENIN"), 0x8E, 0 }, + { NL("OPENOUT"), 0xAE, 0 }, + { NL("OPENUP"), 0xAD, 0 }, + { NL("OSCLI"), 0xFF, token_M_flag }, + { NL("PRINT"), 0xF1, token_M_flag }, + { NL("PAGE"), 0x90, token_P_flag | token_M_flag | token_C_flag }, + { NL("PTR"), 0x8F, token_P_flag | token_M_flag | token_C_flag }, + { NL("PI"), 0xAF, token_C_flag }, + { NL("PLOT"), 0xF0, token_M_flag }, + { NL("POINT("), 0xB0, 0 }, + { NL("PROC"), 0xF2, token_F_flag | token_M_flag }, + { NL("POS"), 0xB1, token_C_flag }, + { NL("RETURN"), 0xF8, token_C_flag }, + { NL("REPEAT"), 0xF5, 0 }, + { NL("REPORT"), 0xF6, token_C_flag }, + { NL("READ"), 0xF3, token_M_flag }, + { NL("REM"), 0xF4, token_R_flag }, + { NL("RUN"), 0xF9, token_C_flag }, + { NL("RAD"), 0xB2, 0 }, + { NL("RESTORE"), 0xF7, token_L_flag | token_M_flag }, + { NL("RIGHT$("), 0xC2, 0 }, + { NL("RND"), 0xB3, token_C_flag }, + { NL("RENUMBER"), 0xCC, token_L_flag }, + { NL("STEP"), 0x88, 0 }, + { NL("SAVE"), 0xCD, token_M_flag }, + { NL("SGN"), 0xB4, 0 }, + { NL("SIN"), 0xB5, 0 }, + { NL("SQR"), 0xB6, 0 }, + { NL("SPC"), 0x89, 0 }, + { NL("STR$"), 0xC3, 0 }, + { NL("STRING$("), 0xC4, 0 }, + { NL("SOUND"), 0xD4, token_M_flag }, + { NL("STOP"), 0xFA, token_C_flag }, + { NL("TAN"), 0xB7, 0 }, + { NL("THEN"), 0x8C, token_L_flag | token_S_flag }, + { NL("TO"), 0xB8, 0 }, + { NL("TAB("), 0x8A, 0 }, + { NL("TRACE"), 0xFC, token_L_flag | token_M_flag }, + { NL("TIME"), 0x91, token_P_flag | token_M_flag | token_C_flag }, + { NL("TRUE"), 0xB9, token_C_flag }, + { NL("UNTIL"), 0xFD, token_M_flag }, + { NL("USR"), 0xBA, 0 }, + { NL("VDU"), 0xEF, token_M_flag }, + { NL("VAL"), 0xBB, 0 }, + { NL("VPOS"), 0xBC, token_C_flag }, + { NL("WIDTH"), 0xFE, token_M_flag }, + { NL("PAGE"), 0xD0, 0 }, + { NL("PTR"), 0xCF, 0 }, + { NL("TIME"), 0xD1, 0 }, + { NL("LOMEM"), 0xD2, 0 }, + { NL("HIMEM"), 0xD3, 0 }, +}; + +int token_list_length = ARRAY_LENGTH(token_list); diff --git a/src/basic_tokens.h b/src/basic_tokens.h new file mode 100644 index 0000000..0b13244 --- /dev/null +++ b/src/basic_tokens.h @@ -0,0 +1,36 @@ +/************************************************************************************************* + + basic_tokens.h - a table of BBC BASIC keywords + +*************************************************************************************************/ + +#ifndef _TABLES_H_ +#define _TABLES_H_ + +#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0])) + +typedef unsigned char byte; + +enum token_flags +{ + token_C_flag = 0x01, + token_M_flag = 0x02, + token_S_flag = 0x04, + token_F_flag = 0x08, + token_L_flag = 0x10, + token_R_flag = 0x20, + token_P_flag = 0x40 +}; + +struct token +{ + const char* name; + byte length; + byte code; + byte flags; +}; + +extern const token token_list[]; +extern int token_list_length; + +#endif // _TABLES_H diff --git a/src/commands.cpp b/src/commands.cpp index 20e1d79..d0e9a14 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -37,7 +37,7 @@ #include "sourcefile.h" #include "asmexception.h" #include "discimage.h" -#include "BASIC.h" +#include "tokenize.h" #include "random.h" @@ -1606,34 +1606,30 @@ void LineParser::HandlePutBasic() if ( GlobalData::Instance().IsSecondPass() && GlobalData::Instance().UsesDiscImage() ) { - Uint8* buffer = new Uint8[ 0x10000 ]; - int fileSize; - bool bSuccess = ImportBASIC( hostFilename.c_str(), buffer, &fileSize ); - - if (!bSuccess) + FILE* basic_file = fopen(hostFilename.c_str(), "rb"); + if (!basic_file) { - if (GetBASICErrorNum() == 2) - { - AsmException_AssembleError_FileOpen e; - e.SetString( m_line ); - e.SetColumn( m_column ); - throw e; - } - else - { - std::string message = hostFilename + ": " + GetBASICError(); - throw AsmException_UserError( m_line, m_column, message ); - } + AsmException_AssembleError_FileOpen e; + e.SetString( m_line ); + e.SetColumn( m_column ); + throw e; + } + std::vector tokenized; + TokenizeError err = tokenize_file(basic_file, tokenized); + fclose(basic_file); + if (err.IsError()) + { + std::stringstream message; + message << hostFilename << ":" << err.lineNumber << ": " << err.messageText; + throw AsmException_UserError( m_line, m_column, message.str() ); } // disc image version of the save GlobalData::Instance().GetDiscImage()->AddFile( beebFilename.c_str(), - reinterpret_cast< unsigned char* >( buffer ), + tokenized.data(), 0xFFFF1900, 0xFFFF8023, - fileSize ); - - delete [] buffer; + tokenized.size() ); } } diff --git a/src/main.cpp b/src/main.cpp index 05bd85f..4db4ddd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,7 +34,6 @@ #include "objectcode.h" #include "symboltable.h" #include "discimage.h" -#include "BASIC.h" #include "macro.h" #include "random.h" @@ -313,7 +312,6 @@ int main( int argc, char* argv[] ) ObjectCode::Create(); MacroTable::Create(); - SetupBASICTables(); time_t randomSeed = time( NULL ); diff --git a/src/tokenize.cpp b/src/tokenize.cpp new file mode 100644 index 0000000..545d8c9 --- /dev/null +++ b/src/tokenize.cpp @@ -0,0 +1,506 @@ +/************************************************************************************************* + + tokenize.cpp - tokenize BBC BASIC + + Copyright (C) Charles Reilly 2022 + + This file is licensed under the GNU General Public License version 3 + +*************************************************************************************************/ + +#include +#include +#include +#include "basic_tokens.h" +#include "tokenize.h" + +class Reader +{ +public: + Reader(FILE* file) : m_file(file) + { + m_line = 1; + m_current = 0; + m_end = false; + m_errno = 0; + m_lastcr = false; + Next(); + } + + int LineNumber() const { return m_line; } + char Current() const { return m_current; } + bool End() const { return m_end; } + + void Next() + { + if (m_current == 0x0D) + { + if (m_end) + { + return; + } + m_line++; + } + int next = fgetc(m_file); + if (m_lastcr && (next == 0x0A)) + { + next = fgetc(m_file); + } + if (next == EOF) + { + if (ferror(m_file)) + { + m_errno = errno; + } + // m_lastcr no longer matters + m_end = true; + m_current = 0x0D; + } + else if (next == 0x0A) + { + // Convert LF to CR + m_lastcr = false; + m_current = 0x0D; + } + else + { + m_lastcr = (next == 0x0D); + m_current = next; + } + } + +private: + FILE* m_file; + bool m_end; + bool m_lastcr; + char m_current; + int m_errno; + int m_line; +}; + +class Writer +{ +public: + void Init(int line_number) + { + m_fail = false; + m_buffer[0] = 0x0D; + m_buffer[1] = (line_number >> 8) & 0xFF; + m_buffer[2] = line_number & 0xFF; + m_length = 4; + } + bool Finish() + { + if (!m_fail) + { + assert(m_length < 0x100); + m_buffer[3] = m_length; + } + return !m_fail; + } + void write(char c) + { + if (m_length < static_cast(sizeof(m_buffer))) + { + m_buffer[m_length++] = c; + } + else + { + m_fail = true; + } + } + int Length() const { return m_length; } + const char* Data() const { return m_buffer; } + +private: + // Buffer cannot be any bigger because writes must fail when size exceeds byte + char m_buffer[255]; + int m_length; + bool m_fail; +}; + +typedef bool (CHAR_TEST)(char c); + +void skip_write(CHAR_TEST f, Reader &reader, Writer &writer) +{ + while (f(reader.Current())) + { + writer.write(reader.Current()); + reader.Next(); + } +} + +static bool is_not_cr(char c) +{ + return c != 0x0D; +} + +static bool is_alpha(char c) +{ + return ('A' <= c) && (c <= 'Z'); +} + +static bool is_digit(char c) +{ + return ('0' <= c) && (c <= '9'); +} + +static bool is_alpha_digit(char c) +{ + // Note that this includes backtick aka pounds sterling + return (('_' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')) || is_digit(c); +} + +static bool is_dot_digit(char c) +{ + return c == '.' || is_digit(c); +} + +static bool is_hex_digit(char c) +{ + return (('A' <= c) && (c <= 'F')) || is_digit(c); +} + +static bool tokenize_linenum(Reader &reader, Writer &writer) +{ + char buffer[6]; + int zero_count = 0; + while (reader.Current() == '0') + { + ++zero_count; + reader.Next(); + } + int index = 0; + int acc = 0; + while (is_digit(reader.Current())) + { + char c = reader.Current(); + acc = 10 * acc + (c - '0'); + if (acc >= 0x8000) + { + while (zero_count--) + writer.write('0'); + for (int i = 0; i != index; ++i) + { + writer.write(buffer[i]); + } + skip_write(is_digit, reader, writer); + return false; + } + buffer[index++] = c; + reader.Next(); + } + writer.write(static_cast(0x8D)); + writer.write((((acc & 0xC000) >> 12) | ((acc & 0xC0) >> 2)) ^ 0x54); + writer.write((acc & 0x3F) | 0x40); + writer.write((acc >> 8) | 0x40); + return true; +} + +static char read_next_char(Reader &reader) +{ + reader.Next(); + return reader.Current(); +} + +// Parse the characters from reader starting with the current character. +// If they form a keyword (and they are not C flagged with a digit or letter following) then: +// Consume all the characters. +// Return the keyword. +// If they form the prefix of a keyword then: +// Consume all the matching prefix characters. +// Write those same characters to the output. +// If the last matching character was alphabetic (i.e. not '$') then: +// Consume and write all the remaining is_alpha_digit characters. +// return 0 +// If there were no prefix characters (e.g. just 'Q' or '_') then +// Consume and write all the remaining is_alpha_digit characters. +// return 0 +static const token* parse_keyword(Reader &reader, Writer &writer) +{ + // The number of characters consumed and matched from ReadStream + int match_count = 0; + // The name of the token whose first match_count characters are those read from ReadStream + const char* match_name; + + for (int token_index = 0; token_index != token_list_length; ++token_index) + { + const token tok = token_list[token_index]; + if (!match_count || ((match_count <= tok.length) && !memcmp(match_name, tok.name, match_count))) + { + // Prefix seen so far matches this token - consume more matching characters + while ((match_count < tok.length) && (reader.Current() == tok.name[match_count])) + { + reader.Next(); + ++match_count; + } + if (match_count) + { + if (match_count == tok.length) + { + // Complete match + if (tok.flags & token_C_flag) + { + // Has C flag, so cannot be followed by letters or digits + if (is_alpha_digit(reader.Current())) + { + for (int i = 0; i != match_count; ++i) + { + writer.write(tok.name[i]); + } + skip_write(is_alpha_digit, reader, writer); + return 0; + } + } + return &token_list[token_index]; + } + if (reader.Current() == '.') + { + // Abbreviation so consume dot and return + reader.Next(); + return &token_list[token_index]; + } + match_name = tok.name; + } + } + } + if (match_count) + { + // Found a prefix but it wasn't a match so output it + for (int i = 0; i != match_count; ++i) + { + writer.write(match_name[i]); + } + if (is_alpha(match_name[match_count-1])) + { + skip_write(is_alpha_digit, reader, writer); + } + } + else + { + skip_write(is_alpha_digit, reader, writer); + } + return 0; +} + +void tokenize_line(Reader &reader, Writer &writer) +{ + // From the prompt BASIC starts in tokenize-numbers mode. + // This function works like the tokenizer used by AUTO. + + bool start_of_line = true; + bool tokenize_numbers = false; + + while (true) + { + char c = reader.Current(); + + if (c == 0x0D) + return; + + if (c == ' ') + { + writer.write(c); + reader.Next(); + continue; + } + + if (c == '&') + { + writer.write(c); + reader.Next(); + skip_write(is_hex_digit, reader, writer); + continue; + } + + if (c == '\"') + { + writer.write(c); + do + { + c = read_next_char(reader); + if (c == 0x0D) + return; + writer.write(c); + } + while (c != '\"'); + reader.Next(); + continue; + } + + if (c == ':') + { + writer.write(c); + reader.Next(); + start_of_line = true; + tokenize_numbers = false; + continue; + } + + if (c == ',') + { + writer.write(c); + reader.Next(); + continue; + } + + if (c == '*') + { + if (start_of_line) + { + skip_write(is_not_cr, reader, writer); + return; + } + writer.write(c); + reader.Next(); + start_of_line = false; + tokenize_numbers = false; + continue; + } + + if (is_dot_digit(c)) + { + if ((c != '.') && tokenize_numbers) + { + tokenize_linenum(reader, writer); + continue; + } + skip_write(is_dot_digit, reader, writer); + start_of_line = false; + tokenize_numbers = false; + continue; + } + + if (!is_alpha_digit(reader.Current())) + { + start_of_line = false; + tokenize_numbers = false; + writer.write(reader.Current()); + reader.Next(); + continue; + } + + const token* keyword = parse_keyword(reader, writer); + if (!keyword) + { + start_of_line = false; + tokenize_numbers = false; + continue; + } + else + { + byte code = keyword->code; + byte flags = keyword->flags; + + if ((flags & token_C_flag) && is_alpha_digit(reader.Current())) + { + // This should never happen because parse_keyword handles the C flag + assert(false); + start_of_line = false; + tokenize_numbers = false; + continue; + } + + if ((flags & token_P_flag) && start_of_line) + { + code += 0x40; + } + + writer.write(code); + + if (flags & token_M_flag) + { + start_of_line = false; + tokenize_numbers = false; + } + + if (flags & token_S_flag) + { + start_of_line = true; + tokenize_numbers = false; + } + + if (flags & token_F_flag) + { + skip_write(is_alpha_digit, reader, writer); + } + + if (flags & token_L_flag) + { + tokenize_numbers = true; + } + + if (flags & token_R_flag) + { + skip_write(is_not_cr, reader, writer); + return; + } + } + } +} + +// Read a plain text BBC BASIC program from `file` and write it tokenized to `tokenized` +TokenizeError tokenize_file(FILE* file, std::vector& tokenized) +{ + Reader reader(file); + + int last_line = -1; + + Writer writer; + + while (!reader.End()) + { + while (reader.Current() == ' ') + { + reader.Next(); + } + + int line = 0; + bool saw_digit = false; + while (is_digit(reader.Current())) + { + saw_digit = true; + line = 10 * line + (reader.Current() - '0'); + if (line > 0x7FFF) + { + break; + } + reader.Next(); + } + + if (saw_digit) + { + if (line <= last_line) + { + return TokenizeError(reader.LineNumber(), "Line numbers must increase"); + } + } + else + { + // Start auto-numbering at 1 but permit explicit line 0 + line = last_line < 0 ? 1 : last_line + 1; + } + last_line = line; + + if (line > 0x7FFF) + { + return TokenizeError(reader.LineNumber(), "Line number too big"); + } + + writer.Init(line); + tokenize_line(reader, writer); + if (!writer.Finish()) + { + return TokenizeError(reader.LineNumber(), "Line too long after tokenizing"); + } + + // Write the line to the buffer + tokenized.insert(tokenized.end(), writer.Data(), writer.Data() + writer.Length()); + + reader.Next(); + } + tokenized.push_back(0x0D); + tokenized.push_back(0xFF); + + return TokenizeError(); +} diff --git a/src/tokenize.h b/src/tokenize.h new file mode 100644 index 0000000..1cb77d2 --- /dev/null +++ b/src/tokenize.h @@ -0,0 +1,37 @@ +/************************************************************************************************* + + tokenize.h - tokenize BBC BASIC + + Copyright (C) Charles Reilly 2022 + + This file is licensed under the GNU General Public License version 3 + +*************************************************************************************************/ + +#ifndef _TOKENIZE_H +#define _TOKENIZE_H + +#include +#include + +struct TokenizeError +{ + TokenizeError() + { + messageText = 0; + lineNumber = 0; + } + TokenizeError(int line, const char* message) + { + lineNumber = line; + messageText = message; + } + bool IsError() const { return messageText != 0; }; + const char* messageText; + int lineNumber; +}; + +// Read a plain text BBC BASIC program from `file` and write it tokenized to `tokenized` +TokenizeError tokenize_file(FILE* file, std::vector& tokenized); + +#endif // _TOKENIZE_H diff --git a/test/3-directives/invalidbasic1.bas b/test/3-directives/invalidbasic1.bas deleted file mode 100644 index 62eb4c3..0000000 --- a/test/3-directives/invalidbasic1.bas +++ /dev/null @@ -1 +0,0 @@ -10PRINT "Hello diff --git a/test/3-directives/invalidbasic1.fail.6502 b/test/3-directives/invalidbasic1.fail.6502 deleted file mode 100644 index 4764ff4..0000000 --- a/test/3-directives/invalidbasic1.fail.6502 +++ /dev/null @@ -1,9 +0,0 @@ -\ beebasm -do test.ssd - -org &2000 -.start - rts -.end - -save "test", start, end -putbasic "invalidbasic1.bas", "ib1" diff --git a/test/3-directives/putbasic/abbreviations.6502 b/test/3-directives/putbasic/abbreviations.6502 new file mode 100644 index 0000000..86bde06 --- /dev/null +++ b/test/3-directives/putbasic/abbreviations.6502 @@ -0,0 +1 @@ +PUTBASIC "abbreviations.bas", "$.ABBRV" diff --git a/test/3-directives/putbasic/abbreviations.bas b/test/3-directives/putbasic/abbreviations.bas new file mode 100644 index 0000000..729fe84 --- /dev/null +++ b/test/3-directives/putbasic/abbreviations.bas @@ -0,0 +1,2804 @@ +AND +ANDX +AND* +A. +AN. +AND. +AX +ANX +ANDX +ABS +ABSX +ABS* +A. +AB. +ABS. +AX +ABX +ABSX +ACS +ACSX +ACS* +A. +AC. +ACS. +AX +ACX +ACSX +ADVAL +ADVALX +ADVAL* +A. +AD. +ADV. +ADVA. +ADVAL. +AX +ADX +ADVX +ADVAX +ADVALX +ASC +ASCX +ASC* +A. +AS. +ASC. +AX +ASX +ASCX +ASN +ASNX +ASN* +A. +AS. +ASN. +AX +ASX +ASNX +ATN +ATNX +ATN* +A. +AT. +ATN. +AX +ATX +ATNX +AUTO +AUTOX +AUTO* +A. +AU. +AUT. +AUTO. +AX +AUX +AUTX +AUTOX +BGET +BGETX +BGET* +B. +BG. +BGE. +BGET. +BX +BGX +BGEX +BGETX +BPUT +BPUTX +BPUT* +B. +BP. +BPU. +BPUT. +BX +BPX +BPUX +BPUTX +COLOUR +COLOURX +COLOUR* +C. +CO. +COL. +COLO. +COLOU. +COLOUR. +CX +COX +COLX +COLOX +COLOUX +COLOURX +CALL +CALLX +CALL* +C. +CA. +CAL. +CALL. +CX +CAX +CALX +CALLX +CHAIN +CHAINX +CHAIN* +C. +CH. +CHA. +CHAI. +CHAIN. +CX +CHX +CHAX +CHAIX +CHAINX +CHR$ +CHR$X +CHR$* +C. +CH. +CHR. +CHR$. +CX +CHX +CHRX +CHR$X +CLEAR +CLEARX +CLEAR* +C. +CL. +CLE. +CLEA. +CLEAR. +CX +CLX +CLEX +CLEAX +CLEARX +CLOSE +CLOSEX +CLOSE* +C. +CL. +CLO. +CLOS. +CLOSE. +CX +CLX +CLOX +CLOSX +CLOSEX +CLG +CLGX +CLG* +C. +CL. +CLG. +CX +CLX +CLGX +CLS +CLSX +CLS* +C. +CL. +CLS. +CX +CLX +CLSX +COS +COSX +COS* +C. +CO. +COS. +CX +COX +COSX +COUNT +COUNTX +COUNT* +C. +CO. +COU. +COUN. +COUNT. +CX +COX +COUX +COUNX +COUNTX +DATA +DATAX +DATA* +D. +DA. +DAT. +DATA. +DX +DAX +DATX +DATAX +DEG +DEGX +DEG* +D. +DE. +DEG. +DX +DEX +DEGX +DEF +DEFX +DEF* +D. +DE. +DEF. +DX +DEX +DEFX +DELETE +DELETEX +DELETE* +D. +DE. +DEL. +DELE. +DELET. +DELETE. +DX +DEX +DELX +DELEX +DELETX +DELETEX +DIV +DIVX +DIV* +D. +DI. +DIV. +DX +DIX +DIVX +DIM +DIMX +DIM* +D. +DI. +DIM. +DX +DIX +DIMX +DRAW +DRAWX +DRAW* +D. +DR. +DRA. +DRAW. +DX +DRX +DRAX +DRAWX +ENDPROC +ENDPROCX +ENDPROC* +E. +EN. +END. +ENDP. +ENDPR. +ENDPRO. +ENDPROC. +EX +ENX +ENDX +ENDPX +ENDPRX +ENDPROX +ENDPROCX +END +ENDX +END* +E. +EN. +END. +EX +ENX +ENDX +ENVELOPE +ENVELOPEX +ENVELOPE* +E. +EN. +ENV. +ENVE. +ENVEL. +ENVELO. +ENVELOP. +ENVELOPE. +EX +ENX +ENVX +ENVEX +ENVELX +ENVELOX +ENVELOPX +ENVELOPEX +ELSE +ELSEX +ELSE* +E. +EL. +ELS. +ELSE. +EX +ELX +ELSX +ELSEX +EVAL +EVALX +EVAL* +E. +EV. +EVA. +EVAL. +EX +EVX +EVAX +EVALX +ERL +ERLX +ERL* +E. +ER. +ERL. +EX +ERX +ERLX +ERROR +ERRORX +ERROR* +E. +ER. +ERR. +ERRO. +ERROR. +EX +ERX +ERRX +ERROX +ERRORX +EOF +EOFX +EOF* +E. +EO. +EOF. +EX +EOX +EOFX +EOR +EORX +EOR* +E. +EO. +EOR. +EX +EOX +EORX +ERR +ERRX +ERR* +E. +ER. +ERR. +EX +ERX +ERRX +EXP +EXPX +EXP* +E. +EX. +EXP. +EX +EXX +EXPX +EXT +EXTX +EXT* +E. +EX. +EXT. +EX +EXX +EXTX +FOR +FORX +FOR* +F. +FO. +FOR. +FX +FOX +FORX +FALSE +FALSEX +FALSE* +F. +FA. +FAL. +FALS. +FALSE. +FX +FAX +FALX +FALSX +FALSEX +FN +FNX +FN* +F. +FN. +FX +FNX +GOTO +GOTOX +GOTO* +G. +GO. +GOT. +GOTO. +GX +GOX +GOTX +GOTOX +GET$ +GET$X +GET$* +G. +GE. +GET. +GET$. +GX +GEX +GETX +GET$X +GET +GETX +GET* +G. +GE. +GET. +GX +GEX +GETX +GOSUB +GOSUBX +GOSUB* +G. +GO. +GOS. +GOSU. +GOSUB. +GX +GOX +GOSX +GOSUX +GOSUBX +GCOL +GCOLX +GCOL* +G. +GC. +GCO. +GCOL. +GX +GCX +GCOX +GCOLX +HIMEM +HIMEMX +HIMEM* +H. +HI. +HIM. +HIME. +HIMEM. +HX +HIX +HIMX +HIMEX +HIMEMX +INPUT +INPUTX +INPUT* +I. +IN. +INP. +INPU. +INPUT. +IX +INX +INPX +INPUX +INPUTX +IF +IFX +IF* +I. +IF. +IX +IFX +INKEY$ +INKEY$X +INKEY$* +I. +IN. +INK. +INKE. +INKEY. +INKEY$. +IX +INX +INKX +INKEX +INKEYX +INKEY$X +INKEY +INKEYX +INKEY* +I. +IN. +INK. +INKE. +INKEY. +IX +INX +INKX +INKEX +INKEYX +INT +INTX +INT* +I. +IN. +INT. +IX +INX +INTX +INSTR( +INSTR(X +INSTR(* +I. +IN. +INS. +INST. +INSTR. +INSTR(. +IX +INX +INSX +INSTX +INSTRX +INSTR(X +LIST +LISTX +LIST* +L. +LI. +LIS. +LIST. +LX +LIX +LISX +LISTX +LINE +LINEX +LINE* +L. +LI. +LIN. +LINE. +LX +LIX +LINX +LINEX +LOAD +LOADX +LOAD* +L. +LO. +LOA. +LOAD. +LX +LOX +LOAX +LOADX +LOMEM +LOMEMX +LOMEM* +L. +LO. +LOM. +LOME. +LOMEM. +LX +LOX +LOMX +LOMEX +LOMEMX +LOCAL +LOCALX +LOCAL* +L. +LO. +LOC. +LOCA. +LOCAL. +LX +LOX +LOCX +LOCAX +LOCALX +LEFT$( +LEFT$(X +LEFT$(* +L. +LE. +LEF. +LEFT. +LEFT$. +LEFT$(. +LX +LEX +LEFX +LEFTX +LEFT$X +LEFT$(X +LEN +LENX +LEN* +L. +LE. +LEN. +LX +LEX +LENX +LET +LETX +LET* +L. +LE. +LET. +LX +LEX +LETX +LOG +LOGX +LOG* +L. +LO. +LOG. +LX +LOX +LOGX +LN +LNX +LN* +L. +LN. +LX +LNX +MID$( +MID$(X +MID$(* +M. +MI. +MID. +MID$. +MID$(. +MX +MIX +MIDX +MID$X +MID$(X +MODE +MODEX +MODE* +M. +MO. +MOD. +MODE. +MX +MOX +MODX +MODEX +MOD +MODX +MOD* +M. +MO. +MOD. +MX +MOX +MODX +MOVE +MOVEX +MOVE* +M. +MO. +MOV. +MOVE. +MX +MOX +MOVX +MOVEX +NEXT +NEXTX +NEXT* +N. +NE. +NEX. +NEXT. +NX +NEX +NEXX +NEXTX +NEW +NEWX +NEW* +N. +NE. +NEW. +NX +NEX +NEWX +NOT +NOTX +NOT* +N. +NO. +NOT. +NX +NOX +NOTX +OLD +OLDX +OLD* +O. +OL. +OLD. +OX +OLX +OLDX +ON +ONX +ON* +O. +ON. +OX +ONX +OFF +OFFX +OFF* +O. +OF. +OFF. +OX +OFX +OFFX +OR +ORX +OR* +O. +OR. +OX +ORX +OPENIN +OPENINX +OPENIN* +O. +OP. +OPE. +OPEN. +OPENI. +OPENIN. +OX +OPX +OPEX +OPENX +OPENIX +OPENINX +OPENOUT +OPENOUTX +OPENOUT* +O. +OP. +OPE. +OPEN. +OPENO. +OPENOU. +OPENOUT. +OX +OPX +OPEX +OPENX +OPENOX +OPENOUX +OPENOUTX +OPENUP +OPENUPX +OPENUP* +O. +OP. +OPE. +OPEN. +OPENU. +OPENUP. +OX +OPX +OPEX +OPENX +OPENUX +OPENUPX +OSCLI +OSCLIX +OSCLI* +O. +OS. +OSC. +OSCL. +OSCLI. +OX +OSX +OSCX +OSCLX +OSCLIX +PRINT +PRINTX +PRINT* +P. +PR. +PRI. +PRIN. +PRINT. +PX +PRX +PRIX +PRINX +PRINTX +PAGE +PAGEX +PAGE* +P. +PA. +PAG. +PAGE. +PX +PAX +PAGX +PAGEX +PTR +PTRX +PTR* +P. +PT. +PTR. +PX +PTX +PTRX +PI +PIX +PI* +P. +PI. +PX +PIX +PLOT +PLOTX +PLOT* +P. +PL. +PLO. +PLOT. +PX +PLX +PLOX +PLOTX +POINT( +POINT(X +POINT(* +P. +PO. +POI. +POIN. +POINT. +POINT(. +PX +POX +POIX +POINX +POINTX +POINT(X +PROC +PROCX +PROC* +P. +PR. +PRO. +PROC. +PX +PRX +PROX +PROCX +POS +POSX +POS* +P. +PO. +POS. +PX +POX +POSX +RETURN +RETURNX +RETURN* +R. +RE. +RET. +RETU. +RETUR. +RETURN. +RX +REX +RETX +RETUX +RETURX +RETURNX +REPEAT +REPEATX +REPEAT* +R. +RE. +REP. +REPE. +REPEA. +REPEAT. +RX +REX +REPX +REPEX +REPEAX +REPEATX +REPORT +REPORTX +REPORT* +R. +RE. +REP. +REPO. +REPOR. +REPORT. +RX +REX +REPX +REPOX +REPORX +REPORTX +READ +READX +READ* +R. +RE. +REA. +READ. +RX +REX +REAX +READX +REM +REMX +REM* +R. +RE. +REM. +RX +REX +REMX +RUN +RUNX +RUN* +R. +RU. +RUN. +RX +RUX +RUNX +RAD +RADX +RAD* +R. +RA. +RAD. +RX +RAX +RADX +RESTORE +RESTOREX +RESTORE* +R. +RE. +RES. +REST. +RESTO. +RESTOR. +RESTORE. +RX +REX +RESX +RESTX +RESTOX +RESTORX +RESTOREX +RIGHT$( +RIGHT$(X +RIGHT$(* +R. +RI. +RIG. +RIGH. +RIGHT. +RIGHT$. +RIGHT$(. +RX +RIX +RIGX +RIGHX +RIGHTX +RIGHT$X +RIGHT$(X +RND +RNDX +RND* +R. +RN. +RND. +RX +RNX +RNDX +RENUMBER +RENUMBERX +RENUMBER* +R. +RE. +REN. +RENU. +RENUM. +RENUMB. +RENUMBE. +RENUMBER. +RX +REX +RENX +RENUX +RENUMX +RENUMBX +RENUMBEX +RENUMBERX +STEP +STEPX +STEP* +S. +ST. +STE. +STEP. +SX +STX +STEX +STEPX +SAVE +SAVEX +SAVE* +S. +SA. +SAV. +SAVE. +SX +SAX +SAVX +SAVEX +SGN +SGNX +SGN* +S. +SG. +SGN. +SX +SGX +SGNX +SIN +SINX +SIN* +S. +SI. +SIN. +SX +SIX +SINX +SQR +SQRX +SQR* +S. +SQ. +SQR. +SX +SQX +SQRX +SPC +SPCX +SPC* +S. +SP. +SPC. +SX +SPX +SPCX +STR$ +STR$X +STR$* +S. +ST. +STR. +STR$. +SX +STX +STRX +STR$X +STRING$( +STRING$(X +STRING$(* +S. +ST. +STR. +STRI. +STRIN. +STRING. +STRING$. +STRING$(. +SX +STX +STRX +STRIX +STRINX +STRINGX +STRING$X +STRING$(X +SOUND +SOUNDX +SOUND* +S. +SO. +SOU. +SOUN. +SOUND. +SX +SOX +SOUX +SOUNX +SOUNDX +STOP +STOPX +STOP* +S. +ST. +STO. +STOP. +SX +STX +STOX +STOPX +TAN +TANX +TAN* +T. +TA. +TAN. +TX +TAX +TANX +THEN +THENX +THEN* +T. +TH. +THE. +THEN. +TX +THX +THEX +THENX +TO +TOX +TO* +T. +TO. +TX +TOX +TAB( +TAB(X +TAB(* +T. +TA. +TAB. +TAB(. +TX +TAX +TABX +TAB(X +TRACE +TRACEX +TRACE* +T. +TR. +TRA. +TRAC. +TRACE. +TX +TRX +TRAX +TRACX +TRACEX +TIME +TIMEX +TIME* +T. +TI. +TIM. +TIME. +TX +TIX +TIMX +TIMEX +TRUE +TRUEX +TRUE* +T. +TR. +TRU. +TRUE. +TX +TRX +TRUX +TRUEX +UNTIL +UNTILX +UNTIL* +U. +UN. +UNT. +UNTI. +UNTIL. +UX +UNX +UNTX +UNTIX +UNTILX +USR +USRX +USR* +U. +US. +USR. +UX +USX +USRX +VDU +VDUX +VDU* +V. +VD. +VDU. +VX +VDX +VDUX +VAL +VALX +VAL* +V. +VA. +VAL. +VX +VAX +VALX +VPOS +VPOSX +VPOS* +V. +VP. +VPO. +VPOS. +VX +VPX +VPOX +VPOSX +WIDTH +WIDTHX +WIDTH* +W. +WI. +WID. +WIDT. +WIDTH. +WX +WIX +WIDX +WIDTX +WIDTHX +PAGE +PAGEX +PAGE* +P. +PA. +PAG. +PAGE. +PX +PAX +PAGX +PAGEX +PTR +PTRX +PTR* +P. +PT. +PTR. +PX +PTX +PTRX +TIME +TIMEX +TIME* +T. +TI. +TIM. +TIME. +TX +TIX +TIMX +TIMEX +LOMEM +LOMEMX +LOMEM* +L. +LO. +LOM. +LOME. +LOMEM. +LX +LOX +LOMX +LOMEX +LOMEMX +HIMEM +HIMEMX +HIMEM* +H. +HI. +HIM. +HIME. +HIMEM. +HX +HIX +HIMX +HIMEX +HIMEMX +A=AND +A=ANDX +A=AND* +A=A. +A=AN. +A=AND. +A=AX +A=ANX +A=ANDX +A=ABS +A=ABSX +A=ABS* +A=A. +A=AB. +A=ABS. +A=AX +A=ABX +A=ABSX +A=ACS +A=ACSX +A=ACS* +A=A. +A=AC. +A=ACS. +A=AX +A=ACX +A=ACSX +A=ADVAL +A=ADVALX +A=ADVAL* +A=A. +A=AD. +A=ADV. +A=ADVA. +A=ADVAL. +A=AX +A=ADX +A=ADVX +A=ADVAX +A=ADVALX +A=ASC +A=ASCX +A=ASC* +A=A. +A=AS. +A=ASC. +A=AX +A=ASX +A=ASCX +A=ASN +A=ASNX +A=ASN* +A=A. +A=AS. +A=ASN. +A=AX +A=ASX +A=ASNX +A=ATN +A=ATNX +A=ATN* +A=A. +A=AT. +A=ATN. +A=AX +A=ATX +A=ATNX +A=AUTO +A=AUTOX +A=AUTO* +A=A. +A=AU. +A=AUT. +A=AUTO. +A=AX +A=AUX +A=AUTX +A=AUTOX +A=BGET +A=BGETX +A=BGET* +A=B. +A=BG. +A=BGE. +A=BGET. +A=BX +A=BGX +A=BGEX +A=BGETX +A=BPUT +A=BPUTX +A=BPUT* +A=B. +A=BP. +A=BPU. +A=BPUT. +A=BX +A=BPX +A=BPUX +A=BPUTX +A=COLOUR +A=COLOURX +A=COLOUR* +A=C. +A=CO. +A=COL. +A=COLO. +A=COLOU. +A=COLOUR. +A=CX +A=COX +A=COLX +A=COLOX +A=COLOUX +A=COLOURX +A=CALL +A=CALLX +A=CALL* +A=C. +A=CA. +A=CAL. +A=CALL. +A=CX +A=CAX +A=CALX +A=CALLX +A=CHAIN +A=CHAINX +A=CHAIN* +A=C. +A=CH. +A=CHA. +A=CHAI. +A=CHAIN. +A=CX +A=CHX +A=CHAX +A=CHAIX +A=CHAINX +A=CHR$ +A=CHR$X +A=CHR$* +A=C. +A=CH. +A=CHR. +A=CHR$. +A=CX +A=CHX +A=CHRX +A=CHR$X +A=CLEAR +A=CLEARX +A=CLEAR* +A=C. +A=CL. +A=CLE. +A=CLEA. +A=CLEAR. +A=CX +A=CLX +A=CLEX +A=CLEAX +A=CLEARX +A=CLOSE +A=CLOSEX +A=CLOSE* +A=C. +A=CL. +A=CLO. +A=CLOS. +A=CLOSE. +A=CX +A=CLX +A=CLOX +A=CLOSX +A=CLOSEX +A=CLG +A=CLGX +A=CLG* +A=C. +A=CL. +A=CLG. +A=CX +A=CLX +A=CLGX +A=CLS +A=CLSX +A=CLS* +A=C. +A=CL. +A=CLS. +A=CX +A=CLX +A=CLSX +A=COS +A=COSX +A=COS* +A=C. +A=CO. +A=COS. +A=CX +A=COX +A=COSX +A=COUNT +A=COUNTX +A=COUNT* +A=C. +A=CO. +A=COU. +A=COUN. +A=COUNT. +A=CX +A=COX +A=COUX +A=COUNX +A=COUNTX +A=DATA +A=DATAX +A=DATA* +A=D. +A=DA. +A=DAT. +A=DATA. +A=DX +A=DAX +A=DATX +A=DATAX +A=DEG +A=DEGX +A=DEG* +A=D. +A=DE. +A=DEG. +A=DX +A=DEX +A=DEGX +A=DEF +A=DEFX +A=DEF* +A=D. +A=DE. +A=DEF. +A=DX +A=DEX +A=DEFX +A=DELETE +A=DELETEX +A=DELETE* +A=D. +A=DE. +A=DEL. +A=DELE. +A=DELET. +A=DELETE. +A=DX +A=DEX +A=DELX +A=DELEX +A=DELETX +A=DELETEX +A=DIV +A=DIVX +A=DIV* +A=D. +A=DI. +A=DIV. +A=DX +A=DIX +A=DIVX +A=DIM +A=DIMX +A=DIM* +A=D. +A=DI. +A=DIM. +A=DX +A=DIX +A=DIMX +A=DRAW +A=DRAWX +A=DRAW* +A=D. +A=DR. +A=DRA. +A=DRAW. +A=DX +A=DRX +A=DRAX +A=DRAWX +A=ENDPROC +A=ENDPROCX +A=ENDPROC* +A=E. +A=EN. +A=END. +A=ENDP. +A=ENDPR. +A=ENDPRO. +A=ENDPROC. +A=EX +A=ENX +A=ENDX +A=ENDPX +A=ENDPRX +A=ENDPROX +A=ENDPROCX +A=END +A=ENDX +A=END* +A=E. +A=EN. +A=END. +A=EX +A=ENX +A=ENDX +A=ENVELOPE +A=ENVELOPEX +A=ENVELOPE* +A=E. +A=EN. +A=ENV. +A=ENVE. +A=ENVEL. +A=ENVELO. +A=ENVELOP. +A=ENVELOPE. +A=EX +A=ENX +A=ENVX +A=ENVEX +A=ENVELX +A=ENVELOX +A=ENVELOPX +A=ENVELOPEX +A=ELSE +A=ELSEX +A=ELSE* +A=E. +A=EL. +A=ELS. +A=ELSE. +A=EX +A=ELX +A=ELSX +A=ELSEX +A=EVAL +A=EVALX +A=EVAL* +A=E. +A=EV. +A=EVA. +A=EVAL. +A=EX +A=EVX +A=EVAX +A=EVALX +A=ERL +A=ERLX +A=ERL* +A=E. +A=ER. +A=ERL. +A=EX +A=ERX +A=ERLX +A=ERROR +A=ERRORX +A=ERROR* +A=E. +A=ER. +A=ERR. +A=ERRO. +A=ERROR. +A=EX +A=ERX +A=ERRX +A=ERROX +A=ERRORX +A=EOF +A=EOFX +A=EOF* +A=E. +A=EO. +A=EOF. +A=EX +A=EOX +A=EOFX +A=EOR +A=EORX +A=EOR* +A=E. +A=EO. +A=EOR. +A=EX +A=EOX +A=EORX +A=ERR +A=ERRX +A=ERR* +A=E. +A=ER. +A=ERR. +A=EX +A=ERX +A=ERRX +A=EXP +A=EXPX +A=EXP* +A=E. +A=EX. +A=EXP. +A=EX +A=EXX +A=EXPX +A=EXT +A=EXTX +A=EXT* +A=E. +A=EX. +A=EXT. +A=EX +A=EXX +A=EXTX +A=FOR +A=FORX +A=FOR* +A=F. +A=FO. +A=FOR. +A=FX +A=FOX +A=FORX +A=FALSE +A=FALSEX +A=FALSE* +A=F. +A=FA. +A=FAL. +A=FALS. +A=FALSE. +A=FX +A=FAX +A=FALX +A=FALSX +A=FALSEX +A=FN +A=FNX +A=FN* +A=F. +A=FN. +A=FX +A=FNX +A=GOTO +A=GOTOX +A=GOTO* +A=G. +A=GO. +A=GOT. +A=GOTO. +A=GX +A=GOX +A=GOTX +A=GOTOX +A=GET$ +A=GET$X +A=GET$* +A=G. +A=GE. +A=GET. +A=GET$. +A=GX +A=GEX +A=GETX +A=GET$X +A=GET +A=GETX +A=GET* +A=G. +A=GE. +A=GET. +A=GX +A=GEX +A=GETX +A=GOSUB +A=GOSUBX +A=GOSUB* +A=G. +A=GO. +A=GOS. +A=GOSU. +A=GOSUB. +A=GX +A=GOX +A=GOSX +A=GOSUX +A=GOSUBX +A=GCOL +A=GCOLX +A=GCOL* +A=G. +A=GC. +A=GCO. +A=GCOL. +A=GX +A=GCX +A=GCOX +A=GCOLX +A=HIMEM +A=HIMEMX +A=HIMEM* +A=H. +A=HI. +A=HIM. +A=HIME. +A=HIMEM. +A=HX +A=HIX +A=HIMX +A=HIMEX +A=HIMEMX +A=INPUT +A=INPUTX +A=INPUT* +A=I. +A=IN. +A=INP. +A=INPU. +A=INPUT. +A=IX +A=INX +A=INPX +A=INPUX +A=INPUTX +A=IF +A=IFX +A=IF* +A=I. +A=IF. +A=IX +A=IFX +A=INKEY$ +A=INKEY$X +A=INKEY$* +A=I. +A=IN. +A=INK. +A=INKE. +A=INKEY. +A=INKEY$. +A=IX +A=INX +A=INKX +A=INKEX +A=INKEYX +A=INKEY$X +A=INKEY +A=INKEYX +A=INKEY* +A=I. +A=IN. +A=INK. +A=INKE. +A=INKEY. +A=IX +A=INX +A=INKX +A=INKEX +A=INKEYX +A=INT +A=INTX +A=INT* +A=I. +A=IN. +A=INT. +A=IX +A=INX +A=INTX +A=INSTR( +A=INSTR(X +A=INSTR(* +A=I. +A=IN. +A=INS. +A=INST. +A=INSTR. +A=INSTR(. +A=IX +A=INX +A=INSX +A=INSTX +A=INSTRX +A=INSTR(X +A=LIST +A=LISTX +A=LIST* +A=L. +A=LI. +A=LIS. +A=LIST. +A=LX +A=LIX +A=LISX +A=LISTX +A=LINE +A=LINEX +A=LINE* +A=L. +A=LI. +A=LIN. +A=LINE. +A=LX +A=LIX +A=LINX +A=LINEX +A=LOAD +A=LOADX +A=LOAD* +A=L. +A=LO. +A=LOA. +A=LOAD. +A=LX +A=LOX +A=LOAX +A=LOADX +A=LOMEM +A=LOMEMX +A=LOMEM* +A=L. +A=LO. +A=LOM. +A=LOME. +A=LOMEM. +A=LX +A=LOX +A=LOMX +A=LOMEX +A=LOMEMX +A=LOCAL +A=LOCALX +A=LOCAL* +A=L. +A=LO. +A=LOC. +A=LOCA. +A=LOCAL. +A=LX +A=LOX +A=LOCX +A=LOCAX +A=LOCALX +A=LEFT$( +A=LEFT$(X +A=LEFT$(* +A=L. +A=LE. +A=LEF. +A=LEFT. +A=LEFT$. +A=LEFT$(. +A=LX +A=LEX +A=LEFX +A=LEFTX +A=LEFT$X +A=LEFT$(X +A=LEN +A=LENX +A=LEN* +A=L. +A=LE. +A=LEN. +A=LX +A=LEX +A=LENX +A=LET +A=LETX +A=LET* +A=L. +A=LE. +A=LET. +A=LX +A=LEX +A=LETX +A=LOG +A=LOGX +A=LOG* +A=L. +A=LO. +A=LOG. +A=LX +A=LOX +A=LOGX +A=LN +A=LNX +A=LN* +A=L. +A=LN. +A=LX +A=LNX +A=MID$( +A=MID$(X +A=MID$(* +A=M. +A=MI. +A=MID. +A=MID$. +A=MID$(. +A=MX +A=MIX +A=MIDX +A=MID$X +A=MID$(X +A=MODE +A=MODEX +A=MODE* +A=M. +A=MO. +A=MOD. +A=MODE. +A=MX +A=MOX +A=MODX +A=MODEX +A=MOD +A=MODX +A=MOD* +A=M. +A=MO. +A=MOD. +A=MX +A=MOX +A=MODX +A=MOVE +A=MOVEX +A=MOVE* +A=M. +A=MO. +A=MOV. +A=MOVE. +A=MX +A=MOX +A=MOVX +A=MOVEX +A=NEXT +A=NEXTX +A=NEXT* +A=N. +A=NE. +A=NEX. +A=NEXT. +A=NX +A=NEX +A=NEXX +A=NEXTX +A=NEW +A=NEWX +A=NEW* +A=N. +A=NE. +A=NEW. +A=NX +A=NEX +A=NEWX +A=NOT +A=NOTX +A=NOT* +A=N. +A=NO. +A=NOT. +A=NX +A=NOX +A=NOTX +A=OLD +A=OLDX +A=OLD* +A=O. +A=OL. +A=OLD. +A=OX +A=OLX +A=OLDX +A=ON +A=ONX +A=ON* +A=O. +A=ON. +A=OX +A=ONX +A=OFF +A=OFFX +A=OFF* +A=O. +A=OF. +A=OFF. +A=OX +A=OFX +A=OFFX +A=OR +A=ORX +A=OR* +A=O. +A=OR. +A=OX +A=ORX +A=OPENIN +A=OPENINX +A=OPENIN* +A=O. +A=OP. +A=OPE. +A=OPEN. +A=OPENI. +A=OPENIN. +A=OX +A=OPX +A=OPEX +A=OPENX +A=OPENIX +A=OPENINX +A=OPENOUT +A=OPENOUTX +A=OPENOUT* +A=O. +A=OP. +A=OPE. +A=OPEN. +A=OPENO. +A=OPENOU. +A=OPENOUT. +A=OX +A=OPX +A=OPEX +A=OPENX +A=OPENOX +A=OPENOUX +A=OPENOUTX +A=OPENUP +A=OPENUPX +A=OPENUP* +A=O. +A=OP. +A=OPE. +A=OPEN. +A=OPENU. +A=OPENUP. +A=OX +A=OPX +A=OPEX +A=OPENX +A=OPENUX +A=OPENUPX +A=OSCLI +A=OSCLIX +A=OSCLI* +A=O. +A=OS. +A=OSC. +A=OSCL. +A=OSCLI. +A=OX +A=OSX +A=OSCX +A=OSCLX +A=OSCLIX +A=PRINT +A=PRINTX +A=PRINT* +A=P. +A=PR. +A=PRI. +A=PRIN. +A=PRINT. +A=PX +A=PRX +A=PRIX +A=PRINX +A=PRINTX +A=PAGE +A=PAGEX +A=PAGE* +A=P. +A=PA. +A=PAG. +A=PAGE. +A=PX +A=PAX +A=PAGX +A=PAGEX +A=PTR +A=PTRX +A=PTR* +A=P. +A=PT. +A=PTR. +A=PX +A=PTX +A=PTRX +A=PI +A=PIX +A=PI* +A=P. +A=PI. +A=PX +A=PIX +A=PLOT +A=PLOTX +A=PLOT* +A=P. +A=PL. +A=PLO. +A=PLOT. +A=PX +A=PLX +A=PLOX +A=PLOTX +A=POINT( +A=POINT(X +A=POINT(* +A=P. +A=PO. +A=POI. +A=POIN. +A=POINT. +A=POINT(. +A=PX +A=POX +A=POIX +A=POINX +A=POINTX +A=POINT(X +A=PROC +A=PROCX +A=PROC* +A=P. +A=PR. +A=PRO. +A=PROC. +A=PX +A=PRX +A=PROX +A=PROCX +A=POS +A=POSX +A=POS* +A=P. +A=PO. +A=POS. +A=PX +A=POX +A=POSX +A=RETURN +A=RETURNX +A=RETURN* +A=R. +A=RE. +A=RET. +A=RETU. +A=RETUR. +A=RETURN. +A=RX +A=REX +A=RETX +A=RETUX +A=RETURX +A=RETURNX +A=REPEAT +A=REPEATX +A=REPEAT* +A=R. +A=RE. +A=REP. +A=REPE. +A=REPEA. +A=REPEAT. +A=RX +A=REX +A=REPX +A=REPEX +A=REPEAX +A=REPEATX +A=REPORT +A=REPORTX +A=REPORT* +A=R. +A=RE. +A=REP. +A=REPO. +A=REPOR. +A=REPORT. +A=RX +A=REX +A=REPX +A=REPOX +A=REPORX +A=REPORTX +A=READ +A=READX +A=READ* +A=R. +A=RE. +A=REA. +A=READ. +A=RX +A=REX +A=REAX +A=READX +A=REM +A=REMX +A=REM* +A=R. +A=RE. +A=REM. +A=RX +A=REX +A=REMX +A=RUN +A=RUNX +A=RUN* +A=R. +A=RU. +A=RUN. +A=RX +A=RUX +A=RUNX +A=RAD +A=RADX +A=RAD* +A=R. +A=RA. +A=RAD. +A=RX +A=RAX +A=RADX +A=RESTORE +A=RESTOREX +A=RESTORE* +A=R. +A=RE. +A=RES. +A=REST. +A=RESTO. +A=RESTOR. +A=RESTORE. +A=RX +A=REX +A=RESX +A=RESTX +A=RESTOX +A=RESTORX +A=RESTOREX +A=RIGHT$( +A=RIGHT$(X +A=RIGHT$(* +A=R. +A=RI. +A=RIG. +A=RIGH. +A=RIGHT. +A=RIGHT$. +A=RIGHT$(. +A=RX +A=RIX +A=RIGX +A=RIGHX +A=RIGHTX +A=RIGHT$X +A=RIGHT$(X +A=RND +A=RNDX +A=RND* +A=R. +A=RN. +A=RND. +A=RX +A=RNX +A=RNDX +A=RENUMBER +A=RENUMBERX +A=RENUMBER* +A=R. +A=RE. +A=REN. +A=RENU. +A=RENUM. +A=RENUMB. +A=RENUMBE. +A=RENUMBER. +A=RX +A=REX +A=RENX +A=RENUX +A=RENUMX +A=RENUMBX +A=RENUMBEX +A=RENUMBERX +A=STEP +A=STEPX +A=STEP* +A=S. +A=ST. +A=STE. +A=STEP. +A=SX +A=STX +A=STEX +A=STEPX +A=SAVE +A=SAVEX +A=SAVE* +A=S. +A=SA. +A=SAV. +A=SAVE. +A=SX +A=SAX +A=SAVX +A=SAVEX +A=SGN +A=SGNX +A=SGN* +A=S. +A=SG. +A=SGN. +A=SX +A=SGX +A=SGNX +A=SIN +A=SINX +A=SIN* +A=S. +A=SI. +A=SIN. +A=SX +A=SIX +A=SINX +A=SQR +A=SQRX +A=SQR* +A=S. +A=SQ. +A=SQR. +A=SX +A=SQX +A=SQRX +A=SPC +A=SPCX +A=SPC* +A=S. +A=SP. +A=SPC. +A=SX +A=SPX +A=SPCX +A=STR$ +A=STR$X +A=STR$* +A=S. +A=ST. +A=STR. +A=STR$. +A=SX +A=STX +A=STRX +A=STR$X +A=STRING$( +A=STRING$(X +A=STRING$(* +A=S. +A=ST. +A=STR. +A=STRI. +A=STRIN. +A=STRING. +A=STRING$. +A=STRING$(. +A=SX +A=STX +A=STRX +A=STRIX +A=STRINX +A=STRINGX +A=STRING$X +A=STRING$(X +A=SOUND +A=SOUNDX +A=SOUND* +A=S. +A=SO. +A=SOU. +A=SOUN. +A=SOUND. +A=SX +A=SOX +A=SOUX +A=SOUNX +A=SOUNDX +A=STOP +A=STOPX +A=STOP* +A=S. +A=ST. +A=STO. +A=STOP. +A=SX +A=STX +A=STOX +A=STOPX +A=TAN +A=TANX +A=TAN* +A=T. +A=TA. +A=TAN. +A=TX +A=TAX +A=TANX +A=THEN +A=THENX +A=THEN* +A=T. +A=TH. +A=THE. +A=THEN. +A=TX +A=THX +A=THEX +A=THENX +A=TO +A=TOX +A=TO* +A=T. +A=TO. +A=TX +A=TOX +A=TAB( +A=TAB(X +A=TAB(* +A=T. +A=TA. +A=TAB. +A=TAB(. +A=TX +A=TAX +A=TABX +A=TAB(X +A=TRACE +A=TRACEX +A=TRACE* +A=T. +A=TR. +A=TRA. +A=TRAC. +A=TRACE. +A=TX +A=TRX +A=TRAX +A=TRACX +A=TRACEX +A=TIME +A=TIMEX +A=TIME* +A=T. +A=TI. +A=TIM. +A=TIME. +A=TX +A=TIX +A=TIMX +A=TIMEX +A=TRUE +A=TRUEX +A=TRUE* +A=T. +A=TR. +A=TRU. +A=TRUE. +A=TX +A=TRX +A=TRUX +A=TRUEX +A=UNTIL +A=UNTILX +A=UNTIL* +A=U. +A=UN. +A=UNT. +A=UNTI. +A=UNTIL. +A=UX +A=UNX +A=UNTX +A=UNTIX +A=UNTILX +A=USR +A=USRX +A=USR* +A=U. +A=US. +A=USR. +A=UX +A=USX +A=USRX +A=VDU +A=VDUX +A=VDU* +A=V. +A=VD. +A=VDU. +A=VX +A=VDX +A=VDUX +A=VAL +A=VALX +A=VAL* +A=V. +A=VA. +A=VAL. +A=VX +A=VAX +A=VALX +A=VPOS +A=VPOSX +A=VPOS* +A=V. +A=VP. +A=VPO. +A=VPOS. +A=VX +A=VPX +A=VPOX +A=VPOSX +A=WIDTH +A=WIDTHX +A=WIDTH* +A=W. +A=WI. +A=WID. +A=WIDT. +A=WIDTH. +A=WX +A=WIX +A=WIDX +A=WIDTX +A=WIDTHX +A=PAGE +A=PAGEX +A=PAGE* +A=P. +A=PA. +A=PAG. +A=PAGE. +A=PX +A=PAX +A=PAGX +A=PAGEX +A=PTR +A=PTRX +A=PTR* +A=P. +A=PT. +A=PTR. +A=PX +A=PTX +A=PTRX +A=TIME +A=TIMEX +A=TIME* +A=T. +A=TI. +A=TIM. +A=TIME. +A=TX +A=TIX +A=TIMX +A=TIMEX +A=LOMEM +A=LOMEMX +A=LOMEM* +A=L. +A=LO. +A=LOM. +A=LOME. +A=LOMEM. +A=LX +A=LOX +A=LOMX +A=LOMEX +A=LOMEMX +A=HIMEM +A=HIMEMX +A=HIMEM* +A=H. +A=HI. +A=HIM. +A=HIME. +A=HIMEM. +A=HX +A=HIX +A=HIMX +A=HIMEX +A=HIMEMX diff --git a/test/3-directives/putbasic/abbreviations.gold.ssd b/test/3-directives/putbasic/abbreviations.gold.ssd new file mode 100644 index 0000000..e5455d3 Binary files /dev/null and b/test/3-directives/putbasic/abbreviations.gold.ssd differ diff --git a/test/3-directives/putbasic/issue-62.6502 b/test/3-directives/putbasic/issue-62.6502 new file mode 100644 index 0000000..c8b72f3 --- /dev/null +++ b/test/3-directives/putbasic/issue-62.6502 @@ -0,0 +1 @@ +PUTBASIC "issue-62.bas", "$.ISS-62" diff --git a/test/3-directives/putbasic/issue-62.bas b/test/3-directives/putbasic/issue-62.bas new file mode 100644 index 0000000..9936322 --- /dev/null +++ b/test/3-directives/putbasic/issue-62.bas @@ -0,0 +1,2 @@ +0 REM Start at line zero +1 REM And add a line one diff --git a/test/3-directives/putbasic/issue-62.gold.ssd b/test/3-directives/putbasic/issue-62.gold.ssd new file mode 100644 index 0000000..446e0b7 Binary files /dev/null and b/test/3-directives/putbasic/issue-62.gold.ssd differ diff --git a/test/3-directives/putbasic/issue-63.6502 b/test/3-directives/putbasic/issue-63.6502 new file mode 100644 index 0000000..6b626a7 --- /dev/null +++ b/test/3-directives/putbasic/issue-63.6502 @@ -0,0 +1 @@ +PUTBASIC "issue-63.bas", "$.ISS-63" diff --git a/test/3-directives/putbasic/issue-63.bas b/test/3-directives/putbasic/issue-63.bas new file mode 100644 index 0000000..9a3fb75 --- /dev/null +++ b/test/3-directives/putbasic/issue-63.bas @@ -0,0 +1,2 @@ +10 REM Tokenizing of PAGE on LHS +20 ?(PAGE+1024)=1 diff --git a/test/3-directives/putbasic/issue-63.gold.ssd b/test/3-directives/putbasic/issue-63.gold.ssd new file mode 100644 index 0000000..ae89a58 Binary files /dev/null and b/test/3-directives/putbasic/issue-63.gold.ssd differ diff --git a/test/3-directives/putbasic/issue-65.6502 b/test/3-directives/putbasic/issue-65.6502 new file mode 100644 index 0000000..417fb91 --- /dev/null +++ b/test/3-directives/putbasic/issue-65.6502 @@ -0,0 +1 @@ +PUTBASIC "issue-65.bas", "$.ISS-65" diff --git a/test/3-directives/putbasic/issue-65.bas b/test/3-directives/putbasic/issue-65.bas new file mode 100644 index 0000000..ed9b0f2 --- /dev/null +++ b/test/3-directives/putbasic/issue-65.bas @@ -0,0 +1,2 @@ +1REM Should not require a space before the MOD +2PROCADJUST(1,(?&276BMOD16)+10*(?&276B DIV16)) diff --git a/test/3-directives/putbasic/issue-65.gold.ssd b/test/3-directives/putbasic/issue-65.gold.ssd new file mode 100644 index 0000000..94ef45a Binary files /dev/null and b/test/3-directives/putbasic/issue-65.gold.ssd differ diff --git a/test/3-directives/putbasic/pound.6502 b/test/3-directives/putbasic/pound.6502 new file mode 100644 index 0000000..ef01824 --- /dev/null +++ b/test/3-directives/putbasic/pound.6502 @@ -0,0 +1 @@ +PUTBASIC "pound.bas", "$.POUND" diff --git a/test/3-directives/putbasic/pound.bas b/test/3-directives/putbasic/pound.bas new file mode 100644 index 0000000..d3f8979 --- /dev/null +++ b/test/3-directives/putbasic/pound.bas @@ -0,0 +1,8 @@ +10 END`EOR=1 +20 COUNT_MOD=2 +30 `PRINT=3 +40 _END=4 +50 PRINTEND`EOR +60 PRINTCOUNT_MOD +70 PRINT`PRINT +80 PRINT_END diff --git a/test/3-directives/putbasic/pound.gold.ssd b/test/3-directives/putbasic/pound.gold.ssd new file mode 100644 index 0000000..6f32347 Binary files /dev/null and b/test/3-directives/putbasic/pound.gold.ssd differ