summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/LingTrees/Development/texoptarg.py
blob: 8b725d1fd1e1c3a4c1349d20000a0be6105bf431 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#! /usr/bin/python
#
# COPYRIGHT 2006, Avery D Andrews 3rd
#
# License: GPL2
#
# Purpose: this script converts macro 'declarations' in the style
#   of the accompanying macros.txo to a chain of TeX macros with
#   optional arguments, with [#d=X] indicating an optional argument
#   with default value X.  Allowed delimiters are [], (), <>; Input
#   verification not very thorough.

#
#  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 ProgramError(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 ProgramWhinge(issue):
    sys.stderr.write(issue)
    global error_occurred
    error_occurred=1


blanklinepattern = re.compile("^\s*(%.*)?$")

#
# pulls out three fields, the first ought be \def, \gdef etc.
#    the second is the name, preceeding by backslash
#    the third is the arguments.
# they can be separated by whitespace, but don't have to be
#
deflinepattern = re.compile("^\s*(\\\\[a-zA-Z]+)\s*(\\\\[a-zA-Z@]+)\s*(\S*)\s*$")

#    [ indicates [, (, <, likewise ].  1 indicates any digit
#
#         #1 or [#1#], not followed by a closing bracket  
#                            
oblargpattern = re.compile("([\[\(<])?#(\d)(?![=\]\)>])(#[\]\)>])?(.*)")
#                                 1      2                 3        4
#
#                      [#1(=opt)]
#
optargpattern = re.compile("([\[\(<])#(\d)(=[^[([\]\)>]*)?([([\]\)>])(.*)")
#                               1       2        3            4       5
#
def process_file(infile, outfile):
    global error_occurred
    error_occurred =0
    while 1:
        line = infile.readline()
        if line == '':
            break;
        blankmatch = blanklinepattern.match(line)
        if blankmatch:
            pass
        else:
            defmatch = deflinepattern.match(line)
            if defmatch:
                (defin, name, arguments) = defmatch.group(1,2,3)
                outfile.write("\n%%\n%%    %s\n%%\n%%\n"%name)
                produce_definition(defin, name, arguments, 1, [], infile, outfile)
            else:
                raise ProgramError("line %d ill-formed"%infile.linenum)        

def produce_definition(defcom, name, arguments, count, arglist, infile, outfile):
    blankmatch = blanklinepattern.match(arguments)
    if blankmatch:
        write_definition(defcom, name, arglist, outfile)
        return
    #
    # obligatory arguments
    #
    argmatch = oblargpattern.match(arguments)
    if argmatch:
#        print "%s: %s"%(name,argmatch.group(3))
        if argmatch.group(1):
            if not argmatch.group(3):
                raise ProgramError("no closing bracket in line %d"%infile.linenum)
        if argmatch.group(3):
            if not argmatch.group(2):
                raise ProgramError("no opening bracket in line %d"%infile.linenum)
        if count!=int(argmatch.group(2)):
            raise ProgramError("argument number sequence error line %d"%infile.linenum)
        if argmatch.group(1):
#            print `argmatch.group(2)`
            arg = "%s#%d%s"%(argmatch.group(1), count, argmatch.group(3))
            arglist.append((arg,arg))
        else:
            arglist.append(("#%d"%count, "{#%d}"%count))
        produce_definition(defcom,name,argmatch.group(4),count+1, arglist,infile, outfile)
        return
    #
    # optional arguments
    #
    argmatch = optargpattern.match(arguments)
    if argmatch:
        write_definition_start(defcom, name, arglist, outfile)
        nextname = '\@'+name[1:]
        outfile.write("{\@ifnextchar %s\n  {%s"%(argmatch.group(1), nextname))
        #
        #  iftrue
        #
        write_args_in_def(arglist,outfile)
        outfile.write("}")
        outfile.write("\n")
        #
        # iffalse
        #
        if argmatch.group(3):
            defaultval = argmatch.group(3)[1:]
        else:
            defaultval = ""
#        print "default: %s"%defaultval
        outfile.write("  {%s"%nextname)
        write_args_in_def(arglist,outfile)
        outfile.write("%s%s%s}\n}\n"%(argmatch.group(1),defaultval,argmatch.group(4)))
        #
        # next argument
        #
        arg ="%s#%s%s"%argmatch.group(1,2,4)
        arglist.append((arg, arg))
        produce_definition(defcom, nextname, argmatch.group(5), count+1, arglist, infile, outfile)

    
def write_args_in_def(arglist, outfile):
    for arg in arglist:
        outfile.write(arg[1])

def write_definition_start(defcom, name, arglist, outfile):
    outfile.write("%s%s"%(defcom, name))
    for arg in arglist:
        outfile.write(arg[0])

def write_definition(defcom, name, arglist, outfile):
    write_definition_start(defcom, name, arglist, outfile)
    outfile.write("{\n\n}\n")

if __name__=="__main__":
    argv=sys.argv
#    print 'cwd:'+os.getcwd()
    if len(argv)<2:# run as filter
        infile=sys.stdin
        outfile=sys.stdout
        errfilename = 'texoptarg.err'
#        errfile=open("texoptarg.err","w")
    else:
        infile=open(argv[1]+'.txo','r')
        outfile=open(argv[1]+'.tex','w')
        errfilename = argv[1]+'.err'
#        errfile=open(argv[1]+'.err','w')

    try:
        process_file(Source(infile), outfile)
    except ProgramError, error:
        sys.stderr.write(error.value)
        errfile=open(errfilename,'w')
        errfile.write(error.value)
    if error_occurred:
        sys.exit(1)
    sys.stderr.write("texoptarg ran without issues\n")
    
#    
# Changelog:
#
#   Jan 24 2006:  first apparently working version
#