#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/******************************************************************************/
/* */
/* TOKENISER */
/* */
/******************************************************************************/
enum token_type {
TOK_NONE,
TOK_PAREN_OPEN, TOK_PAREN_CLOSE, TOK_NEWLINE, TOK_EOF,
TOK_FUN, TOK_END,
TOK_IDENT, TOK_LITERAL_INT
};
struct token {
enum token_type type;
char* str;
};
int ch;
char* buf;
int buf_len;
struct token* tokens;
int token_len;
int isidentch(int c) {
return isalnum(c) || c == '_';
}
void next_ch() {
ch = getchar();
}
void accept_ch() {
buf = realloc(buf, ++buf_len);
buf[buf_len-1] = (char)ch;
}
void skip_ws() {
//printf("attempting to skip whitespace, next (%d)\n", ch);
while(ch == ' ' || ch == '\t') {
//printf("skipping ws: (%d)\n", ch);
next_ch();
}
}
void finalise_buf() {
buf = realloc(buf, ++buf_len);
buf[buf_len-1] = 0;
}
void reset_buf() { /* warning, memory leaking by design */
buf = 0;
buf_len = 0;
}
void add_token(enum token_type type, char* str) {
tokens = realloc(tokens, sizeof(struct token) * (++token_len));
tokens[token_len - 1].type = type;
tokens[token_len - 1].str = str;
}
void tokenise() {
enum token_type mode = TOK_NONE;
reset_buf();
tokens = 0;
token_len = 0;
next_ch();
do {
printf(">> %c <<\n", ch);
switch(mode) {
case TOK_NONE:
if(ch == '(') {
add_token(TOK_PAREN_OPEN, 0);
next_ch();
skip_ws();
}
else if(ch == ')') {
add_token(TOK_PAREN_CLOSE, 0);
next_ch();
skip_ws();
}
else if(ch == '\n' || ch == '\r') {
add_token(TOK_NEWLINE, 0);
next_ch();
/* collapse all versions, and multiples to a single token */
while(ch == '\n' || ch == '\r') next_ch();
skip_ws();
}
else if(isalpha(ch)) {
mode = TOK_IDENT;
accept_ch();
next_ch();
}
else if(isdigit(ch)) {
mode = TOK_LITERAL_INT;
accept_ch();
next_ch();
}
else {
printf("ERROR: unexpected character '%c' (%d)\n", ch, ch);
return;
}
break;
case TOK_IDENT:
if(isidentch(ch)) {
accept_ch();
next_ch();
}
else {
finalise_buf();
if(strcmp(buf, "fun") == 0)
add_token(TOK_FUN, buf);
else if(strcmp(buf, "end") == 0)
add_token(TOK_END, buf);
else
add_token(TOK_IDENT, buf);
printf("ident: >>%s<<\n", buf);
reset_buf();
mode = TOK_NONE;
skip_ws();
}
break;
case TOK_LITERAL_INT:
if(isdigit(ch)) {
accept_ch();
next_ch();
}
else {
finalise_buf();
add_token(TOK_LITERAL_INT, buf);
printf("int_literal: >>%s<<\n", buf);
reset_buf();
mode = TOK_NONE;
skip_ws();
}
break;
default:
printf("ERROR: unknown mode\n");
return;
}
} while(ch != EOF);
add_token(TOK_EOF, 0);
}
/******************************************************************************/
/* */
/* PARSER */
/* */
/******************************************************************************/
int parse_pos;
struct node {
struct node* childs;
int child_count;
};
struct token* expect(enum token_type type) {
if(type == tokens[parse_pos].type) {
++parse_pos;
return &tokens[parse_pos-1];
}
else {
printf("expected (%d), got (%d)\n", type, tokens[parse_pos].type);
exit(-1);
}
}
int is_next_tok(enum token_type type) {
return tokens[parse_pos].type == type;
}
struct node* p_func_call() {
char* name = expect(TOK_IDENT)->str;
expect(TOK_PAREN_OPEN);
expect(TOK_LITERAL_INT);
expect(TOK_PAREN_CLOSE);
}
struct node* p_statement() {
struct node* ret;
switch(tokens[parse_pos].type) {
case TOK_IDENT:
ret = p_func_call();
expect(TOK_NEWLINE);
break;
default:
printf("can't parse statement, (%d)\n", tokens[parse_pos].type);
exit(-1);
}
}
struct node* p_fun() {
expect(TOK_FUN);
char* name = expect(TOK_IDENT)->str;
expect(TOK_PAREN_OPEN);
expect(TOK_PAREN_CLOSE);
expect(TOK_NEWLINE);
while(!is_next_tok(TOK_END)) {
p_statement();
}
expect(TOK_END);
expect(TOK_NEWLINE);
}
void parse() {
parse_pos = 0;
switch(tokens[parse_pos].type) {
case TOK_EOF:
return;
case TOK_FUN:
p_fun();
}
}
/******************************************************************************/
/* */
/* MAIN */
/* */
/******************************************************************************/
void print_tokens() {
for(int i = 0; i < token_len; ++i)
printf("TOKEN %d %s\n", tokens[i].type, tokens[i].str);
}
int main() {
tokenise();
print_tokens();
parse();
return 0;
}