source: proto/charsetcompiler/charset_compiler.py @ 666

Last change on this file since 666 was 666, checked in by ksherdy, 9 years ago

Add JSON number character set definition. Add commented out method calls to generate Python bitstream code generation.

File size: 29.1 KB
Line 
1# -*- coding: utf-8 -*-
2#
3#  Character Class Compiler
4#
5#  Version 0.7 - August 14, 2009
6#     Adding generation of Python code;  parabix 2 definitions
7#  Copyright (c) 2007, Robert D. Cameron
8#  All rights reserved.
9#
10#  TO DO Notes
11#
12#  1.  Perhaps the character set definition should be extended to
13#      allow other set operations.   For example, the 'Restricted' set
14#      of XML might be defined as ['\x00-\x1f'] - ['\x09', '\x0a', '\x0d']
15#      This would require fewer operations to compute.
16#
17#  2.  The range logic generator should be modified to group
18#      bit variables the same way as the individual character logic
19#      generator (i.e., combining bits 0 and 1, 2 and 3, 4 and 5 and
20#      6 and 7 first.
21#
22#  3.  Extend for 16-bit and full Unicode character values.
23#
24#
25#--------------------------------------------------------------------------
26#
27#  Data types
28#  1. Character Set Definitions
29#  2. Boolean Expressions
30#  3. Code Generator Objects
31#
32import re, binascii, string
33
34#
35#  Character sets are defined as lists of items that
36#  are either individual characters or ranges of contiguous
37#  characters.
38#
39class CharSetDef:
40    """Definitions of character sets.   Examples:
41    CharSetDef('alpha_', ['a-z', 'A-Z', '_'])
42    CharDef('semicolon', ';') (equiv. to CharSetDef('semicolon', [';']))
43    """
44    def __init__(self, name, items, invert = False):
45        self.name = name
46        self.items = items
47        self.complemented = invert
48    def show(self): 
49        if self.complemented:
50            return "CharSetDef(%s, %s, True)" % (self.name, self.items)
51        else: return "CharSetDef(%s, %s)" % (self.name, self.items)
52
53       
54class CharDef(CharSetDef):
55    def __init__(self, name, char, invert = False):
56        self.name = name
57        self.items = [char]
58        self.complemented = invert
59    def show(self): 
60        if self.complemented:
61            return "CharDef(%s, '\\%X', True)" % (self.name, ord(self.items[0]))
62        else: return "CharDef(%s, '\\%X')" % (self.name, ord(self.items[0]))
63
64
65#
66# UTF-8 bytes occurring in the additional XML 1.1 line break
67# characters NEL and LS.
68
69UTF8_XML11_WS_bytes = [CharDef('NEL1', chr(0xC2)),
70                        CharDef('NEL2', chr(0x85)),
71                        CharDef('LS1', chr(0xE2)),
72                        CharDef('LS2', chr(0x80)),
73                        CharDef('LS3', chr(0xA8))]
74           
75DefinitionSet = {}
76
77
78
79DefinitionSet['WS_Control_10'] = [CharSetDef('control.x00_x1F', ['\x00-\x1F']),
80                                  CharDef('control.CR', '\x0D'),
81                                  CharDef('control.LF', '\x0A'),
82                                  CharDef('control.HT', '\x09'),
83                                  CharDef('control.SP', ' '),
84                                  CharSetDef('lex.WS', ['\x0D', '\x0A', '\x09', ' '])]
85
86DefinitionSet['WS_Control_10_EBCDIC'] = [CharSetDef('Control', ['\x00-\x03', '\x37',
87                                                                '\x2d-\x2f', '\x16',
88                                                                '\x0b-\x13', '\x3c-\x3d',
89                                                                '\x32', '\x26-\x27',
90                                                                '\x18-\x19', '\x3f', 
91                                                                '\x1c-\x1f']),
92                                         CharDef('CR', '\x0D'),
93                                         CharDef('LF', '\x25'),
94                                         CharDef('HT', '\x05'),
95                                         CharDef('SP', '\x40')]
96
97DefinitionSet['WS_Control_11_EBCDIC'] = [CharSetDef('Control', ['\x00-\x3f']),
98                                         CharDef('CR', '\x0D'),
99                                         CharDef('LF', '\x25'),
100                                         CharDef('HT', '\x05'),
101                                         CharDef('SP', '\x40'),
102                                         CharDef('NEL', '\x15')]
103
104
105DefinitionSet['WS_Control_11_ISO8859'] = [CharSetDef('Control', ['\x00-\x1F', '\x7F', '\x80-\x9F']),
106                                          CharDef('CR', '\x0D'),
107                                          CharDef('LF', '\x0A'),
108                                          CharDef('HT', '\x09'),
109                                          CharDef('SP', ' '),
110                                          CharDef('NEL', '\x85')]
111
112DefinitionSet['Markup'] = [CharDef('RefStart', '&'),
113                           CharDef('Semicolon', ';'),
114                           CharDef('LAngle', '<'),
115                           CharDef('RAngle', '>'),
116                           CharDef('RBracket', ']'),
117                           CharDef('Hyphen', '-'),
118                           CharDef('QMark', '?'),
119                           CharDef('Equals', "="),
120                           CharDef('SQuote', "'"),
121                           CharDef('DQuote', '"'),
122                           CharDef('Slash', '/')
123                           ]
124
125DefinitionSet['Digit_and_Hex'] = [CharSetDef('Digit', ['0-9']),
126                                  CharSetDef('Hex', ['0-9', 'A-F', 'a-f'])]
127
128DefinitionSet['Markup2'] = DefinitionSet['Markup'] + DefinitionSet['Digit_and_Hex']
129
130DefinitionSet['LexicalItems'] = [CharSetDef('MarkupStart', ['<', '&']),
131                                 CharDef('RAngle', '>'),
132                                 CharDef('RBracket', ']'),
133                                 CharDef('Hyphen', '-'),
134                                 CharDef('QMark', '?'),
135                                 CharSetDef('Quote', ['"', "'", '<', '&']),
136                                 CharSetDef('NameFollow', [';', '=', '/', '>', '?', ')', '[', '|', '?', '*', '+', ','])
137                                 ]
138DefinitionSet['LexicalItems2'] = [CharSetDef('MarkupStart', ['<', '&']),
139                                 CharDef('RAngle', '>'),
140                                 CharDef('RBracket', ']'),
141                                 CharDef('Hyphen', '-'),
142                                 CharDef('QMark', '?'),
143                                 CharSetDef('Quote', ['"', "'", '<', '&']),
144                                 CharSetDef('NameFollow', [' -,', '/', ';-?', '[-^', '{-~'])
145                                 ]
146
147
148
149DefinitionSet['Digit_and_Hex'] = [CharSetDef('lex.Digit', ['0-9']),
150                                  CharSetDef('lex.Hex', ['0-9', 'A-F', 'a-f'])]
151                                 
152DefinitionSet['LexicalItems_with_Digit'] = DefinitionSet['LexicalItems2'] + DefinitionSet['Digit_and_Hex']
153
154DefinitionSet['LI_with_MarkupPass'] = DefinitionSet['LexicalItems_with_Digit'] + [CharSetDef('AmpHashSlash', ['&', '#', '/'])]
155
156DefinitionSet['JSON_number'] = [CharSetDef('lex.Minus', '-'),
157                        CharDef('lex.Zero', '0'),
158                        CharSetDef('lex.Digit_1_9', ['1-9']),
159                        CharSetDef('lex.Digit_0_9', ['0-9']),
160                        CharDef('lex.Decimal_Point', '.'),
161                        CharSetDef('lex.E_e', ['E','e']),
162                        CharSetDef('lex.Plus_Minus', ['+','-'])]
163
164#
165# Following definitions for the parabix2 unbounded bitstream prototype
166#
167# First all the special characters in the XML delimiters.
168
169xml_marks =    [CharDef('lex.RefStart', '&'),
170                CharDef('lex.Semicolon', ';'),
171                CharDef('lex.LAngle', '<'),
172                CharDef('lex.RAngle', '>'),
173                CharDef('lex.LBracket', '['),
174                CharDef('lex.RBracket', ']'),
175                CharDef('lex.Exclam', '!'),
176                CharDef('lex.QMark', '?'),
177                CharDef('lex.Hyphen', '-'),
178                CharDef('lex.Equals', "="),
179                CharDef('lex.SQuote', "'"),
180                CharDef('lex.DQuote', '"'),
181                CharDef('lex.Slash', '/'),
182                CharDef('lex.Hash', '#'),
183                CharDef('lex.x', 'x'),
184                CharDef('lex.Colon', ':')
185                ]
186#
187# NameFollow: all characters that may legally follow an XML name, plus
188# any others that may not be used in names.
189# 1. All non-WS characters that may legally follow an XML name.
190namefollow = [CharSetDef('lex.NameFollow', [';', '=', '/', '>', '?', ')', '[', '|', '?', '*', '+', ','])]
191#
192# NameScan: all ASCII characters that may legally occur in a Name,
193# plus all UTF-8 prefix and suffix bytes.
194namescan = [CharSetDef('lex.NameScan', ['_', '-', '.', '0-:', 'A-Z', 'a-z', '\x80-\xFF'])]
195
196#
197namelex = [CharSetDef('lex.ASCII_name_start', ['_', ':', 'A-Z', 'a-z']),
198           CharSetDef('lex.ASCII_name_char', ['_', '-', '.', '0-:', 'A-Z', 'a-z']),
199           CharSetDef('lex.NameScan', ['_', '-', '.', '0-:', 'A-Z', 'a-z', '\x80-\xFF'])]
200
201#
202# Byte classifications in UTF-8 validation.
203UTF8_defs = [CharSetDef('u8.unibyte', ['\x00-\x7F']),
204             CharSetDef('u8.prefix', ['\xC0-\xFF']),
205             CharSetDef('u8.prefix2', ['\xC0-\xDF']),
206             CharSetDef('u8.prefix3', ['\xE0-\xEF']),
207             CharSetDef('u8.prefix4', ['\xF0-\xFF']),
208             CharSetDef('u8.suffix', ['\x80-\xBF']),
209             CharSetDef('u8.badprefix', ['\xC0-\xC1', '\xF5-\xFF']),
210             CharDef('u8.xE0', '\xE0'),
211             CharDef('u8.xED', '\xED'),
212             CharDef('u8.xF0', '\xF0'),
213             CharDef('u8.xF4', '\xF4'),
214             CharSetDef('u8.xA0_xBF', ['\xA0-\xBF']),
215             CharSetDef('u8.x80_x9F', ['\x80-\x9F']),
216             CharSetDef('u8.x90_xBF', ['\x90-\xBF']),
217             CharSetDef('u8.x80_x8F', ['\x80-\x8F'])]
218
219
220#
221UTF8_BOM_bytes = [CharDef('u8.xEF', '\xEF'), CharDef('u8.xBF', '\xBF'), CharDef('u8.xBE', '\xBE')]
222
223DefinitionSet['parabix2'] = (xml_marks + namelex + DefinitionSet['WS_Control_10']
224                             + DefinitionSet['Digit_and_Hex'] + UTF8_defs + UTF8_BOM_bytes)
225                             
226DefinitionSet['UTF8'] = UTF8_defs
227
228DefinitionSet['CSV'] = [CharDef('BackSlash', '\\'),
229                        CharDef('DQuote', '"'),
230                        CharDef('SQuote', '\''),
231                        CharDef('CR', '\x0D'),
232                        CharDef('LF', '\x0A'),
233                        CharDef('Comma', ','),
234                        CharDef('HT', '\x09'),
235                        CharDef('Period', '.')]
236
237
238#
239# Symbolic Representations of Boolean Expressions
240#
241
242class BoolExpr:
243   """The BoolExpr class and its subclasses provide a symbolic
244      representation of Boolean expressions.
245   """
246   pass
247
248class Var(BoolExpr):
249    def __init__(self, varname):
250        self.varname = varname
251    def show(self): return 'Var("' + self.varname + '")'
252
253class TrueLiteral(BoolExpr):
254    def __init__(self):
255        self.value = True
256    def show(self): return 'T'
257
258class FalseLiteral(BoolExpr):
259    def __init__(self):
260        self.value = False
261    def show(self): return 'F'
262
263class Not(BoolExpr):
264    def __init__(self, expr):
265        self.operand = expr
266    def show(self): return 'Not(%s)' % (self.operand.show())
267
268class And(BoolExpr):
269    def __init__(self, expr1, expr2):
270        self.operand1 = expr1
271        self.operand2 = expr2
272    def show(self): return 'And(%s, %s)' % (self.operand1.show(), self.operand2.show())
273
274class Or(BoolExpr):
275    def __init__(self, expr1, expr2):
276        self.operand1 = expr1
277        self.operand2 = expr2
278    def show(self): return 'Or(%s, %s)' % (self.operand1.show(), self.operand2.show())
279
280class Xor(BoolExpr):
281    def __init__(self, expr1, expr2):
282        self.operand1 = expr1
283        self.operand2 = expr2
284    def show(self): return 'Xor(%s, %s)' % (self.operand1.show(), self.operand2.show())
285
286class Sel(BoolExpr):
287    def __init__(self, expr1, expr2, expr3):
288        self.sel = expr1
289        self.true_branch = expr2
290        self.false_branch = expr3
291    def show(self): return 'Sel(%s, %s, %s)' % (self.sel.show(), self.true_branch.show(), self.false_branch.show())
292
293
294#
295# Optimizing Constructors for Boolean Expressions
296# - Maintaining Assembler Instruction Form:
297#   - All boolean algebraic rules involving true/false applied.
298#   - Negations restricted:
299#       - no negations within or (DeMorgan's to nand)
300#       - at most one negation within and
301#
302
303def make_not(expr):
304    if isinstance(expr, TrueLiteral):
305        return FalseLiteral()
306    elif isinstance(expr, FalseLiteral):
307        return TrueLiteral()
308    elif isinstance(expr, Not):
309        return expr.operand
310    else: return Not(expr)
311
312def make_and(expr1, expr2):
313    if isinstance(expr1, TrueLiteral):
314        return expr2
315    elif isinstance(expr2, TrueLiteral):
316        return expr1
317    elif isinstance(expr1, FalseLiteral):
318        return FalseLiteral()
319    elif isinstance(expr2, FalseLiteral):
320        return FalseLiteral()
321    elif equal_exprs(expr1, expr2): return expr1
322    elif isinstance(expr1, Not):
323        if isinstance(expr2, Not):
324            return make_not(make_or(expr1.operand, expr2.operand))
325        elif equal_exprs(expr1.operand, expr2): return FalseLiteral()
326        else: return And(expr1, expr2)
327    elif isinstance(expr2, Not):
328        if equal_exprs(expr1, expr2.operand): return FalseLiteral()
329        else: return And(expr1, expr2)
330    else: return And(expr1, expr2)
331
332def make_or(expr1, expr2):
333    if isinstance(expr1, FalseLiteral):
334        return expr2
335    elif isinstance(expr2, FalseLiteral):
336        return expr1
337    elif isinstance(expr1, TrueLiteral):
338        return TrueLiteral()
339    elif isinstance(expr2, TrueLiteral):
340        return TrueLiteral()
341    elif isinstance(expr1, Not):
342        return make_not(make_and(expr1.operand, make_not(expr2)))
343    elif isinstance(expr2, Not):
344        return make_not(make_and(make_not(expr1), expr2.operand))
345    elif equal_exprs(expr1, expr2): return expr1
346    elif isinstance(expr1, And) and isinstance(expr2, And):
347        # These optimizations factor out common components that
348        # can occur when sets are formed by union (e.g., union of
349        # [a-z] and [A-Z].
350        if equal_exprs(expr1.operand1, expr2.operand1):
351            return make_and(expr1.operand1, make_or(expr1.operand2, expr2.operand2))
352        elif equal_exprs(expr1.operand2, expr2.operand2):
353            return make_and(expr1.operand2, make_or(expr1.operand1, expr2.operand1))
354        elif equal_exprs(expr1.operand1, expr2.operand2):
355            return make_and(expr1.operand1, make_or(expr1.operand2, expr2.operand1))
356        elif equal_exprs(expr1.operand2, expr2.operand1):
357            return make_and(expr1.operand2, make_or(expr1.operand1, expr2.operand2))
358        else: return Or(expr1, expr2)
359    else: return Or(expr1, expr2)
360
361def make_sel(if_expr, T_expr, F_expr):
362    if isinstance(if_expr, TrueLiteral):
363        return T_expr
364    elif isinstance(if_expr, FalseLiteral):
365        return F_expr
366    elif isinstance(T_expr, TrueLiteral):
367        # if x then T else y = x or y
368        return make_or(if_expr, F_expr) 
369    elif isinstance(T_expr, FalseLiteral):
370        # if x then F else y = not(x) and y
371        return make_and(make_not(if_expr), F_expr) 
372    elif isinstance(F_expr, FalseLiteral):
373        # if x then y else F = x and y
374        return make_and(if_expr, T_expr) 
375    elif isinstance(F_expr, TrueLiteral):
376        # if x then y else T = not(x) or y
377        return make_or(make_not(if_expr), T_expr)
378    elif equal_exprs(T_expr, F_expr):
379        return T_expr
380    else: return Sel(if_expr, T_expr, F_expr)
381
382
383def make_xor(expr1, expr2):
384    if isinstance(expr1, FalseLiteral):
385        return expr2
386    elif isinstance(expr1, FalseLiteral):
387        return expr1
388    elif isinstance(expr1, TrueLiteral):
389        return make_not(expr2)
390    elif isinstance(expr2, TrueLiteral):
391        return make_not(expr1)
392    elif isinstance(expr1, Not) and isinstance(expr2, Not):
393        return make_xor(expr1.operand, expr2.operand)
394    else: return Xor(expr1, expr2)
395
396def equal_exprs(e1, e2):
397    if isinstance(e1, FalseLiteral): return isinstance(e2, FalseLiteral)
398    elif isinstance(e1, TrueLiteral): return isinstance(e2, TrueLiteral)
399    elif isinstance(e1, Var) and isinstance(e2, Var):
400        return e1.varname == e2.varname
401    elif isinstance(e1, Not) and isinstance(e2, Not):
402        return equal_exprs(e1.operand, e2.operand)
403    elif isinstance(e1, And) and isinstance(e2, And):
404        if equal_exprs(e1.operand1, e2.operand1):
405            return equal_exprs(e1.operand2, e2.operand2)
406        elif equal_exprs(e1.operand1, e2.operand2):
407            return equal_exprs(e1.operand2, e2.operand1)
408        else: return False
409    elif isinstance(e1, Or) and isinstance(e2, Or):
410        if equal_exprs(e1.operand1, e2.operand1):
411            return equal_exprs(e1.operand2, e2.operand2)
412        elif equal_exprs(e1.operand1, e2.operand2):
413            return equal_exprs(e1.operand2, e2.operand1)
414        else: return False
415    elif isinstance(e1, Xor) and isinstance(e2, Xor):
416        if equal_exprs(e1.operand1, e2.operand1):
417            return equal_exprs(e1.operand2, e2.operand2)
418        elif equal_exprs(e1.operand1, e2.operand2):
419            return equal_exprs(e1.operand2, e2.operand1)
420        else: return False
421    elif isinstance(e1, Sel) and isinstance(e2, Sel):
422        if equal_exprs(e1.sel, e2.sel):
423             if equal_exprs(e1.true_branch, e2.true_branch):
424                 return equal_exprs(e1.false_branch, e2.false_branch)
425             else: return False
426        else: return False
427
428
429#
430#
431#  Boolean Expressions for Character Class Definitions
432#
433
434def bit_var(n):
435    return 'bit[%i]' % n
436def make_bitv(n):
437    return Var(bit_var(n))
438
439# Deprecated
440def make_2bit_test(var1, var2, bit_pattern):
441  if bit_pattern == 0: 
442    return make_not(make_or(var1, var2))
443  elif bit_pattern == 1:
444    return make_and(make_not(var1), var2)
445  elif bit_pattern == 2:
446    return make_and(var1, make_not(var2))
447  else: return make_and(var1, var2)
448
449# Deprecated
450def make_8bit_test(bit_pattern):
451  return make_and(make_and(make_2bit_test(make_bitv(0), make_bitv(1), (bit_pattern >> 6) & 3),
452                           make_2bit_test(make_bitv(2), make_bitv(3), (bit_pattern >> 4) & 3)),
453                  make_and(make_2bit_test(make_bitv(4), make_bitv(5), (bit_pattern >> 2) & 3),
454                           make_2bit_test(make_bitv(6), make_bitv(7), (bit_pattern) & 3)))
455
456
457def make_bit_test(pattern, bit_count):
458    bit_terms = []
459    test_bit = 2**(bit_count - 1)
460    for i in range(0, bit_count):
461        if (pattern & test_bit) == 0:
462            bit_terms.append(make_not(make_bitv(i)))
463        else: bit_terms.append(make_bitv(i))
464        test_bit >>= 1
465    while len(bit_terms) > 1:
466        new_terms = []
467        for i in range(0, len(bit_terms)/ 2):
468            new_terms.append(make_and(bit_terms[2*i], bit_terms[2*i+1]))
469        if len(bit_terms) % 2 == 1:
470            new_terms.append(bit_terms[-1])
471        bit_terms = new_terms
472    return bit_terms[0]
473
474
475def char_test_expr(ch):
476    return make_bit_test(ord(ch), 8)
477    #return make_8bit_test(ord(ch))
478
479def GE_Range(N, n):
480    if N == 0: return TrueLiteral()
481    elif N % 2 == 0 and (n >> (N - 2)) == 0:
482        return make_or(make_or(make_bitv(8-N), make_bitv(9-N)),
483                        GE_Range(N - 2, n))
484    elif N % 2 == 0 and (n >> (N - 2)) == 3:   # >= 11xxxx
485        return make_and(make_and(make_bitv(8-N), make_bitv(9-N)),
486                        GE_Range(N - 2, n - (3 << (N-2))))
487    elif N >= 1:
488        hi_bit = n & (1 << (N-1))
489        lo_bits = n - hi_bit
490        lo_range = GE_Range(N-1, lo_bits)
491        if hi_bit == 0:
492            # If the hi_bit of n is not set, then whenever the corresponding bit
493            # is set in the target, the target will certainly be >=.  Otherwise,
494            # the value of GE_range(N-1, lo_bits) is required.
495            return make_or(make_bitv(8-N), lo_range)
496        else: 
497            # If the hi_bit of n is set, then the corresponding bit must be set
498            # in the target for >= and GE_range(N-1, lo_bits) must also be true.
499            return make_and(make_bitv(8-N), lo_range)
500
501def LE_Range(N, n):
502    # If an N-bit pattern is all ones, then it is always
503    # true that any n-bit value is LE this pattern.
504    # Handling this as a special case avoids an overflow
505    # issue with n+1 requiring more than N bits.
506    if n+1 == 2 ** N:
507        return TrueLiteral()
508    else:
509        return make_not(GE_Range(N, n+1))
510
511BadRange = Exception()
512
513
514def Make_Range(n1, n2):  # require n2 >= n1
515    diff_bits = n1 ^ n2
516    diff_count = 0
517    while diff_bits > 0:
518        diff_count += 1
519        diff_bits >>= 1
520    if n2 < n1 or diff_count > 8: raise BadRange()
521    common = make_bit_test(n1 >> diff_count, 8 - diff_count)
522    if diff_count == 0: return common
523    mask = 2**(diff_count-1) - 1
524    lo_test = GE_Range(diff_count-1, n1 & mask)
525    hi_test = LE_Range(diff_count-1, n2 & mask)
526    return make_and(common, make_sel(make_bitv(8-diff_count), hi_test, lo_test))
527
528# Deprecated   
529def Inclusive_Range(N, n1, n2):  # require n2 >= n1
530    if N == 0: return TrueLiteral()
531    elif n1 >= 2**(N-1):
532        return make_and(make_bitv(8-N), Inclusive_Range(N-1, n1 - 2**(N-1), n2 - 2**(N-1)))
533    elif n2 < 2**(N-1):
534        return make_and(make_not(make_bitv(8-N)), Inclusive_Range(N-1, n1, n2))
535    else:
536        n2_lo = n2 - 2**(N-1)
537        lo_test = GE_Range(N-1, n1)
538        hi_test = LE_Range(N-1, n2_lo)
539        # special optimization?
540        # if n2_lo + 1 == n1: return make_xor(make_bit_test(8-N), lo_test)
541        return make_sel(make_bitv(8-N), lo_test, hi_test)
542
543
544
545
546BadCharSetItem = Exception()
547
548def char_or_range_expr(charset_item):
549    if len(charset_item) == 1:
550        return char_test_expr(charset_item[0])
551    elif len(charset_item) == 3:
552        if charset_item[1] == '-' and ord(charset_item[0]) <= ord(charset_item[2]):
553             return Make_Range(ord(charset_item[0]), ord(charset_item[2]))
554             #  return Inclusive_Range(8, ord(charset_item[0]), ord(charset_item[2]))
555    print charset_item
556    raise BadCharSetItem
557
558def charset_expr(chardef):
559    e1 = char_or_range_expr(chardef.items[0])
560    for i in range(1, len(chardef.items)):
561        e1 = make_or(e1, char_or_range_expr(chardef.items[i]))
562    if chardef.complemented: return make_not(e1)
563    else: return e1
564
565
566
567#
568#
569#  Code Generation
570#
571class CodeGenObject:
572    def __init__(self, predeclared, typedecl='BitBlock '):
573        self.gensym_template = 'temp%i'
574        self.gensym_counter = 0
575        self.generated_code = []
576        self.common_expression_map = {}
577        for sym in predeclared: self.common_expression_map[sym] = sym
578        self.typedecl = typedecl
579    def add_assignment(self, varname, expr):
580        self.common_expression_map[expr] = varname
581        self.generated_code.append(%s%s = %s;\n' % (self.typedecl, varname, expr))
582    def expr_string_to_variable(self, expr_string):
583        if self.common_expression_map.has_key(expr_string): 
584            return self.common_expression_map[expr_string]
585        else:
586            self.gensym_counter += 1
587            sym = self.gensym_template % self.gensym_counter
588            self.add_assignment(sym, expr_string)
589            return sym
590    def showcode(self):
591        s = ''
592        for stmt in self.generated_code: s += stmt
593        return s
594
595
596
597def expr2simd(genobj, expr):
598    """Translate a Boolean expression into three-address Altivec code
599       using code generator object genobj.
600    """
601    if isinstance(expr, TrueLiteral): return 'simd_const_1(1)'
602    elif isinstance(expr, FalseLiteral): return 'simd_const_1(0)'
603    elif isinstance(expr, Var): return expr.varname
604    elif isinstance(expr, Not):
605       e = genobj.expr_string_to_variable(expr2simd(genobj, expr.operand))
606       return 'simd_andc(simd_const_1(1), %s)' % (e)
607    elif isinstance(expr, Or):
608       e1 = genobj.expr_string_to_variable(expr2simd(genobj, expr.operand1))
609       e2 = genobj.expr_string_to_variable(expr2simd(genobj, expr.operand2))
610       return 'simd_or(%s, %s)' % (e1, e2)
611    elif isinstance(expr, Xor):
612       e1 = genobj.expr_string_to_variable(expr2simd(genobj, expr.operand1))
613       e2 = genobj.expr_string_to_variable(expr2simd(genobj, expr.operand2))
614       return 'simd_xor(%s, %s)' % (e1, e2)
615    elif isinstance(expr, And):
616       if isinstance(expr.operand1, Not):
617           e1 = genobj.expr_string_to_variable(expr2simd(genobj, expr.operand1.operand))
618           e2 = genobj.expr_string_to_variable(expr2simd(genobj, expr.operand2))
619           return 'simd_andc(%s, %s)' % (e2, e1)
620       elif isinstance(expr.operand2, Not):
621           e1 = genobj.expr_string_to_variable(expr2simd(genobj, expr.operand1))
622           e2 = genobj.expr_string_to_variable(expr2simd(genobj, expr.operand2.operand))
623           return 'simd_andc(%s, %s)' % (e1, e2)
624       else:
625           e1 = genobj.expr_string_to_variable(expr2simd(genobj, expr.operand1))
626           e2 = genobj.expr_string_to_variable(expr2simd(genobj, expr.operand2))
627           return 'simd_and(%s, %s)' % (e1, e2)
628    elif isinstance(expr, Sel):
629       sel = genobj.expr_string_to_variable(expr2simd(genobj, expr.sel))
630       e1 = genobj.expr_string_to_variable(expr2simd(genobj, expr.true_branch))
631       e2 = genobj.expr_string_to_variable(expr2simd(genobj, expr.false_branch))
632       return 'simd_if(%s, %s, %s)' %(sel, e1, e2)
633
634def chardef2simd(genobj, chardef):
635    genobj.add_assignment(chardef.name, expr2simd(genobj, charset_expr(chardef)))
636
637def chardeflist2simd(chardeflist):
638    cgo = CodeGenObject([bit_var(i) for i in range(0,8)])
639    for d in chardeflist:
640        chardef2simd(cgo, d)
641    return cgo.showcode()
642
643
644
645def expr2py(genobj, expr):
646    """Translate a Boolean expression into three-address python code
647       using code generator object genobj.
648    """
649    if isinstance(expr, TrueLiteral): return '-1'
650    elif isinstance(expr, FalseLiteral): return '0'
651    elif isinstance(expr, Var): return expr.varname
652    elif isinstance(expr, Not):
653       e = genobj.expr_string_to_variable(expr2py(genobj, expr.operand))
654       return '(~%s)' % (e)
655    elif isinstance(expr, Or):
656       e1 = genobj.expr_string_to_variable(expr2py(genobj, expr.operand1))
657       e2 = genobj.expr_string_to_variable(expr2py(genobj, expr.operand2))
658       return '(%s | %s)' % (e1, e2)
659    elif isinstance(expr, Xor):
660       e1 = genobj.expr_string_to_variable(expr2py(genobj, expr.operand1))
661       e2 = genobj.expr_string_to_variable(expr2py(genobj, expr.operand2))
662       return '(%s ^ %s)' % (e1, e2)
663    elif isinstance(expr, And):
664       if isinstance(expr.operand1, Not):
665           e1 = genobj.expr_string_to_variable(expr2py(genobj, expr.operand1.operand))
666           e2 = genobj.expr_string_to_variable(expr2py(genobj, expr.operand2))
667           return '(%s &~ %s)' % (e2, e1)
668       elif isinstance(expr.operand2, Not):
669           e1 = genobj.expr_string_to_variable(expr2py(genobj, expr.operand1))
670           e2 = genobj.expr_string_to_variable(expr2py(genobj, expr.operand2.operand))
671           return '(%s &~ %s)' % (e1, e2)
672       else:
673           e1 = genobj.expr_string_to_variable(expr2py(genobj, expr.operand1))
674           e2 = genobj.expr_string_to_variable(expr2py(genobj, expr.operand2))
675           return '(%s & %s)' % (e1, e2)
676    elif isinstance(expr, Sel):
677       sel = genobj.expr_string_to_variable(expr2py(genobj, expr.sel))
678       e1 = genobj.expr_string_to_variable(expr2py(genobj, expr.true_branch))
679       e2 = genobj.expr_string_to_variable(expr2py(genobj, expr.false_branch))
680       return '((%s & %s)|(~(%s) & %s))' %(sel, e1, sel, e2)
681
682def chardef2py(genobj, chardef):
683    genobj.add_assignment(chardef.name, expr2py(genobj, charset_expr(chardef)))
684
685
686def py_chardefmap(chardeflist):
687    defs = ["'%s' : %s" % (d.name,d.name) for d in chardeflist]
688    return  '{%s}' % string.join(defs, ',\n\t')
689
690def chardeflist2py(chardeflist):
691    cgo = CodeGenObject([bit_var(i) for i in range(0,8)],'')
692    for d in chardeflist:
693        chardef2py(cgo, d) 
694    return cgo.showcode()# + "  return "+ py_chardefmap(chardeflist) + "\n"
695
696
697def code_gen_for_transcode(transcode_tbl_h, transcode_tbl_l):
698  cgo = CodeGenObject([bit_var(i) for i in range(0,8)])
699  xor_tbl_l = [transcode_tbl_l[code] ^ code for code in range(256)]
700  code_gen_for_transcode_8bit(cgo, "x16h", transcode_tbl_h)
701  code_gen_for_transcode_8bit(cgo, "x16l", xor_tbl_l)
702  return cgo.showcode()
703
704def code_gen_for_transcode_8bit(cgo, pfx, tbl):
705  for bit in range(8):
706    bit_mask = 256 >> bit
707    in_run = False
708    first_expr_found = False
709    bit_expr = FalseLiteral()
710    for code in range(256):
711      if tbl[code] & bit_mask != 0:
712        if not in_run:
713          in_run = True
714          run_start = code
715      else:
716        if in_run:
717          if run_start == code-1:
718            e1 = char_test_expr(chr(code - 1))
719          else:
720            e1 = Make_Range(run_start, code - 1)
721          if first_expr_found:
722            bit_expr = make_or(bit_expr, e1)
723          else:
724            first_expr_found = True
725            bit_expr = e1
726    if first_expr_found:
727      cgo.add_assignment("%s[%i]" % (pfx, bit), expr2simd(cgo, bit_expr))
728
729# Work with tables from
730# /home/cameron/glibc-2.3.5/localedata/charmaps/
731
732charmap_line_RE = re.compile("<U([0-9A-F][0-9A-F])([0-9A-Z][0-9A-Z])>\s+/x([0-9a-f][0-9a-f])\s")
733
734def read_char_map(file):
735  f = open(file)
736  lines = f.readlines()
737  matches = [charmap_line_RE.match(l) for l in lines]
738  u16hi = [ord(binascii.unhexlify(m.group(1))) for m in matches if m]
739  u16lo = [ord(binascii.unhexlify(m.group(2))) for m in matches if m]
740  codes = [ord(binascii.unhexlify(m.group(3))) for m in matches if m]
741  codes_OK = [c for c in range(256) if codes[c] == c]
742  if len(codes_OK) != 256:
743    print("Code map failure reading %s" % file)
744  return (u16hi, u16lo)
745
746import codecs
747def ascii2ebcdic_chardeflist(defs):
748        encoder = codecs.getencoder('cp037')
749        return [xlate_chardef(d, encoder) for d in defs]
750
751def xlate_char_or_range(charset_item, encoder):
752    if len(charset_item) == 1:
753        return encoder(charset_item[0])
754    elif len(charset_item) == 3:
755        if charset_item[1] == '-' and ord(charset_item[0]) <= ord(charset_item[2]):
756             return Make_Range(ord(charset_item[0]), ord(charset_item[2]))
757             #  return Inclusive_Range(8, ord(charset_item[0]), ord(charset_item[2]))
758    print charset_item
759    raise BadCharSetItem
760       
761def xlate_chardef(chardef, encoder):
762  if isinstance(chardef, CharDef):
763    return CharDef(chardef.name, encoder(chardef.items[0])[0], chardef.complemented)
764  else:
765    cdefs = []
766    for item in chardef.items:
767        if len(item) == 1: cdefs.append(encoder(item)[0])
768        elif len(item) == 3:
769          for v in range(ord(item[0]), ord(item[-1])+1):
770            cdefs.append(encoder(chr(v))[0])
771        else: raise BadCharSetItem
772    return CharSetDef(chardef.name, cdefs, chardef.complemented)
773
774import charset_input_parser
775def input_chardef(filename):
776    """
777    Returns a list of declared CharSet from the declarations in the input file
778    """
779    defs = []
780    charset_declaration_list = charset_input_parser.processCharsetInput(filename)
781   
782    for charset_declaration in charset_declaration_list:
783        defs.append(CharSetDef (charset_declaration[0], charset_declaration[1]))
784
785    return defs
786                                 
787import sys
788def main():
789    if len(sys.argv) == 2:
790        # if the specified argument is not in the DefinitionSet, then assume that it's a filename
791        if sys.argv[1] not in DefinitionSet:
792            #define the characters in the list
793            defs = input_chardef(sys.argv[1])
794            print chardeflist2simd(defs)
795            #print chardeflist2py(defs)
796        else:
797            print chardeflist2simd(DefinitionSet[sys.argv[1]])
798            #print chardeflist2py(DefinitionSet[sys.argv[1]])
799    elif len(sys.argv) == 3 and sys.argv[2] == 'EBCDIC':
800        defs = ascii2ebcdic_chardeflist(DefinitionSet[sys.argv[1]])
801        print chardeflist2simd(defs)
802    else:
803        print "Usage python charset_compiler.py <name> [EBCDIC]"
804        for k in DefinitionSet.keys(): print k
805
806if __name__ == "__main__": main()
Note: See TracBrowser for help on using the repository browser.