Created
December 1, 2014 15:53
-
-
Save ynkdir/a4c481e94f3b7b02cbc6 to your computer and use it in GitHub Desktop.
cc500.vim
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
" This is a port of CC500 | |
" http://homepage.ntlworld.com/edmund.grimley-evans/cc500/ | |
" | |
"------------------------------------------------------------------------------- | |
" ORIGINAL HEADER | |
"------------------------------------------------------------------------------- | |
" Copyright (C) 2006 Edmund GRIMLEY EVANS <[email protected]> | |
" | |
" This program is free software; you can redistribute it and/or modify | |
" it under the terms of the GNU General Public License as published by | |
" the Free Software Foundation; either version 2 of the License, or | |
" (at your option) any later version. | |
" | |
" This program is distributed in the hope that it will be useful, | |
" but WITHOUT ANY WARRANTY; without even the implied warranty of | |
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
" GNU General Public License for more details. | |
" | |
" You should have received a copy of the GNU General Public License | |
" along with this program; if not, write to the Free Software | |
" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
"------------------------------------------------------------------------------- | |
" A self-compiling compiler for a small subset of C. | |
" Usage: | |
" :source cc500.vim | |
" :call CC500Compile('foo.c', 'a.out') | |
function! CC500Compile(infile, outfile) | |
let s:stdin = [] | |
let s:stdout = [] | |
let s:token = '' | |
let s:nextc = '' | |
let s:code = [] | |
let s:codepos = 0 | |
let s:code_offset = 0 | |
let s:table = {} | |
let s:stack_pos = 0 | |
let s:number_of_args = 0 | |
try | |
let s:stdin = s:readfile(a:infile) | |
call s:main1() | |
call s:writefile(s:code, a:outfile) | |
endtry | |
endfunction | |
function! s:lines2bytes(lines) | |
let bytes = [] | |
let first = 1 | |
for line in a:lines | |
if !first | |
call add(bytes, 10) | |
endif | |
let first = 0 | |
call extend(bytes, map(range(len(line)), 'line[v:val] == "\n" ? 0 : char2nr(line[v:val])')) | |
endfor | |
return bytes | |
endfunction | |
function! s:bytes2lines(bytes) | |
let table = map(range(256), 'printf(''\x%02x'', v:val == 0 ? 10 : v:val)') | |
let lines = [] | |
let start = 0 | |
while start < len(a:bytes) | |
let end = index(a:bytes, 10, start) | |
if end == -1 | |
let end = len(a:bytes) | |
endif | |
let line = eval('"' . join(map(range(start, end - 1), 'table[a:bytes[v:val]]'), '') . '"') | |
call add(lines, line) | |
if end == len(a:bytes) - 1 | |
call add(lines, '') | |
endif | |
let start = end + 1 | |
endwhile | |
return lines | |
endfunction | |
function! s:readfile(filename) | |
try | |
let lines = readfile(a:filename, 'b') | |
catch /^Vim\%((\a\+)\)\=:E484:/ | |
throw "Can't read file" | |
endtry | |
let bytes = s:lines2bytes(lines) | |
return bytes | |
endfunction | |
function! s:writefile(bytes, filename) | |
let lines = s:bytes2lines(a:bytes) | |
if writefile(lines, a:filename, 'b') != 0 | |
throw "Can't write file" | |
endif | |
endfunction | |
function! s:lshift(a, n) | |
return a:n == 0 ? a:a : a:n > 31 ? 0 : a:a * s:pow2[a:n] | |
endfunction | |
function! s:rshift(a, n) | |
return a:n == 0 ? a:a : a:n > 31 ? 0 : | |
\ a:a < 0 | |
\ ? (a:a - 0x80000000) / s:pow2[a:n] + 0x40000000 / s:pow2[a:n - 1] | |
\ : a:a / s:pow2[a:n] | |
endfunction | |
let s:pow2 = [ | |
\ 0x1, 0x2, 0x4, 0x8, | |
\ 0x10, 0x20, 0x40, 0x80, | |
\ 0x100, 0x200, 0x400, 0x800, | |
\ 0x1000, 0x2000, 0x4000, 0x8000, | |
\ 0x10000, 0x20000, 0x40000, 0x80000, | |
\ 0x100000, 0x200000, 0x400000, 0x800000, | |
\ 0x1000000, 0x2000000, 0x4000000, 0x8000000, | |
\ 0x10000000, 0x20000000, 0x40000000, 0x80000000, | |
\ ] | |
let s:EOF = '' | |
" Our library functions. | |
"void exit(int); | |
function! s:exit(int) | |
throw printf("exit(%d)", a:int) | |
endfunction | |
let s:stdin = [] | |
let s:stdout = [] | |
"int getchar(void); | |
function! s:getchar() | |
if empty(s:stdin) | |
return s:EOF | |
else | |
return nr2char(remove(s:stdin, 0)) | |
endif | |
endfunction | |
"void *malloc(int); | |
"int putchar(int); | |
function! s:putchar(c) | |
call add(s:stdout, a:c) | |
endfunction | |
"char *my_realloc(char *old, int oldlen, int newlen) | |
function! s:my_realloc(old, newlen) | |
return a:old + repeat([0], a:newlen - len(a:old)) | |
endfunction | |
"int nextc; | |
"char *token; | |
"int token_size; | |
let s:token = '' | |
let s:nextc = '' | |
"void error() | |
function! s:error() | |
throw "exit(1)" | |
endfunction | |
"int i; | |
"void takechar() | |
function! s:takechar() | |
let s:token .= s:nextc | |
let s:nextc = s:getchar() | |
endfunction | |
"void get_token() | |
function! s:get_token() | |
let w = 1 | |
while w | |
let w = 0 | |
while s:nextc ==# ' ' || s:nextc ==# "\t" || s:nextc ==# "\n" | |
let s:nextc = s:getchar() | |
endwhile | |
let s:token = '' | |
while ('a' <=# s:nextc && s:nextc <=# 'z') || ('0' <=# s:nextc && s:nextc <=# '9') || s:nextc ==# '_' | |
call s:takechar() | |
endwhile | |
if empty(s:token) | |
while s:nextc ==# '<' || s:nextc ==# '=' || s:nextc ==# '>' || s:nextc ==# '|' || s:nextc ==# '&' || s:nextc ==# '!' | |
call s:takechar() | |
endwhile | |
endif | |
if empty(s:token) | |
if s:nextc ==# "'" | |
call s:takechar() | |
while s:nextc !=# "'" | |
call s:takechar() | |
endwhile | |
call s:takechar() | |
elseif s:nextc ==# '"' | |
call s:takechar() | |
while s:nextc !=# '"' | |
call s:takechar() | |
endwhile | |
call s:takechar() | |
elseif s:nextc ==# '/' | |
call s:takechar() | |
if s:nextc ==# '*' | |
let s:nextc = s:getchar() | |
while s:nextc !=# '/' | |
while s:nextc !=# '*' | |
let s:nextc = s:getchar() | |
endwhile | |
let s:nextc = s:getchar() | |
endwhile | |
let s:nextc = s:getchar() | |
let w = 1 | |
endif | |
elseif s:nextc !=# s:EOF | |
call s:takechar() | |
endif | |
endif | |
endwhile | |
endfunction | |
"int peek(char *s) | |
function! s:peek(s) | |
return a:s ==# s:token | |
endfunction | |
"int accept(char *s) | |
function! s:accept(s) | |
if s:peek(a:s) | |
call s:get_token() | |
return 1 | |
else | |
return 0 | |
endif | |
endfunction | |
"void expect(char *s) | |
function! s:expect(s) | |
if s:accept(a:s) == 0 | |
call s:error() | |
endif | |
endfunction | |
"char *code; | |
"int code_size; | |
"int codepos; | |
"int code_offset; | |
let s:code = [] | |
let s:codepos = 0 | |
let s:code_offset = 0 | |
function! s:int32_to_bytes(n) | |
return [and(a:n, 0xFF), and(s:rshift(a:n, 8), 0xFF), and(s:rshift(a:n, 16), 0xFF), and(s:rshift(a:n, 24), 0xFF)] | |
endfunction | |
"void save_int(char *p, int n) | |
function! s:save_int(p, i, n) | |
let a:p[a:i + 0] = and(a:n, 0xFF) | |
let a:p[a:i + 1] = and(s:rshift(a:n, 8), 0xFF) | |
let a:p[a:i + 2] = and(s:rshift(a:n, 16), 0xFF) | |
let a:p[a:i + 3] = and(s:rshift(a:n, 24), 0xFF) | |
endfunction | |
"int load_int(char *p) | |
function! s:load_int(p, i) | |
return and(a:p[a:i + 0], 0xFF) + (and(a:p[a:i + 1], 0xFF) * 0x100) + (and(a:p[a:i + 2], 0xFF) * 0x10000) + (and(a:p[a:i + 3], 0xFF) * 0x1000000) | |
endfunction | |
"void emit(int n, char *s) | |
function! s:emit(s) | |
call extend(s:code, a:s) | |
let s:codepos = len(s:code) | |
endfunction | |
"void be_push() | |
function! s:be_push() | |
call s:emit([0x50]) " push %eax | |
endfunction | |
" void be_pop(int n) | |
function! s:be_pop(n) | |
call s:emit([0x81, 0xc4] + s:int32_to_bytes(a:n * 4)) " add $(n * 4),%esp | |
endfunction | |
"char *table; | |
"int table_size; | |
"int table_pos; | |
"int stack_pos; | |
let s:table = {} | |
let s:stack_pos = 0 | |
"int sym_lookup(char *s) | |
function! s:sym_lookup(s) | |
return get(s:table, a:s, {}) | |
endfunction | |
"void sym_declare(char *s, int type, int value) | |
function! s:sym_declare(s, type, value) | |
let s:table[a:s] = {'name': a:s, 'type': a:type, 'value': a:value} | |
endfunction | |
"int sym_declare_global(char *s) | |
function! s:sym_declare_global(s) | |
let current_symbol = s:sym_lookup(a:s) | |
if empty(current_symbol) | |
call s:sym_declare(a:s, 'U', s:code_offset) | |
let current_symbol = s:table[a:s] | |
endif | |
return current_symbol | |
endfunction | |
"void sym_define_global(int current_symbol) | |
function! s:sym_define_global(current_symbol) | |
let v = s:codepos + s:code_offset | |
if a:current_symbol.type != 'U' | |
call s:error() " symbol redefined | |
endif | |
let i = a:current_symbol.value - s:code_offset | |
while i | |
let j = s:load_int(s:code, i) - s:code_offset | |
call s:save_int(s:code, i, v) | |
let i = j | |
endwhile | |
let a:current_symbol.type = 'D' | |
let a:current_symbol.value = v | |
endfunction | |
"int number_of_args; | |
let s:number_of_args = 0 | |
"void sym_get_value(char *s) | |
function! s:sym_get_value(s) | |
let t = s:sym_lookup(a:s) | |
if empty(t) | |
call s:error() | |
endif | |
call s:emit([0xb8] + s:int32_to_bytes(t.value)) | |
if t.type == 'D' " defined global | |
elseif t.type == 'U' " undefined global | |
let t.value = s:codepos + s:code_offset - 4 | |
elseif t.type == 'L' " local variable | |
let k = (s:stack_pos - t.value - 1) * 4 | |
call s:emit([0x8d, 0x84, 0x24] + s:int32_to_bytes(k)) " lea (n * 4)(%esp),%eax | |
elseif t.type == 'A' " argument | |
let k = (s:stack_pos + s:number_of_args - t.value + 1) * 4 | |
call s:emit([0x8d, 0x84, 0x24] + s:int32_to_bytes(k)) " lea (n * 4)(%esp),%eax | |
else | |
call s:error() | |
endif | |
endfunction | |
"void be_start() | |
function! s:be_start() | |
call s:emit([0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) | |
call s:emit([0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0x80, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00]) | |
call s:emit([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00]) | |
call s:emit([0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x08]) | |
call s:emit([0x00, 0x80, 0x04, 0x08, 0x10, 0x4b, 0x00, 0x00, 0x10, 0x4b, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00]) | |
call s:emit([0x00, 0x10, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x89, 0xc3, 0x31, 0xc0, 0x40, 0xcd, 0x80]) | |
call s:sym_define_global(s:sym_declare_global("exit")) | |
" pop %ebx ; pop %ebx ; xor %eax,%eax ; inc %eax ; int $0x80 | |
call s:emit([0x5b, 0x5b, 0x31, 0xc0, 0x40, 0xcd, 0x80]) | |
call s:sym_define_global(s:sym_declare_global("getchar")) | |
" mov $3,%eax ; xor %ebx,%ebx ; push %ebx ; mov %esp,%ecx | |
call s:emit([0xb8, 0x03, 0x00, 0x00, 0x00, 0x31, 0xdb, 0x53, 0x89, 0xe1]) | |
" xor %edx,%edx ; inc %edx ; int $0x80 | |
" test %eax,%eax ; pop %eax ; jne . + 7 | |
call s:emit([0x31, 0xd2, 0x42, 0xcd, 0x80, 0x85, 0xc0, 0x58, 0x75, 0x05]) | |
" mov $-1,%eax ; ret | |
call s:emit([0xb8, 0xff, 0xff, 0xff, 0xff, 0xc3]) | |
call s:sym_define_global(s:sym_declare_global("malloc")) | |
" mov 4(%esp),%eax | |
call s:emit([0x8b, 0x44, 0x24, 0x04]) | |
" push %eax ; xor %ebx,%ebx ; mov $45,%eax ; int $0x80 | |
call s:emit([0x50, 0x31, 0xdb, 0xb8, 0x2d, 0x00, 0x00, 0x00, 0xcd, 0x80]) | |
" pop %ebx ; add %eax,%ebx ; push %eax ; push %ebx ; mov $45,%eax | |
call s:emit([0x5b, 0x01, 0xc3, 0x50, 0x53, 0xb8, 0x2d, 0x00, 0x00, 0x00]) | |
" int $0x80 ; pop %ebx ; cmp %eax,%ebx ; pop %eax ; je . + 7 | |
call s:emit([0xcd, 0x80, 0x5b, 0x39, 0xc3, 0x58, 0x74, 0x05]) | |
" mov $-1,%eax ; ret | |
call s:emit([0xb8, 0xff, 0xff, 0xff, 0xff, 0xc3]) | |
call s:sym_define_global(s:sym_declare_global("putchar")) | |
" mov $4,%eax ; xor %ebx,%ebx ; inc %ebx | |
call s:emit([0xb8, 0x04, 0x00, 0x00, 0x00, 0x31, 0xdb, 0x43]) | |
" lea 4(%esp),%ecx ; mov %ebx,%edx ; int $0x80 ; ret | |
call s:emit([0x8d, 0x4c, 0x24, 0x04, 0x89, 0xda, 0xcd, 0x80, 0xc3]) | |
call s:save_int(s:code, 85, s:codepos - 89) " entry set to first thing in file */ | |
endfunction | |
"void be_finish() | |
function! s:be_finish() | |
call s:save_int(s:code, 68, s:codepos) | |
call s:save_int(s:code, 72, s:codepos) | |
let i = 0 | |
while i <= s:codepos - 1 | |
call s:putchar(s:code[i]) | |
let i += 1 | |
endwhile | |
endfunction | |
"void promote(int type) | |
function! s:promote(type) | |
" 1 = char lval, 2 = int lval, 3 = other | |
if a:type == 1 | |
call s:emit([0x0f, 0xbe, 0x00]) " movsbl (%eax),%eax | |
elseif a:type == 2 | |
call s:emit([0x8b, 0x00]) " mov (%eax),%eax | |
endif | |
endfunction | |
"int expression(); | |
" primary-expr: | |
" identifier | |
" constant | |
" ( expression ) | |
"int primary_expr() | |
function! s:primary_expr() | |
if '0' <=# s:token[0] && s:token[0] <=# '9' | |
let n = str2nr(s:token, 10) | |
call s:emit([0xb8] + s:int32_to_bytes(n)) " mov $x,%eax | |
let type = 3 | |
elseif 'a' <=# s:token[0] && s:token[0] <=# 'z' | |
call s:sym_get_value(s:token) | |
let type = 2 | |
elseif s:accept('(') | |
let type = s:expression() | |
if s:peek(')') == 0 | |
call s:error() | |
endif | |
elseif len(s:token) == 3 && s:token[0] == "'" && s:token[2] == "'" | |
call s:emit([0xb8] + s:int32_to_bytes(char2nr(s:token[1]))) " mov $x,%eax | |
let type = 3 | |
elseif s:token[0] ==# '"' | |
let b = [] | |
let i = 1 | |
while s:token[i] !=# '"' | |
if s:token[i] ==# '\' && s:token[i + 1] ==# 'x' | |
call add(b, str2nr(s:token[i + 2] . s:token[i + 3], 16)) | |
let i += 4 | |
else | |
call add(b, char2nr(s:token[i])) | |
let i += 1 | |
endif | |
endwhile | |
call add(b, 0x00) | |
" call ... ; the string ; pop %eax | |
call s:emit([0xe8] + s:int32_to_bytes(len(b))) | |
call s:emit(b) | |
call s:emit([0x58]) | |
let type = 3 | |
else | |
call s:error() | |
endif | |
call s:get_token() | |
return type | |
endfunction | |
"void binary1(int type) | |
function! s:binary1(type) | |
call s:promote(a:type) | |
call s:be_push() | |
let s:stack_pos += 1 | |
endfunction | |
"int binary2(int type, int n, char *s) | |
function! s:binary2(type, b) | |
call s:promote(a:type) | |
call s:emit(a:b) | |
let s:stack_pos -= 1 | |
return 3 | |
endfunction | |
" postfix-expr: | |
" primary-expr | |
" postfix-expr [ expression ] | |
" postfix-expr ( expression-list-opt ) | |
"int postfix_expr() | |
function! s:postfix_expr() | |
let type = s:primary_expr() | |
if s:accept('[') | |
call s:binary1(type) " pop %ebx ; add %ebx,%eax | |
call s:binary2(s:expression(), [0x5b, 0x01, 0xd8]) | |
call s:expect(']') | |
let type = 1 | |
elseif s:accept('(') | |
let s = s:stack_pos | |
call s:be_push() | |
let s:stack_pos = s:stack_pos + 1 | |
if s:accept(')') == 0 | |
call s:promote(s:expression()) | |
call s:be_push() | |
let s:stack_pos = s:stack_pos + 1 | |
while s:accept(',') | |
call s:promote(s:expression()) | |
call s:be_push() | |
let s:stack_pos = s:stack_pos + 1 | |
endwhile | |
call s:expect(')') | |
endif | |
call s:emit([0x8b, 0x84, 0x24] + s:int32_to_bytes((s:stack_pos - s - 1) * 4)) " mov (n * 4)(%esp),%eax | |
call s:emit([0xff, 0xd0]) " call *%eax | |
call s:be_pop(s:stack_pos - s) | |
let s:stack_pos = s | |
let type = 3 | |
endif | |
return type | |
endfunction | |
" additive-expr: | |
" postfix-expr | |
" additive-expr + postfix-expr | |
" additive-expr - postfix-expr | |
"int additive_expr() | |
function! s:additive_expr() | |
let type = s:postfix_expr() | |
while 1 | |
if s:accept('+') | |
call s:binary1(type) " pop %ebx ; add %ebx,%eax | |
let type = s:binary2(s:postfix_expr(), [0x5b, 0x01, 0xd8]) | |
elseif s:accept('-') | |
call s:binary1(type) " pop %ebx ; sub %eax,%ebx ; mov %ebx,%eax | |
let type = s:binary2(s:postfix_expr(), [0x5b, 0x29, 0xc3, 0x89, 0xd8]) | |
else | |
return type | |
endif | |
endwhile | |
endfunction | |
" shift-expr: | |
" additive-expr | |
" shift-expr << additive-expr | |
" shift-expr >> additive-expr | |
"int shift_expr() | |
function! s:shift_expr() | |
let type = s:additive_expr() | |
while 1 | |
if s:accept('<<') | |
call s:binary1(type) " mov %eax,%ecx ; pop %eax ; shl %cl,%eax | |
let type = s:binary2(s:additive_expr(), [0x89, 0xc1, 0x58, 0xd3, 0xe0]) | |
elseif s:accept('>>') | |
call s:binary1(type) " mov %eax,%ecx ; pop %eax ; sar %cl,%eax | |
let type = s:binary2(s:additive_expr(), [0x89, 0xc1, 0x58, 0xd3, 0xf8]) | |
else | |
return type | |
endif | |
endwhile | |
endfunction | |
" relational-expr: | |
" shift-expr | |
" relational-expr <= shift-expr | |
"int relational_expr() | |
function! s:relational_expr() | |
let type = s:shift_expr() | |
while s:accept('<=') | |
call s:binary1(type) | |
" pop %ebx ; cmp %eax,%ebx ; setle %al ; movzbl %al,%eax | |
let type = s:binary2(s:shift_expr(), [0x5b, 0x39, 0xc3, 0x0f, 0x9e, 0xc0, 0x0f, 0xb6, 0xc0]) | |
endwhile | |
return type | |
endfunction | |
" equality-expr: | |
" relational-expr | |
" equality-expr == relational-expr | |
" equality-expr != relational-expr | |
"int equality_expr() | |
function! s:equality_expr() | |
let type = s:relational_expr() | |
while 1 | |
if s:accept('==') | |
call s:binary1(type) | |
" pop %ebx ; cmp %eax,%ebx ; sete %al ; movzbl %al,%eax | |
let type = s:binary2(s:relational_expr(), [0x5b, 0x39, 0xc3, 0x0f, 0x94, 0xc0, 0x0f, 0xb6, 0xc0]) | |
elseif s:accept('!=') | |
call s:binary1(type) | |
" pop %ebx ; cmp %eax,%ebx ; setne %al ; movzbl %al,%eax | |
let type = s:binary2(s:relational_expr(), [0x5b, 0x39, 0xc3, 0x0f, 0x95, 0xc0, 0x0f, 0xb6, 0xc0]) | |
else | |
return type | |
endif | |
endwhile | |
endfunction | |
" bitwise-and-expr: | |
" equality-expr | |
" bitwise-and-expr & equality-expr | |
"int bitwise_and_expr() | |
function! s:bitwise_and_expr() | |
let type = s:equality_expr() | |
while s:accept('&') | |
call s:binary1(type) " pop %ebx ; and %ebx,%eax | |
let type = s:binary2(s:equality_expr(), [0x5b, 0x21, 0xd8]) | |
endwhile | |
return type | |
endfunction | |
" bitwise-or-expr: | |
" bitwise-and-expr | |
" bitwise-and-expr | bitwise-or-expr | |
"int bitwise_or_expr() | |
function! s:bitwise_or_expr() | |
let type = s:bitwise_and_expr() | |
while s:accept('|') | |
call s:binary1(type) " pop %ebx ; or %ebx,%eax | |
let type = s:binary2(s:bitwise_and_expr(), [0x5b, 0x09, 0xd8]) | |
endwhile | |
return type | |
endfunction | |
" expression: | |
" bitwise-or-expr | |
" bitwise-or-expr = expression | |
"int expression() | |
function! s:expression() | |
let type = s:bitwise_or_expr() | |
if s:accept('=') | |
call s:be_push() | |
let s:stack_pos = s:stack_pos + 1 | |
call s:promote(s:expression()) | |
if type == 2 | |
call s:emit([0x5b, 0x89, 0x03]) " pop %ebx ; mov %eax,(%ebx) | |
else | |
call s:emit([0x5b, 0x88, 0x03]) " pop %ebx ; mov %al,(%ebx) | |
endif | |
let s:stack_pos = s:stack_pos - 1 | |
let type = 3 | |
endif | |
return type | |
endfunction | |
" type-name: | |
" char * | |
" int | |
"void type_name() | |
function! s:type_name() | |
call s:get_token() | |
while s:accept('*') | |
endwhile | |
endfunction | |
" statement: | |
" { statement-list-opt } | |
" type-name identifier ; | |
" type-name identifier = expression; | |
" if ( expression ) statement | |
" if ( expression ) statement else statement | |
" while ( expression ) statement | |
" return ; | |
" expr ; | |
"void statement() | |
function! s:statement() | |
if s:accept('{') | |
let t = copy(s:table) | |
let s = s:stack_pos | |
while s:accept('}') == 0 | |
call s:statement() | |
endwhile | |
let s:table = t | |
call s:be_pop(s:stack_pos - s) | |
let s:stack_pos = s | |
elseif s:peek('char') || s:peek('int') | |
call s:type_name() | |
call s:sym_declare(s:token, 'L', s:stack_pos) | |
call s:get_token() | |
if s:accept('=') | |
call s:promote(s:expression()) | |
endif | |
call s:expect(";") | |
call s:be_push() | |
let s:stack_pos = s:stack_pos + 1 | |
elseif s:accept('if') | |
call s:expect("(") | |
call s:promote(s:expression()) | |
call s:emit([0x85, 0xc0, 0x0f, 0x84, 0, 0, 0, 0]) " test %eax,%eax ; je ... | |
let p1 = s:codepos | |
call s:expect(")") | |
call s:statement() | |
call s:emit([0xe9, 0, 0, 0, 0]) " jmp ... | |
let p2 = s:codepos | |
call s:save_int(s:code, p1 - 4, s:codepos - p1) | |
if s:accept('else') | |
call s:statement() | |
endif | |
call s:save_int(s:code, p2 - 4, s:codepos - p2) | |
elseif s:accept('while') | |
call s:expect("(") | |
let p1 = s:codepos | |
call s:promote(s:expression()) | |
call s:emit([0x85, 0xc0, 0x0f, 0x84, 0, 0, 0, 0]) " test %eax,%eax ; je ... | |
let p2 = s:codepos | |
call s:expect(")") | |
call s:statement() | |
call s:emit([0xe9, 0, 0, 0, 0]) " jmp ... | |
call s:save_int(s:code, s:codepos - 4, p1 - s:codepos) | |
call s:save_int(s:code, p2 - 4, s:codepos - p2) | |
elseif s:accept('return') | |
if s:peek(';') == 0 | |
call s:promote(s:expression()) | |
endif | |
call s:expect(";") | |
call s:be_pop(s:stack_pos) | |
call s:emit([0xc3]) " ret | |
else | |
call s:expression() | |
call s:expect(";") | |
endif | |
endfunction | |
" program: | |
" declaration | |
" declaration program | |
" | |
" declaration: | |
" type-name identifier ; | |
" type-name identifier ( parameter-list ) ; | |
" type-name identifier ( parameter-list ) statement | |
" | |
" parameter-list: | |
" parameter-declaration | |
" parameter-list, parameter-declaration | |
" | |
" parameter-declaration: | |
" type-name identifier-opt | |
"void program() | |
function! s:program() | |
while !empty(s:token) | |
call s:type_name() | |
let current_symbol = s:sym_declare_global(s:token) | |
call s:get_token() | |
if s:accept(';') | |
call s:sym_define_global(current_symbol) | |
call s:emit([0x00, 0x00, 0x00, 0x00]) | |
elseif s:accept('(') | |
let t = copy(s:table) | |
let s:number_of_args = 0 | |
while s:accept(')') == 0 | |
let s:number_of_args = s:number_of_args + 1 | |
call s:type_name() | |
if s:peek(')') == 0 | |
call s:sym_declare(s:token, 'A', s:number_of_args) | |
call s:get_token() | |
endif | |
call s:accept(",") " ignore trailing comma | |
endwhile | |
if s:accept(';') == 0 | |
call s:sym_define_global(current_symbol) | |
call s:statement() | |
call s:emit([0xc3]) " ret | |
endif | |
let s:table = t | |
else | |
call s:error() | |
endif | |
endwhile | |
endfunction | |
"int main1() | |
function! s:main1() | |
let s:code_offset = 134512640 " 0x08048000 | |
call s:be_start() | |
let s:nextc = s:getchar() | |
call s:get_token() | |
call s:program() | |
call s:be_finish() | |
return 0 | |
endfunction |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment