模块:Complex Number/Calculate

维基百科,自由的百科全书
跳到导航 跳到搜索
文档图示 模块文档[创建]
local p = {}
local getArgs = require('Module:Arguments').getArgs
local ext_mathlib = require("Module:Complex Number/Functions")._init

function p.calc_table(frame)
	local variable_process = require("Module:Number/data")
    local args
    local can_math = false
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        args = getArgs(frame) --frame.args
        local yesno = require('Module:Yesno')
        can_math = yesno(args['use math'] or args['use_math'])
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
    end
    local first_number_list = {"2","3","4","5","6","7","8","9"}
    local second_number_list
    local calculate_str, calculate_title = "{{{left}}} * {{{right}}}", "×"
	if args['number list'] or args['number_list'] then first_number_list = mw.text.split(args['number list'] or args['number_list'] or '',',') end
	if args['number list2'] or args['number_list2'] then second_number_list = mw.text.split(args['number list2'] or args['number_list2'] or '',',') end
	if args['calculate'] then calculate_str = mw.text.trim(args['calculate']) end
	if args['calculate title'] or args['calculate_title'] then calculate_title = mw.text.trim(args['calculate title'] or args['calculate_title']) end
	if second_number_list == nil or (second_number_list and (second_number_list == {} or #second_number_list == 0) ) then
		second_number_list = first_number_list
	end
	local body, buffer_str, table_str = "", '', ''
	if comp_number == nil then comp_number = require("Module:Complex Number") end
    local cmath, qmath, bmath = comp_number.cmath.init(), comp_number.qmath.init(), comp_number.bmath.init()
    local mathtag = p.tagmath.init()
	body = body .. "! " .. (args["main head css"] or args["main_head_css"] or '') .. " | " .. calculate_title .. ' \n'
	for j=1,#second_number_list do
		local second_it = mw.text.trim(second_number_list[j] or '')
		if second_it ~= nil then
			local second_num_math = second_it
			if can_math then second_num_math = frame:callParserFunction{name = "#tag:math", args = {second_num_math}} end
			body = body .. "! " .. (args["head css"] or args["head_css"] or '') .. " | " .. second_num_math .. ' \n'
		end
	end
	body = body .. '\n'
	for i=1,#first_number_list do
		local first_it = mw.text.trim(first_number_list[i] or '')
		if first_it ~= nil then
			body = body .. "|-\n"; table_str = ''
			local first_num_math = tostring(first_it)
			if can_math then first_num_math = frame:callParserFunction{name = "#tag:math", args = {first_num_math}} end
			body = body .. "! " .. (args["head css"] or args["head_css"] or '') .. " | "  .. first_num_math .. " \n"
			for j=1,#second_number_list do
				local second_it = mw.text.trim(second_number_list[j] or '')
				if second_it ~= nil then
					
					buffer_str = variable_process._getFormatingStringByArgument(calculate_str, {
						left=tostring(first_it),right=tostring(second_it)
					})
					local exec_result = p.calc( buffer_str or '', ( {
						cmath = cmath,
						qmath = qmath,
						bmath = bmath,
						mathtag = mathtag,
					} ) [ args['class'] ] , (( {
						cmath = cmath.toComplexNumber,
						qmath = qmath.toQuaternionNumber,
						bmath = bmath.toBoolean,
						mathtag = mathtag.toTagMath,
					} ) [ args['class'] ] ) )
					local exec_result_str = mw.text.trim(tostring(exec_result) or '')
					local exec_check = mw.text.trim((tonumber(exec_result_str) and args[tonumber(exec_result_str)]) or args[exec_result_str] or '')
					if exec_check == '' then exec_check = nil end
					table_str = table_str .. '|' .. (exec_check or args["number css"] or args["number_css"] or '') .. "| "
					if can_math then exec_result_str = frame:callParserFunction{name = "#tag:math", args = {exec_result_str}} end
					table_str = table_str .. mw.text.trim(exec_result_str) .. ' \n'
				end
			end
			body = body .. table_str
		end
	end
	if use_ext_mathlib == true then body = mw.text.trim(body) .. "[[Category:使用擴充複變函數庫的頁面]]" end
	return body
end

function p.calculate(frame)
    local args
    local can_math = false
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        args = getArgs(frame) --frame.args
        local yesno = require('Module:Yesno')
        can_math = yesno(args['use math'] or args['use_math'])
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
    end
	if comp_number == nil then comp_number = require("Module:Complex Number") end
    local cmath, qmath, bmath = comp_number.cmath.init(), comp_number.qmath.init(), comp_number.bmath.init()
    local mathtag = p.tagmath.init()
	local body = p.calc( args[1] or args['1'] or '', ( {
		cmath = cmath,
		qmath = qmath,
		bmath = bmath,
		mathtag = mathtag,
	} ) [ args['class'] ] , (( {
		cmath = cmath.toComplexNumber,
		qmath = qmath.toQuaternionNumber,
		bmath = bmath.toBoolean,
		mathtag = mathtag.toTagMath,
	} ) [ args['class'] ] ) )
	if can_math then body = frame:callParserFunction{name = "#tag:math", args = {tostring(body)}} end
	return body
end

function p.functionGraph(frame)
	if comp_number == nil then comp_number = require("Module:Complex Number") end
    local cmath, qmath = comp_number.cmath.init(), comp_number.qmath.init()
	if not getArgs then getArgs = require('Module:Arguments').getArgs end
	local args = getArgs(frame, {parentFirst=true})
	local exprs = {}
	local body_args, x_start, x_end, y_min, y_max, sampling = {}, 0, 1, nil, nil, 50
	for arg_name, arg_value in pairs( args ) do
		if tonumber(arg_name) ~= nil then exprs[#exprs + 1] = arg_value
		elseif  mw.ustring.lower(arg_name) == "start" then x_start = tonumber(arg_value)
		elseif  mw.ustring.lower(arg_name) == "end" then x_end = tonumber(arg_value)
		elseif  mw.ustring.lower(arg_name) == "sampling" then sampling = tonumber(arg_value)
		elseif  mw.ustring.lower(arg_name) == "min" then y_min = tonumber(arg_value)
		elseif  mw.ustring.lower(arg_name) == "max" then y_max = tonumber(arg_value)
		else body_args[arg_name] = arg_value
		end
	end
    local body = p._functionGraph(exprs,
    	x_start, x_end, sampling, y_min, y_max, body_args, ( {
		cmath = cmath,
		qmath = qmath,
	} ) [ frame.args['class'] ] , (( {
		cmath = cmath.toComplexNumber,
		qmath = qmath.toQuaternionNumber,
	} ) [ frame.args['class'] ] ) )
	body.width = 400
	body.height = 100; body.type="line"
	body.interpolate = frame.args['interpolate'] or "monotone"
	for arg_name, arg_value in pairs( body_args ) do
		body[arg_name] = arg_value
	end
	body = mw.getCurrentFrame():expandTemplate{title = "Graph:Chart", args = body}
	if use_ext_mathlib == true then body = mw.text.trim(body) .. "[[Category:使用擴充複變函數庫的頁面]]" end
	return body
end

function p.toPostfix(frame)
    local args
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        args = getArgs(frame) --frame.args
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
    end
	local format =  args['format'] or "{{{1}}} ";
	format = mw.ustring.gsub(format, "%{%{%{.-%}%}%}", "%%s" );
	local it = mw.ustring.find(format, "%%s", 1)
	format = mw.ustring.gsub(format, "\\n", "\n")
	local result, body = p.infixToPostfix( args[1] or args['1'] or '' ), ''
	for i, result_str in pairs( result ) do
		if mw.text.trim(result_str.name) ~= '|' then
			body = body .. mw.ustring.gsub(format, "%%s", tostring(result_str.name)) 
		end
	end
	if use_ext_mathlib == true then body = mw.text.trim(body) .. "[[Category:使用擴充複變函數庫的頁面]]" end
	return body
end

function p._functionGraph(expr_arr,x_start,x_end,sampling, y_min, y_max, body_args,  math_lib, number_Constructer)
	if comp_number == nil then comp_number = require("Module:Complex Number") end
	math = comp_number.math.init()
	local mathlib, numberConstructer = math_lib or math, number_Constructer or tonumber
	local postfix = {}
	local check_func = {}
	local x_arr, y_arr = {}, {}
	if type(expr_arr) == type({}) then
		for i=1,#expr_arr do
			local check_parametric = mw.text.split(expr_arr[i],';')
			if #check_parametric == 1 then
				postfix[#postfix + 1] = p.infixToPostfix(expr_arr[i], debug_flag)
			elseif #check_parametric >= 3 then
				postfix[#postfix + 1]={parametric=true}
				postfix[#postfix].x_name = check_parametric[1] or 't'
				postfix[#postfix].y_name = check_parametric[2] or 't'
				postfix[#postfix].x = p.infixToPostfix(check_parametric[1] or 't', debug_flag)
				postfix[#postfix].y = p.infixToPostfix(check_parametric[2] or 't', debug_flag)
				postfix[#postfix].t = check_parametric[3] or 't'
				postfix[#postfix].min = numberConstructer(check_parametric[4]) or numberConstructer(0)
				postfix[#postfix].max = numberConstructer(check_parametric[5]) or numberConstructer(1)
			end
			y_arr[#y_arr + 1] = {}
			x_arr[#x_arr + 1] = {}
		end
	else
		local check_parametric = mw.text.split(expr_arr,';')
		if #check_parametric == 1 then
			postfix[#postfix + 1] = p.infixToPostfix(expr_arr, debug_flag)
		elseif #check_parametric >= 3 then
			postfix[#postfix + 1]={parametric=true}
			postfix[#postfix].x_name = check_parametric[1] or 't'
			postfix[#postfix].y_name = check_parametric[2] or 't'
			postfix[#postfix].x = p.infixToPostfix(check_parametric[1] or 't', debug_flag)
			postfix[#postfix].y = p.infixToPostfix(check_parametric[2] or 't', debug_flag)
			postfix[#postfix].t = check_parametric[3] or 't'
			postfix[#postfix].min = numberConstructer(check_parametric[4]) or numberConstructer(0)
			postfix[#postfix].max = numberConstructer(check_parametric[5]) or numberConstructer(1)
		end
		y_arr[#y_arr + 1] = {}
		x_arr[#x_arr + 1] = {}
	end
	for i=0,sampling do
		local it = x_start + (i * (x_end-x_start) / sampling)
		local x_val = it
		for j=1,#expr_arr do
			local calc_val = " "
			xpcall(function() 
				if type(postfix[j]) == type({}) and postfix[j].parametric == true then
					local it_t = postfix[j].min + (i * (postfix[j].max - postfix[j].min) / sampling)
					calc_val = p.calc_by_postfix(postfix[j].y, {[postfix[j].t]=it_t}, mathlib, numberConstructer, false)
					x_val = p.calc_by_postfix(postfix[j].x, {[postfix[j].t]=it_t}, mathlib, numberConstructer, false)
				else
					calc_val = p.calc_by_postfix(postfix[j], {x=it}, mathlib, numberConstructer, false) 
					if( tonumber((body_args or {})["calc diff " .. tostring(j) ]) == 1 )then
						local dy = p.calc_by_postfix(postfix[j], {x=(it + 1e-6)}, mathlib, numberConstructer, false)
						calc_val = 1e6 * (dy - calc_val)
					end
				end
				if y_max and mathlib.re(calc_val) > y_max then calc_val = y_max end
				if y_min and mathlib.re(calc_val) < y_min then calc_val = y_min end
				if x_end and mathlib.re(x_val) > x_end then x_val = x_end end
				if x_start and mathlib.re(x_val) < x_start then x_val = x_start end
			end,function(_)end)
			if tonumber((body_args or {})["round number"]) ~= nil then 
				if calc_val then 
					calc_val = mathlib.round(calc_val, tonumber((body_args or {})["round number"]), 10)
				end
			end
			if tonumber((body_args or {})["nonreal is nan"]) == 1 then 
				if math.abs(tonumber(mathlib.abs(mathlib.nonRealPart(calc_val))) or 0) > 1e-14 then calc_val = nil end
			end
			local num_check = mw.ustring.lower(tostring(numberConstructer(calc_val)))
			if mw.ustring.match(num_check,"nan") or mw.ustring.match(num_check,"nil") or mw.ustring.match(num_check,"inf") then calc_val = ' ' end
			 num_check = mw.ustring.lower(tostring(numberConstructer(x_val)))
			if mw.ustring.match(num_check,"nan") or mw.ustring.match(num_check,"nil") or mw.ustring.match(num_check,"inf") then x_val = ' ' end
			y_arr[j][ (#(y_arr[j]) + 1) ] = tostring(calc_val)
			x_arr[j][ (#(x_arr[j]) + 1) ] = tostring(x_val)
		end
	end
	local result={}
	if #expr_arr > 0 then result.legend = "functions" end
	for i=1,#expr_arr do
		result['x'] = table.concat(x_arr[i],',')
		result['y' .. tostring(i)] = table.concat(y_arr[i],',')
		result['y' .. tostring(i) .. "Title"] = tostring( (body_args or {})[tostring(i) .. " name" ] or expr_arr[i] )
		if type(postfix[i]) == type({}) and postfix[i].parametric == true then
			result['y' .. tostring(i) .. "Title"] = "x=" .. postfix[i].x_name .. "; y=" .. postfix[i].y_name
		elseif( tonumber((body_args or {})["calc diff " .. tostring(i) ]) == 1 )then
			result['y' .. tostring(i) .. "Title"] = '( ' .. result['y' .. tostring(i) .. "Title"] .. " )\'"
		end
		
		if check_func[ result['y' .. tostring(i) .. "Title"] ] ~= nil then
			local new_name = result['y' .. tostring(i) .. "Title"] .. " ,(" .. tostring(check_func[ result['y' .. tostring(i) .. "Title"] ]+1) .. ")"
			check_func[ result['y' .. tostring(i) .. "Title"] ] = check_func[ result['y' .. tostring(i) .. "Title"] ] + 1
			result['y' .. tostring(i) .. "Title"] = new_name
		else check_func[ result['y' .. tostring(i) .. "Title"] ] = 1
		end
	end
	return result
end

function numberToAZ(num)
	local body = ''
	local s = tostring(math.floor(tonumber(num)))
	for i = 1, #s do
		body = body .. mw.ustring.char(tonumber(s:sub(i, i)) + 65)
	end
	return body
end

function stringToTable(s) --字串轉陣列
	local t, i = {}, 1
	while i <= #s do
		if s:sub(i, i) ~= ' ' then
			local j, k = mw.ustring.find(s,"[%d%a]+",i)
			if (j or (i+1)) > i then
				t[#t + 1] = s:sub(i, i)
			else
				t[#t + 1] = s:sub(j, k)
				i = k
			end
		end
		i = i + 1
	end
	return t
end

function print_sk(sk,sp)
	local body, sp_checker = '', mw.text.trim(sp or '')
	for i = 1,#sk do
		if mw.text.trim( ((type(sk[i]) == type({})) and sk[i].name or nil) or sk[i]) ~= sp_checker then
			if body ~= '' then body = body .. (sp or ' ') end
			if type(sk[i]) == type({}) and sk[i].name then 
				if sk[i].name == "$END" then body = body .. '$' else body = body .. sk[i].name end
			else body = body .. tostring(sk[i]) end
		end
	end
	return body
end

--mw.log(p.calc("45*5+(1+5-9+((12-5)+5i+(9)/4)*sqrt(-6))*-8",require("Module:Complex Number").cmath.init(),require("Module:Complex Number").cmath.init().toComplexNumber,true))
-- 346.97959 - 181.262241 i
--mw.log(p.calc("45*5+(1+5-9+((12-5)+5+(9)/4)*sin(-6))*-8",nil,nil,true))
-- 217.146633205
--mw.log(p.calc("(i*j*k)",require("Module:Complex Number").qmath.init(),require("Module:Complex Number").qmath.init().toQuaternionNumber,true))
-- (-1)
function p.calc(input_str, math_lib, number_Constructer, debug_flag)
	if comp_number == nil then comp_number = require("Module:Complex Number") end
	math = comp_number.math.init()
	local mathlib, numberConstructer = math_lib or math, number_Constructer or tonumber
	local adj_input_str = input_str
	if math_lib and math_lib.is_bool_lib == true then adj_input_str = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(' ' .. input_str .. ' ',"%s+and%s+"," * "),"[&∧]","*"),"%s+or%s+"," + "),"∨","+"),"%s+not%s+"," - "),"¬","-") end
	local postfix = p.infixToPostfix(adj_input_str, debug_flag)
	return p.calc_by_postfix(postfix, {}, math_lib, number_Constructer, debug_flag)
end

function p.calc_by_postfix(postfix, scope, math_lib, number_Constructer, debug_flag)
	if comp_number == nil then comp_number = require("Module:Complex Number") end
	math = comp_number.math.init()
	local mathlib, numberConstructer = math_lib or math, number_Constructer or tonumber

	local call_stack = {{}}
	local calc_stack = {}
	local dbg_func, do_dbg = mw.log, true
	if debug_flag ~= true then dbg_func, do_dbg = function()end,false end
	for i = 1,#postfix do
		local it = postfix[i]
		if it.propetry == "func start" then
			call_stack[#call_stack + 1] = {}
		elseif it.propetry == "operator" then
			local opdata = p.symbol_table[it.name]
			xpcall(function() 
				if it.name == ',' then
					if calc_stack[#calc_stack-1] ~= ',' then (call_stack[#call_stack])[#(call_stack[#call_stack]) + 1] = calc_stack[#calc_stack-1] end 
					if calc_stack[#calc_stack] ~= ',' then (call_stack[#call_stack])[#(call_stack[#call_stack]) + 1] = calc_stack[#calc_stack] end 
					calc_stack[#calc_stack] = nil; calc_stack[#calc_stack] = ','
				elseif opdata.count == 1 then
					calc_stack[#calc_stack] = opdata.calc(calc_stack[#calc_stack],mathlib,numberConstructer)
				else
					calc_stack[#calc_stack - 1] = opdata.calc(calc_stack[#calc_stack - 1]or 0 ,calc_stack[#calc_stack]or 0,mathlib,numberConstructer)
					calc_stack[#calc_stack] = nil
				end
			end, function(message)
				error("計算失敗:套用運算子 \"" .. mw.text.trim(it.name) .. "\" 發生錯誤 \"" .. message .. "\" .")
			end)
			xpcall(function() (calc_stack[#calc_stack]):clean() end,function(_)end)
			if do_dbg == true then dbg_func(it.name, '\t', print_sk(calc_stack,', ') ) end
		elseif it.propetry == "func" then
			local calfunc, functype = mathlib[it.name], type(tonumber)
			if type(calfunc) ~= functype and type((scope or {})[it.name]) == functype then calfunc = scope[it.name] end
			if type(calfunc) ~= functype and type(_G[it.name]) == functype then calfunc = _G[it.name] end
			if type(calfunc) ~= functype and mathlib.noncalculate ~= true and mathlib.ext_loaded ~= true then
				mathlib = ext_mathlib(mathlib, numberConstructer)
				calfunc = mathlib[it.name]
				if use_ext_mathlib ~= true and type(calfunc) == functype then use_ext_mathlib = true end
			end
			local callstr = it.name
			if type(calfunc) == functype then
				xpcall(function() 
					local call_stack_top = {}
					for j = 1, #(call_stack[#call_stack]) do call_stack_top[#call_stack_top + 1] = (call_stack[#call_stack])[j] end
					if call_stack_top == ',' or call_stack_top == '' or call_stack_top == nil then 
						call_stack_top[#call_stack_top + 1] = calc_stack[#calc_stack]
					end
					if #call_stack_top > 0 then
						if do_dbg == true then callstr = callstr .. '(' .. print_sk(call_stack_top,',') .. ')' end
						calc_stack[#calc_stack] = calfunc( unpack( call_stack_top ) )
					else
						calc_stack[#calc_stack] = calfunc( calc_stack[#calc_stack] )
					end
					call_stack[#call_stack] = nil
				end, function(message)
					error("計算失敗:執行函數 \"" .. it.name .. "\" 發生錯誤 \"" .. message .. "\" .")
				end)
			else
				error("計算失敗:無法執行函數 \"" .. it.name .. "\" ")
			end
			xpcall(function() (calc_stack[#calc_stack]):clean() end,function(_)end)
			if do_dbg == true then dbg_func(callstr, '\t', print_sk(calc_stack,', ') ) end
		else
			local get_data = numberConstructer(it.name)
			if get_data == nil then get_data = numberConstructer((scope or {})[it.name]) or numberConstructer(_G[it.name]) or numberConstructer(mathlib[it.name]) or numberConstructer(it.name) end
			if get_data == nil then error("計算失敗:未知的變數 \"" .. it.name .. "\" ") end
			calc_stack[#calc_stack + 1] = get_data
			xpcall(function() (calc_stack[#calc_stack]):clean() end,function(_)end)
			if do_dbg == true then dbg_func(it.name, '\t', print_sk(calc_stack,', ') ) end
		end
	end
	if #calc_stack == 1 then 
		return calc_stack[#calc_stack] 
	elseif #calc_stack > 1 then 
		error("計算失敗:缺少運算子,數字 [" .. print_sk(calc_stack,', ') .. "] 無法運算。")
	end
	return numberConstructer(0)
end

p.symbol_table = {
		['+'] = { propetry="op", multp = true, count = 2, priority=2, ppriority=2, calc=function(a,b,c,d)return d(a)+d(b) end},
		["+ "] = { propetry="op", count = 1, priority=6, ppriority=6, calc=function(a,c,d)return d(a) end},
		['-'] = { propetry="op", multp = true, count = 2, priority=2, ppriority=2, calc=function(a,b,c,d)return d(a)-d(b) end},
		["- "] = { propetry="op", count = 1, priority=6, ppriority=6, calc=function(a,c,d)return -d(a) end},
		['*'] = { propetry="op", multp = true, count = 2, priority=3, ppriority=3, calc=function(a,b,c,d)return d(a)*d(b) end},
		["* "] = { propetry="op", count = 1, priority=6, ppriority=6 , calc=function(a,c,d) if type(c.conjugate)==type(function()end) then return c.conjugate(d(a))else return d(a)end end},
		['/'] = { propetry="op", count = 2, priority=3, ppriority=3, calc=function(a,b,c,d)return d(a)/d(b) end},
		['%'] = { propetry="op", count = 2, priority=3, ppriority=3, calc=function(a,b,c,d)return d(a)%d(b) end},
		['^'] = { propetry="op", count = 2, priority=5, ppriority=4, calc=function(a,b,c,d)return c.pow(d(a),d(b)) end},
		[','] = { propetry="op", count = 2, priority=1, ppriority=1 },
}



function p.infixToPostfix(input_str, debug_flag)
	local str, index, num_list = input_str, 0, {}; 
	local dbg_func, do_dbg = mw.log, true
	if debug_flag ~= true then dbg_func, do_dbg = function()end,false end
	str = mw.ustring.gsub(str,"([A-Za-hj-z])i","%1I")
	str = mw.ustring.gsub(str,"([A-Za-ik-z])j","%1J")
	str = mw.ustring.gsub(str,"([A-Za-jl-z])k","%1K")
	str = mw.ustring.gsub(str,"i([A-Za-hj-z])","I%1")
	str = mw.ustring.gsub(str,"j([A-Za-ik-z])","J%1")
	str = mw.ustring.gsub(str,"k([A-Za-jl-z])","K%1")
	local result = mw.ustring.gsub(str,"%d*%.?%d*%s*[ijk]?",
		function(b) 
			if b ~= nil and mw.text.trim(b) ~= '' then 
				index = index + 1 
				num_list[#num_list + 1] = b 
				return tostring(index) 
			end 
			return ''
		end 
	); 
	result = mw.ustring.gsub(result,"I","i")
	result = mw.ustring.gsub(result,"J","j")
	result = mw.ustring.gsub(result,"K","k")
	--------------------------------------------------------
	local str2, index, azid, func_list = result, 0, '', {}; 
	local result = mw.ustring.gsub(str2,"%a[%a%d]*%s*%(?",
		function(b) 
			if b ~= nil and mw.text.trim(b) ~= '' then 
				if mw.ustring.find(b,"%(") then
					local func_name = mw.ustring.match(b,"%a[%a%d]*")
					if func_name ~= nil and mw.text.trim(func_name) ~= '' then  
						index, azid = index + 1, numberToAZ(index)
						func_list[azid] = func_name 
						return ' ' .. azid .. ' '
					end
				else
					num_list[#num_list + 1] = b 
					return tostring(#num_list) 
				end
			end 
			return ''
		end 
	); 
	for i=1,#num_list do num_list[i] = mw.ustring.gsub(num_list[i],"%s+",'') end
	
	local mid_expr = stringToTable(result)
	mid_expr[#mid_expr + 1] = "$END"
	local stack, postfix = {{name="$END",elements=0}}, {}
	for i = 1,#mid_expr do
		local it = mid_expr[i]
		if it == "$END" then
			while #stack > 0 and stack[#stack].name ~= "$END"  do
				if stack[#stack].elements < p.symbol_table[stack[#stack].name].count then
					if do_dbg == true then dbg_func("==operator ",stack[#stack].name, " need ",p.symbol_table[stack[#stack].name].count, " elements, but got ",stack[#stack].elements) end
					return {}
				end
				postfix[#postfix + 1] = {name=stack[#stack].name, propetry=stack[#stack].propetry}
				stack[#stack] = nil --pop
				stack[#stack].elements = (stack[#stack].elements or 0) + 1
			end
			if do_dbg == true then dbg_func("結束",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack)) end
		elseif mw.ustring.match(it,"[%a%(]") then
			stack[#stack + 1] = {name=it,elements=0,propetry='func'}
			if do_dbg == true then dbg_func(it, "括號開始",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack)) end
			if func_list[it] ~= nil then postfix[#postfix + 1] = {name=' ', propetry="func start"} end
		elseif p.symbol_table[it] ~= nil and p.symbol_table[it].propetry == "op" then
			local op_it = p.symbol_table[it]
			local op_ls = p.symbol_table[mid_expr[i-1]]
			local flag = mw.ustring.match(mid_expr[i-1] or '',"[%a%(]") if (mid_expr[i-1] or '娜娜奇') == '娜娜奇' then flag = false end
			if ( op_ls or (i == 1) or flag ) and op_it.multp == true then
				stack[#stack + 1] = {name=it .. ' ',elements=0,propetry='operator'}
			else
				while p.symbol_table[stack[#stack].name] and p.symbol_table[stack[#stack].name].priority and
					p.symbol_table[stack[#stack].name].ppriority >= p.symbol_table[it].priority do
						if stack[#stack].elements < p.symbol_table[stack[#stack].name].count then
							if do_dbg == true then dbg_func("==operator ",stack[#stack].name, " need ",p.symbol_table[stack[#stack].name].count, " elements, but got ",stack[#stack].elements) end
							return {}
						end
					postfix[#postfix + 1] = {name=stack[#stack].name, propetry=stack[#stack].propetry}
					stack[#stack] = nil --pop
					stack[#stack].elements = (stack[#stack].elements or 0) + 1
				end
				stack[#stack + 1] = {name=it,elements=1, propetry='operator'}
			end
			if do_dbg == true then dbg_func(it, "運算子",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack)) end
		elseif mw.ustring.match(it,"%d+") then
			postfix[#postfix + 1] = {name=num_list[tonumber(it)] or ("N" .. it), propetry="number"}
			stack[#stack].elements = (stack[#stack].elements or 0) + 1
			if do_dbg == true then dbg_func(it, "數字",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack)) end
		elseif it == ')' then
			local flag = mw.ustring.match(stack[#stack].name,"[%a%(]")
			while flag == nil do --遇 ) 輸出至 ( 
				if stack[#stack].elements < p.symbol_table[stack[#stack].name].count then
					if do_dbg == true then dbg_func("==operator ",stack[#stack].name, " need ",p.symbol_table[stack[#stack].name].count, " elements, but got ",stack[#stack].elements) end
					return {}
				end
				postfix[#postfix + 1] = {name=stack[#stack].name, propetry=stack[#stack].propetry}
				stack[#stack] = nil --pop
				stack[#stack].elements = (stack[#stack].elements or 0) + 1
				flag = mw.ustring.match(stack[#stack].name,"[%a%(]")
			end
			if mw.ustring.match(stack[#stack].name,"%a") then
				postfix[#postfix + 1] = {name=func_list[stack[#stack].name] or stack[#stack].name, propetry=stack[#stack].propetry}
			end
			stack[#stack] = nil --pop
			stack[#stack].elements = (stack[#stack].elements or 0) + 1
			if do_dbg == true then dbg_func(it, "結束括號",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack))end
		end
	end
	return postfix

end

--表達式輸出為<math></math>支援
p.tagmath={
	pow=function(op1,op2)
		return p.tagmath.apply_binary_operator(op1,op2,'^','^',false,true)
	end,
	div=function(op1,op2)
		local left, right = p.tagmath.toTagMath(op1), p.tagmath.toTagMath(op2)
		left.lowoperator = ''
		left.value = "\\frac{ " .. left.value .. " }{ " .. right.value .. "}"
		return left 
	end,
	sqrt=function(op1,op2)
		local left = p.tagmath.toTagMath(op1)
		if op2 ~= nil then
			local right = p.tagmath.toTagMath(op2)
			left.value = "\\sqrt[ " .. right.value .. " ]{ " .. left.value .. "}"
		else
			left.value = "\\sqrt{ " .. left.value .. " }"
		end
		left.lowoperator = ''
		return left 
	end,
	log=function(op1,op2)
		local left, right, vals, log_symbol
		if op2 ~= nil then
			right, left = p.tagmath.toTagMath(op1), p.tagmath.toTagMath(op2)
			vals = "_{" .. right.value .. "}"
			log_symbol = "log " 
		else 
			left, vals = p.tagmath.toTagMath(op1), ''
			log_symbol = "ln "
		end
		if left.lowoperator ~= '(' and left.lowoperator ~= '' then left.value = "\\left( " .. left.value .. "\\right) "end
		left.lowoperator = ''
		left.value = '\\' .. log_symbol .. vals .. left.value
		return left 
	end,
	abs=function(this)
		local that, oper_id = p.tagmath.toTagMath(this), ''
		that.lowoperator = oper_id
		that.value = "\\left\\vert " .. that.value .. "\\right\\vert "
		return that 
	end,
	floor=function(this)
		local that, oper_id = p.tagmath.toTagMath(this), ''
		that.lowoperator = oper_id
		that.value = "\\left\\lfloor " .. that.value .. "\\right\\rfloor "
		return that 
	end,
	ceil=function(this)
		local that, oper_id = p.tagmath.toTagMath(this), ''
		that.lowoperator = oper_id
		that.value = "\\left\\lceil " .. that.value .. "\\right\\rceil "
		return that 
	end,
	apply_function=function(this, func_name)
		local that, oper_id = p.tagmath.toTagMath(this), '('
		local math_ext_funcs={["min"]="\\min",["max"]="\\max",["max"]="\\max",["sin"]="\\sin",["cos"]="\\cos",["tan"]="\\tan",["sec"]="\\sec",["csc"]="\\csc",["cot"]="\\cot",
			["asin"]="\\arcsin",["acos"]="\\arccos",["atan"]="\\arctan",["asec"]="\\operatorname{arcsec}",["acsc"]="\\operatorname{arccsc}",["acot"]="\\operatorname{arccot}",
			["sinh"]="\\sinh",["cosh"]="\\cosh",["tanh"]="\\tanh",["sech"]="\\operatorname{sech}",["csch"]="\\operatorname{csch}",["coth"]="\\coth",
			["asinh"]="\\operatorname{arcsinh}",["acosh"]="\\operatorname{arccosh}",["atanh"]="\\operatorname{arctanh}",["asech"]="\\operatorname{arcsech}",["acsch"]="\\operatorname{arccsch}",["acoth"]="\\operatorname{arccoth}",
			["sgn"]="\\sgn"
		}
		if this.lowoperator ~= '(' then that.value = "\\left( " .. that.value .. "\\right) "end
		that.lowoperator = oper_id
		that.value = (math_ext_funcs[func_name] or func_name) .. ' ' .. that.value
		return that 
	end,
	apply_binary_operator = function(op1, op2, oper_id, oper_math,left_no,right_no)
		local left, right = p.tagmath.toTagMath(op1), p.tagmath.toTagMath(op2)
		if left.lowoperator ~= '(' and left.lowoperator ~= '' and
			((p.symbol_table[left.lowoperator] and p.symbol_table[left.lowoperator].ppriority and
			p.symbol_table[left.lowoperator].ppriority < p.symbol_table[oper_id].priority)) then
				if not left_no then
					left.value = "\\left( " .. left.value .. "\\right) " 
				end left.lowoperator = '('
		end
			
		if right.lowoperator ~= '(' and right.lowoperator ~= '' and 
			((p.symbol_table[right.lowoperator] and p.symbol_table[right.lowoperator].ppriority and
			p.symbol_table[right.lowoperator].ppriority < p.symbol_table[oper_id].priority)) then
				if not right_no then
					right.value = "\\left( " .. right.value .. "\\right) " 
				end right.lowoperator = '('
		end
			
		local low_operator = oper_id
		if ((p.symbol_table[left.lowoperator] or {ppriority=0}).ppriority or 0) ~= 0 then
			if p.symbol_table[left.lowoperator].ppriority < p.symbol_table[low_operator].ppriority then
				low_operator = left.lowoperator
			end
		end
		if ((p.symbol_table[right.lowoperator] or {ppriority=0}).ppriority or 0) ~= 0 then
			if p.symbol_table[right.lowoperator].ppriority < p.symbol_table[low_operator].ppriority then
				low_operator = right.lowoperator
			end
		end
		left.lowoperator = low_operator
		left.value = "{ {" .. left.value .. '}'  .. oper_math .. '{' .. right.value .. "} }"
		return left 
	end,
	TagMathMeta = {
		__add = function (op1, op2) 
			return p.tagmath.apply_binary_operator(op1,op2,'+','+')
		end,
		__sub = function (op1, op2) 
			return p.tagmath.apply_binary_operator(op1,op2,'-','-')
		end,
		__mul = function (op1, op2) 
			return p.tagmath.apply_binary_operator(op1,op2,'*',"\\times ")
		end,
		__div = function (op1, op2) 
			return p.tagmath.apply_binary_operator(op1,op2,'/',"\\div ")
		end,
		__tostring = function (this) return this.value end,
		__unm = function (this)
			local that, oper_id = p.tagmath.toTagMath(this), "- "
			if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
			that.lowoperator = oper_id
			that.value = "-{ " .. that.value .. "}"
			return that 
		end,
		__eq = function (op1, op2)return p.tagmath.tagMathString(op1).value == p.tagmath.tagMathString(op2).value end,
	},
	toTagMath = function(tagMathString)
		if type(tagMathString) == type(nil) then return nil end
		local math_ext_const={["pi"]="\\pi",["inf"]="\\infty"}
		if (type(tagMathString) == type({})) and tagMathString.value ~= nil and tagMathString.lowoperator ~= nil then 
			TagMath = {value=tagMathString.value,lowoperator=tagMathString.lowoperator}
		else
			TagMath = {}
			TagMath.value = math_ext_const[tagMathString] or tagMathString
			TagMath.lowoperator = ''
		end
		setmetatable(TagMath,p.tagmath.TagMathMeta) 
		return TagMath
	end,
	init = function()
		p.tagmath.zero = p.tagmath.toTagMath(0) 
		p.tagmath.one = p.tagmath.toTagMath(1) 
		p.tagmath.noncalculate=true
		p.tagmath[0],p.tagmath[1] = p.tagmath.zero,p.tagmath.one
		new_meta = getmetatable( p.tagmath ) or {}
		new_meta.__index = function (this, func_name) 
			return function(that)return p.tagmath.apply_function(that, func_name)end
		end
		setmetatable(p.tagmath,new_meta) 
		return p.tagmath
	end
}

return p