all repos — xyw @ eb2365b3bdfc2a620e2da1a4975eab4b60910efe

A minimal virtual machine and assembler for terminals.

xyw.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
#include <stdio.h>
#include <string.h>
#include "xyw.h"

int xyw_debug = 0;
int xyw_argv_processed = 0;
char *xyw_argv[32];
int xyw_argc = 0;

// Instruction mnemonics definition
const char xyw_instructions[][4] = {
    "HLT", "NOP", "PSH", "POP",
    "LDB", "LDW", "STB", "STW",
    "INC", "DEC", "SHL", "SHR",
    "ADD", "SUB", "MUL", "DIV",
    "EQU", "NEQ", "GTH", "LTH",
    "NOT", "AND", "IOR", "XOR",
    "DUP", "SWP", "OVR", "ROT",
    "JMP", "JCN", "JSR", "RTS"};

int flag(const char *arg, const char *str)
{
    if (!str || !arg || !*str)
        return 0;
    if (strncmp(arg, "--", 2) == 0 && strcmp(arg + 2, str) == 0)
        return 1;
    if (arg[0] == '-' && arg[1] != '\0' && arg[2] == '\0' && arg[1] == str[0])
        return 1;
    return 0;
}

void print_help() {
    unsigned int v[2];
    v[0] = (XYW_VERSION >> 4) & 0xFFF; 
    v[1] = XYW_VERSION & 0xF;      
    printf("xyw v%03X-%X - (c) 2026 Fabio Cevasco\n\n", v[0], v[1]);
    printf("USAGE\n"
           "  xyw [options] <file>.[xyw|xim]\n"
           "\n"
           "ARGUMENTS\n"
           "  <file> The name of the file to process:\n"
           "   - a .xyw source file will be assembled into a .xim file.\n"
           "   - a .xim image file will be executed.\n"
           "\n"
           "OPTIONS\n"
           "  -d, --debug     Enable debug mode.\n"
           "  -v, --version   Display xyw version.\n"
           "  -h, --help      Print this message.\n");
}

int main(int argc, char *argv[])
{
    // First pass: detect flags
    for (int i = 1; i < argc; i++)
    {
        if (flag(argv[i], "debug"))
        {
            xyw_debug = 1;
        }
        if (flag(argv[i], "version"))
        {
            printf("%04X\n", XYW_VERSION);
            return 0;
        }
        if (flag(argv[i], "help"))
        {
            print_help();
            return 0;
        }

    }

    // Second pass: copy non-flag args into xyw_argv
    xyw_argc = 0;
    for (int i = 0; i < argc && xyw_argc < 32; i++)
    {
        if (i > 0 && (flag(argv[i], "debug") || flag(argv[i], "version") || flag(argv[i], "help")))
        {
            continue;
        }
        xyw_argv[xyw_argc++] = argv[i];
    }

    if (argc <= 1) {
        print_help();
        return 0;
    }

    for (int i = 1; i < argc; i++)
    {
        if (flag(argv[i], "debug") || flag(argv[i], "version") || flag(argv[i], "help"))
        {
            continue; // already handled
        }

        const char *input_file = argv[i];
        char output_file[256];
        const char *ext = strrchr(input_file, '.');
        if (ext && strcmp(ext, ".xyw") == 0)
        {
            snprintf(output_file, sizeof(output_file), "%.*s.xim", (int)(ext - input_file), input_file);
            if (xyw_assemble(input_file, output_file) != 0)
            {
                fprintf(stderr, "Assembly failed for file: %s\n", input_file);
                return -1;
            }
            else
            {
                if (xyw_debug)
                {
                    printf("Assembled %s to %s\n", input_file, output_file);
                }
            }
            break;
        }
        else if (ext && strcmp(ext, ".xim") == 0)
        {
            if (xyw_run(input_file) != 0)
            {
                fprintf(stderr, "Execution failed for file: %s\n", input_file);
                return -1;
            }
            break;
        }
    }
    return 0;
}