git @ Cat's Eye Technologies Dipple / master c / stringie.c
master

Tree @master (Download .tar.gz)

stringie.c @masterraw · history · blame

/*
 * stringie.c -- a brain-freezingly pedantic implementation of Underload in C
 * (with all the limitations that that implies)
 * Chris Pressey, September 2010
 *
 * SPDX-FileCopyrightText: Chris Pressey, the original author of this work, has dedicated it to the public domain.
 * For more information, please refer to <https://unlicense.org/>
 * SPDX-License-Identifier: Unlicense
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct stack {
    char *string;
    struct stack *next;
} *root;

void run(char *);

char *pop(void)
{
    char *r;
    struct stack *old;
    r = root->string;
    old = root;
    root = root->next;
    free(old);
    return r;
}

void push(char *string)
{
    struct stack *s;
    s = malloc(sizeof(struct stack));
    s->next = root;
    s->string = string;
    root = s;
}

void dup(void)
{
    char *e, *f;
    e = pop();
    f = strdup(e);
    push(e);
    push(f);
}

void swap(void)
{
    char *e, *f;
    e = pop();
    f = pop();
    push(e);
    push(f);
}

void eval(void)
{
    char *e;
    e = pop();
    run(e);
}

void concat(void)
{
    char *e, *f, *g;
    e = pop();
    f = pop();
    g = malloc(strlen(e) + strlen(f) + 1);
    strcpy(g, f);
    strcat(g, e);
    push(g);
    free(f);
    free(e);
}

void enclose(void)
{
    char *e, *g;
    e = pop();
    g = malloc(strlen(e) + 3);
    sprintf(g, "(%s)", e);
    push(g);
    free(e);
}

void output(void)
{
    char *e;
    e = pop();
    printf("%s", e);
    free(e);
}

void dumpstack(void)
{
    struct stack *s;
    
    fprintf(stderr, "STACK: ");
    for (s = root; s != NULL; s = s->next)
    {
        fprintf(stderr, "(%s)", s->string);
    }
    fprintf(stderr, "!\n");
}

void run(char *program)
{
    int i = 0;
    int last_pos = strlen(program) - 1;
    for (i = 0; program[i] != '\0'; i++) {
        switch (program[i]) {
            case ':': dup(); break;
            case '!': pop(); break;
            case '^':
              {
                /* tail recursion */
                if (i == last_pos) {
                    i = -1;
                    free(program);
                    program = pop();
                    continue;
                } else {
                    eval();
                }
              }
              break;
            case '~': swap(); break;
            case '*': concat(); break;
            case 'S': output(); break;
            case 'a': enclose(); break;
            case '(':
              {
                int level = 0;
                int j = 0;
                char *t = malloc(256);

                i++;
                level++;
                while (level > 0) {
                    if (program[i] == '(')
                        level++;
                    else if (program[i] == ')')
                        level--;
                    if (level > 0) {
                        t[j] = program[i];
                        j++;
                    }
                    i++;
                }
                i--;
                t[j] = '\0';
                push(t);
              }
              break;
        }
        /*dumpstack();*/
    }
    free(program);
}

int main(int argc, char **argv)
{
    char *program = strdup(argv[1]);
    root = NULL;
    run(program);
    exit(0);
}