Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
#!/usr/bin/env lua51 -- dednat5.lua - a TeX preprocessor to typeset trees and diagrams -- This is a rewrite of dednat4. -- Status: this is a very preliminary version, don't expect it -- to work... -- See: -- (find-es "dednat" "dednat5") -- Reescrevendo o dednat4: -- prefixos pra encurtar tudo: -- A: abbreviations -- D: diagrams -- T: trees -- F: Forth -- See: (find-dn4ex "edrxmain.tex") -- and: (find-dn4ex "edrxmain41.tex") -- and: (find-dn4ex "edrxmain41a.tex") -- Written by: Eduardo Ochs <eduardoochs@gmail.com> -- Current revision: 2010apr21 -- For the full history etc see some text that I haven't written yet. -- See: http://angg.twu.net/dednat4.html -- See: http://angg.twu.net/dednat4/ -- License: GPL -- -- «.prefixes-and-ptables» (to "prefixes-and-ptables") -- «.heads» (to "heads") -- «.dednat4dir» (to "dednat4dir") -- «.edrxlib» (to "edrxlib") -- «.compat.lua» (to "compat.lua") -- «.string-methods» (to "string-methods") -- -- «.heads» (to "heads") -- «.processfile» (to "processfile") -- «.abbrevs» (to "abbrevs") -- Terminology and main ideas -- ========================== -- A dictionary is a table whose keys are all strings. -- A prefix_table is a dictionary in which "partial matches" point to 0. -- prefix_tables are used for two things: -- line_heads, where the expansions are functions, -- abbrevs, where the expansions are strings. -- expand is the function that expands all abbrevs in a string. -- -- Each tree_line is split into tree_words. -- Each tree_word may be a tree_node, a tree_bar, or a tree_name, or garbage. -- Each tree_bar is split into a tree_bar_char and a tree_bar_comment. -- tree_dict is a dictionary that maps "tree word names", like "tw:20:2" -- (the second tree word in line 20 of the .tex) to structures. -- If a tree_word is a tree_bar we get the list of tree_nodes above it. -- If a tree_word is a tree_name we look for the tree_word above its "^". -- If a tree_word is a tree_node we look for a tree_bar above it. -- tree_nodes_between is the low-level function used to find "tree_words above". -- tree_output is called at each tree_name. It may be: -- tree_output_pt for Paul Taylor's version, -- tree_output_tat for Makoto Tatsuta's package, -- tree_output_buss for Sam Buss's package (currently unimplemented). -- tree_output_body is like tree_output, but without the "\def" header. -- -- Each diag_line is a sequence of words, to be executed one by one. -- Each diag_word is executed by running the correspondent function in _D, -- or by pushing the diag_node with that name into the stack. -- diag_this_word is the variable that holds the word that we will execute. -- diag_this_col is the "column pointer"; it is used and modified by words -- that take over the parser to read and process immediate data. -- -- Each stack has methods push, pop, pick, pock. -- -- For running the diag language we have several stacks: -- diag_nodes, for nodes declared in 2D, plus maybe others; -- diag_arrows, that are used by diag_output (in enddiagram); -- diag_contexts, for the (( ))s. -- diag_node_names is a dictionary that lets us refer to nodes by their 2D names. -- -- diag_output produces a -- -- TO DO: abbrevs with arguments. eval = function (str) return assert(loadstring(str))() end --%%%%% --% --% «prefixes-and-ptables» (to ".prefixes-and-ptables") --% --%%%%% -- Tests: -- (find-dn4 "dednat5-shadow.lua" "expansion") -- Internal functions with ugly names: prefix_longest = function (str, j, ptable) local bestk, expansion for k=j,#str do local candidate = string.sub(str, j, k) if ptable[candidate] == nil then return bestk, expansion end if ptable[candidate] ~= 0 then bestk, expansion = k, ptable[candidate] end end return bestj, expansion end prefix_fixed_then_longest = function (str, i, ptable) for j=i,#str do local k, expansion = prefix_longest(str, j, ptable) if k then return j, k, expansion end end end expand_all = function (str, i, ptable, expansions) local j, k, expansion = prefix_fixed_then_longest(str, i, ptable) if j then tinsert(expansions, string.sub(str, i, j-1)) tinsert(expansions, expansion) return expand_all(str, k+1, ptable, expansions) else tinsert(expansions, string.sub(str, i)) return expansions end end ptable_add = function (ptable, key, expansion) ptable[key] = expansion for len=#key-1,1,-1 do local subkey = string.sub(key, 1, len) if ptable[subkey] == nil then ptable[subkey] = 0 else break end end end -- Call as: ptable_adds(ptable, key1, exp1, key2, exp2, ...) ptable_adds = function (ptable, ...) local args = pack(...) for i=1,#args,2 do ptable_add(ptable, args[i], args[i+1]) end end -- Call as: ptable_adds(ptable, key1, key2, ...) ptable_dels = function (ptable, ...) for _,key in ipairs({...}) do ptable[key] = 0 end end -- Interface functions with nice names: expansion_table = {} expansion_adds = function (...) ptable_adds(expansion_table, ...) end expansion_add = expansion_adds expansion_del = function (...) ptable_dels(expansion_table, ...) end expand = function (str) return table.concat(expand_all(str, 1, expansion_table, {})) end --%%%%% --% --% «heads» (to ".heads") --% --%%%%% -- Tests: -- (find-dn4 "dednat5-shadow.lua" "heads") head_table = {} head_add = function (...) ptable_adds(head_table, ...) end head_add("", "NONE") head_for = function (str) local k, expansion = prefix_longest(str, 1, head_table) if k then return string.sub(str, 1, k), string.sub(str, k+1), expansion end return "", str, head_table[""] end -- process_blocks is less than dednat[45]'s "processfile". -- (find-dn4 "dednat5.lua" "processfile") process_block = function () linestr = flines[linen] prefix, rest, head = head_for(linestr) local beforefirst = head.beforefirst or function () end local aftereach = head.aftereach or function () end local afterlast = head.afterlast or function () end if head.afterlast then beforefirst() aftereach(rest) while flines[linen+1] and head_for(flines[linen+1]) == prefix do linen = linen + 1 linestr = flines[linen] prefix, rest, head = head_for(linestr) aftereach(rest); end afterlast() else aftereach(linestr) end linen = linen + 1 end process_blocks = function () while flines[linen] do process_block() end end --%%%% --% --% «abbrevs» (to ".abbrevs") --% --%%%% abbrevs = {} abbrev_add = function (abbrev, expansion) for i=1,#abbrev-1 do local s = abbrev:sub(1,i) abbrevs[s] = abbrevs[s] or 0 -- make s a prefix (if it is not an abbrev) end abbrevs[abbrev] = expansion end abbrev_longest = function (str, i) local bestj, abbrev, expansion for j=i,#str do local teststr = str:sub(i, j) local a = abbrevs[teststr] -- is teststr a prefix, or an abbrev? if a == nil then break end -- it is neither: break the loop if a ~= 0 then -- it's an abbrev: save j and a and continue bestj, abbrev, expansion = j, teststr, a end -- if a == 0 then PP(i, j, teststr, "is a prefix and not an abbrev") end end return bestj, abbrev, expansion end abbrev_expand1 = function (str, i) for j=i,#str do local k, abbrev, expansion = abbrev_longest(str, j) if k then local literal = str:sub(i, j-1) -- the literal part before the abbrev return j, k, literal, abbrev, expansion end -- PP(i, j, str:sub(j), "does not start with an abbrev") end end unabbrev = function (str) local result = {} local i = 1 while i <= #str do local j, k, literal, abbrev, expansion = abbrev_expand1(str, i) if j then table.insert(result, literal) table.insert(result, expansion) i = k + 1 else table.insert(result, str:sub(i)) break end end -- PP(result) return table.concat(result) end addabbrevs = function (...) local arg = {...} for i=1,#arg,2 do abbrev_add(arg[i], arg[i+1]) end end --[[ -- Tests: * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) abbrevs = {} abbrev_add("cde", "CCDDEE") PP(abbrevs) --> {"c"=0, "cd"=0, "cde"="CCDDEE"} = abbrev_expand1("abcdefg", 1) --> 3 5 ab cde CCDDEE = abbrev_expand1("abcdefg", 2) --> 3 5 b cde CCDDEE = unabbrev("abcdefg") --> abCCDDEEfg = unabbrev("abcdefg_cd_cde__") --> abCCDDEEfg_cd_CCDDEE__ abbrev_add("c", "**") = unabbrev("abcdefg_cd_cde__") --> abCCDDEEfg_**d_CCDDEE__ abbrevs = {} addabbrevs("cde", "CCDDEE", "c", "**") PP(abbrevs) --> {"c"="**", "cd"=0, "cde"="CCDDEE"} --]] -- «standardabbrevs» (to ".standardabbrevs") -- (find-dn4ex "edrx08.sty") standardabbrevs = function () addabbrevs( "->^", "\\ton ", "`->", "\\ito ", "-.>", "\\tnto ", "=>", "\\funto ", "<->", "\\bij ", "->", "\\to ", "|-", "\\vdash ", "|->", "\\mto ", "\"", " ") end -- Local Variables: -- coding: raw-text-unix -- End: