Improve compiler

master
Joachim Stolberg 2022-07-16 20:42:31 +02:00
parent 4c449fab62
commit beb2e9eaae
13 changed files with 206 additions and 33 deletions

View File

@ -13,7 +13,7 @@
--]]
vm16.Comp = {}
vm16.Comp.version = "1.6"
vm16.Comp.version = "1.8"
local function error_msg(err)
local t = string.split(err, "\001")

90
bcomp/bconst_expr.lua Normal file
View File

@ -0,0 +1,90 @@
--[[
VM16 BLL Compiler
=================
Copyright (C) 2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Constant Expression parser
]]--
local T_NUMBER = vm16.T_NUMBER
local BConstEx = vm16.BExpr
function BConstEx:bconstex_init()
self:bexpr_init()
end
--[[
const_expression:
= const_term
| const_term '+' const_expression
| const_term '-' const_expression
]]--
function BConstEx:const_expression()
local opnd1 = self:const_term()
local val = self:tk_peek().val
if val == "+" then
self:tk_match()
local opnd2 = self:const_expression()
return opnd1 + opnd2
elseif val == "-" then
self:tk_match()
local opnd2 = self:const_expression()
return opnd1 - opnd2
end
return opnd1
end
--[[
const_term:
= const_factor
| const_factor '*' const_term
| const_factor '/' const_term
]]--
function BConstEx:const_term()
local opnd1 = self:const_factor()
local val = self:tk_peek().val
if val == "*" then
self:tk_match()
local opnd2 = self:const_term()
return math.floor(opnd1 * opnd2)
elseif val == "/" then
self:tk_match()
local opnd2 = self:const_term()
return math.floor(opnd1 / opnd2)
end
return opnd1
end
--[[
const_factor:
= '(' const_expression ')'
| number
| CONST
]]--
function BConstEx:const_factor()
local tok = self:tk_peek()
if tok.type == T_NUMBER then
self:tk_match()
return tok.val
elseif self:sym_is_const(tok.val) then
self:tk_match()
return tonumber(string.sub(self:sym_get_const(tok.val), 2))
elseif tok.val == "(" then
self:tk_match("(")
local res = self:const_expression()
self:tk_match(")")
return res
else
self:error_msg(string.format("Syntax error at '%s'", tok.val or ""))
return tok.val or ""
end
end
vm16.BConstEx = BConstEx

View File

@ -138,6 +138,7 @@ unary:
| '~' postfix
| '*' postfix
| '&' postfix
| 'sizeof' '(' variable ')'
]]--
function BExpr:unary()
local val = self:tk_peek().val
@ -171,6 +172,16 @@ function BExpr:unary()
return reg
end
return "#" .. opnd
elseif val == "sizeof" then
self:tk_match("sizeof")
self:tk_match("(")
local ident = (self:tk_match(T_IDENT) or {}).val
if not self:sym_get_var(ident) then
self:error_msg(string.format("Unknown variable '%s'", ident or ""))
end
local size = self:sym_get_var_size(ident)
self:tk_match(")")
return "#" .. size
end
return self:postfix()
end

View File

