#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();
if(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);
}
/******************************************************************************/
/* */
/* 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();
return 0;
}