git @ Cat's Eye Technologies Cfluviurrh / master src / cfluviurrh.c
master

Tree @master (Download .tar.gz)

cfluviurrh.c @masterraw · history · blame

/*
 * cfluviurrh.c
 * reference interpreter for
 * the Cfluviurrh programming language, version 1.0
 * Copyright (c)2012, Chris Pressey, Cat's Eye Technologies
 * covered under a BSD-style license: see LICENSE
 */

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

/*
 * Note that these are arbitrarily limited in this implementation --
 * the language itself does not impose limited on the number of
 * size of registers, or size of the program.
 */
#define MEMTYPE int
#define MEMSIZE 8000
#define PROGSIZE 8000

MEMTYPE mem[MEMSIZE];
char program[PROGSIZE];

/*
 * Prototypes
 */
void die(const char *, char);
MEMTYPE get_ref(char);
MEMTYPE get_val(char);
void advance_ip(const char **);
int is_whitespace(char);
int is_op(char);
MEMTYPE do_op(char, MEMTYPE, MEMTYPE);
MEMTYPE find_label(const char *, char);
void load_program(const char *);
void emote(MEMTYPE, MEMTYPE);
void contractually_obligate_emoter(void);

/*
 * Subroutines
 */
void
die(const char *msg, char c)
{
    fputs(msg, stderr);
    if (c != '\0') {
        fputs(": '", stderr);
        fputc(c, stderr);
        fputs("'", stderr);
    }
    fputs("\n", stderr);
    exit(1);
}

MEMTYPE
get_ref(char c)
{
    if (c >= 'a' && c <= 'z') {
        return (MEMTYPE)(c - 'a');
    } else if (c >= 'A' && c <= 'Z') {
        return mem[(MEMTYPE)(c - 'A')];
    } else {
        return -1;
    }
}

MEMTYPE
get_val(char c)
{
    int ref;

    if (c >= '0' && c <= '9') {
        return (MEMTYPE)(c - '0');
    }
    ref = get_ref(c);
    if (ref < 0 || ref >= MEMSIZE) {
        die("invalid register reference", c);
    }
    return mem[ref];
}

void
advance_ip(const char **c)
{
    (*c)++;
    if (**c == '\0') {
        die("premature end of program", (char)0);
    }
}

int
is_whitespace(char c)
{
    return c == ' ' || c == '\t' || c == '\n' || c == '\r';
}

int
is_op(char c)
{
    return c == '+' || c == '-' || c == '*' || c == '/' || c == '@';
}

MEMTYPE
do_op(char op, MEMTYPE lhs, MEMTYPE rhs)
{
    if (op == ' ') {
        return rhs;
    } else if (op == '+') {
        return lhs + rhs;
    } else if (op == '-') {
        return lhs - rhs;
    } else if (op == '*') {
        return lhs * rhs;
    } else if (op == '/') {
        return lhs / rhs;
    } else {
        return lhs;
    }
}

MEMTYPE
find_label(const char *s, char label)
{
    int i;

    for (i = 0; s[i] != '\0'; i++) {
        if (s[i] == ':' && s[i+1] == label) {
            return i;
        }
    }
    return -1;
}

void
load_program(const char *filename) {
    FILE *in;
    int i, c;

    if ((in = fopen(filename, "r")) == NULL) {
	perror("Can't open program file for reading");
	exit(1);
    }
    for (i = 0; i < (PROGSIZE-1) ; i++) {
        c = fgetc(in);
        if (c == EOF) {
            break;
        }
        program[i] = (char)c;
    }
    program[++i] = '\0';
    fclose(in);
}

/*
 * Emoting Subsystem
 */
#define EMOTIONSIZE 74
const char *emotion[] = {
    "sadness",
    "sorrow",
    "despair",
    "worry",
    "depression",
    "misery",
    "melancholy",
    "wistfulness",
    "disappointment",
    "regret",
    "longing",
    "impatience",
    "anger",
    "hostility",
    "rage",
    "hatred",
    "disgust",
    "contempt",
    "envy",
    "arrogance",
    "betrayal",
    "hurt",
    "grief",
    "remorse",
    "shame",
    "embarrassment",
    "guilt",
    "timidity",
    "loneliness",
    "annoyance",
    "frustration",
    "confusion",
    "shock",
    "angst",
    "anguish",
    "anxiety",
    "apathy",
    "vindication",
    "gratitude",
    "hope",
    "awe",
    "wonder",
    "surprise",
    "pity",
    "boredom",
    "apprehension",
    "distrust",
    "dread",
    "horror",
    "loathing",
    "terror",
    "panic",
    "hysteria",
    "pride",
    "anticipation",
    "curiosity",
    "boldness",
    "excitement",
    "thrill",
    "zeal",
    "enthusiasm",
    "calmness",
    "contentment",
    "satisfaction",
    "happiness",
    "bliss",
    "joy",
    "ecstasy",
    "euphoria",
    "admiration",
    "desire",
    "passion",
    "love",
    "lust"
};

