#include #include #include #include #include #include // https://www.c64-wiki.com/wiki/BASIC_token /* The URLs here provide examples of other BASIC dialects that include the specified commands or keywords. All except VERIFY are known with certainty to be part of other BASIC dialects, and thus cannot be subject to copyright infringement when implemented on a C64. The VERIFY Command however appears in other programming languages, and as a single word, is the obvious complement to LOAD and SAVE when considering the following storage functions: 1. Load a file from storage into memory. 2. Save a file from memory to storage. 3. Verify that a file has been correctly written from memory to storage. Note that verify is the key verb in the behaviour of this function. Therefore it is the obvious choice for the name for such a function, taking into account the convention of LOAD and SAVE. Indeed, that this is so is highlighted by the fact that it was used in the C64 ROM. Therefore there is no exercise of creativity here, and a reasonable person would likely select this name independently. Also, single words cannot be copyright. Further, the list is a list of facts, and thus not copyrightable. We sourced the list from a public source, https://www.c64-wiki.com/wiki/BASIC, which has been public on the internet for a long time, as have many other similar sources. That website offers the page under the GFDL license, and we can therefore take the list under those license terms if we wish, should the need arise. Note that in providing these justifications above, we do not in any way acknowledge that without these conditions that the BASIC keyword list could be copyright, but provide this information as a further layer of defence against any claims that it could somehow infringe on the copyrights of the C64/C65/C128 etc ROMs. */ char *keyword_list[]={ "END", // https://www.landsnail.com/a2ref.htm "FOR", // https://www.landsnail.com/a2ref.htm "NEXT", // https://www.landsnail.com/a2ref.htm "DATA", // https://www.landsnail.com/a2ref.htm "INPUT#", // https://www.atariarchives.org/creativeatari/Using_Disks_With_Atari_Basic.php "INPUT", // https://www.landsnail.com/a2ref.htm "DIM", // https://www.landsnail.com/a2ref.htm "READ", // https://www.landsnail.com/a2ref.htm "LET", // https://en.wikipedia.org/wiki/Atari_BASIC "GOTO", // https://www.landsnail.com/a2ref.htm "RUN", // https://www.landsnail.com/a2ref.htm "IF", // https://www.landsnail.com/a2ref.htm "RESTORE", // https://www.landsnail.com/a2ref.htm "GOSUB", // https://www.landsnail.com/a2ref.htm "RETURN", // https://www.landsnail.com/a2ref.htm "REM", // https://www.landsnail.com/a2ref.htm "STOP", // https://www.landsnail.com/a2ref.htm "ON", // https://www.landsnail.com/a2ref.htm "WAIT", // http://www.picaxe.com/BASIC-Commands/Time-Delays/wait/ "LOAD", // https://www.landsnail.com/a2ref.htm "SAVE", // https://www.landsnail.com/a2ref.htm "VERIFY", // https://golang.org/cmd/go/ "DEF", // https://www.landsnail.com/a2ref.htm "POKE", // https://www.landsnail.com/a2ref.htm "PRINT#", // https://www.atariarchives.org/creativeatari/Using_Disks_With_Atari_Basic.php "PRINT", // https://www.landsnail.com/a2ref.htm "CONT", // https://www.landsnail.com/a2ref.htm "LIST", // https://www.landsnail.com/a2ref.htm "CLR", // Apple I Replica Creation: Back to the Garage, p125 "CMD", // https://en.wikipedia.org/wiki/List_of_DOS_commands "SYS", // https://www.lifewire.com/dos-commands-4070427 "OPEN", // https://www.atariarchives.org/creativeatari/Using_Disks_With_Atari_Basic.php "CLOSE", // https://www.atariarchives.org/creativeatari/Using_Disks_With_Atari_Basic.php "GET", // https://www.landsnail.com/a2ref.htm "NEW", // https://www.landsnail.com/a2ref.htm "TAB(", // http://www.antonis.de/qbebooks/gwbasman/tab.html "TO", // https://www.landsnail.com/a2ref.htm "FN", // https://www.landsnail.com/a2ref.htm "SPC(", // http://www.antonis.de/qbebooks/gwbasman/spc.html "THEN", // https://www.landsnail.com/a2ref.htm "NOT", // https://www.landsnail.com/a2ref.htm "STEP", // https://www.landsnail.com/a2ref.htm "+", // https://www.landsnail.com/a2ref.htm "-", // https://www.landsnail.com/a2ref.htm "*", // https://www.landsnail.com/a2ref.htm "/", // https://www.landsnail.com/a2ref.htm "^", // https://www.landsnail.com/a2ref.htm "AND", // https://www.landsnail.com/a2ref.htm "OR", // https://www.landsnail.com/a2ref.htm ">", // https://www.landsnail.com/a2ref.htm "=", // https://www.landsnail.com/a2ref.htm "<", // https://www.landsnail.com/a2ref.htm "SGN", // https://www.landsnail.com/a2ref.htm "INT", // https://www.landsnail.com/a2ref.htm "ABS", // https://www.landsnail.com/a2ref.htm "USR", // https://www.landsnail.com/a2ref.htm "FRE", // http://www.antonis.de/qbebooks/gwbasman/fre.html "POS", // http://www.antonis.de/qbebooks/gwbasman/pos.html "SQR", // https://www.landsnail.com/a2ref.htm "RND", // https://www.landsnail.com/a2ref.htm "LOG", // https://www.landsnail.com/a2ref.htm "EXP", // https://www.landsnail.com/a2ref.htm "COS", // https://www.landsnail.com/a2ref.htm "SIN", // https://www.landsnail.com/a2ref.htm "TAN", // https://www.landsnail.com/a2ref.htm "ATN", // https://www.landsnail.com/a2ref.htm "PEEK", // https://www.landsnail.com/a2ref.htm "LEN", // https://www.landsnail.com/a2ref.htm "STR$", // https://www.landsnail.com/a2ref.htm "VAL", // https://www.landsnail.com/a2ref.htm "ASC", // https://www.landsnail.com/a2ref.htm "CHR$", // https://www.landsnail.com/a2ref.htm "LEFT$", // https://www.landsnail.com/a2ref.htm "RIGHT$", // https://www.landsnail.com/a2ref.htm "MID$", // https://www.landsnail.com/a2ref.htm "GO", // https://en.wikipedia.org/wiki/Goto NULL }; /* These error messages are generally so well known, that it seems silly to have to even point out that they are so widely used and known, if not completely genericised. The most of them are inherited from the MICROSOFT BASIC on which the C64's BASIC is based, so for those, there cannot even be any claim to copyright over them in any exclusive way. However, copyright of such short phrases that express ideas in short form cannot be copyrighted: https://fairuse.stanford.edu/2003/09/09/copyright_protection_for_short/ */ char *error_list[]={ "TOO MANY FILES", // https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/error-messages/too-many-files "FILE OPEN", // https://forums.autodesk.com/t5/3ds-max-forum/quot-file-open-error-quot/td-p/4036150 "FILE NOT OPEN", // https://www.synthetos.com/topics/file-not-open-error/ "FILE NOT FOUND", // https://answers.microsoft.com/en-us/windows/forum/windows_10-files/file-not-found-check-the-file-name-and-try-again/0734e837-b9f7-485e-93c5-5592f804b4c8 "DEVICE NOT PRESENT", // https://answers.microsoft.com/en-us/windows/forum/all/device-not-present/d9f96498-cf92-4ba0-9076-a206cf058131 "NOT INPUT FILE", // https://stackoverflow.com/questions/13055889/sed-with-literal-string-not-input-file/37682812 http://iama.stupid.cow.org/OldComputerMagazines/Commodore%20Power-Play%20100%25/Commodore_Power-Play_1985_Issue_16_V4_N04_Aug_Sep.pdf "NOT OUTPUT FILE", // http://www.un4seen.com/forum/?topic=12547.0 "MISSING FILENAME", // https://arduino.stackexchange.com/questions/22839/missing-filename-compilation-error "ILLEGAL DEVICE NUMBER", // https://comp.unix.solaris.narkive.com/dkqcQFg3/svm-mirror-not-working-illegal-major-device-number "NEXT WITHOUT FOR", // https://stackoverflow.com/questions/18232928/compile-error-next-without-for-vba "SYNTAX", // https://en.wikipedia.org/wiki/Syntax_error "RETURN WITHOUT GOSUB", // https://stackoverflow.com/questions/11467746/return-without-gosub-when-using-subforms-in-access "OUT OF DATA", // http://forum.qbasicnews.com/index.php?topic=8619.0 "ILLEGAL QUANTITY", // https://community.dynamics.com/ax/f/33/t/238113 "OVERFLOW", // https://www.webopedia.com/TERM/O/overflow_error.html "OUT OF MEMORY", // https://support.microsoft.com/en-au/help/126962/out-of-memory-error-message-appears-when-you-have-a-large-number-of-pr "UNDEF\'D STATEMENT", // http://ivanx.com/appleii/magicgoto/ "BAD SUBSCRIPT", // https://www.computing.net/answers/windows-8/how-does-bad-subscript-error-appear-in-gwbasic/2301.html "REDIM\'D ARRAY", // https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html "DIVISION BY ZERO", // https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html "ILLEGAL DIRECT", // https://hwiegman.home.xs4all.nl/gw-man/Appendix%20A.html "TYPE MISMATCH", // https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html "STRING TOO LONG", // https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html "FILE DATA", // https://www.minitool.com/data-recovery/data-error-crc.html "FORMULA TOO COMPLEX", // https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html "CAN\'T CONTINUE", // https://hwiegman.home.xs4all.nl/gw-man/Appendix%20A.html "UNDEF\'D FUNCTION", // https://www.saatchiart.com/print/Painting-Undef-d-Function-3495/16167/3829193/view "VERIFY", // https://forums.openvpn.net/viewtopic.php?t=22040 "LOAD", // https://www.discogs.com/Gimmik-Load-Error/release/482462 "BREAK", // #29 // Non-error messages "READY.\r", // #30 // https://www.ibm.com/support/knowledgecenter/zosbasics/com.ibm.zos.zconcepts/zconc_whatistsonative.htm https://github.com/stefanhaustein/expressionparser " IN ", // #31 "BRK AT $", // #32 " ERROR", // #33 // Simply the word error that is attached to the other parts of messages https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html " BASIC BYTES FREE", // #34 // https://github.com/stefanhaustein/expressionparser "MEMORY CORRUPT", // #35 "NOT IMPLEMENTED", // #36 NULL}; // XXX: create separate list for Kernal // "LOADING", // #30 // https://community.tibco.com/wiki/how-show-loading-prompt-when-reloading-external-data // "VERIFYING", // https://discussions.apple.com/thread/8087203 // "SAVING", // Token $FF is end of message, so we can have only 255 unique words #define MAX_WORDS 255 char *words[MAX_WORDS]; int word_count=0; #define MAX_LEN 1024 unsigned char message_tokens[MAX_LEN]; int token_count=0; unsigned char packed_words[MAX_LEN]; int packed_len=0; unsigned char packed_keywords[MAX_LEN]; int packedkey_len=0; struct char_freq { unsigned char c; int count; }; int total_chars=0; int repeats=0; int cmpfreq(const void *a,const void *b) { const struct char_freq *aa=a,*bb=b; if (aa->countcount) return 1; if (aa->count>bb->count) return -1; return 0; } #define MAX_CHARS 256 struct char_freq char_freqs[MAX_CHARS]; int char_max=0; int find_word(char *w) { int i; for(i=0;iMAX_CHARS) { fprintf(stderr,"Too many unique characters in message list. Max is %d\n",MAX_CHARS); exit(-1); } if (char_num>=char_max) char_max=char_num+1; char_freqs[char_num].c=s[j]; char_freqs[char_num].count++; total_chars++; if (j&&s[j]==s[j-1]) repeats++; } return 0; } int pack_word(const char *w,unsigned char *out,int *len) { fprintf(stderr,"Packing word '%s' at offset 0x%03x\n",w,*len); int nybl_waiting=0; int nybl_val=0; for(int j=0;w[j];j++) { int char_num; for(char_num=0;char_num=strlen(words[i])) { if ((packed_len-old_offset)>strlen(words[i])) fprintf(stderr," Packed word '%s' longer than original: ",words[i]); else fprintf(stderr," Packed word '%s' no smaller than original: ",words[i]); for(int j=old_offset;j=strlen(keyword_list[i])) { if ((packedkey_len-old_offset)>strlen(keyword_list[i])) fprintf(stderr," Packed word '%s' longer than original: ",keyword_list[i]); else fprintf(stderr," Packed word '%s' no smaller than original: ",keyword_list[i]); for(int j=old_offset;j255) { fprintf(stderr,"ERROR: packed_len>255\n"); exit(-1); } if (token_count>255) { fprintf(stderr,"ERROR: token_count>255\n"); exit(-1); } printf(".macro put_packed_chars()\n{\n"); for(int i=0;i=8) { printf("\t.byte $%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x\n", message_tokens[i+0],message_tokens[i+1],message_tokens[i+2],message_tokens[i+3], message_tokens[i+4],message_tokens[i+5],message_tokens[i+6],message_tokens[i+7]); i+=7; } else printf("\t.byte $%02x\n",message_tokens[i]); } printf("}\n"); printf(".macro put_packed_words()\n{\n"); for(int i=0;i=8) { printf("\t.byte $%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x\n", packed_words[i+0],packed_words[i+1],packed_words[i+2],packed_words[i+3], packed_words[i+4],packed_words[i+5],packed_words[i+6],packed_words[i+7]); i+=7; } else printf("\t.byte $%02x\n",packed_words[i]); } printf("}\n"); printf(".macro put_packed_keywords()\n{\n"); for(int i=0;i=8) { printf("\t.byte $%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x\n", packed_keywords[i+0],packed_keywords[i+1],packed_keywords[i+2],packed_keywords[i+3], packed_keywords[i+4],packed_keywords[i+5],packed_keywords[i+6],packed_keywords[i+7]); i+=7; } else printf("\t.byte $%02x\n",packed_keywords[i]); } printf("}\n"); printf(".label packed_keyword_table_len = $%X\n",packedkey_len); fprintf(stderr,"Error list takes %d bytes raw.\n",raw_size); fprintf(stderr,"%d token bytes used to encode all messages.\n",token_count); fprintf(stderr,"Plus %d bytes for the words\n",packed_len); fprintf(stderr,"Space saving = %d bytes\n",raw_size-packed_len-token_count); fprintf(stderr,"\nKeyword list takes %d bytes raw.\n",keyraw_size); fprintf(stderr,"Keyword list takes %d bytes packed.\n",packedkey_len); }