@ -20,10 +20,10 @@ local T_NEWFILE = vm16.T_NEWFILE
local T_STRING = vm16.T_STRING
local T_ENDFILE = vm16.T_ENDFILE
local BPars = vm16.BExpr:new({})
local BPars = vm16.BConstEx:new({})
function BPars:bpars_init()
self:bexpr_init()
self:bconstex_init()
end
--[[
@ -43,6 +43,7 @@ definition:
= 'var' var_def
| 'static' 'var' var_def
| 'const' const_def
| 'static' 'const' const_def
| 'func' func_def
| 'static' 'func' func_def
| T_NEWFILE
@ -62,6 +63,9 @@ function BPars:definition()
elseif tok.val == "func" then
self:tk_match("func")
self:func_def(true)
elseif tok.val == "const" then
self:tk_match("const")
self:const_def(true)
else
self:error_msg(string.format("Unexpected item '%s'", tok.val))
end
@ -105,10 +109,12 @@ function BPars:var_def(static)
local ident = self:ident()
local val = self:tk_peek().val
local is_array = val == "["
local old_ident
if static then
local old_ident = ident
old_ident = ident
local postfix = is_array and "[]" or ""
ident = self:sym_add_filelocal(ident, is_array)
ident = self:sym_get_filelocal_ref(ident)
self:add_debugger_info("lvar", self.lineno, ident, old_ident .. postfix)
else
local postfix = is_array and "[]" or ""
@ -117,17 +123,21 @@ function BPars:var_def(static)
self:switch_to_var_def()
self:set_global(ident)
if is_array then
local size = self:array_def(ident)
if static then
self:sym_add_filelocal(ident, true)
-- post-define array size
self:sym_add_filelocal(old_ident, true, size) -- name without postfix
self:sym_add_filelocal(ident, true, size)
else
self:sym_add_global(ident, true)
self:sym_add_global(ident, true, size)
end
self:array_def(ident)
self:tk_match(";")
self:reset_reg_use()
else
if static then
self:sym_add_filelocal(ident)
-- post-define array size
self:sym_add_filelocal(old_ident, false, 1) -- name without postfix
self:sym_add_filelocal(ident, false, 1)
else
self:sym_add_global(ident)
end
@ -145,14 +155,14 @@ end
--[[
const_def:
= ident '=' number ';' def_list
= ident '=' const_expression ';' def_list
]]--
function BPars:const_def()
function BPars:const_def(static)
self:switch_to_var_def()
local ident = self:ident()
self:tk_match("=")
local right = '#' .. self:number()
self:sym_add_const(ident, right, "global")
local right = '#' .. self:const_expression()
self:sym_add_const(ident, right, static and "local" or "global")
self:tk_match(";")
self:reset_reg_use()
self:switch_to_func_def()
@ -162,23 +172,24 @@ end
array_def:
= '[' ']' '=' '{' const_list '}'
= '[' ']' '=' STRING
= '[' number ']' '=' '{' const_list '}'
= '[' number ']'
= '[' const_expression ']' '=' '{' const_list '}'
= '[' const_expression ']'
]]--
function BPars:array_def(ident)
self:tk_match("[")
local size = 0
if self:tk_peek().val ~= ']' then
size = self:number()
size = self:const_expression()
end
self:tk_match("]")
if self:tk_peek().val ~= '=' and size > 0 then
self:add_data(ident)
while size > 1 do
local num = size
while num > 1 do
self:append_val(0)
size = size - 1
num = num - 1
end
return
return size
end
self:tk_match("=")
if self:tk_peek().type == T_STRING then
@ -189,19 +200,21 @@ function BPars:array_def(ident)
self:add_string(ident, tok.val)
else
self:tk_match("{")
self:const_list(ident, size)
size = self:const_list(ident, size)
self:tk_match("}")
end
return size
end
--[[
const_list:
number { ',' const_list }
const_expression { ',' const_list }
]]--
function BPars:const_list(ident, size)
local num = self:number()
local num = self:const_expression()
self:add_data(ident, num)
size = size - 1
local realsize = 1
while self:tk_peek().val == ',' do
self:tk_match(",")
@ -214,12 +227,16 @@ function BPars:const_list(ident, size)
self:append_val(tok.val)
end
size = size - 1
realsize = realsize + 1
end
while size > 0 do
self:append_val(0)
size = size - 1
realsize = realsize + 1
end
return realsize
end
--[[

View File

@ -17,7 +17,7 @@ local KEYWORDS = {var=1, func=1, ["while"]=1, ["return"]=1, input=1, output=1,
["for"]=1, ["switch"]=1, ["case"]=1, ["break"]=1, ["continue"]=1, ["goto"]=1,
["and"]=1, ["or"]=1, ["not"]=1, ["xor"]=1, ["mod"]=1,
A=1, B=1, C=1, D=1, X=1, Y=1, PC=1, SP=1,
import=1, pragma=1, _asm_=1}
import=1, pragma=1, _asm_=1, sizeof=1}
local BSym = vm16.BScan:new({})
@ -47,9 +47,9 @@ function BSym:sym_add_local(ident, array_size)
end
self.stack_size = self.stack_size + 1
if array_size then
self.locals[ident] = {type = "array", ref = self.stack_size, offs = array_size - 1}
self.locals[ident] = {type = "array", ref = self.stack_size, offs = array_size - 1, size = array_size}
else
self.locals[ident] = {type = "var", ref = self.stack_size}
self.locals[ident] = {type = "var", ref = self.stack_size, size = 1}
end
end
@ -73,13 +73,13 @@ end
-------------------------------------------------------------------------------
-- Globals
-------------------------------------------------------------------------------
function BSym:sym_add_global(ident, is_array)
function BSym:sym_add_global(ident, is_array, array_size)
if self.globals[ident] then
self:error_msg(string.format("Redefinition of '%s'", ident))
elseif KEYWORDS[ident] then
self:error_msg(string.format("'%s' is a protected keyword", ident))
end
self.globals[ident] = {type = is_array and "array" or "var"}
self.globals[ident] = {type = is_array and "array" or "var", size = array_size or 1}
end
function BSym:sym_is_global(val)
@ -107,16 +107,21 @@ function BSym:next_file_for_local_vars()
self.file_locals = {}
end
function BSym:sym_add_filelocal(ident, is_array)
function BSym:sym_add_filelocal(ident, is_array, array_size)
if self.file_locals[ident] then
self:error_msg(string.format("Redefinition of '%s'", ident))
elseif KEYWORDS[ident] then
self:error_msg(string.format("'%s' is a protected keyword", ident))
end
self.file_locals[ident] = {type = is_array and "array" or "var", ref = ident .. "@" .. self.file_locals_cnt}
self.file_locals[ident] = {type = is_array and "array" or "var",
ref = ident .. "@" .. self.file_locals_cnt, size = array_size or 1}
return self.file_locals[ident].ref
end
function BSym:sym_get_filelocal_ref(ident)
return ident .. "@" .. self.file_locals_cnt
end
function BSym:sym_get_filelocal(ident)
local item = self.file_locals[ident]
if item then
@ -232,4 +237,14 @@ function BSym:sym_get_var(ident)
return self:sym_get_local(ident) or self:sym_get_filelocal(ident) or self:sym_get_global(ident)
end
function BSym:sym_get_var_size(ident)
if self:sym_get_local(ident) then
return self.locals[ident].size
elseif self:sym_get_filelocal(ident) then
return self.file_locals[ident].size
elseif self:sym_get_global(ident) then
return self.globals[ident].size
end
end
vm16.BSym = BSym

View File

@ -36,6 +36,7 @@ dofile(MP.."/bcomp/bgenerator.lua")
dofile(MP.."/bcomp/bscanner.lua")
dofile(MP.."/bcomp/bsymbols.lua")
dofile(MP.."/bcomp/bexpression.lua")
dofile(MP.."/bcomp/bconst_expr.lua")
dofile(MP.."/bcomp/bparser.lua")
dofile(MP.."/bcomp/bcompiler.lua")
dofile(MP.."/bcomp/libc.lua")

View File

@ -212,7 +212,7 @@ function Lut:is_return_line(file, address)
DBG("Lut:is_return_line", address)
if address then
local lineno = self.addr2lineno[address]
return lineno and self.step_out[file][lineno]
return lineno and self.step_out[file] and self.step_out[file][lineno]
end
DBG("Lut:is_return_line", "oops")
end

View File

@ -67,7 +67,7 @@ local function format_watch(pos, mem)
if item.name == "" then
out[#out + 1] = "----------------:----------"
else
local val = vm16.peek(mem.cpu_pos, item.addr)
local val = vm16.peek(mem.cpu_pos, item.addr or 0)
local s = minetest.formspec_escape(string.format("%-16s: %04X %d", item.name, val, val))
out[#out + 1] = s
end

View File

@ -122,6 +122,12 @@ Licensed under the GNU GPLv3 (See LICENSE.txt)
## History
### API v3.5 / Core v2.7.4 / ASM v2.5 / Compiler v1.8 / Debugger v1.3 (2022-07-08)
- Compiler: Add constant expressions
- Compiler: Add sizeof operator
- Compiler: Add static constants
### API v3.5 / Core v2.7.4 / ASM v2.5 / Compiler v1.7 / Debugger v1.3 (2022-07-08)
- Add file popup menu to the debugger

View File

@ -24,6 +24,7 @@ dofile(MP.."/bcomp/bgenerator.lua")
dofile(MP.."/bcomp/bscanner.lua")
dofile(MP.."/bcomp/bsymbols.lua")
dofile(MP.."/bcomp/bexpression.lua")
dofile(MP.."/bcomp/bconst_expr.lua")
dofile(MP.."/bcomp/bparser.lua")
dofile(MP.."/bcomp/bcompiler.lua")
dofile(MP.."/programmer/lib.lua")
@ -105,3 +106,4 @@ compile2("test12.c") -- Pointers
compile2("test13.c") -- Function local arrays
compile2("test14.c") -- Function local arrays
compile2("test15.c") -- comparison vs. expression
compile2("test16.c") -- const-expr, sizeof

View File

@ -3499,4 +3499,4 @@ brnch 25 009D: "@lbl10"
svar 27 2: "@num_stack_var@"
func 30 00A0: "loop"
svar 30 0: "@num_stack_var@"
endf 31 00AB: "test15.c"
endf 32 00AB: "test15.c"

30
test/compiler/test16.c Normal file
View File

@ -0,0 +1,30 @@
import "stdio.asm"
const MAX1 = 10;
const MAX2 = 2 * MAX1;
static const MAX3 = (MAX2 + 1) / 2;
var arr1[MAX1];
var arr2[MAX3+1] = {0,0,0,0};
static var arr3[2] = {0,0,0,0};
func init() {
var arr4[3];
putnum(MAX1);
putchar(' ');
putnum(MAX2);
putchar(' ');
putnum(MAX3);
putchar(' ');
putnum(sizeof(arr1));
putchar(' ');
putnum(sizeof(arr2));
putchar(' ');
putnum(sizeof(arr3));
putchar(' ');
putnum(sizeof(arr4));
}
func loop() {
}

View File

@ -24,6 +24,7 @@ dofile(MP.."/bcomp/bgenerator.lua")
dofile(MP.."/bcomp/bscanner.lua")
dofile(MP.."/bcomp/bsymbols.lua")
dofile(MP.."/bcomp/bexpression.lua")
dofile(MP.."/bcomp/bconst_expr.lua")
dofile(MP.."/bcomp/bparser.lua")
dofile(MP.."/bcomp/bcompiler.lua")
dofile(MP.."/programmer/lib.lua")
@ -227,4 +228,4 @@ end
--test_lookup("test08.c")
--compile_and_assemble("test01.c")
--beduino_compile("test09.c")
beduino_compile("test15.c")
beduino_compile("test16.c")