#define INTENSITYSIZE 5
const char *intensity[] = {
    "faint", "mild", "moderate", "marked", "extreme"
};

void
emote(MEMTYPE e, MEMTYPE i)
{
    printf("[EMOTER: please genuinely experience %s %s and press Enter] ",
           intensity[i], emotion[e]);
    do {
        i = getchar();
    } while (i != '\n');
}

void
contractually_obligate_emoter(void)
{
    int c;

    printf(
      "[By running this program, you agree to act as the EMOTER.    ]\n"
      "[The EMOTER may be asked to perform certain limited tasks    ]\n"
      "[on behalf of this program, tasks that the system on which   ]\n"
      "[this program is running may not be capable of.              ]\n"
      "[In particular, you may be asked to express certain emotions.]\n"
      "[Your experience of these emotions must be genuine.          ]\n"
      "\n"
      "[Do you agree to act as the EMOTER?                          ]\n"
      "[If so, press the letter 'Y' on your keyboard, then Enter.   ] ");
    c = getchar();
    if (c != 'y' && c != 'Y') {
        printf("[Goodbye.]\n");
        exit(0);
    }
    while (c != '\n') {
        c = getchar();
    }
}

/*
 * Main
 */
int
main(int argc, char **argv)
{
    const char *ip;
    MEMTYPE ref, val, val2, result;
    char op;
    FILE *input, *output;

    if (argc < 4) {
        die("usage: cfluviurrh program-file input-file output-file", (char)0);
    }

    load_program(argv[1]);
    memset(mem, 0, MEMSIZE);

    if ((input = fopen(argv[2], "r")) == NULL) {
	perror("Can't open input file for reading");
	exit(1);
    }
    if ((output = fopen(argv[3], "w")) == NULL) {
	perror("Can't open output file for writing");
	exit(1);
    }

    contractually_obligate_emoter();

    ip = program;
    while (*ip) {
        ref = get_ref(*ip);
        if (ref >= 0) {
            op = ' ';
            advance_ip(&ip);
            if (is_op(*ip)) {
                op = *ip;
                advance_ip(&ip);
            }
            if (*ip == '=') {
                advance_ip(&ip);
                if (op == '@') {
                    val = find_label(program, *ip);
                    if (val < 0) {
                        die("undefined label", *ip);
                    }
                    mem[ref] = val;
                } else {
                    val = get_val(*ip);
                    mem[ref] = do_op(op, mem[ref], val);
                }
                ip++;
            } else if (*ip == '>') {
                fputc(mem[ref], output);
                fflush(output);
                ip++;
            } else if (*ip == '<') {
                mem[ref] = fgetc(input);
                ip++;
            } else if (*ip == '?') {
                advance_ip(&ip);
                val = get_val(*ip);
                advance_ip(&ip);
                op = *ip;
                advance_ip(&ip);
                val2 = get_val(*ip);

                if (op == '=') {
                    result = (val == val2);
                } else if (op == '>') {
                    result = (val > val2);
                } else if (op == '<') {
                    result = (val < val2);
                } else {
                    die("unimplemented relop", op);
                }
                {
                    int ix, ex, i;

                    for (ex = 0, i = 0; i < 26; i++) {
                        ex = (ex + mem[i]) % EMOTIONSIZE;
                    }
                    for (ix = 0, i = 0; i < 26; i++) {
                        ix += (mem[i] * 3) % INTENSITYSIZE;
                    }
                    ix %= INTENSITYSIZE;
                    emote(ex, ix);
                }
                if (result) {
                    ip = program + mem[ref];
                } else {
                    ip++;
                }
            } else {
                die("unimplemented operator", *ip);
            }
        } else if (is_whitespace(*ip)) {
            ip++;
        } else if (*ip == '(') {
            while (*ip != ')' && *ip != '\0') {
                ip++;
            }
            if (*ip == ')') {
                ip++;
            }
        } else if (*ip == ':') {
            ip += 2;
        } else {
            die("unimplemented instruction", *ip);
        }
    }

    return 0;
}