type TokenValue = union intValue: Int; stringValue: pointer to Char end, Token = record kind: Int; value: TokenValue end, FILE = record dummy: Int end; const SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2, TOKEN_IDENTIFIER = 1, TOKEN_IF = 2, TOKEN_THEN = 3, TOKEN_ELSE = 4, TOKEN_ELSIF = 5, TOKEN_WHILE = 6, TOKEN_DO = 7; -- -- External procedures. -- proc fopen(pathname: String, mode: String): pointer to FILE; extern; proc fclose(stream: pointer to FILE): Int; extern; proc fseek(stream: pointer to FILE, off: Int, whence: Int): Int; extern; proc ftell(stream: pointer to FILE): Int; extern; proc fread(ptr: pointer to Char, size: Int, nmemb: Int, stream: pointer to FILE): Int; extern; proc write(fd: Int, buf: pointer to Char, count: Int): Int; extern; proc malloc(size: Int): pointer to Char; extern; proc free(ptr: pointer to Char); extern; proc calloc(nmemb: Int, size: Int): pointer to Char; extern; proc realloc(ptr: pointer to Char, size: Int): pointer to Char; extern; proc memset(ptr: pointer to Char, c: Int, n: Int): pointer to Char; extern; proc strncmp(s1: pointer to Char, s2: pointer to Char, n: Word): Int; extern; proc strncpy(dst: pointer to Char, src: pointer to Char, dsize: Word): pointer to Char; extern; proc strncpy(dst: pointer to Char, src: pointer to Char, dsize: Word): pointer to Char; extern; proc strlen(ptr: pointer to Char): Word; extern; proc exit(code: Int); extern; -- -- Standard procedures. -- proc write_s(value: String); begin write(0, value, strlen(value)) end; proc write_b(value: Bool); begin if value then write_s("true") else write_s("false") end end; proc write_c(value: Char); begin write(0, @value, 1) end; proc write_i(value: Int); var digit: Int, n: Int, buffer: array 10 of Char; begin n := 9; buffer[9] := '0'; while value /= 0 do digit := value % 10; value := value / 10; buffer[n] := cast(cast('0' as Int) + digit as Char); n := n - 1 end; while n < 10 do n := n + 1; write_c(buffer[n]) end end; proc write_u(value: Word); begin write_i(value) end; proc is_digit(c: Char): Bool; begin return cast(c as Int) >= cast('0' as Int) and cast(c as Int) <= cast('9' as Int) end; proc is_alpha(c: Char): Bool; begin return cast(c as Int) >= cast('A' as Int) and cast(c as Int) <= cast('z' as Int) end; proc is_alnum(c: Char): Bool; begin return is_digit(c) or is_alpha(c) end; proc is_space(c: Char): Bool; begin return c = ' ' or c = '\n' end; -- -- End of standard procedures. -- proc test_record(); var r: Token; begin write_s("\nTest record:\n"); r.kind := 4; r.value.intValue := 8; write_i(r.value.intValue) end; proc test_primitive(); begin write_s("\nTest primitives:\n"); write_u(25u); write_c('\n'); write_i(8); write_c('\n'); write_b(true); write_c('\n') end; proc read_source(filename: String): pointer to Char; var input_file: pointer to FILE, source_size: Int, input: pointer to Char; begin input_file := fopen(filename, "rb"); fseek(input_file, 0, SEEK_END); source_size := ftell(input_file); fseek(input_file, 0, SEEK_SET); input := calloc(source_size + 1, 1); fread(input, source_size, 1, input_file); fclose(input_file); return input end; proc skip_spaces(input: pointer to Char): pointer to Char; begin while is_space(input^) do input := input + 1 end; return input end; proc lex_identifier(input: pointer to Char): pointer to Char; begin while is_alnum(input^) or input^ = '_' do input := input + 1 end; return input end; proc compile(); var input: pointer to Char, input_pointer: pointer to Char, token_end: pointer to Char, token_length: Int, tokens: pointer to Token, current_token: pointer to Token, tokens_size: Int, i: Int; begin tokens_size := 0; tokens := cast(0 as pointer to Token); input := read_source("example.elna"); input_pointer := skip_spaces(input); while input_pointer^ /= '\0' do if is_alpha(input_pointer^) or input_pointer^ = '_' then token_end := lex_identifier(input_pointer + 1); token_length := cast(token_end as Int) - cast(input_pointer as Int); tokens := cast(realloc(tokens, tokens_size + sizeof(Token)) as pointer to Token); current_token := tokens + tokens_size; if strncmp("if", input_pointer, token_length) = 0 then current_token^.kind := TOKEN_IF elsif strncmp("then", input_pointer, token_length) = 0 then current_token^.kind := TOKEN_THEN elsif strncmp("else", input_pointer, token_length) = 0 then current_token^.kind := TOKEN_ELSE elsif strncmp("elsif", input_pointer, token_length) = 0 then current_token^.kind := TOKEN_ELSIF elsif strncmp("while", input_pointer, token_length) = 0 then current_token^.kind := TOKEN_WHILE elsif strncmp("do", input_pointer, token_length) = 0 then current_token^.kind := TOKEN_DO else current_token^.kind := TOKEN_IDENTIFIER; current_token^.value.stringValue := cast(calloc(token_length + 1, 1) as pointer to Char); strncpy(current_token^.value.stringValue, input_pointer, token_length) end; tokens_size := tokens_size + sizeof(Token); input_pointer := token_end else input_pointer := input_pointer + 1 end end; i := 0; while i < tokens_size do current_token := tokens + i; if current_token^.kind = TOKEN_IF then write_s("IF") elsif current_token^.kind = TOKEN_THEN then write_s("THEN") elsif current_token^.kind = TOKEN_ELSE then write_s("ELSE") elsif current_token^.kind = TOKEN_ELSIF then write_s("ELSIF") elsif current_token^.kind = TOKEN_WHILE then write_s("WHILE") elsif current_token^.kind = TOKEN_DO then write_s("DO") elsif current_token^.kind = TOKEN_IDENTIFIER then write_s("IDENTIFIER<"); write_s(current_token^.value.stringValue); write_c('>') else write_s("UNKNOWN<"); write_i(current_token^.kind); write_s('>') end; write_c(' '); i := i + sizeof(Token) end; free(input) end; begin compile(); test_record(); test_primitive(); exit(0) end.