/* A simple F*ckf*ck to C converter, v0.1 Copyright 2003 Julian Graham This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include char *output_buffer = NULL; int indent = 0; enum ff2c_states { WAITING_FOR_KEYWORD, WAITING_FOR_SECOND_CHAR, WAITING_FOR_THIRD_CHAR, WAITING_FOR_LAST_CHAR, WAITING_FOR_REPEAT_CHAR, WAITING_FOR_COMMENT_STAR, COMMENT, COMMENT_WAITING_FOR_COMMENT_SLASH }; enum ff2c_errors { ILLEGAL_BANG, ILLEGAL_FLIW }; enum ff_keywords { NONE, FUCK, SHAG, TITS, BOOB_OR_BUTT, BOOB, BUTT, COCK, KNOB, ARSE }; void add_to_buffer (const char *addendum) { static int buffer_length = 0; int addendum_length = strlen(addendum); int i; output_buffer = realloc(output_buffer, buffer_length + addendum_length + indent + 1); for (i = 0; i < indent; i++) output_buffer = strcat(output_buffer, " "); output_buffer = strcat(output_buffer, addendum); buffer_length += addendum_length + indent; return; } void expand (int fliw, int repeat_count) { char *sprint_buffer = calloc (80, sizeof(char)); switch(fliw) { case FUCK: (void) snprintf(sprint_buffer, 80, "f_ptr = (f_ptr + %d) %% mem_size;\n", repeat_count + 1); add_to_buffer(sprint_buffer); break; case SHAG: (void) snprintf(sprint_buffer, 80, "f_ptr = (f_ptr - %d) %% mem_size;\n", repeat_count + 1); add_to_buffer(sprint_buffer); break; case BOOB: (void) snprintf(sprint_buffer, 80, "memory[f_ptr] = (memory[f_ptr] + %d) %% mem_size;\n", repeat_count + 1); add_to_buffer(sprint_buffer); break; case TITS: (void) snprintf(sprint_buffer, 80, "memory[f_ptr] = (memory[f_ptr] - %d) %% mem_size;\n", repeat_count + 1); add_to_buffer(sprint_buffer); break; case COCK: if (repeat_count > 0) { (void) snprintf(sprint_buffer, 80, "for (i = 0; i < %d; i++) {\n", repeat_count + 1); add_to_buffer(sprint_buffer); indent += 2; } add_to_buffer("printf(\"%%c\", memory[f_ptr]);\n"); if (repeat_count > 0) { indent -= 2; add_to_buffer("}\n"); } break; case KNOB: if (repeat_count > 0) { (void) snprintf(sprint_buffer, 80, "for (i = 0; i < %d; i++) {\n", repeat_count + 1); add_to_buffer(sprint_buffer); indent += 2; } add_to_buffer("temp_char = get_char();\n"); add_to_buffer("if (temp_char == EOF)\n"); indent += 2; add_to_buffer("temp_char = 0;\n"); indent -= 2; if (repeat_count > 0) { indent -= 2; add_to_buffer("}\n"); } add_to_buffer("memory[f_ptr] = temp_char;\n"); break; case ARSE: add_to_buffer("while(memory[f_ptr]) {\n"); indent += 2; break; case BUTT: indent -= 2; add_to_buffer("}\n"); break; } free(sprint_buffer); return; } int bad_exit(int reason, int line_num) { switch(reason) { case ILLEGAL_FLIW: fprintf(stderr, "Illegal FLIW at line %d.\n", line_num); break; case ILLEGAL_BANG: fprintf(stderr, "'!' may not be applied to the FLIW at line %d.\n", line_num); break; default: fprintf(stderr, "Unknown error at line %d.\n", line_num); } return 1; } int main (int argc, char *argv[]) { int line_num = 1; int repeat_count = 0; int ff_state_backup; int ff_state = WAITING_FOR_KEYWORD; char input_char; int expected_keyword; int last_fliw; int input; char *tiny_string = calloc(2, sizeof(char)); add_to_buffer("#include \n"); add_to_buffer("#include \n\n"); add_to_buffer("const int mem_size = 1048576;\n\n"); add_to_buffer("int main (int argc, char *argv[]) {\n"); indent += 2; add_to_buffer ("unsigned char *memory = calloc(mem_size, sizeof(char));\n"); add_to_buffer("int f_ptr = 0;\n"); add_to_buffer("int i = 0;\n\n"); while(1) { input = getchar(); if (input == EOF) break; input_char = (char) input; if (input_char == '\n') { line_num++; continue; } switch(ff_state) { case WAITING_FOR_REPEAT_CHAR: if (isspace(input_char)) continue; if (input_char == '!') { repeat_count++; } else { expand(last_fliw, repeat_count); ungetc(input_char, stdin); ff_state = WAITING_FOR_KEYWORD; } break; case WAITING_FOR_KEYWORD: if (isspace(input_char)) continue; switch(tolower(input_char)) { case 'f': expected_keyword = FUCK; ff_state = WAITING_FOR_SECOND_CHAR; break; case 's': expected_keyword = SHAG; ff_state = WAITING_FOR_SECOND_CHAR; break; case 'b': expected_keyword = BOOB_OR_BUTT; ff_state = WAITING_FOR_SECOND_CHAR; break; case 't': expected_keyword = TITS; ff_state = WAITING_FOR_SECOND_CHAR; break; case 'c': expected_keyword = COCK; ff_state = WAITING_FOR_SECOND_CHAR; break; case 'k': expected_keyword = KNOB; ff_state = WAITING_FOR_SECOND_CHAR; break; case 'a': expected_keyword = ARSE; ff_state = WAITING_FOR_SECOND_CHAR; break; case '!': return bad_exit(ILLEGAL_BANG, line_num); break; case '/': ff_state_backup = ff_state; ff_state = WAITING_FOR_COMMENT_STAR; break; default: return bad_exit(ILLEGAL_FLIW, line_num); } break; case WAITING_FOR_SECOND_CHAR: if (isspace(input_char)) continue; ff_state = WAITING_FOR_THIRD_CHAR; break; case WAITING_FOR_THIRD_CHAR: if (isspace(input_char)) continue; ff_state = WAITING_FOR_LAST_CHAR; break; case WAITING_FOR_LAST_CHAR: if (isspace(input_char)) continue; switch(tolower(input_char)) { case 'k': if (expected_keyword == FUCK) { last_fliw = FUCK; repeat_count = 0; ff_state = WAITING_FOR_REPEAT_CHAR; break; } if (expected_keyword == COCK) { last_fliw = COCK; repeat_count = 0; ff_state = WAITING_FOR_REPEAT_CHAR; } else return bad_exit(ILLEGAL_FLIW, line_num); break; case 'g': if (expected_keyword == SHAG) { last_fliw = SHAG; repeat_count = 0; ff_state = WAITING_FOR_REPEAT_CHAR; } else return bad_exit(ILLEGAL_FLIW, line_num); break; case 'b': if (expected_keyword == BOOB_OR_BUTT) { last_fliw = BOOB; repeat_count = 0; ff_state = WAITING_FOR_REPEAT_CHAR; break; } if (expected_keyword == KNOB) { last_fliw = KNOB; repeat_count = 0; ff_state = WAITING_FOR_REPEAT_CHAR; } else return bad_exit(ILLEGAL_FLIW, line_num); break; case 's': if (expected_keyword == TITS) { last_fliw = TITS; repeat_count = 0; ff_state = WAITING_FOR_REPEAT_CHAR; } else return bad_exit(ILLEGAL_FLIW, line_num); break; case 'e': if (expected_keyword == ARSE) { expand(ARSE, 0); last_fliw = ARSE; ff_state = WAITING_FOR_KEYWORD; } else return bad_exit(ILLEGAL_FLIW, line_num); break; case 't': if (expected_keyword == BOOB_OR_BUTT) { expand(BUTT, 0); last_fliw = BUTT; ff_state = WAITING_FOR_KEYWORD; } else return bad_exit(ILLEGAL_FLIW, line_num); break; default: return bad_exit(ILLEGAL_FLIW, line_num); } break; case WAITING_FOR_COMMENT_STAR: if (input_char == '*') { ff_state = COMMENT; add_to_buffer("/*"); } else return bad_exit(ILLEGAL_FLIW, line_num); break; case COMMENT: if (input_char == '*') ff_state = COMMENT_WAITING_FOR_COMMENT_SLASH; else { int indent_backup = indent; tiny_string[0] = (char) 0; indent = 0; (void) snprintf(tiny_string, 2, "%c", input_char); add_to_buffer(tiny_string); indent = indent_backup; } break; case COMMENT_WAITING_FOR_COMMENT_SLASH: if (input_char == '/') { ff_state = ff_state_backup; add_to_buffer("*/"); } else { int indent_backup = indent; ff_state = COMMENT; tiny_string[0] = (char) 0; indent = 0; (void) snprintf(tiny_string, 2, "*"); add_to_buffer(tiny_string); (void) snprintf(tiny_string, 2, "%c", input_char); add_to_buffer(tiny_string); indent = indent_backup; } break; } } add_to_buffer ("return 0;\n"); indent -= 2; add_to_buffer ("}\n"); printf("%s", output_buffer); free(output_buffer); return 0; }