|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- Warning: this file uses "regmatch", defined in my (edrx's) modified
-- version of rtt's regexp libs...
-- (find-angg "lua-4.0/src/libdllua/lrexlib-new.c")
-- (find-angg "lua-4.0/src/libdllua/lrexlib-new.c" "regmatch")
-- (find-angg "LATEX/Makefile" "dednat.lua")
-- (find-angg "LATEX/Makefile" "dn_to_dnt")
regcomp = regex
treestuff = {}
-- «.store_macro» (to "store_macro")
-- «.substitute_str» (to "substitute_str")
-- «.hsplit» (to "hsplit")
-- «.nodes_intersecting» (to "nodes_intersecting")
-- «.hsplit_do_node» (to "hsplit_do_node")
-- «.preprocess_tree_node» (to "preprocess_tree_node")
-- «.preprocess_tree_rule» (to "preprocess_tree_rule")
-- «.iprint_do_node» (to "iprint_do_node")
-- «.iprint_do_tree» (to "iprint_do_tree")
-- «.generate_tree_TeX_code» (to "generate_tree_TeX_code")
-- «.tatsuta_do_node» (to "tatsuta_do_node")
-- «.tatsuta_do_tree» (to "tatsuta_do_tree")
-- «.buss_do_node» (to "buss_do_node")
-- «.buss_do_node» (to "buss_do_node")
-- «.tatsuta» (to "tatsuta")
-- «.buss» (to "buss")
-- «.getline» (to "getline")
-- «.preprocess» (to "preprocess")
-- «.preprocess_on» (to "preprocess_on")
-- «.preprocess_off» (to "preprocess_off")
-- «.process_macroline» (to "process_macroline")
-- «.process_treeline» (to "process_treeline")
-- «.process_lualine» (to "process_lualine")
-- «.process_otherline» (to "process_otherline")
-- «.process_line» (to "process_line")
-- «.main_loop» (to "main_loop")
--# How this program works (from the programmer's point of view):
--# It has a "main_loop" function that gets lines and processes them.
--# If a line is of the form "%:*...*...*" process it with "store_macro";
--# if not, and if it is of the form "%:...", process it as a part of
--# a tree diagram, with hsplit.
--# Hsplit splits the "..." in "%:..." in words, and processes each
--# of them as a "node"; for each "%:..." line, say the line linenum
--# (where we start counting from 1), treestuff[linenum] is an array
--# containing all the nodes from line linenum; for non-"%:..."
--# lines treestuff[linenum] is nil.
--# The processing of each node is done by the function "f_store",
--# that is given as an argument to hsplit; f_store is usually
--# hsplit_do_node. This processing includes adding the node (as a
--# table with fields {str, p1, p2, linenum} -- other fields may be
--# added later) to treestuff[linenum].
--# If a node is of the form "^..." then it is a label with the
--# name of a tree, and processing it is a complex task. We
--# describe the other case first.
--# If a node (say, "thisnode") is not the name of a tree then
--# just build (with "nodes_intersecting") the array "aboves" of
--# all the nodes in the preceding line that intersect thisnode,
--# i.e., an array with the nodes that have some column in common
--# with thisnode. If the array "aboves" turns out to be non-empty
--# then set thisnode.aboves = aboves. Note that we are not yet
--# doing anything special to distinguish nodes that are real tree
--# nodes and nodes that are rules ("----..." or "====...").
--# Each "^..." node points to another node, two lines above, that
--# is the root of a tree. Issue an error if this tree-root node
--# does not exist, and if it exists start the preprocessing of
--# the tree -- note that now we will be able to determine which
--# nodes are "tree node" nodes and which are "rule" nodes.
--# Process these "tree node/rule" nodes recursively, preparing a
--# field node.TeXstr for each of them; for "tree node" nodes this
--# field is the result of running substitute_str on node.str, but
--# for rule nodes node.str is split in a "rule" part (a sequence
--# of "-"s or a sequence of "="s -- the field node.rulechar says
--# which char) and a "right string" part, node.rightstr,
--# containing the rest; for rule nodes node.TeXstr is the result
--# of substitute_str(node.rightstr).
--# If a tree node has a rule above it then it will have a
--# "node.uprule" field pointing to the node of the rule. A rule
--# node don't have any special field to point to the tree nodes
--# above it; this data is in the field "node.aboves" (that for
--# every node is always either nil or a non-empty array).
--# The "^..." nodes get a "treelabel" field, containing the "..."
--# string; after the preprocessing is done the function
--# generate_tree_TeX_code is called, with the "^..." node as its
--# only parameter. I haven't written generate_tree_TeX_code yet.
--###
--#
--# Functions to take care of macro substitution.
--# Store_macro will use the fields of a "%:*...*...*" line to update
--# the array of macros; substitute_str will apply all the
--# substitutions in the "macros" array on str.
--#
--###
macros = {}
-- «store_macro» (to ".store_macro")
store_macro = function(fromstr, tostr)
local n = macros[fromstr] -- macros may be redefined
local qfromstr = gsub(fromstr, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1")
local fun = function (str) return gsub(str, %qfromstr, %tostr) end
if n then
macros[n].tostr = tostr
macros[n].fun = fun
else
tinsert(macros, {fromstr=fromstr, tostr=tostr, fun=fun})
macros[fromstr] = getn(macros)
end
end
-- «substitute_str» (to ".substitute_str")
substitute_str = function(str)
if str=="" then return str end -- trivial optimization
local i
for i=1,getn(macros) do
str = macros[i].fun(str)
end
return str
end
--###
--#
--# Functions to process "%:..." lines.
--# The outside will call hsplit for each "%:..." line; the functions
--# in this block will call generate_tree_TeX_code for each "^..."
--# node, after all the required preprocessing having been done.
--#
--###
-- «hsplit» (to ".hsplit")
hsplit_re = regcomp("[^ ]+")
hsplit = function(linestr, arr, f_store)
local pos, offset, newpos, str = 0
f_store = f_store or hsplit_do_node
while 1 do
offset, str = regmatch(hsplit_re, linestr, pos)
if offset==nil then
return arr
end
f_store(arr, str, pos+offset, pos+offset+strlen(str))
pos = pos+offset+strlen(str)
end
end
-- «nodes_intersecting» (to ".nodes_intersecting")
-- Return an array with the nodes of "ts" (i.e., ts[1], ts[2], etc)
-- that "intersect" the range (p1,p2). The array may be ={}.
function nodes_intersecting(p1, p2, ts)
local arr, i, node = {}
if ts then
for i=1,getn(ts) do
node = ts[i]
if not (node.p2<=p1 or p2<=node.p1) then
tinsert(arr, node)
end
end
end
return arr
end
-- «hsplit_do_node» (to ".hsplit_do_node")
treelabel_re = regcomp("^\\^(.+)")
hsplit_do_node = function(arr, str, p1, p2)
local linenum, thisnode, pos, m0, treelabel, treeroot, aboves
linenum = arr.linenum
thisnode = {str=str, p1=p1, p2=p2, linenum=linenum}
tinsert(arr, thisnode)
pos, m0, treelabel = regmatch(treelabel_re, str)
if pos then
thisnode.treelabel = treelabel
treeroot = nodes_intersecting(p1, p2, treestuff[linenum - 2])[1]
if not treeroot then
printf("Tree name points to no root: %q, line %d\n", str, linenum)
exit(1)
end
thisnode.treeroot = treeroot
preprocess_tree_node(treeroot)
generate_tree_TeX_code(thisnode)
else
aboves = nodes_intersecting(p1, p2, treestuff[linenum - 1])
if getn(aboves)>0 then
thisnode.aboves = aboves
end
end
end
-- «preprocess_tree_node» (to ".preprocess_tree_node")
preprocess_tree_node = function(node)
node.TeXstr = substitute_str(node.str)
if node.aboves then
node.uprule = node.aboves[1]
preprocess_tree_rule(node.uprule)
end
end
-- «preprocess_tree_rule» (to ".preprocess_tree_rule")
preprocess_tree_rule_re = regcomp("^(-+|=+)(.*)")
preprocess_tree_rule = function(node)
local pos, m0, rule, rightstr = regmatch(preprocess_tree_rule_re, node.str)
if not pos then
printf("Rule has no bar: %q, line %d\n", node.str, node.linenum)
exit(1)
end
node.rulechar = strsub(rule, 1, 1)
node.TeXstr = substitute_str(rightstr)
if node.aboves then
foreachi(node.aboves, function(i,node) preprocess_tree_node(node) end)
end
end
--###
--#
--# Emitting trees (in TeX or in some debugging form)
--#
--###
function spaces(n) return strrep(" ", n) end
-- «iprint_do_node» (to ".iprint_do_node")
function iprint_donode(indent, node)
local uprule, i, upnode
uprule = node.uprule
if uprule then
print(spaces(indent+2)..strrep(uprule.rulechar,4).." "..uprule.TeXstr)
if uprule.aboves then
for i=1,getn(uprule.aboves) do
iprint_donode(indent+4, uprule.aboves[i])
end
end
end
end
-- «iprint_do_tree» (to ".iprint_do_tree")
function iprint_do_tree(treelabelnode)
print(treelabelnode.str)
iprint_donode(2, treelabelnode.treeroot)
return ""
end
TeX_trees = {}
default_do_tree = iprint_do_tree
-- «generate_tree_TeX_code» (to ".generate_tree_TeX_code")
generate_tree_TeX_code = function(treelabelnode)
tinsert(TeX_trees, default_do_tree(treelabelnode))
end
--###
--#
--# Functions to generate TeX code for already-preprocessed trees
--#
--###
mathstrut = "\\mathstrut "
-- «tatsuta_do_node» (to ".tatsuta_do_node")
-- (find-es "tex" "tatsutaproof")
function tatsuta_do_node(indent, node)
local uprule = node.uprule
if uprule then
local modifier = ""
if uprule.rulechar == "=" then modifier = "=" end
if uprule.TeXstr ~= "" then
modifier = modifier .. "[{" .. uprule.TeXstr .. "}]"
end
local upnodes = uprule.aboves or {}
local arr = {}
local i
for i=1,getn(upnodes) do
tinsert(arr, "\n"..tatsuta_do_node(indent + 1, upnodes[i]).." ")
end
return format("%s\\infer%s{ %s %s }{%s}",
spaces(indent),
modifier,
mathstrut,
node.TeXstr,
join(arr, "&"))
else
return spaces(indent) .. mathstrut .. node.TeXstr
end
end
-- «tatsuta_do_tree» (to ".tatsuta_do_tree")
function tatsuta_do_tree(treelabelnode)
return format("\\defded{%s}{\n%s }\n",
treelabelnode.treelabel,
tatsuta_do_node(1, treelabelnode.treeroot))
end
-- «buss_do_node» (to ".buss_do_node")
function buss_do_node(indent, node)
local uprule = node.uprule
local sp, sp1 = spaces(indent), spaces(indent + 1)
local thispstring = mathstrut .. node.TeXstr
if uprule then
local modifier = ""
if uprule.rulechar == "=" then modifier = "\\doubleLine " end
if uprule.TeXstr ~= "" then
modifier = modifier.."\\RightLabel{\\( "..uprule.TeXstr.." \\)} "
end
local upnodes = uprule.aboves or {}
local n = getn(upnodes)
local upstr = ""
local i
if n == 0 then
return sp.."\\AxiomC{} "..modifier ..
"\\UnaryInfC{\\( "..thispstring.." \\)}\n"
elseif n == 1 then
return buss_do_node(indent + 1, upnodes[1]) ..
sp..modifier.."\\UnaryInfC{\\( "..thispstring.." \\)}\n"
elseif n == 2 then
return buss_do_node(indent + 1, upnodes[1]) ..
buss_do_node(indent + 1, upnodes[2]) ..
sp..modifier.."\\BinaryInfC{\\( "..thispstring.." \\)}\n"
elseif n == 3 then
return buss_do_node(indent + 1, upnodes[1]) ..
buss_do_node(indent + 1, upnodes[2]) ..
buss_do_node(indent + 1, upnodes[3]) ..
sp..modifier.."\\TrinaryInfC{\\( "..thispstring.." \\)}\n"
elseif n > 3 then
return "\\AxiomC{!!!!(n>3)!!!!}\n"
end
else
return sp.."\\AxiomC{\\( "..thispstring.." \\)}\n"
end
end
-- «buss_do_node» (to ".buss_do_node")
function buss_do_tree(treelabelnode)
printf("\\defded{%s}{\n%s \\DisplayProof\n}\n",
treelabelnode.treelabel,
buss_do_node(1, treelabelnode.treeroot))
end
--###
--#
--# Functions to set the environment to use a certain TeX output
--# function (tatsuta_do_tree or buss_do_tree), a certain input file
--# and a certain output file
--#
--###
-- «tatsuta» (to ".tatsuta")
tatsuta = function(srcfname, destfname, pp_destfname)
default_do_tree = tatsuta_do_tree
file_as_string = readfile(srcfname)
TeX_trees.destfname = destfname
pped_lines.destfname = pp_destfname
end
-- «buss» (to ".buss")
buss = function(srcfname, destfname, pp_destfname)
default_do_tree = buss_do_tree
file_as_string = readfile(srcfname)
TeX_trees.destfname = destfname
pped_lines.destfname = pp_destfname
end
--###
--#
--# The main loop
--#
--###
file_as_string = "" -- we set it later
file_pos = 0
file_linebeg = 0
linenum = 0
lines = {}
-- «getline» (to ".getline")
getline_re = regex("^([^\n]*)(\n?)")
getline = function()
file_linebeg = file_pos
local p, all, bulk, nl = regmatch(getline_re, file_as_string, file_pos)
if all=="" then
return nil
end
linenum = linenum + 1
file_pos = file_pos + strlen(all)
tinsert(lines, bulk)
return bulk
end
-- «preprocess» (to ".preprocess")
-- «preprocess_on» (to ".preprocess_on")
-- «preprocess_off» (to ".preprocess_off")
pped_lines = {} -- array of preprocessed lines (opt field: destfile)
preprocess_subst = function(linestr)
tinsert(pped_lines, substitute_str(linestr))
end
preprocess_nochange = function(linestr)
tinsert(pped_lines, linestr)
end
preprocess = preprocess_nochange
preprocess_on = function() preprocess = preprocess_subst end
preprocess_off = function() preprocess = preprocess_nochange end
-- «process_macroline» (to ".process_macroline")
macroline_re = regcomp("^%:*([^*]+)*([^*]*)*(.*)")
process_macroline = function(linestr)
local p, all, fromstr, tostr, rest = regmatch(macroline_re, linestr)
if p then
store_macro(fromstr, tostr)
return "processed"
end
end
-- (eev "cd ~/LATEX/; touch tmp.tex; make tmp.auto.dnt")
-- (eev "cd ~/LATEX/; mylua -f ~/dednat/dednat2.lua 'tatsuta(arg[2],arg[3])' tmp.tex tmp.dnt")
-- «process_treeline» (to ".process_treeline")
treeline_re = regcomp("^%:(.*)")
process_treeline = function(linestr)
local pos, all, bulk = regmatch(treeline_re, linestr)
if pos then
treestuff[linenum] = {linenum=linenum}
hsplit(untabify_line(" "..bulk), treestuff[linenum])
return "processed"
end
end
-- «process_lualine» (to ".process_lualine")
bigluacode = ""
lualine_re = regcomp("^(.*?)%lua([^ \t]*)(.*)")
process_lualine = function(linestr)
local pos, all, pre, special, luacode = regmatch(lualine_re, linestr)
if pos then
if special=="/" then -- allow glueing lines before running the code
bigluacode = bigluacode.."\n"..luacode
else
bigluacode = luacode
dostring(bigluacode)
end
return "processed"
end
end
-- «process_otherline» (to ".process_otherline")
process_otherline = function(linestr)
preprocess(linestr)
return "processed"
end
-- «process_line» (to ".process_line")
process_line = function(linestr)
local dummy = process_macroline(linestr) or
process_treeline(linestr) or
process_lualine(linestr) or
process_otherline(linestr)
end
-- «main_loop» (to ".main_loop")
main_loop = function()
local linestr
while 1 do
linestr = getline()
if linestr==nil then break end
process_line(linestr)
end
end
--###
--#
--# a test
--#
--###
file_as_string = [[
%:*aa*<a>*
%:
%: ==
%: aa bb
%: ------aa
%: cc
%:
%: ^test
]]
if arg then
dostring(arg[1])
end
-- (eev "cd ~/LUA/; mylua dednat2.lua")
-- (eev "mylua -f ~/dednat/dednat2.lua 'tatsuta(arg[2],arg[3])' ~/LATEX/tmp.tex /tmp/o")
main_loop()
if TeX_trees.destfname then
writefile(TeX_trees.destfname, join(TeX_trees))
end
if pped_lines.destfname then
writefile(pped_lines.destfname, join(pped_lines, "\n"))
end
print("finished.")