Posted by: Buttsex Aug 22 2009, 04:59 PM
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.
Posted by: mipadi Aug 24 2009, 01:05 PM
So how does it work? At first I assumed that the bit-flipping operations turned single bits in a byte on/off, and that the strings were encoded using ASCII, but that doesn't seem to be the case.
Posted by: Buttsex Aug 24 2009, 04:31 PM
The bit-flipping operations turn single bits on and off.
+ = 1 and - = 0, and the strings translate directly from binary to ascii.
Posted by: mipadi Aug 24 2009, 07:08 PM
Oh, I see. I was looking for an encoded "~", but there isn't one (I guess that's just assumed).
Posted by: jcp Aug 24 2009, 07:28 PM
How do you run it? And where is the file created?
Posted by: Buttsex Aug 24 2009, 07:29 PM
QUOTE
.[->+>+>->+>->->->->+>+>->->+>->+>->+>+>->+>+>->->->+>+>->+>+>->->->+>+>->+>+>+>+>->->+>->->->->->->+>+>+>->+>+>->+>+>->+>+>+>+>->+>+>+>->->+>->->+>+>->+>+>->->->+>+>->->+>->->->->+>->->->->+]~[->+>+>+>+>+>+>->->->+>->+>+>+>+>->+>+>->+>->->->->+>+>->->+>->+>->+>+>->+>+>->->->+>+>->+>+>->->->+>+>->+>+>+>+>->+>+>+>->+>+>+>->+>+>->+>+>+>+>->+>+>+>->->+>->->+>+>->+>+>->->->+>+>->->+>->->->->+>->+>+>+>->->+>+>+>->+>->->->+>+>+>+>->->->->+>+>+>->+>->-]
fyi
also joseph, you need to write a compiler or an instruction set for a virtual machine.
Posted by: mipadi Aug 24 2009, 07:33 PM
QUOTE(Buttsex @ Aug 24 2009, 08:29 PM)
fyi
No, I misread the post and thought the location of the file came first, not the other way around.
Posted by: Buttsex Aug 24 2009, 07:39 PM
Oh, alright. Makes sense.
Posted by: mipadi Aug 24 2009, 10:31 PM
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: http://bit.ly/2nRa8V (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.
Posted by: jcp Aug 24 2009, 10:56 PM
PHP:
CODE
<?php
Print "Hello, World!";
?>
HTML:
CODE
<html><head><title></title></head><body>Hello, World!</body></html>
java script:
CODE
<script type="text/javascript">
document.write('<b>Hello World</b>');
</script>
Text format:
Hello, World!
Im hardcore. Win?
Posted by: mipadi Oct 29 2009, 02:18 PM
Boring day at work, wrote a Python version of the Buttfuck VM:
CODE
#!/usr/bin/env python
import os
import sys
class Buttf*ckToken(object):
TYPES = ("STRING", "LOCATION", "EOF", "ERROR")
def __init__(self, type, line, col, val=None):
if type not in Buttf*ckToken.TYPES:
raise ValueError("type must be one of %s" %
", ".join(Buttf*ckToken.TYPES))
self.type = type
self.line = line
self.col = col
self.val = val
def __str__(self):
if self.val:
return "%s(%s)" % (self.type, self.val)
else:
return "%s [%d]" % (self.type, self.line)
class Buttf*ckTokenizer(object):
def __init__(self, stream):
self.stream = stream
self.line = 0
self.col = 0
self.buffer = []
def getc(self):
if self.buffer:
ch = self.buffer[0]
self.buffer = self.buffer[1:]
else:
ch = self.stream.read(1)
self.col += 1
if not ch:
ch = '\'
elif ch == '\t':
ch = ' '
self.col += 7
elif ch == '\n':
ch = ' '
self.line += 1
return ch
def ungetc(self, ch):
self.buffer.append(ch)
def next(self):
state = "START"
buf = ""
bitpos = 0
masked = 0
tkntype = None
while state != "DONE":
ch = self.getc()
if state == "START":
if ch == '\':
state = "DONE"
tkn = Buttf*ckToken("EOF", self.line, self.col)
elif ch == '.':
state = "START"
elif ch == '[':
state = "STRING"
elif ch == '~':
state = "TILDE"
else:
state = "ERROR"
buf += ch
elif state == "DATA":
if ch == '[':
state = "DATA"
elif ch == '>':
bitpos += 1
if bitpos > 7:
buf += chr(masked)
bitpos = 0
masked = 0
bitmask = 2 ** (7 - bitpos)
elif ch == '+':
state = "DATA"
masked |= (0xffffffff & bitmask)
elif ch == '-':
state = "DATA"
masked |= (0x0 & bitmask)
elif ch == ']':
state = "DONE"
buf += chr(masked)
tkn = Buttf*ckToken(tkntype, self.line, self.col)
else:
state = "ERROR"
buf += ch
elif state == "TILDE":
if ch == '[':
state = "LOCATION"
else:
state = "ERROR"
buf += ch
elif state == "STRING":
state = "DATA"
tkntype = "STRING"
elif state == "LOCATION":
state = "DATA"
tkntype = "LOCATION"
elif state == "ERROR":
if ch == '\':
state = "DONE"
tkn = Buttf*ckToken("ERROR", self.line, self.col)
else:
buf += ch
else:
assert False, "Invalid state: " + state
tkn.val = buf
return tkn
class Buttf*ckParser(object):
def __init__(self, tokenizer):
self.tokenizer = tokenizer
self.path = None
self.str = None
def parse(self):
self._parse_string()
self._parse_location()
perror("Path: " + self.path)
perror("String: " + self.str)
self.path = os.path.expanduser(self.path)
self.path = os.path.realpath(self.path)
with open(self.path, "w") as fh:
fh.write(self.str)
return True
def _parse_string(self):
tkn = self.tokenizer.next()
if tkn.type == "STRING":
self.str = tkn.val
else:
perror("Error: Line %d, Col %d" % (tkn.line, tkn.col))
def _parse_location(self):
tkn = self.tokenizer.next()
if tkn.type == "LOCATION":
self.path = tkn.val
elif tkn.type == "EOF":
pass
else:
perror("Error: Line %d, Col %d" % (tkn.line, tkn.col))
def perror(msg):
print >>sys.stderr, "buttf*ck: " + msg
def main(argv):
if len(argv) > 0:
try:
stream = open(argv[0])
except IOError as e:
perror(str(e))
return 1
else:
stream = sys.stdin
parser = Buttf*ckParser(Buttf*ckTokenizer(stream))
if parser.parse():
stream.close()
return 0
else:
stream.close()
return 2
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
Source: http://bit.ly/1VziXB (usual problem with the URL applies)
Posted by: Cristy Oct 29 2009, 08:24 PM
QUOTE(mipadi @ Oct 29 2009, 03:18 PM)
Source: http://mipadi.cbstaff.com/code/buttf*ck.py (usual problem with the URL applies)
Use a URL shortener, like http://bit.ly?
Posted by: mipadi Oct 29 2009, 10:36 PM
QUOTE(Cristy @ Oct 29 2009, 09:24 PM)
Use a URL shortener, like http://bit.ly?
I thought those were only used to disguise really nasty porn links.
Posted by: jcp Oct 29 2009, 10:39 PM
QUOTE(mipadi @ Oct 29 2009, 10:36 PM)
I thought those were only used to disguise really nasty porn links.
not only that. maybe you should get
https://addons.mozilla.org/en-US/firefox/addon/2207
whats so wrong tinyurl?
Posted by: mipadi Oct 29 2009, 11:29 PM
Ha!
Well, I used bit.ly to generate better URLs.
Posted by: mipadi Nov 8 2009, 01:50 AM
Wrote one for Ruby. Thought I'd have more fun with the Ruby version, so I used http://treetop.rubyforge.org/ to generate a grammar.
Here's the grammar (buttf*ck.tt):
CODE
grammar Buttf*ck
rule program
'.[' string ']~[' location ']'
end
rule string
bit+
end
rule location
bit+
end
rule bit
[+-] '>'?
end
end
And here's the program that uses that grammar to parse a file (bf.rb):
CODE
#!/usr/bin/env ruby
require 'rubygems'
require 'treetop'
require 'buttf*ck'
class String
def from_buttf*ck
data = {:bitpos => 0, :masked => 0, :bitmask => 0}
buf = ''
each_char do |ch|
case ch
when '>'
data[:bitpos] += 1
if data[:bitpos] > 7
buf << data[:masked]
data[:bitpos] = 0
data[:masked] = 0
end
data[:bitmask] = 2 ** (7 - data[:bitpos])
when '+'
data[:masked] |= (0xffffffff & data[:bitmask])
when '-'
data[:masked] |= (0x0 & data[:bitmask])
end
end
buf
end
def to_path
File.expand_path self
end
end
if $0 == __FILE__
if $*.length < 1
$stderr.puts 'Usage: ruby bf.rb file.bf'
exit 1
end
string = nil
location = nil
open($*[0], 'r') do |fh|
nodes = Buttf*ckParser.new.parse fh.read.strip
string = nodes.string.text_value.from_buttf*ck
location = nodes.location.text_value.from_buttf*ck
end
open(location.to_path, 'w') { |fh| fh.print string }
end
Grammar: http://bit.ly/1OQtEF
Source: http://bit.ly/22USGV
Posted by: superstitious Nov 8 2009, 02:38 PM
I honestly don't know what any of this means, but it sure is funny reading all this code with "buttf*ck" being used throughout. hahaha