Log In · Register

 
scripting challenge, easy mode
heyo-captain-jac...
post Aug 22 2009, 04:59 PM
Post #1


/人◕‿‿◕人\
*******

Group: Official Member
Posts: 8,283
Joined: Dec 2007
Member No: 602,927



1. think up your own esoteric language.
2. write a hello world script with it.
3. explain the code.
4. show the output.
5. ???
6. profit!


Mine: a brainfuck-esque language that uses four commands and seven characters. Useful for learning binary in an extreme way.
CODE
.[->+>+>->+>->->->->+>+>->->+>->+>->+>+>->+>+>->->->+>+>->+>+>->->->+>+>->+>+>+>+>->->+>->->->->->->+>+>+>->+>+>->+>+>->+>+>+>+>->+>+>+>->->+>->->+>+>->+>+>->->->+>+>->->+>->->->->+>->->->->+]~[->+>+>+>+>+>+>->->->+>->+>+>+>+>->+>+>->+>->->->->+>+>->->+>->+>->+>+>->+>+>->->->+>+>->+>+>->->->+>+>->+>+>+>+>->+>+>+>->+>+>+>->+>+>->+>+>+>+>->+>+>+>->->+>->->+>+>->+>+>->->->+>+>->->+>->->->->+>->+>+>+>->->+>+>+>->+>->->->+>+>+>+>->->->->+>+>+>->+>->-]

This code creates "~/helloworld.txt" and writes "hello world!" to it.

.[(string)]~[(location)] = write (string) to (location)
- = turn bit off
+ = turn bit on
> = next bit





You can make a compiler if you really want to.
 
 
Start new topic
Replies
mipadi
post Aug 24 2009, 10:31 PM
Post #2


Senior Member
******

Group: Administrator
Posts: 2,648
Joined: Apr 2008
Member No: 639,265



I wrote an interpreter in C for this language. I've named the interpreter "buttf*ck" since this is a f*cked-up version of brainf*ck. The interpreter is pretty minimal. I made no attempt to write "good" code, I used unsafe C functions like strcpy(), and I made no attempt to free memory (but it gets freed after the program exits anyway). The parser also doesn't really report errors correctly, unless you compile a debug version. Oh, and in some cases it'll break on really large programs/strings. But here it is anyway, all 413 lines of sexy interpreter code:

CODE
/*
* buttf*ck.c - Interpreter for the Buttf*ck programming language.
* <http://www.createblog.com/forums/index.php?showtopic=240400>
* Compile:
*   $ gcc -o buttf*ck buttf*ck.c
*/

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


#define TKN_BUF_SIZE    256
#define MAX_PATH        256
#define FIRST_LINE      1
#define FIRST_COL       1


typedef enum {ERR_BAD_ARGS = 1, ERR_OUT_OF_MEMORY, ERR_BAD_FILE} bf_memory_error;
typedef enum {TKN_STRING = 0, TKN_LOCATION, TKN_EOF, TKN_ERROR} bf_token_type;
typedef enum {
    S_START, S_DONE, S_EOF, S_STRING,
    S_LOCATION, S_TILDE, S_DATA, S_ERROR
} bf_token_state;

const char *TOKEN_NAMES[] = {"STRING", "LOCATION", "EOF", "ERROR"};

#define PLUS_MASK   0xffffffff
#define MINUS_MASK  0x0

typedef struct {
    bf_token_type type;
    unsigned int line;
    unsigned int col;
    char *val;
} bf_token;

typedef struct {
    const char *path;
    FILE *stream;
    unsigned int line;
    unsigned int col;
} bf_tokenizer;

typedef struct {
    bf_tokenizer *stream;
    char *path;
    char *str;
} bf_parser;


static char *expand_tildes(char *origpath, char *newpath)
{
    char *home = NULL;
    char *xpath = NULL;
    home = getenv("HOME");
    xpath = strchr(origpath, '~');
    xpath++;
    sprintf(newpath, "%s%s", home, xpath);
    return newpath;
}


static bf_token *bf_create_token(bf_token_type type, unsigned int line, unsigned int col)
{
    bf_token *tkn = NULL;
    
    tkn = (bf_token *) malloc(sizeof(bf_token));
    if (!tkn) {
        perror("bf_create_token");
        exit(ERR_OUT_OF_MEMORY);
    }
    
    tkn->type = type;
    tkn->line = FIRST_LINE;
    tkn->col = FIRST_COL;
    tkn->val = NULL;
    
    return tkn;
}

