summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/LingTrees/trees.py
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/LingTrees/trees.py')
-rw-r--r--macros/latex/contrib/LingTrees/trees.py309
1 files changed, 309 insertions, 0 deletions
diff --git a/macros/latex/contrib/LingTrees/trees.py b/macros/latex/contrib/LingTrees/trees.py
new file mode 100644
index 0000000000..4fcbb243ef
--- /dev/null
+++ b/macros/latex/contrib/LingTrees/trees.py
@@ -0,0 +1,309 @@
+#! /usr/bin/python
+#
+# COPYRIGHT 2005, 2006, Avery D Andrews 3rd
+#
+# GPL2
+#
+# changelog at end
+
+import sys, string, os, re
+
+#
+# would be an idea to subclass 'file', but then I wouldn't
+# know how to make it work with sys.stdin
+#
+class Source:
+
+ def __init__(self, source):
+ self.linenum = 0
+ self.file = source
+ self.nextline = source.readline()
+
+ def readline(self):
+ self.linenum = self.linenum+1
+ returnline = self.nextline
+ self.nextline = self.file.readline()
+ return returnline
+
+class TreesError(Exception):
+
+ def __init__(self, value):
+ self.value = value+'\n'
+ #
+ # UGH: there must be a better way to do this
+ #
+ global error_occurred
+ error_occurred=1
+
+ #
+ # UMM: actually this doesn't seem to do what I expect it to (be
+ # the spelling of an error instance in backquotes)
+ #
+ def __str__(self):
+ return self.value
+
+#
+# complain and set error flag but don't stop
+#
+def TreesWhinge(issue):
+ sys.stderr.write(issue)
+ global error_occurred
+ error_occurred=1
+
+
+class Node:
+ def __init__(self, label):
+ self.tri = 0
+ self.mother = None
+ self.daughters = None
+ self.next = None
+ self.tag = ""
+ self.label = label
+
+OUTPUT_DEFAULT = 0 # write output to command-line-specified file our sysout
+OUTPUT_TEMP = 1 # write the next tree to a specified output file
+OUTPUT_PERM = 2 # write all to a specified output file
+
+def parse_line(line, infile):
+ text = string.strip(line)
+ if text=='':
+ raise TreesError('Blank line in tree at line %d.'%infile.linenum)
+ white = line[:string.find(line,text[0])]
+ return len(white), text
+
+
+def get_line(infile):
+ line = infile.readline()
+ while infile.nextline[:2]=='.-':
+ line = line + string.strip(infile.readline()[2:])
+ if line=='':
+ raise TreesError('File ends during tree at line %d.'%infile.linenum)
+ return parse_line(line, infile)
+
+
+#
+# gets sub-trees whose first line has the same indentation as first param
+#
+def get_daughters(indent, text, infile, mother):
+ daughter, newindent, newtext = build_tree(indent, text, infile)
+ daughter.mother = mother
+ daughters = [daughter]
+ prevdaughter = daughter
+ while newindent==indent:
+ newdaughter, newindent, newtext = build_tree(newindent, newtext, infile)
+ newdaughter.mother = mother
+ prevdaughter.next = newdaughter
+ daughters.append(newdaughter)
+ prevdaughter=newdaughter
+ if newindent > indent:
+ raise TreesError('Indentation fault at line %d.'%infile.linenum)
+ return daughters, newindent, newtext
+
+
+#
+# pattern for option parsing
+#
+optpattern = re.compile("\s*(\S*)\s*(.*?)\s*$")
+
+#
+# text is not supposed to be '.]'
+#
+def build_tree(indent, text, infile):
+ linenum = infile.linenum
+ textlist = re.split("[|]",text)
+ node = Node(textlist[0])
+ dict = node.optdict = {}
+ for command in textlist[1:]:
+ matchcom = optpattern.match(command)
+ if matchcom:
+ comm = matchcom.group(1)
+ if not comm in [
+ 'tag', # custom tag for the line
+ 'tri', # node has a triangle over it
+ 'none', # node has no line going to it
+ 'dot', # node line is dotted
+ 'dash', # node line is dashed
+ 'after', # something after the connection command
+ 'style', # style commands
+ 'dotted', # nice pstricks dots
+ 'connect', # custom connection command
+ 'width', # node is of set width
+ 'dtwidths',# widths of daughter nodes
+ ]:
+ TreesWhinge("Warning: unknown option '%s' near line %d\n"%(command,linenum))
+ dict[comm] = matchcom.group(2)
+ if dict.has_key("tag"):
+ node.tag = dict["tag"]
+ else:
+ global tag_count
+ node.tag = "Z%d"%tag_count
+ tag_count=tag_count+1
+ if dict.has_key("none"):
+ if dict.has_key("tri"):
+ TreesWhinge("Incompatible options 'none' and 'tri' near line %d (tri wins)\n"%linenum)
+ if dict.has_key("dash") or dict.has_key("dot") or dict.has_key("linestyle"):
+ TreesWhinge("Incompatible options 'none' and some line style near line %d (none wins)\n"%linenum)
+
+ newindent, newtext = get_line(infile)
+ if newindent > indent:
+ node.daughters, newindent, newtext = get_daughters(newindent, newtext, infile, node)
+ return node, newindent, newtext
+
+
+def write_tree(node, outfile, indent=0):
+ dict = node.optdict
+ lineoptions=""
+ if node.mother:
+ if dict.has_key('dash'):
+ line = "\\makedash{3pt}"
+ elif dict.has_key('dot'):
+ line = "\\makedash{1pt}"
+ else:
+ line = ""
+ if dict.has_key('dotted'):
+ lineoptions = lineoptions+"linestyle=dotted,linewidth=\\treedotwidth"
+ if dict.has_key('style'):
+ if lineoptions:
+ lineoptions = lineoptions+','+dict['style']
+ else:
+ lineoptions = dict['style']
+ if lineoptions:
+ lineoptions = "[%s]"%lineoptions
+ if dict.has_key('after'):
+ lineoptions = lineoptions+dict['after']
+ if dict.has_key('tri'):
+ line = line+"\\nodetriangle{%s}{%s}%s%%\n"%(node.mother.tag, node.tag, lineoptions)
+ elif dict.has_key('none'):
+ if dict.has_key('after'):
+ line = dict['after']
+ else:
+ if dict.has_key('connect'):
+ connect = dict['connect']
+ else:
+ connect = "\\nodeconnect"
+ line = line+"%s{%s}{%s}%s"%(connect, node.mother.tag, node.tag, lineoptions)
+ else:
+ line = ''
+ if dict.has_key('width'):
+ width = '\\setnodewidth{%s}'%dict['width']
+ elif node.mother!=None and node.mother.optdict.has_key('dtwidths'):
+ width = '\\setnodewidth{%s}'%node.mother.optdict['dtwidths']
+ else:
+ width = ""
+ if node.daughters:
+ outfile.write("{%s\\ntnode{%s}{%s}{%s},\n"%(width,node.tag,node.label,line))
+ for daughter in node.daughters:
+ write_tree(daughter, outfile, indent+2)
+ outfile.write('}')
+ else:
+ outfile.write("{%s\\tnode{%s}{%s}{%s}}"%(width,node.tag,node.label, line))
+ if node.next:
+# if node.mother.next:
+ outfile.write(",\n")
+
+
+def process_tree(infile, outfile):
+ indent, text = get_line(infile)
+ if text[:2]=='.]':
+ return
+# outfile.write('indent: %d; text: %s\n'%(indent, text))
+ global tag_count
+ tag_count = 0
+ tree, newindent, newtext = build_tree(indent, text, infile)
+ if newindent!=0:
+ raise TreesError('Indentation fault at line %d.'%infile.linenum)
+ if newtext!='.]':
+ raise TreesError('Bad tree end at line %d.'%infile.linenum)
+ outfile.write('%%% begin tree\n\\tree')
+ write_tree(tree, outfile)
+ outfile.write('%%\n%%end tree\n')
+
+
+def make_folders(path):
+ folder, file = os.path.split(path)
+ folder = string.strip(folder)
+ if folder and not os.path.exists(folder):
+ os.makedirs(folder)
+
+def process_file(infile, outfile):
+ global error_occurred
+ error_occurred =0
+ outfilemode = OUTPUT_DEFAULT
+ while 1:
+ line = infile.readline()
+ if line == '':
+ break;
+ if line[:3]=='.>>':
+ outfilemode = OUTPUT_PERM
+ line = string.strip(line[3:])
+ make_folders(line)
+ outfile2 = outfile
+ outfile = open(line,'w')
+ elif line[:3] == '.<<':
+ outfilemode = OUTPUT_DEFAULT
+ elif line[:2] == '.>':
+ if outfilemode == OUTPUT_PERM:
+ sys.stderr.write("Warning: temp output directive after permanent at line %d"%infile.linenum)
+ else:
+ line = string.strip(line[2:])
+ make_folders(line)
+ outfile2 = outfile
+ outfilemode = OUTPUT_TEMP
+ outfile = open(line,'w')
+ elif line[:2] == '.[':
+ try:
+ process_tree(infile, outfile)
+ except TreesError, error:
+ sys.stderr.write(error.value)
+ errfile=open(errfilename,'w')
+ errfile.write(error.value)
+ outfile.write('BAD TREE:\n %s'%error.value)
+ try:
+ if outfilemode == OUTPUT_TEMP and outfile2:
+ outfile = outfile2
+ del outfile2
+ except UnboundLocalError:
+ pass
+ else:
+ outfile.write(line)
+
+
+if __name__=="__main__":
+ argv=sys.argv
+# print 'cwd:'+os.getcwd()
+ if len(argv)<2:# run as filter
+ infile=sys.stdin
+ outfile=sys.stdout
+ errfilename = 'trees.err'
+# errfile=open("trees.err","w")
+ else:
+ infile=open(argv[1]+'.txp','r')
+ outfile=open(argv[1]+'.tex','w')
+ errfilename = argv[1]+'.err'
+# errfile=open(argv[1]+'.err','w')
+
+ process_file(Source(infile), outfile)
+ if error_occurred:
+ sys.exit(1)
+ sys.stderr.write("trees ran without issues\n")
+
+#
+# changelog
+#
+# v 3.1 Feb 28 2006
+# widths and dtwidths commands, for controlling width
+# of nodes.
+#
+# v 3.0 Jan 30 2006
+# adjusted to write for pst-node
+# name changed to lingtrees.py
+# implement additional options for PSTricks
+#
+# v 2.2, Jan 18 2006
+# implemented none, dash and dot options from Chris Manning's version
+#
+# v 2.1, Dec 28 2005
+# .>, .>>, >> directives added for writing to files
+# .- directive added for continuation of lines
+#
+