Radicalc  Documentation

#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;
}