static void bf_free_token(bf_token *t)
{
    free(t->val);
    free(t);
}


static char *bf_token_format(bf_token *t)
{
    char *s;
    
    s = (char *) malloc(64);
    if (!s) {
        perror("bf_token_format");
        exit(ERR_OUT_OF_MEMORY);
    }
    
    s = strcpy(s, TOKEN_NAMES[t->type]);
    
    if (t->val) {
        sprintf(s, "%s(%s)", s, t->val);
    }
    
    sprintf(s, "%s [%u]", s, t->line);
    
    return s;
}


static bf_tokenizer *bf_create_tokenizer(const char *path)
{
    bf_tokenizer *t = NULL;
    FILE *fh = NULL;
    
    t = (bf_tokenizer *) malloc(sizeof(bf_tokenizer));
    if (!t) {
        perror("bf_create_tokenizer");
        exit(ERR_OUT_OF_MEMORY);
    }
    
    t->path = path;
    fh = fopen(path, "r");
    if (!fh) {
        perror("bf_create_tokenizer");
        exit(ERR_BAD_FILE);
    }
    t->stream = fh;
    t->line = 0;
    t->col = 0;
    
    return t;
}


static void bf_free_tokenizer(bf_tokenizer *t)
{
    fclose(t->stream);
    t->stream = NULL;
    free(t);
}


static unsigned char bf_getc(bf_tokenizer *t)
{
    int c;
    c = getc(t->stream);
    
    t->col++;
    switch (c) {
    case '\t':
        c = ' ';
        t->col += 7;
        break;
    case '\n':
        c = ' ';
        t->line++;
        break;
    case EOF:
        c = '\';
        break;
    }
    
    return (unsigned char) c;
}


static unsigned char bf_ungetc(bf_tokenizer *t, unsigned char ch)
{
    int c;
    c = ungetc(ch, t->stream);
    return c != EOF ? (unsigned char) c : '\';
}


static bf_token *bf_next_token(bf_tokenizer *t)
{
    bf_token_type type;
    bf_token *tkn = NULL;
    bf_token_state state = S_START;
    char *buf = NULL;
    unsigned int bufpos = 0;
    unsigned int bitpos = 0;
    unsigned int masked = 0;
    unsigned int bitmask = 0;
    
    buf = (char *) malloc(TKN_BUF_SIZE);
    if (!buf) {
        perror("bf_next_token");
        exit(ERR_OUT_OF_MEMORY);
    }

    while (state != S_DONE) {
        unsigned char ch = bf_getc(t);
        switch (state) {
        case S_START:
            switch (ch) {
            case '\':
                state = S_DONE;
                tkn = bf_create_token(TKN_EOF, t->line, t->col);
                break;
            case '.':
                state = S_START;
                break;
            case '[':
                state = S_STRING;
                break;
            case '~':
                state = S_TILDE;
                break;
            default:
#ifdef DEBUG
                fprintf(stderr, "Error (START), expected EOF, '.', '[', or '~', got %c\n", ch);
#endif
                state = S_ERROR;
                buf[bufpos++] = ch;
                break;
            }
            break;
        
        case S_DATA:
            switch (ch) {
            case '[':
                state = S_DATA;
                break;
            case '>':
                bitpos++;
                if (bitpos > 7) {
                    unsigned char bc = (unsigned char) masked;
                    if (!isprint(bc)) {
                        fprintf(stderr, "Warning: non-printable character %#x, "
                                        "line %u, col %u\n",
                                bc, t->line, t->col);
                    }
                    buf[bufpos++] = bc;
                    bitpos = 0;
                    masked = 0;
                }
                bitmask = (unsigned int) pow(2, (7 - bitpos));
                break;
            case '+':
                state = S_DATA;
                masked |= (PLUS_MASK & bitmask);
                break;
            case '-':
                state = S_DATA;
                masked |= (MINUS_MASK & bitmask);
                break;
            case ']':
                state = S_DONE;
                buf[bufpos++] = (unsigned char) masked;
                tkn = bf_create_token(type, t->line, t->col);
                break;
            default:
#ifdef DEBUG
                fprintf(stderr, "Error (%s), expected '[', '>', '+', '-', ']', got %c\n",
                        (type == TKN_STRING ? "STRING" : "LOCATION"), ch);
#endif
                state = S_ERROR;
                buf[bufpos++] = ch;
                break;
            }
            break;
        
        case S_TILDE:
            switch (ch) {
            case '[':
                state = S_LOCATION;
                break;
            default:
#ifdef DEBUG
                fprintf(stderr, "Error, expected '~', got %c\n", ch);
#endif
                state = S_ERROR;
                buf[bufpos++] = ch;
                break;
            }
            break;
        
        case S_STRING:
            state = S_DATA;
            type = TKN_STRING;
            break;
        
        case S_LOCATION:
            state = S_DATA;
            type = TKN_LOCATION;
            break;
        
        case S_ERROR:
            if (ch == '\') {
                state = S_DONE;
                tkn = bf_create_token(TKN_ERROR, t->line, t->col);
            } else {
                buf[bufpos++] = ch;
            }
            break;
        }
    }
    
    buf[bufpos] = '\';     /* Terminate that string, son! */
    tkn->val = buf;
    
    return tkn;
}


