You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
449 lines
11 KiB
449 lines
11 KiB
local grammar = require 'parser.grammar'
|
|
|
|
local ast
|
|
|
|
local parse_exp
|
|
local parse_lines
|
|
|
|
local function parser_error(str)
|
|
error(('[%s]第[%d]行: %s'):format(ast.file, ast.current_line, str))
|
|
end
|
|
|
|
local function base_type(type)
|
|
while ast.types[type].extends do
|
|
type = ast.types[type].extends
|
|
end
|
|
return type
|
|
end
|
|
|
|
local function get_var(name)
|
|
if ast.current_function then
|
|
if ast.current_function.locals[name] then
|
|
return ast.current_function.locals[name]
|
|
end
|
|
if ast.current_function.args and ast.current_function.args[name] then
|
|
return ast.current_function.args[name]
|
|
end
|
|
end
|
|
return ast.globals[name]
|
|
end
|
|
|
|
local function get_function(name)
|
|
return ast.functions[name]
|
|
end
|
|
|
|
local function get_var_type(exp)
|
|
local var = get_var(exp.name)
|
|
return var.type
|
|
end
|
|
|
|
local function get_vari_type(exp)
|
|
local var = get_var(exp.name)
|
|
parse_exp(exp[1], 'integer')
|
|
return var.type
|
|
end
|
|
|
|
local function get_call(exp)
|
|
local func = ast.functions[exp.name]
|
|
if not func then
|
|
parser_error(('函数[%s]不存在'):format(exp.name))
|
|
end
|
|
for _, arg in ipairs(exp) do
|
|
parse_exp(arg)
|
|
end
|
|
return func.returns or 'null'
|
|
end
|
|
|
|
local function get_op(exp)
|
|
local t1 = parse_exp(exp[1])
|
|
local t2 = parse_exp(exp[2])
|
|
if (t1 == 'integer' or t1 == 'real') and (t2 == 'integer' or t2 == 'real') then
|
|
if t1 == 'real' or t2 == 'real' then
|
|
return 'real'
|
|
else
|
|
return 'integer'
|
|
end
|
|
end
|
|
return nil, t1, t2
|
|
end
|
|
|
|
local function get_add(exp)
|
|
local type, t1, t2 = get_op(exp)
|
|
if type then
|
|
return type
|
|
end
|
|
if (t1 == 'string' or t1 == 'null') and (t2 == 'string' or t2 == 'null') then
|
|
return 'string'
|
|
end
|
|
parser_error(('不能对[%s]与[%s]做加法运算'):format(t1, t2))
|
|
end
|
|
|
|
local function get_sub(exp)
|
|
local type, t1, t2 = get_op(exp)
|
|
if type then
|
|
return type
|
|
end
|
|
parser_error(('不能对[%s]与[%s]做减法运算'):format(t1, t2))
|
|
end
|
|
|
|
local function get_mul(exp)
|
|
local type, t1, t2 = get_op(exp)
|
|
if type then
|
|
return type
|
|
end
|
|
parser_error(('不能对[%s]与[%s]做乘法运算'):format(t1, t2))
|
|
end
|
|
|
|
local function get_div(exp)
|
|
local type, t1, t2 = get_op(exp)
|
|
if type then
|
|
return type
|
|
end
|
|
parser_error(('不能对[%s]与[%s]做除法运算'):format(t1, t2))
|
|
end
|
|
|
|
local function get_neg(exp)
|
|
local t = parse_exp(exp[1])
|
|
if t == 'real' or t == 'integer' then
|
|
return t
|
|
end
|
|
parser_error(('不能对[%s]做负数运算'):format(t))
|
|
end
|
|
|
|
local function get_equal(exp)
|
|
local t1 = parse_exp(exp[1])
|
|
local t2 = parse_exp(exp[2])
|
|
if t1 == 'null' or t2 == 'null' then
|
|
return 'boolean'
|
|
end
|
|
if (t1 == 'integer' or t1 == 'real') and (t2 == 'integer' or t2 == 'real') then
|
|
return 'boolean'
|
|
end
|
|
local b1 = base_type(t1)
|
|
local b2 = base_type(t2)
|
|
if b1 == b2 then
|
|
return 'boolean'
|
|
end
|
|
parser_error(('不能比较[%s]与[%s]是否相等'):format(t1, t2))
|
|
end
|
|
|
|
local function get_compare(exp)
|
|
local t1 = parse_exp(exp[1])
|
|
local t2 = parse_exp(exp[2])
|
|
if (t1 == 'integer' or t1 == 'real') and (t2 == 'integer' or t2 == 'real') then
|
|
return 'boolean'
|
|
end
|
|
parser_error(('不能比较[%s]与[%s]的大小'):format(t1, t2))
|
|
end
|
|
|
|
local function get_and(exp)
|
|
parse_exp(exp[1], 'boolean')
|
|
parse_exp(exp[2], 'boolean')
|
|
return 'boolean'
|
|
end
|
|
|
|
local function get_or(exp)
|
|
parse_exp(exp[1], 'boolean')
|
|
parse_exp(exp[2], 'boolean')
|
|
return 'boolean'
|
|
end
|
|
|
|
local function get_not(exp)
|
|
parse_exp(exp[1], 'boolean')
|
|
return 'boolean'
|
|
end
|
|
|
|
local function get_code(exp)
|
|
return 'code'
|
|
end
|
|
|
|
function parse_exp(exp, expect)
|
|
if exp.type == 'null' then
|
|
exp.vtype = 'null'
|
|
elseif exp.type == 'integer' then
|
|
exp.vtype = 'integer'
|
|
elseif exp.type == 'real' then
|
|
exp.vtype = 'real'
|
|
elseif exp.type == 'string' then
|
|
exp.vtype = 'string'
|
|
elseif exp.type == 'boolean' then
|
|
exp.vtype = 'boolean'
|
|
elseif exp.type == 'var' then
|
|
exp.vtype = get_var_type(exp)
|
|
elseif exp.type == 'vari' then
|
|
exp.vtype = get_vari_type(exp)
|
|
elseif exp.type == 'call' then
|
|
exp.vtype = get_call(exp)
|
|
elseif exp.type == '+' then
|
|
exp.vtype = get_add(exp)
|
|
elseif exp.type == '-' then
|
|
exp.vtype = get_sub(exp)
|
|
elseif exp.type == '*' then
|
|
exp.vtype = get_mul(exp)
|
|
elseif exp.type == '/' then
|
|
exp.vtype = get_div(exp)
|
|
elseif exp.type == 'neg' then
|
|
exp.vtype = get_neg(exp)
|
|
elseif exp.type == 'paren' then
|
|
exp.vtype = parse_exp(exp[1])
|
|
elseif exp.type == '==' then
|
|
exp.vtype = get_equal(exp)
|
|
elseif exp.type == '!=' then
|
|
exp.vtype = get_equal(exp)
|
|
elseif exp.type == '>' then
|
|
exp.vtype = get_compare(exp)
|
|
elseif exp.type == '<' then
|
|
exp.vtype = get_compare(exp)
|
|
elseif exp.type == '>=' then
|
|
exp.vtype = get_compare(exp)
|
|
elseif exp.type == '<=' then
|
|
exp.vtype = get_compare(exp)
|
|
elseif exp.type == 'and' then
|
|
exp.vtype = get_and(exp)
|
|
elseif exp.type == 'or' then
|
|
exp.vtype = get_or(exp)
|
|
elseif exp.type == 'not' then
|
|
exp.vtype = get_not(exp)
|
|
elseif exp.type == 'code' then
|
|
exp.vtype = get_code(exp)
|
|
else
|
|
print('解析未定义的表达式类型:', exp.type)
|
|
end
|
|
if not exp.vtype then
|
|
print('没有解析到类型:', exp.type)
|
|
end
|
|
return exp.vtype
|
|
end
|
|
|
|
local function parse_type(data)
|
|
ast.current_line = data.line
|
|
if not ast.types[data.extends] then
|
|
parser_error(('类型[%s]未定义'):format(data.extends))
|
|
end
|
|
if ast.types[data.name] and not ast.types[data.name].extends then
|
|
parser_error('不能重新定义本地类型')
|
|
end
|
|
if ast.types[data.name] then
|
|
parser_error(('类型[%s]重复定义 --> 已经定义在[%s]第[%d]行'):format(data.name, ast.types[data.name].file, ast.types[data.name].line))
|
|
end
|
|
ast.types[data.name] = data
|
|
end
|
|
|
|
local function parse_global(data)
|
|
ast.current_line = data.line
|
|
if ast.globals[data.name] then
|
|
parser_error(('全局变量[%s]重复定义 --> 已经定义在[%s]第[%d]行'):format(data.name, ast.globals[data.name].file, ast.globals[data.name].line))
|
|
end
|
|
if data.constant and not data[1] then
|
|
parser_error('常量必须初始化')
|
|
end
|
|
if not ast.types[data.type] then
|
|
parser_error(('类型[%s]未定义'):format(data.type))
|
|
end
|
|
if data.array and data[1] then
|
|
parser_error('数组不能直接初始化')
|
|
end
|
|
if data[1] then
|
|
parse_exp(data[1], data.type)
|
|
end
|
|
table.insert(ast.globals, data)
|
|
ast.globals[data.name] = data
|
|
end
|
|
|
|
local function parse_globals(chunk)
|
|
for _, func in ipairs(ast.functions) do
|
|
if not func.native then
|
|
ast.current_line = chunk.line
|
|
parser_error '全局变量必须在函数前定义'
|
|
end
|
|
end
|
|
for _, data in ipairs(chunk) do
|
|
parse_global(data)
|
|
end
|
|
end
|
|
|
|
local function parse_arg(data, args)
|
|
args[data.name] = data
|
|
end
|
|
|
|
local function parse_args(chunk)
|
|
if not chunk.args then
|
|
return
|
|
end
|
|
for _, arg in ipairs(chunk.args) do
|
|
parse_arg(arg, chunk.args)
|
|
end
|
|
end
|
|
|
|
local function parse_local(data, locals, args)
|
|
ast.current_line = data.line
|
|
if not ast.types[data.type] then
|
|
parser_error(('类型[%s]未定义'):format(data.type))
|
|
end
|
|
if data.array and data[1] then
|
|
parser_error('数组不能直接初始化')
|
|
end
|
|
if args and args[data.name] then
|
|
parser_error(('局部变量[%s]和函数参数重名'):format(data.name))
|
|
end
|
|
if data[1] then
|
|
parse_exp(data[1], data.type)
|
|
end
|
|
locals[data.name] = data
|
|
end
|
|
|
|
local function parse_locals(chunk)
|
|
for _, data in ipairs(chunk.locals) do
|
|
parse_local(data, chunk.locals, chunk.args)
|
|
end
|
|
end
|
|
|
|
local function parse_loop(chunk)
|
|
ast.loop_count = ast.loop_count + 1
|
|
parse_lines(chunk)
|
|
ast.loop_count = ast.loop_count - 1
|
|
end
|
|
|
|
local function parse_if(data)
|
|
for _, chunk in ipairs(data) do
|
|
if chunk.type == 'if' or chunk.type == 'elseif' then
|
|
parse_exp(chunk.condition, 'boolean')
|
|
end
|
|
parse_lines(chunk)
|
|
end
|
|
end
|
|
|
|
local function parse_call(line)
|
|
local func = get_function(line.name)
|
|
if not func.args then
|
|
return
|
|
end
|
|
for i, arg in ipairs(func.args) do
|
|
parse_exp(line[i], arg.type)
|
|
end
|
|
end
|
|
|
|
local function parse_set(line)
|
|
local var = get_var(line.name)
|
|
parse_exp(line[1], var.vtype)
|
|
end
|
|
|
|
local function parse_seti(line)
|
|
local var = get_var(line.name)
|
|
parse_exp(line[1], 'integer')
|
|
parse_exp(line[2], var.vtype)
|
|
end
|
|
|
|
local function parse_return(line)
|
|
local func = ast.current_function
|
|
if not func.returns then
|
|
return
|
|
end
|
|
parse_exp(line[1], func.returns)
|
|
end
|
|
|
|
local function parse_exit(line)
|
|
if ast.loop_count == 0 then
|
|
parser_error '不能在循环外使用exitwhen'
|
|
end
|
|
parse_exp(line[1], 'boolean')
|
|
end
|
|
|
|
local function parse_line(line)
|
|
ast.current_line = line.line
|
|
if line.type == 'loop' then
|
|
parse_loop(line)
|
|
elseif line.type == 'if' then
|
|
parse_if(line)
|
|
elseif line.type == 'call' then
|
|
parse_call(line)
|
|
elseif line.type == 'set' then
|
|
parse_set(line)
|
|
elseif line.type == 'seti' then
|
|
parse_seti(line)
|
|
elseif line.type == 'return' then
|
|
parse_return(line)
|
|
elseif line.type == 'exit' then
|
|
parse_exit(line)
|
|
else
|
|
parser_error('未知的语句类型:'..line.type)
|
|
end
|
|
end
|
|
|
|
function parse_lines(chunk)
|
|
for i, line in ipairs(chunk) do
|
|
parse_line(line)
|
|
end
|
|
end
|
|
|
|
local function parse_function(chunk)
|
|
table.insert(ast.functions, chunk)
|
|
ast.functions[chunk.name] = chunk
|
|
|
|
if chunk.native then
|
|
return
|
|
end
|
|
|
|
ast.current_function = chunk
|
|
ast.loop_count = 0
|
|
|
|
parse_args(chunk)
|
|
parse_locals(chunk)
|
|
parse_lines(chunk)
|
|
|
|
ast.current_function = nil
|
|
end
|
|
|
|
local function parser_gram(gram)
|
|
for i, chunk in ipairs(gram) do
|
|
if chunk.type == 'globals' then
|
|
parse_globals(chunk)
|
|
elseif chunk.type == 'function' then
|
|
parse_function(chunk)
|
|
elseif chunk.type == 'type' then
|
|
parse_type(chunk)
|
|
else
|
|
parser_error('未知的区块类型:'..chunk.type)
|
|
end
|
|
end
|
|
end
|
|
|
|
return function (jass, file, _ast)
|
|
if _ast then
|
|
ast = _ast
|
|
|
|
for i = 1, #ast.functions do
|
|
ast.functions[i] = nil
|
|
end
|
|
for i = 1, #ast.globals do
|
|
ast.globals[i] = nil
|
|
end
|
|
else
|
|
ast = {}
|
|
ast.types = {
|
|
null = {type = 'type'},
|
|
handle = {type = 'type'},
|
|
code = {type = 'type'},
|
|
integer = {type = 'type'},
|
|
real = {type = 'type'},
|
|
boolean = {type = 'type'},
|
|
string = {type = 'type'},
|
|
}
|
|
ast.globals = {}
|
|
ast.functions = {}
|
|
end
|
|
|
|
ast.file = file
|
|
|
|
local gram, comments = grammar(jass, file)
|
|
|
|
parser_gram(gram)
|
|
|
|
ast.current_line = nil
|
|
ast.loop_count = nil
|
|
ast.file = nil
|
|
|
|
ast.comments = comments
|
|
|
|
return ast, gram
|
|
end
|
|
|