Last active
May 19, 2019 02:13
-
-
Save JoshCheek/d9b408bd15311785a2a5d83b4a646af5 to your computer and use it in GitHub Desktop.
Writing Ruby Like C (fun video of the process here: https://vimeo.com/336921852)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
typedef struct list { | |
char* data; | |
struct list* successor; | |
} List; | |
enum ACTIONS { | |
ACTION_PUSH_STRING = 1, | |
ACTION_POP_STRING = 2, | |
ACTION_QUIT = 3 | |
}; | |
// ---- list functions ----- | |
List* list_new() { | |
return NULL; | |
} | |
List* list_push(List* list, void* data) { | |
List* head = malloc(sizeof(List)); // this can technically fail | |
head->data = data; | |
head->successor = list; | |
return head; | |
} | |
void* list_data(List* list) { | |
return list ? list->data : NULL; | |
} | |
// Note that we do not manage the list's data. | |
// Caller is responsible for ensuring it has been freed. | |
List* list_pop(List* list) { | |
if(!list) return NULL; | |
List* successor = list->successor; | |
free(list); | |
return successor; | |
} | |
// ----- I/O functions ----- | |
#define BUFFER_MEMSIZE 1000 | |
char BUFFER[BUFFER_MEMSIZE]; | |
void clear_screen(FILE* outstream) { | |
fprintf(outstream, "\e[H\e[2J"); | |
} | |
void newline(FILE* outstream) { | |
fprintf(outstream, "\n"); | |
} | |
void list_print(List* list, FILE* outstream) { | |
fprintf(outstream, "----- Begin List -----\n"); | |
for(int i = 0; list; ++i) { | |
fprintf(outstream, "%d: %s\n", i, list->data); | |
list = list->successor; | |
} | |
fprintf(outstream, "----- End List -----\n"); | |
} | |
// summary: buffer = $stdin.gets.chomp | |
size_t read_line_into_buffer(FILE* instream) { | |
fgets(BUFFER, BUFFER_MEMSIZE, instream); | |
size_t len = strnlen(BUFFER, BUFFER_MEMSIZE); | |
while(len && '\n' == BUFFER[len-1]) | |
--len; | |
BUFFER[len] = 0; | |
return len; | |
} | |
int prompt_action(FILE* instream, FILE* outstream) { | |
fprintf(outstream, "Whatcha wanna do?!\n"); | |
fprintf(outstream, "1. push a string\n"); | |
fprintf(outstream, "2. pop\n"); | |
fprintf(outstream, "3. quit\n"); | |
fprintf(outstream, "> "); | |
size_t len = read_line_into_buffer(instream); | |
if(len == 1) { | |
int action = BUFFER[0] - '0'; | |
if(action == 1 || action == 2 || action == 3) | |
return action; | |
} | |
fprintf(outstream, "Invalid choice: %s\n", BUFFER); | |
return prompt_action(instream, outstream); | |
} | |
char* prompt_string(FILE* instream, FILE* outstream) { | |
fprintf(outstream, "Enter a string to store:\n"); | |
fprintf(outstream, "> "); | |
size_t len = read_line_into_buffer(instream); | |
char* str = malloc(sizeof(char)*len); | |
memcpy(str, BUFFER, len); | |
return str; | |
} | |
int main(int argc, char** argv) { | |
List* list = list_new(); | |
FILE* instream = stdin; | |
FILE* outstream = stdout; | |
while(true) { | |
clear_screen(outstream); | |
list_print(list, outstream); | |
newline(outstream); | |
int action = prompt_action(instream, outstream); | |
switch (action) { | |
case ACTION_PUSH_STRING: { | |
char* str = prompt_string(instream, outstream); | |
list = list_push(list, str); | |
break; | |
} case ACTION_POP_STRING: { | |
char* str = list_data(list); | |
list = list_pop(list); | |
fprintf(outstream, "String Popped: %s\n", str); | |
free(str); | |
break; | |
} case ACTION_QUIT: { | |
fprintf(outstream, "Cheers!\n"); | |
return 0; | |
} default: { | |
fprintf(outstream, "ERR: action = %d", action); | |
return 1; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
List = Struct.new( | |
:data, | |
:successor | |
); | |
module ACTIONS | |
PUSH_STRING = 1; | |
POP_STRING = 2; | |
QUIT = 3; | |
end; | |
# ---- list functions ----- | |
def list_new() | |
return nil; | |
end | |
def list_push(list, data) | |
head = List.new; | |
head.data = data; | |
head.successor = list; | |
return head; | |
end | |
def list_data(list) | |
return list ? list.data : nil; | |
end | |
def list_pop(list) | |
return nil if(!list); | |
return list.successor; | |
end | |
# ----- I/O functions ----- | |
def clear_screen(outstream) | |
outstream.printf("\e[H\e[2J"); | |
end | |
def newline(outstream) | |
outstream.printf("\n"); | |
end | |
def list_print(list, outstream) | |
outstream.printf("----- Begin List -----\n"); | |
for i in (0..Float::INFINITY) | |
break unless list | |
outstream.printf("%d: %s\n", i, list.data); | |
list = list.successor; | |
end | |
outstream.printf("----- End List -----\n"); | |
end | |
def read_line(instream) | |
str = instream.gets; | |
str.chomp!; | |
return str; | |
end | |
def prompt_action(instream, outstream) | |
outstream.printf("Whatcha wanna do?!\n"); | |
outstream.printf("1. push a string\n"); | |
outstream.printf("2. pop\n"); | |
outstream.printf("3. quit\n"); | |
outstream.printf("> "); | |
line = read_line(instream); | |
if (line.length == 1) | |
action = line[0].ord - '0'.ord; | |
if (action == 1 || action == 2 || action == 3) | |
return action; | |
end | |
end | |
outstream.printf("Invalid choice: %s\n", line); | |
return prompt_action(instream, outstream); | |
end | |
def prompt_string(instream, outstream) | |
outstream.printf("Enter a string to store:\n"); | |
outstream.printf("> "); | |
return read_line(instream); | |
end | |
def main(argc, argv) | |
list = list_new(); | |
instream = $stdin; | |
outstream = $stdout; | |
while(true) | |
clear_screen(outstream); | |
list_print(list, outstream); | |
newline(outstream); | |
action = prompt_action(instream, outstream); | |
case action | |
when ACTIONS::PUSH_STRING; | |
str = prompt_string(instream, outstream); | |
list = list_push(list, str); | |
when ACTIONS::POP_STRING; | |
str = list_data(list); | |
list = list_pop(list); | |
outstream.printf("String Popped: %s\n", str); | |
when ACTIONS::QUIT; | |
outstream.printf("Cheers!\n"); | |
return 0; | |
else | |
outstream.printf("ERR: action = %d", action); | |
return 1; | |
end | |
end | |
end | |
exit main(ARGV.size, ARGV); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment