Added 10 more gists.
This commit is contained in:
1
ts.c/README.md
Normal file
1
ts.c/README.md
Normal file
@@ -0,0 +1 @@
|
||||
A naive interpreter for the Toadskin esoteric language: [https://esolangs.org/wiki/Toadskin](https://esolangs.org/wiki/Toadskin)
|
236
ts.c/ts.c
Normal file
236
ts.c/ts.c
Normal file
@@ -0,0 +1,236 @@
|
||||
/***************************************************************************
|
||||
* This is free and unencumbered software released into the public domain. *
|
||||
* *
|
||||
* Anyone is free to copy, modify, publish, use, compile, sell, or *
|
||||
* distribute this software, either in source code form or as a compiled *
|
||||
* binary, for any purpose, commercial or non-commercial, and by any *
|
||||
* means. *
|
||||
* *
|
||||
* In jurisdictions that recognize copyright laws, the author or authors *
|
||||
* of this software dedicate any and all copyright interest in the *
|
||||
* software to the public domain. We make this dedication for the benefit *
|
||||
* of the public at large and to the detriment of our heirs and *
|
||||
* successors. We intend this dedication to be an overt act of *
|
||||
* relinquishment in perpetuity of all present and future rights to this *
|
||||
* software under copyright law. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
|
||||
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
|
||||
* OTHER DEALINGS IN THE SOFTWARE. *
|
||||
* *
|
||||
* For more information, please refer to <http://unlicense.org/> *
|
||||
***************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define STACK_SIZE 40
|
||||
#define DICT_SIZE 128
|
||||
#define MAX_PROC 513
|
||||
#define JMP_SIZE 1024
|
||||
|
||||
// Procedure dictionary.
|
||||
typedef struct DICTIONARY_ENTRY {
|
||||
char code[MAX_PROC];
|
||||
} entry_t;
|
||||
|
||||
entry_t dictionary[DICT_SIZE];
|
||||
|
||||
// Argument stack.
|
||||
unsigned char stack[STACK_SIZE];
|
||||
unsigned char * sp = stack;
|
||||
|
||||
// Jump stack
|
||||
long jump[JMP_SIZE];
|
||||
long * jp = jump;
|
||||
|
||||
// Argument register.
|
||||
unsigned char arg = 0;
|
||||
|
||||
// Program counter and instruction register.
|
||||
char ir;
|
||||
|
||||
// Execute simple instructions.
|
||||
void execute(char c) {
|
||||
unsigned char aux;
|
||||
int i;
|
||||
|
||||
switch (c) {
|
||||
case '+':
|
||||
// ADD
|
||||
arg++;
|
||||
break;
|
||||
case '-':
|
||||
// SUB
|
||||
arg--;
|
||||
break;
|
||||
case '<':
|
||||
// PUSH
|
||||
*sp++ = arg;
|
||||
arg = 0;
|
||||
sp = (sp >= &stack[STACK_SIZE]) ? (sp = stack) : sp;
|
||||
break;
|
||||
case '>':
|
||||
// POP
|
||||
arg = *--sp;
|
||||
sp = (sp < stack) ? (sp = &stack[STACK_SIZE - 1]) : sp;
|
||||
break;
|
||||
case '.':
|
||||
// PRINT
|
||||
fputc((int)arg, stdout);
|
||||
fflush(stdout);
|
||||
break;
|
||||
case ',':
|
||||
// READ
|
||||
arg = (unsigned char)fgetc(stdin);
|
||||
break;
|
||||
case '%':
|
||||
// SWAP
|
||||
aux = *sp;
|
||||
*sp = *(sp - 1);
|
||||
*(sp - 1) = aux;
|
||||
break;
|
||||
default:
|
||||
// Check if the character is a procedure name, otherwise ignore it.
|
||||
if ((unsigned char)c < 128 && strlen(dictionary[c].code) > 0) {
|
||||
for (i = 0; dictionary[c].code[i]; i++)
|
||||
execute(dictionary[c].code[i]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
unsigned char aux;
|
||||
char key, inst;
|
||||
int i, lc;
|
||||
|
||||
// Check if there is an input file.
|
||||
if (argc == 1) {
|
||||
fprintf(stderr, "%s: fatal error: no input files\n", argv[0]);
|
||||
fprintf(stderr, "Usage: %s FILE\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Clean initial memory.
|
||||
memset(stack, 0, STACK_SIZE * sizeof(char));
|
||||
memset(jump, 0, JMP_SIZE * sizeof(long));
|
||||
memset(dictionary, 0, DICT_SIZE * sizeof(entry_t));
|
||||
|
||||
FILE * prog = fopen(argv[1], "r");
|
||||
if (prog != NULL) {
|
||||
ir = (char)fgetc(prog);
|
||||
|
||||
while (!feof(prog)) {
|
||||
switch (ir) {
|
||||
case '+': // ADD
|
||||
case '-': // SUB
|
||||
case '>': // POP
|
||||
case '<': // PUSH
|
||||
case '.': // PRINT
|
||||
case ',': // READ
|
||||
case '%': // SWAP
|
||||
// Execute these instructions directly.
|
||||
execute(ir);
|
||||
break;
|
||||
|
||||
case ':': // Define procedure.
|
||||
// Read procedure name and check if it's valid.
|
||||
key = (char)fgetc(prog);
|
||||
if ((unsigned char)key > 128) {
|
||||
fprintf(stderr, "%s: runtime error: invalid procedure name 0x%X\n", argv[0], (int)key);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// Read procedure code.
|
||||
i = 0;
|
||||
for (inst = (char)fgetc(prog); inst != ';'; inst = (char)fgetc(prog)) {
|
||||
// Check if code is not too long.
|
||||
if (i >= MAX_PROC) {
|
||||
fprintf(stderr, "%s: runtime error: procedure %c too long\n", argv[0], key);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// Check for premature EOF.
|
||||
if (feof(prog)) {
|
||||
fprintf(stderr, "%s: runtime error: premature EOF while reading procedure %c\n", argv[0], key);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// Save instruction.
|
||||
dictionary[key].code[i++] = inst;
|
||||
}
|
||||
break;
|
||||
|
||||
case '[': // Loop start.
|
||||
// Check value of the Argument register.
|
||||
if (arg) {
|
||||
// If not zero then add this loop's address to the jump stack.
|
||||
*jp = ftell(prog) - 1;
|
||||
jp++;
|
||||
// Check for loop stack overflow.
|
||||
if (jp >= &jump[JMP_SIZE]) {
|
||||
fprintf(stderr, "%s: runtime error: too many nested loops\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Nested loop counter.
|
||||
lc = 1;
|
||||
// If not zero then read the instruction stream until the matching ] is found.
|
||||
inst = (char)fgetc(prog);
|
||||
while (!feof(prog)) {
|
||||
if (inst == '[')
|
||||
lc++;
|
||||
else if (inst == ']')
|
||||
lc--;
|
||||
if (lc == 0)
|
||||
break;
|
||||
inst = (char)fgetc(prog);
|
||||
}
|
||||
|
||||
// Check for premature EOF.
|
||||
if (feof(prog)) {
|
||||
fprintf(stderr, "%s: runtime error: premature EOF\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ']': // Loop end.
|
||||
// Check for loop stack underflow.
|
||||
if (jp <= jump) {
|
||||
fprintf(stderr, "%s: runtime error: mismatched ]\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// Pop the loop address from the stack and jump.
|
||||
fseek(prog, *--jp, SEEK_SET);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Check if the character is a procedure name, otherwise ignore it.
|
||||
if ((unsigned char)ir < 128 && strlen(dictionary[ir].code) > 0) {
|
||||
for (i = 0; dictionary[ir].code[i]; i++)
|
||||
execute(dictionary[ir].code[i]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Fetch next instruction.
|
||||
ir = (char)fgetc(prog);
|
||||
}
|
||||
|
||||
fclose(prog);
|
||||
|
||||
} else {
|
||||
// Bad stuff happened!
|
||||
perror("bad input");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Reference in New Issue
Block a user