3 # Build a linked list (indexed array) of characters to parse a
4 # number of commands and optional arguments and call a function
8 # Date: 25 November 2009
9 # Author: Harry McNally
11 # +-----------------------+
12 # | d e c i s i o n s |
13 # +-----------------------+
14 # | a n d d e s i g n s |
15 # +-----------------------+
17 # Copyright (C) 2009 Decisions and Designs Pty Ltd. All rights reserved.
19 # This software may be distributed and modified under the terms of the GNU
20 # General Public License version 2 (GPL) as published by the Free Software
21 # Foundation and appearing in the file GPL2.TXT included in the packaging of
22 # this file. Please note that GPL Section 2[b] requires that all works based
23 # on this software must also be made publicly available under the terms of
24 # the GPL ("Copyleft").
26 # Contact information:
27 # Decisions and Designs Web site: http://www.decisions-and-designs.com.au
32 """Data for a command string, arguments, and called function"""
33 def __init__(self, cmd, arg, fun):
38 # All of the commands, varg list, and functions to call.
39 # The commands cannot overlap so "ab" and "abc" will clash (because
40 # of the option for following arguments). Coding the command parsing
41 # machine to overcome this would be slightly useful.
42 # Up to four characters can be included in the argument entry for
43 # up to four arguments (read left to right). Each character requests:
44 # u = uint32_t, i = int32_t, d = double
45 # Command("command", "varg_list", "function_name")
47 Command("az", "dddu", "COMMAND_AZIMUTH_SIG"), \
48 Command("ab", "d", "COMMAND_AZIMUTH_BASE_SIG"), \
49 Command("as", "d", "COMMAND_AZIMUTH_SLEW_SIG"), \
50 Command("aa", "d", "COMMAND_AZIMUTH_ACCELERATION_SIG"), \
51 Command("at", "u", "COMMAND_AZIMUTH_STEPS_SIG"), \
52 Command("acw", "", "COMMAND_AZIMUTH_CLOCKWISE_SIG"), \
53 Command("acc", "", "COMMAND_AZIMUTH_CCW_SIG"), \
54 Command("el", "dddu", "COMMAND_ELEVATION_SIG"), \
55 Command("eb", "d", "COMMAND_ELEVATION_BASE_SIG"), \
56 Command("es", "d", "COMMAND_ELEVATION_SLEW_SIG"), \
57 Command("ea", "d", "COMMAND_ELEVATION_ACCELERATION_SIG"), \
58 Command("et", "u", "COMMAND_ELEVATION_STEPS_SIG"), \
59 Command("eu", "", "COMMAND_ELEVATION_UP_SIG"), \
60 Command("ed", "", "COMMAND_ELEVATION_DOWN_SIG"), \
61 Command("sta", "", "COMMAND_START_AZIMUTH_SIG"), \
62 Command("ste", "", "COMMAND_START_ELEVATION_SIG"), \
63 Command("stb", "", "COMMAND_START_AZ_EL_SIG"), \
67 file.write('\n/*\n Commands defined in the ui.py file\n')
68 file.write(' command signal arguments\n')
70 file.write(' ' + repr(item.cmd) + ', ' + repr(item.fun) + ', ' + \
71 repr(item.arg) + '\n')
77 def __init__(self, arg, fun):
81 def write_function_list(file):
82 file.write('MenuSignal menuSignal[] = {\n')
85 for function in function_list:
88 for ch in function.arg:
96 raise WriteFunctionBadVArgChar
98 file.write(' ' + csv + '{ /* ' + repr(index) + ' */ ' + function.fun + ', ' + hex(argb) + ' }\n')
104 def __init__(self, ch):
109 def __init__(self, ch, arg, fun):
111 self.index = len(function_list)
113 raise FunctionListTooBig
114 function_list.append(Function(arg, fun))
117 """A (state) tree to traverse for each arriving character (event)"""
119 self.root = self.branch = []
121 # Search the present list and, if the char is found, index to the char's
122 # new list. Otherwise, add the char and index to the char's empty list.
123 def add_command_entry(self, ch):
124 for entry in self.branch:
125 # Entry already exists for this character
127 if isinstance(entry, FunctionEntry):
128 raise FunctionEntrySubset
129 self.branch = entry.branch
131 # Make a new entry for this character
132 entry = CommandEntry(ch)
133 self.branch.append(entry)
134 self.branch = entry.branch
136 def add_function_entry(self, ch, arg, fun):
137 for entry in self.branch:
138 # Entry already exists for this character
140 if isinstance(entry, FunctionEntry):
141 raise FunctionEntryDuplicate
143 raise FunctioEntrySuperset
144 # Make a function entry for this character
145 entry = FunctionEntry(ch, arg, fun)
146 self.branch.append(entry)
148 def build_tree(self, commands):
149 for command in commands:
150 self.branch = self.root
151 for ch in command.cmd[:-1]:
152 self.add_command_entry(ch)
153 self.add_function_entry(command.cmd[-1], command.arg, command.fun)
155 def index_branch(self, branch):
157 if isinstance(entry, CommandEntry):
158 # Forward index this branch
159 entry.index = self.next_index
160 self.next_index += len(entry.branch) + 1
161 if self.next_index > 127:
162 raise CommandListTooBig
163 # Recurse through the tree branches
164 self.index_branch(entry.branch)
166 def index_tree(self):
167 self.branch = self.root
168 self.next_index = len(self.branch) + 1
169 self.index_branch(self.branch)
171 def write_branch(self, file, branch):
173 if isinstance(entry, CommandEntry):
174 file.write(' { /* ' + repr(self.list_idx) + ' */ \'' + \
175 entry.chr + '\', ' + repr(entry.index) + ' },\n')
177 file.write(' { /* ' + repr(self.list_idx) + ' */ \'' + \
178 entry.chr + '\', ' + repr(entry.index) + ' | EOC },\n')
180 file.write(' { /* ' + repr(self.list_idx) + ' */ 0, 0 },\n')
182 # Recurse through branches
184 if isinstance(entry, CommandEntry):
185 self.write_branch(file, entry.branch)
187 def write_tree(self, file):
188 self.branch = self.root
190 file.write('Menu menu[] = {\n')
191 self.write_branch(file, self.branch)
194 if __name__ == "__main__":
199 # Write default fail signal at index 0
200 function_list.append(Function('', 'COMMAND_FAIL_SIG'))
205 # Write the results into the file
206 output = open(sys.argv[1] + '.tmp', "w")
208 for line in open(sys.argv[1]):
211 if 'Start tag for ui.py' in line:
215 write_function_list(output)
216 elif 'End tag for ui.py' in line:
220 os.remove(sys.argv[1])
221 os.rename(sys.argv[1] + '.tmp', sys.argv[1])