static bf_parser *bf_create_parser(bf_tokenizer *t)
{
    bf_parser *p = NULL;
    
    p = (bf_parser *) malloc(sizeof(bf_parser));
    if (!p) {
        perror("bf_create_parser");
        exit(ERR_OUT_OF_MEMORY);
    }
    
    p->stream = t;
    p->path = NULL;
    p->str = NULL;
    
    return p;
}


static void bf_free_parser(bf_parser *p)
{
    bf_free_tokenizer(p->stream);
    free(p->path);
    free(p->str);
    free(p);
}


static void bf_parse_string(bf_parser *p)
{
    bf_token *t = NULL;
    
    t = bf_next_token(p->stream);
    switch (t->type) {
    case TKN_STRING:
        p->str = t->val;
        break;
    default:
        fprintf(stderr, "Error: Line %u, Col %u\n", t->line, t->col);
        break;
    }
}


static void bf_parse_location(bf_parser *p)
{
    bf_token *t = NULL;
    
    t = bf_next_token(p->stream);
    switch (t->type) {
    case TKN_LOCATION:
        p->path = t->val;
        break;
    case TKN_EOF:
        break;
    default:
        fprintf(stderr, "Error: Line %u, Col %u\n", t->line, t->col);
        break;
    }
}


static int bf_parser_run(bf_parser *p)
{
    FILE *fh = NULL;
    char path[MAX_PATH];
    size_t len = 0;
    
    bf_parse_string(p);
    bf_parse_location(p);

    fprintf(stderr, "Path:   %s\n", p->path);
    fprintf(stderr, "String: %s\n", p->str);
    
    expand_tildes(p->path, path);
    fh = fopen(path, "w");
    if (!fh) {
        perror("bf_parser_run");
        exit(ERR_BAD_FILE);
    }
    len = strlen(p->str);
    if (fwrite(p->str, len, 1, fh) < 1) {
        perror("bf_parser_run");
        exit(ERR_BAD_FILE);
    }
    fclose(fh);
    
    return 0;
}


int main(int argc, char **argv)
{
    bf_tokenizer *tokenizer = NULL;
    bf_parser *parser = NULL;
    
    if (argc < 2) {
        fprintf(stderr, "Usage: buttf*ck source.bf\n");
        exit(ERR_BAD_ARGS);
    }
    
    tokenizer = bf_create_tokenizer(argv[1]);
    parser = bf_create_parser(tokenizer);
    return bf_parser_run(parser);
}


Source file: buttf*ck.c (because CB's code box messes up the format a bit)
(That URL doesn't really have a '*' in it; I assume you know how to change it.)


P.S. Your code is a bit off in some places -- "hello, world!" isn't printed. "hello, v????B" is printed instead, where '?' are unprintable characters. I think the problem starts with the 'v' -- looks like you may have skipped a bit.

This post has been edited by mipadi: Oct 29 2009, 11:28 PM
Reason for edit: use bit.ly for urls
 

Posts in this topic


Reply to this topicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members: