├── .gitignore ├── Makefile ├── stack.h ├── morse.h ├── tokens.h ├── stack.c ├── README.md └── morse.c /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | a.out 3 | morse 4 | *.o 5 | 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: morse 2 | 3 | morse: stack.o morse.o 4 | gcc stack.o morse.o -o morse -lm 5 | 6 | stack.o: stack.c 7 | gcc -Wall -c stack.c 8 | 9 | morse.o: morse.c 10 | gcc -Wall -c morse.c 11 | 12 | clean: 13 | rm morse 14 | rm *.o -------------------------------------------------------------------------------- /stack.h: -------------------------------------------------------------------------------- 1 | #ifndef morse_stack 2 | 3 | #define morse_stack 1 4 | 5 | #include 6 | #include 7 | 8 | #define ERR_INT_STACK_EMPTY "Error: Empty Integer Stack.\n" 9 | #define ERR_CHAR_STACK_EMPTY "Error: Empty Integer Stack.\n" 10 | 11 | struct intNode { 12 | int data; 13 | struct intNode *next; 14 | } *intTop; 15 | 16 | struct charNode { 17 | char data; 18 | struct charNode *next; 19 | } *charTop; 20 | 21 | void initStacks(); 22 | int popInt(); 23 | int peekInt(); 24 | void pushInt(int); 25 | char popChar(); 26 | char peekChar(); 27 | void pushChar(char); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /morse.h: -------------------------------------------------------------------------------- 1 | #ifndef morse 2 | 3 | #define morse 1 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "stack.h" 11 | #include "tokens.h" 12 | 13 | #define ERR_FILE_OPEN "Error: Unable to openfile.\n" 14 | #define ERR_FILE_UNSPECIFIED "Error! No input file specified.\n" 15 | #define ERR_LINE_NOT_FOUND "Error: Line not found.\n" 16 | 17 | #define ERR_FILE_OPEN_CODE 1 18 | #define ERR_LINE_NOT_FOUND_CODE 2 19 | 20 | size_t lineLen = 0; 21 | ssize_t read; 22 | FILE *fp; 23 | int lineNum; 24 | 25 | char *readLine(); 26 | void openFile(char*); 27 | void parseTokens(char*); 28 | char *str_replace(char*, char*, char*); 29 | int parseInt(char*); 30 | int binary_decimal(int); 31 | void jumpLine(char*); 32 | 33 | #endif -------------------------------------------------------------------------------- /tokens.h: -------------------------------------------------------------------------------- 1 | #ifndef morse_token 2 | 3 | #define morse_token 1 4 | 5 | #define PUSH_TO_INT_STACK 0 // . 6 | #define DUPL_TOP_OF_INT_STACK 1 // _ 7 | #define SWAP_INT_STACK_ITEMS 2 // _. 8 | #define POP_FROM_INT_STACK 3 // __ 9 | 10 | #define PUSH_TO_CHAR_STACK 4 // _.. 11 | #define DUPL_TOP_OF_CHAR_STACK 5 // _._ 12 | #define SWAP_CHAR_STACK_ITEMS 6 // __. 13 | #define POP_FROM_CHAR_STACK 7 // ___ 14 | 15 | #define ADD_TWO_INTS 8 // _... 16 | #define SUB_TWO_INTS 9 // _.._ 17 | #define MUL_TWO_INTS 10 // _._. 18 | #define DIV_TWO_INTS 11 // _.__ 19 | #define MOD_TWO_INTS 12 // __.. 20 | 21 | #define PRINT_TOP_INT 13 // __._ 22 | #define PRINT_TOP_CHAR 14 // ___. 23 | #define INPUT_TOP_INT 15 // ____ 24 | #define INPUT_TOP_CHAR 16 // _.... 25 | 26 | #define GOTO_LINE 17 // _..._ 27 | #define GOTO_IF_POSITIVE 18 // _.._. 28 | #define GOTO_IF_NEGATIVE 19 // _..__ 29 | #define GOTO_IF_ZERO 20 // _._.. 30 | 31 | #endif -------------------------------------------------------------------------------- /stack.c: -------------------------------------------------------------------------------- 1 | #include "stack.h" 2 | 3 | void initStacks() { 4 | intTop = NULL; 5 | charTop = NULL; 6 | } 7 | 8 | int popInt() { 9 | struct intNode *var = intTop; 10 | int data; 11 | if (var == intTop) { 12 | data = intTop->data; 13 | intTop = intTop->next; 14 | free(var); 15 | } else 16 | printf(ERR_INT_STACK_EMPTY); 17 | return data; 18 | } 19 | 20 | int peekInt() { 21 | int data = popInt(); 22 | pushInt(data); 23 | return data; 24 | } 25 | 26 | void pushInt(int value) { 27 | struct intNode *temp; 28 | temp = (struct intNode *) malloc(sizeof(struct intNode)); 29 | temp->data = value; 30 | if (intTop == NULL) { 31 | intTop = temp; 32 | intTop->next = NULL; 33 | } else { 34 | temp->next = intTop; 35 | intTop = temp; 36 | } 37 | } 38 | 39 | char popChar() { 40 | struct charNode *var = charTop; 41 | char data; 42 | if (var == charTop) { 43 | data = charTop->data; 44 | charTop = charTop->next; 45 | free(var); 46 | } else 47 | printf(ERR_CHAR_STACK_EMPTY); 48 | return data; 49 | } 50 | 51 | char peekChar() { 52 | int data = popChar(); 53 | pushChar(data); 54 | return data; 55 | } 56 | 57 | void pushChar(char value) { 58 | struct charNode *temp; 59 | temp = (struct charNode *) malloc(sizeof(struct charNode)); 60 | temp->data = value; 61 | if (charTop == NULL) { 62 | charTop = temp; 63 | charTop->next = NULL; 64 | } else { 65 | temp->next = charTop; 66 | charTop = temp; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Morse 2 | 3 | An estoric programming language consisting of only `.` and `_`. 4 | 5 | ## Example 6 | 7 | The following program takes the input of two numbers from the user and adds them. It asks for the input again in case the result is zero. 8 | 9 | ``` 10 | ____ 11 | ____ 12 | _... 13 | _.... 14 | __._ 15 | _._.. _ 16 | ``` 17 | 18 | ## Build 19 | 20 | Download the source code and build it by running: 21 | 22 | make 23 | 24 | ## Usage 25 | 26 | You can run your programs by: 27 | 28 | ./morse [filename] 29 | 30 | ## Syntax 31 | 32 | The execution environment maintains only 2 stacks, one for integers and other for characters. 33 | 34 | ### Stack Manipulation 35 | 36 | Operations on the integer stack: 37 | * `.` - Push an integer to the stack _[parameter: positive integer]_. 38 | * `_` - Duplicate the top most integer in the stack. 39 | * `_.` - Swap two topmost integers in the stack. 40 | * `__` - Pop topmost integer from the stack. 41 | 42 | Operations on the character stack: 43 | * `_..` - Push a character to the stack _[parameter: character]_. 44 | * `_._` - Duplicate the top most character in the stack. 45 | * `__.` - Swap two topmost characters in the stack. 46 | * `___` - Pop topmost character from the stack. 47 | 48 | ### Arithmetic Operations 49 | * `_...` - Add top most integers and replace them with the result. 50 | * `_.._` - Subtract top most integers and replace them with the result. 51 | * `_._.` - Multiply top most integers and replace them with the result. 52 | * `_.__` - Divide top most integers and replace them with the result. 53 | * `__..` - Take modulus of top most integers and replace them with the result. 54 | 55 | ### Input/Output 56 | * `__._` - Print topmost integer on the stack. 57 | * `___.` - Print topmost character on the stack. 58 | * `____` - Take an input of an integer from the user. 59 | * `_....` - Take an input of a character from the user. 60 | 61 | ### Flow Control 62 | * `_..._` - Jump to a line number. _[parameter: line number]_ 63 | * `_.._.` - Jump to a line number if topmost integer is positive. _[parameter: line number]_ 64 | * `_..__` - Jump to a line number if topmost integer is negative. _[parameter: line number]_ 65 | * `_._..` - Jump to a line number if topmost integer is zero. _[parameter: line number]_ 66 | 67 | ### Representing literals 68 | 69 | Numbers can be represented in their binary form, with the 0s being `.` and 1s being `_`. Characters can be represented as the corresponding binary format of their ASCII code. 70 | 71 | **Note:** You can only represent positive integers right now. 72 | 73 | For example: 74 | * 2 is `_.` 75 | * 20 is `_._..` 76 | * A is `_....._` (binary representation of 65) 77 | 78 | ## License 79 | 80 | MIT 81 | 82 | ## Contact 83 | 84 | This was made out of sheer joblessness by Sankha. Follow him [@sankha93](https://twitter.com/sankha93) on Twitter. 85 | -------------------------------------------------------------------------------- /morse.c: -------------------------------------------------------------------------------- 1 | #include "morse.h" 2 | 3 | int main(int argc, char *argv[]) { 4 | if (argc <= 1) { 5 | printf(ERR_FILE_UNSPECIFIED); 6 | exit(ERR_FILE_OPEN_CODE); 7 | } else { 8 | initStacks(); 9 | openFile(argv[1]); 10 | while (1) { 11 | parseTokens(readLine()); 12 | } 13 | } 14 | } 15 | 16 | char *readLine() { 17 | char *line = NULL; 18 | read = getline(&line, &lineLen, fp); 19 | if (read == -1) 20 | exit(0); 21 | lineNum++; 22 | return line; 23 | } 24 | 25 | void openFile(char *file) { 26 | fp = fopen(file, "r"); 27 | if (fp == NULL) { 28 | printf(ERR_FILE_OPEN); 29 | exit(ERR_FILE_OPEN_CODE); 30 | } 31 | lineNum = 0; 32 | } 33 | 34 | char *str_replace(char *str, char *old, char *new) { 35 | char *ret, *r; 36 | const char *p, *q; 37 | size_t oldlen = strlen(old); 38 | size_t count, retlen, newlen = strlen(new); 39 | 40 | if (oldlen != newlen) { 41 | for (count = 0, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) 42 | count++; 43 | retlen = p - str + strlen(p) + count * (newlen - oldlen); 44 | } else 45 | retlen = strlen(str); 46 | 47 | if ((ret = malloc(retlen + 1)) == NULL) 48 | return NULL; 49 | 50 | for (r = ret, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) { 51 | ptrdiff_t l = q - p; 52 | memcpy(r, p, l); 53 | r += l; 54 | memcpy(r, new, newlen); 55 | r += newlen; 56 | } 57 | strcpy(r, p); 58 | 59 | return ret; 60 | } 61 | 62 | int binary_decimal(int n) { 63 | int decimal = 0, i = 0, rem; 64 | while (n != 0) { 65 | rem = n % 10; 66 | n /= 10; 67 | decimal += rem * pow(2, i); 68 | ++i; 69 | } 70 | return decimal; 71 | } 72 | 73 | int parseInt(char *token) { 74 | char *semiMorse = str_replace(token, ".", "0"); 75 | char *binary = str_replace(semiMorse, "_", "1"); 76 | int bin = atoi(binary); 77 | return binary_decimal(bin); 78 | } 79 | 80 | void parseTokens(char *line) { 81 | char* token = strtok(line, " "); 82 | if (token) { 83 | int cmd = parseInt(token); 84 | switch (cmd) { 85 | case PUSH_TO_INT_STACK: { 86 | token = strtok(NULL, " "); 87 | int data = parseInt(token); 88 | pushInt(data); 89 | break; 90 | } 91 | case DUPL_TOP_OF_INT_STACK: 92 | pushInt(peekInt()); 93 | break; 94 | case SWAP_INT_STACK_ITEMS: { 95 | int data1 = popInt(); 96 | int data2 = popInt(); 97 | pushInt(data1); 98 | pushInt(data2); 99 | break; 100 | } 101 | case POP_FROM_INT_STACK: 102 | popInt(); 103 | break; 104 | 105 | case PUSH_TO_CHAR_STACK: { 106 | token = strtok(NULL, " "); 107 | char data = (char) parseInt(token); 108 | pushChar(data); 109 | break; 110 | } 111 | case DUPL_TOP_OF_CHAR_STACK: 112 | pushChar(peekChar()); 113 | break; 114 | case SWAP_CHAR_STACK_ITEMS: { 115 | char data1 = popChar(); 116 | char data2 = popChar(); 117 | pushChar(data1); 118 | pushChar(data2); 119 | break; 120 | } 121 | case POP_FROM_CHAR_STACK: 122 | popChar(); 123 | break; 124 | 125 | case ADD_TWO_INTS: { 126 | int data1 = popInt(); 127 | int data2 = popInt(); 128 | pushInt(data1 + data2); 129 | break; 130 | } 131 | case SUB_TWO_INTS: { 132 | int data1 = popInt(); 133 | int data2 = popInt(); 134 | pushInt(data1 - data2); 135 | break; 136 | } 137 | case MUL_TWO_INTS: { 138 | int data1 = popInt(); 139 | int data2 = popInt(); 140 | pushInt(data1 * data2); 141 | break; 142 | } 143 | case DIV_TWO_INTS: { 144 | int data1 = popInt(); 145 | int data2 = popInt(); 146 | pushInt(data1 / data2); 147 | break; 148 | } 149 | case MOD_TWO_INTS: { 150 | int data1 = popInt(); 151 | int data2 = popInt(); 152 | pushInt(data1 % data2); 153 | break; 154 | } 155 | 156 | case PRINT_TOP_INT: { 157 | int data = peekInt(); 158 | printf("%d\n", data); 159 | break; 160 | } 161 | case PRINT_TOP_CHAR: { 162 | char data = peekChar(); 163 | printf("%c", data); 164 | break; 165 | } 166 | case INPUT_TOP_INT: { 167 | int data; 168 | scanf("%d", &data); 169 | pushInt(data); 170 | break; 171 | } 172 | case INPUT_TOP_CHAR: { 173 | char data; 174 | data = getchar(); 175 | pushChar(data); 176 | break; 177 | } 178 | case GOTO_LINE: 179 | jumpLine(token); 180 | break; 181 | case GOTO_IF_POSITIVE: 182 | if (peekInt() > 0) 183 | jumpLine(token); 184 | break; 185 | case GOTO_IF_NEGATIVE: 186 | if (peekInt() < 0) 187 | jumpLine(token); 188 | break; 189 | case GOTO_IF_ZERO: 190 | if (peekInt() == 0) 191 | jumpLine(token); 192 | break; 193 | } 194 | } 195 | } 196 | 197 | void jumpLine(char *token) { 198 | char *line = NULL; 199 | token = strtok(NULL, " "); 200 | int data = parseInt(token); 201 | data--; 202 | rewind(fp); 203 | lineNum = 0; 204 | while (lineNum != data) { 205 | read = getline(&line, &lineLen, fp); 206 | if (read == -1) { 207 | printf(ERR_LINE_NOT_FOUND); 208 | exit(ERR_LINE_NOT_FOUND_CODE); 209 | } 210 | lineNum++; 211 | } 212 | } --------------------------------------------------------------------------------