source: proto/parabix2/parabix2_compilable.py @ 548

Last change on this file since 548 was 548, checked in by cameron, 9 years ago

Inline and reorganize byteclass and u8 processing

File size: 42.7 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# parabix2.py
4#
5# Parallel XML Parsing with Bitstream Addition
6# - Complete prototype for all bitstream computations in Parabix2
7#
8# Robert D. Cameron
9# August 20, 2009
10#
11#----------------------------------------------------------------------------
12#
13# We use python's unlimited precision integers for unbounded bit streams.
14# This permits simple logical operations on the entire stream.
15# Assumption: bitstreams are little-endian (e.g., as on x86).
16#
17#----------------------------------------------------------------------------
18#
19
20
21#import bitutil
22
23#import byteclass
24
25#import u8u16
26
27#import sys
28
29class u8_streams ():
30  unibyte = 0
31  prefix = 0
32  prefix2 = 0
33  prefix3 = 0
34  prefix4 = 0
35  suffix = 0
36  badprefix = 0
37  xE0_scope = 0
38  xED_scope = 0
39  xF0_scope = 0
40  xF4_scope = 0
41  xA0_xBF = 0
42  x80_x9F = 0
43  x90_xBF = 0
44  x80_x8F = 0
45  xEF_scope = 0
46  xBF = 0
47  xBE = 0
48  scope22 = 0
49  scope32 = 0
50  scope33 = 0
51  scope42 = 0
52  scope43 = 0
53  scope44 = 0
54
55class control_streams ():
56  x00_x1F = 0
57  CR = 0
58  LF = 0
59  HT = 0
60  SP = 0
61  CR_scope = 0
62  CRLF = 0
63 
64class lexical_streams ():
65  RefStart = 0
66  Semicolon = 0 
67  Colon = 0
68  LAngle = 0
69  RAngle = 0
70  LBracket = 0
71  RBracket = 0
72  Exclam = 0
73  QMark = 0
74  Hyphen = 0
75  Equals = 0
76  SQuote = 0
77  DQuote = 0
78  Slash = 0
79  Hash = 0
80  x = 0
81  ASCII_name_start = 0
82  ASCII_name_char = 0
83  NameScan = 0
84  Digit = 0
85  Hex = 0
86  WS = 0
87  PI_start = 0
88  CtCD_start = 0
89  EndTag_start = 0
90  CD_end = 0
91  DoubleHyphen = 0
92  PI_end = 0
93  RefStart_scope = 0
94  LAngle_scope = 0
95  Hyphen_scope = 0
96  QMark_scope = 0
97  RBracket_scope = 0
98
99def classify_bytes(bit) :
100        lex = lexical_streams()
101        control = control_streams()
102        temp1 = (bit[0] | bit[1]);
103        temp2 = (bit[2] &~ bit[3]);
104        temp3 = (temp2 &~ temp1);
105        temp4 = (bit[5] &~ bit[4]);
106        temp5 = (bit[6] &~ bit[7]);
107        temp6 = (temp4 & temp5);
108        lex.RefStart = (temp3 & temp6);
109        temp7 = (bit[2] & bit[3]);
110        temp8 = (temp7 &~ temp1);
111        temp9 = (bit[4] &~ bit[5]);
112        temp10 = (bit[6] & bit[7]);
113        temp11 = (temp9 & temp10);
114        lex.Semicolon = (temp8 & temp11);
115        temp12 = (bit[4] & bit[5]);
116        temp13 = (bit[6] | bit[7]);
117        temp14 = (temp12 &~ temp13);
118        lex.LAngle = (temp8 & temp14);
119        temp15 = (temp12 & temp5);
120        lex.RAngle = (temp8 & temp15);
121        temp16 = (bit[1] &~ bit[0]);
122        temp17 = (bit[3] &~ bit[2]);
123        temp18 = (temp16 & temp17);
124        lex.LBracket = (temp18 & temp11);
125        temp19 = (bit[7] &~ bit[6]);
126        temp20 = (temp12 & temp19);
127        lex.RBracket = (temp18 & temp20);
128        temp21 = (bit[4] | bit[5]);
129        temp22 = (temp19 &~ temp21);
130        lex.Exclam = (temp3 & temp22);
131        temp23 = (temp12 & temp10);
132        lex.QMark = (temp8 & temp23);
133        lex.Hyphen = (temp3 & temp20);
134        lex.Equals = (temp8 & temp20);
135        temp24 = (temp4 & temp10);
136        lex.SQuote = (temp3 & temp24);
137        temp25 = (temp5 &~ temp21);
138        lex.DQuote = (temp3 & temp25);
139        lex.Slash = (temp3 & temp23);
140        temp26 = (temp10 &~ temp21);
141        lex.Hash = (temp3 & temp26);
142        temp27 = (temp16 & temp7);
143        temp28 = (temp9 &~ temp13);
144        lex.x = (temp27 & temp28);
145        temp29 = (temp9 & temp5);
146        lex.Colon = (temp8 & temp29);
147        temp30 = (temp18 & temp23);
148        temp31 = (temp30 | lex.Colon);
149        temp32 = (temp16 &~ bit[2]);
150        temp33 = (bit[5] | temp10);
151        temp34 = (bit[4] & temp33);
152        temp35 = (~temp34);
153        temp36 = (temp21 | temp13);
154        temp37 = ((bit[3] & temp35)|(~(bit[3]) & temp36));
155        temp38 = (temp32 & temp37);
156        temp39 = (temp31 | temp38);
157        temp40 = (temp16 & bit[2]);
158        temp41 = (temp40 & temp37);
159        lex.ASCII_name_start = (temp39 | temp41);
160        temp42 = (temp30 | lex.Hyphen);
161        temp43 = (temp3 & temp15);
162        temp44 = (temp42 | temp43);
163        temp45 = (temp8 &~ temp34);
164        temp46 = (temp44 | temp45);
165        temp47 = (temp46 | temp38);
166        lex.ASCII_name_char = (temp47 | temp41);
167        lex.NameScan = (lex.ASCII_name_char | bit[0]);
168        temp48 = (temp1 | bit[2]);
169        control.x00_x1F = (~temp48);
170        temp49 = (bit[2] | bit[3]);
171        temp50 = (temp1 | temp49);
172        control.CR = (temp20 &~ temp50);
173        control.LF = (temp29 &~ temp50);
174        temp51 = (temp9 & temp19);
175        control.HT = (temp51 &~ temp50);
176        control.SP = (temp3 &~ temp36);
177        temp52 = (temp20 | temp29);
178        temp53 = (temp52 | temp51);
179        temp54 = (temp53 &~ temp50);
180        lex.WS = (temp54 | control.SP);
181        temp55 = (bit[5] | bit[6]);
182        temp56 = (bit[4] & temp55);
183        lex.Digit = (temp8 &~ temp56);
184        temp57 = (temp16 &~ temp49);
185        temp58 = (temp57 &~ bit[4]);
186        temp59 = (~temp10);
187        temp60 = ((bit[5] & temp59)|(~(bit[5]) & temp13));
188        temp61 = (temp58 & temp60);
189        temp62 = (lex.Digit | temp61);
190        temp63 = (temp16 & temp2);
191        temp64 = (temp63 &~ bit[4]);
192        temp65 = (temp64 & temp60);
193        lex.Hex = (temp62 | temp65);
194
195        return (control, lex)
196
197
198def validate_xmlchar(u8, control, lex, EOF_mask):
199        r"""Compute an error stream marking characters illegal in XML:
200        (1) Control characters in the range 0x00-0x1F except HT, LF, CR
201        (2) OxFFFF and OxFFFE, having UTF-8 encodings 0xEF 0xBF 0XBF and 0xEF 0xBF 0xBE.
202
203        >>> demo_validate_xmlchar('plaintext (good: \x09) (bad: \x03) (bad \xEF\xBF\xBF) (good \xEF\xBF\xBC)')
204        input high nybbles: 7666676772266663202226663202226662ebb22266662ebb2
205        input low nybbles : 0c19e4584087ff4a09908214a039082140fff9087ff40ffc9
206        illegal XML chars : __________________________1_________1_____________
207"""
208        EF_BF_pending = bitutil.Advance(u8.xEF_scope & u8.xBF)
209        ret = (EF_BF_pending & (u8.xBE | u8.xBF)) | (control.x00_x1F &~ lex.WS & EOF_mask)
210        return ret
211
212
213def demo_validate_xmlchar(u8data):
214        lgth = len(u8data)
215        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
216        (u8, control, lex) = byteclass.classify_bytes(bit)
217        bitutil.print_aligned_streams([('input high nybbles', bitutil.high_nybble_stream(u8data)), 
218                            ('input low nybbles', bitutil.low_nybble_stream(u8data)),
219                            ('illegal XML chars', bitutil.bitstream2string(validate_xmlchar(u8, control, lex, EOF_mask), lgth+1))])
220
221def normalize_line_breaks(control, bit):
222        r"""Convert CRs to LFs and mark CRLF occurrences for deletion.
223
224        >>> demo_line_breaks('ab \r\n  cd \r  ef \r ')
225        input high nybbles: 662002266202266202
226        input low nybbles : 120da00340d00560d0
227        CR                : ___1______1_____1_
228        LF                : ____1_____________
229        CRLF              : ____1_____________
230"""
231        control.CRLF = control.CR_scope & control.LF
232        # Convert CRs to LFs (flip bits 5, 6 and 7 with xor).
233        bit[5] ^= control.CR
234        bit[6] ^= control.CR
235        bit[7] ^= control.CR
236        return (control, bit)
237
238def demo_line_breaks(u8data):
239        lgth = len(u8data)
240        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
241        (u8, control, lex) = byteclass.classify_bytes(bit)
242        (control, bit) = normalize_line_breaks(control, bit)
243        bitutil.print_aligned_u8_byte_streams([('input high nybbles', bitutil.high_nybble_stream(u8data)), 
244                            ('input low nybbles', bitutil.low_nybble_stream(u8data)),
245                            ('CR', bitutil.bitstream2string(control.CR, lgth)),
246                            ('LF', bitutil.bitstream2string(control.LF, lgth)),
247                            ('CRLF', bitutil.bitstream2string(control.CRLF, lgth))])
248
249
250
251
252
253def add_multiliterals(lex):
254        """Extend the byte-based lexical item streams for some important
255        multibyte literals.
256       
257        >>> demo_multiliterals("  <?php?>  <!--  -->  <![CDATA[  ]]> ")
258        input data  :   <?php?>  <!--  -->  <![CDATA[  ]]>
259        PI_start    : ___1_________________________________
260        CtCD_start  : ____________1__________1_____________
261        EndTag_start: _____________________________________
262        CD_end      : ___________________________________1_
263        DoubleHyphen: ______________1___1__________________
264        PI_end      : ________1____________________________
265        """
266
267        lex.PI_start = lex.LAngle_scope & lex.QMark
268        lex.CtCD_start = lex.LAngle_scope & lex.Exclam
269        lex.EndTag_start = lex.LAngle_scope & lex.Slash
270        lex.CD_end = bitutil.Advance(lex.RBracket_scope & lex.RBracket) & lex.RAngle
271        lex.DoubleHyphen = lex.Hyphen_scope & lex.Hyphen
272        lex.PI_end = lex.QMark_scope & lex.RAngle
273        return lex
274
275def demo_multiliterals(u8data):
276        lgth = len(u8data)
277        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
278        (u8, control, lex) = byteclass.classify_bytes(bit)
279        lex = add_multiliterals(lex)
280        bitutil.print_aligned_u8_byte_streams([('input data', u8data), 
281                            ('PI_start', bitutil.bitstream2string(lex.PI_start, lgth)),
282                            ('CtCD_start', bitutil.bitstream2string(lex.CtCD_start, lgth)),
283                            ('EndTag_start', bitutil.bitstream2string(lex.EndTag_start, lgth)),
284                            ('CD_end', bitutil.bitstream2string(lex.CD_end, lgth)),
285                            ('DoubleHyphen', bitutil.bitstream2string(lex.DoubleHyphen, lgth)),
286                            ('PI_end', bitutil.bitstream2string(lex.PI_end, lgth))])
287
288class CtCDPI_callouts:
289        CD_span = 0
290        Ct_span = 0
291        PI_mask = 0
292        CtCDPI_mask = 0
293        error = 0
294       
295def parse_CtCDPI(lex, EOF_mask):
296        """Parse all comments, CDATA sections and processing instructions.
297       
298        Return bitstreams marking the extent of these markup items,
299        excluding initial and final bracketting.
300       
301        >>> demo_CtCDPI(' <?php?>  <!-- example -->  <![CDATA[  shift: a<<1 ]]> ')
302        input data :  <?php?>  <!-- example -->  <![CDATA[  shift: a<<1 ]]>
303        CD_span    : ______________________________11111111111111111111111__
304        Ct_span    : _____________111111111111______________________________
305        PI_span    : __11111________________________________________________
306        CtCDPI_mask: __111111___111111111111111___1111111111111111111111111_
307        error      : ________________________________________________________
308       
309        Comments are terminated by double-hyphen; immediately require closing ">".
310       
311        >>> demo_CtCDPI(' <!--  <?php?>  --   <!-- -->')
312        input data :  <!--  <?php?>  --   <!-- -->
313        CD_span    : _____________________________
314        Ct_span    : ____11111111111111______1111_
315        PI_span    : _____________________________
316        CtCDPI_mask: __11111111111111111___1111111
317        error      : __________________1___________
318
319
320
321"""
322        callouts = CtCDPI_callouts()
323        PI_starts = 0
324        PI_ends = 0
325        Ct_starts = 0
326        Ct_ends = 0
327        CD_starts = 0
328        CD_ends = 0
329        CtCDPI_starts = 0
330        # Scanning streams
331        CtCDPI_scan = ~(lex.CtCD_start | lex.PI_start) & EOF_mask
332        Ct_end_scan = ~lex.DoubleHyphen & EOF_mask
333        CD_end_scan = ~lex.CD_end & EOF_mask
334        PI_end_scan = ~lex.PI_end & EOF_mask
335        #
336        # Initiate the scan
337        CtCDPI_Cursor = 1
338        CtCDPI_Cursor = bitutil.ScanThru(CtCDPI_Cursor, CtCDPI_scan)
339        CtCDPI_Cursor &= EOF_mask
340        while CtCDPI_Cursor:
341                CtCDPI_starts |= CtCDPI_Cursor
342                PI_Cursor = CtCDPI_Cursor & lex.PI_start
343                CD_Ct_Cursor = bitutil.Advance(CtCDPI_Cursor & ~PI_Cursor)
344                CD_Cursor = CD_Ct_Cursor & lex.LBracket
345                Ct_Cursor = bitutil.Advance(CD_Ct_Cursor & lex.Hyphen) 
346                PI_starts |= PI_Cursor
347                CD_starts |= CD_Cursor
348                Ct_starts |= Ct_Cursor
349                Ct_Cursor = bitutil.Advance(Ct_Cursor)
350                Ct_end_scan |= Ct_Cursor
351                PI_Cursor = bitutil.ScanThru(PI_Cursor, PI_end_scan)
352                CD_Cursor = bitutil.ScanThru(CD_Cursor, CD_end_scan)
353                Ct_Cursor = bitutil.Advance(bitutil.ScanThru(Ct_Cursor, Ct_end_scan))
354                PI_ends |= PI_Cursor
355                CD_ends |= CD_Cursor
356                Ct_ends |= Ct_Cursor
357                CtCDPI_Cursor = PI_Cursor | CD_Cursor | Ct_Cursor
358                CtCDPI_Cursor = bitutil.ScanThru(CtCDPI_Cursor, CtCDPI_scan)
359                CtCDPI_Cursor &= EOF_mask
360        # End of loop: no remaining CtCDPI_Cursor
361        callouts.CD_span = CD_ends - CD_starts
362        callouts.Ct_span = Ct_ends - Ct_starts
363        callouts.PI_span = PI_ends - PI_starts
364       
365        callouts.CtCDPI_mask |= bitutil.Advance(CD_ends | Ct_ends | PI_ends) - CtCDPI_starts
366        callouts.error = Ct_ends & ~lex.RAngle | Ct_starts & ~ lex.Hyphen
367        # If any of the Comment, CDATA or PI markups are unterminated, it is an error.
368        callouts.error |= callouts.CtCDPI_mask &~ EOF_mask
369        return callouts
370
371def demo_CtCDPI(u8data):
372        lgth = len(u8data)
373        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
374        (u8, control, lex) = byteclass.classify_bytes(bit)
375        lex = add_multiliterals(lex)
376        markup = parse_CtCDPI(lex, EOF_mask)
377        bitutil.print_aligned_u8_byte_streams([('input data', u8data), 
378                            ('CD_span', bitutil.bitstream2string(markup.CD_span, lgth)),
379                            ('Ct_span', bitutil.bitstream2string(markup.Ct_span, lgth)),
380                            ('PI_span', bitutil.bitstream2string(markup.PI_span, lgth)),
381                            ('CtCDPI_mask', bitutil.bitstream2string(markup.CtCDPI_mask, lgth)),
382                            ('error', bitutil.bitstream2string(markup.error, lgth+1))])
383
384
385class ref_callouts:
386        GenRefs = 0
387        DecRefs = 0
388        HexRefs = 0
389        delmask = 0
390        error = 0
391
392def parse_refs(lex, CtCDPI_mask):
393        """Parse and call out all general and character references.
394        Mark all but the closing semicolon for deletion.
395       
396        >>> demo_refs(" &gt;  &#13;  &#x0a;  ")
397        input data       :  &gt;  &#13;  &#x0a; 
398        entity refs      : __11__________________
399        decimal char refs: _________11___________
400        hex char refs    : _________________11___
401        ref delmask      : _111___1111___11111___
402        errors           : _______________________
403
404        Empty numeric references are reported as errors.
405        >>> demo_refs(" &#;       &#x; ")
406        input data       :  &#;       &#x;
407        entity refs      : ________________
408        decimal char refs: ________________
409        hex char refs    : ________________
410        ref delmask      : _11________111__
411        errors           : ___1__________1__
412
413        Improperly terminated or unterminated references (lacking ";") are also errors.
414        >>> demo_refs("  &gt:  &#456a;  &#xab:  &unterminated")
415        input data       :   &gt:  &#456a;  &#xab:  &unterminated
416        entity refs      : ___111____________________111111111111
417        decimal char refs: __________111_________________________
418        hex char refs    : ____________________11________________
419        ref delmask      : __1111__11111____11111___1111111111111
420        errors           : ______1______1________1_______________1
421"""
422        CallOuts = ref_callouts()
423        Ref2 = lex.RefStart_scope &~ CtCDPI_mask
424        NumRef2 = Ref2 & lex.Hash
425        GenRef2 = Ref2 &~ lex.Hash
426        NumRef3 = bitutil.Advance(NumRef2)
427        HexRef3 = NumRef3 & lex.x
428        DecRef3 = NumRef3 &~ lex.x
429        HexRef4 = bitutil.Advance(HexRef3) 
430        GenRefEnds = bitutil.ScanThru(GenRef2, lex.NameScan)
431        DecRefEnds = bitutil.ScanThru(DecRef3, lex.Digit)
432        HexRefEnds = bitutil.ScanThru(HexRef4, lex.Hex)
433        # Error checks
434        # At least one digit required for DecRef, one hex digit for HexRef.
435        error1 = DecRef3 &~ lex.Digit
436        error2 = HexRef4 &~ lex.Hex
437        # Semicolon terminator required (also covers unterminated at EOF).
438        error3 = (GenRefEnds | DecRefEnds | HexRefEnds) &~ lex.Semicolon
439        CallOuts.GenRefs = GenRefEnds - GenRef2
440        CallOuts.DecRefs = DecRefEnds - DecRef3
441        CallOuts.HexRefs = HexRefEnds - HexRef4
442        # Mark references for deletion, but leave the trailing semicolon as
443        # the point for insertion of the "expansion" text (most often a
444        # single character).
445        CallOuts.delmask = (GenRefEnds | DecRefEnds | HexRefEnds) - lex.RefStart
446        CallOuts.error = error1 | error2 | error3
447        return CallOuts
448
449def demo_refs(u8data):
450        lgth = len(u8data)
451        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
452        (u8, control, lex) = byteclass.classify_bytes(bit)
453        callouts = parse_refs(lex, 0)
454        bitutil.print_aligned_u8_byte_streams([('input data', u8data), 
455                            ('entity refs', bitutil.bitstream2string(callouts.GenRefs, lgth)),
456                            ('decimal char refs', bitutil.bitstream2string(callouts.DecRefs, lgth)),
457                            ('hex char refs', bitutil.bitstream2string(callouts.HexRefs, lgth)),
458                            ('ref delmask', bitutil.bitstream2string(callouts.delmask, lgth)),
459                            ('errors', bitutil.bitstream2string(callouts.error, lgth+1))])
460
461
462class tag_callouts:
463        ElemNames = 0
464        AttNames = 0
465        AttVals = 0
466        Tags = 0
467        EmptyTagEnds = 0
468        EndTags = 0
469        error = 0
470       
471        # POTENTIAL ADDITIONAL FIELDS
472        # StartTagEnds = 0
473        # EmptyTagEnds = 0     
474        # EndTagEnds = 0
475
476def parse_tags(lex, CtCDPI_mask, EOF_mask):
477        """Parse start, empty and end tags, calling out element names, attribute
478        names and values, empty tag positions, and tag extents.
479
480        >>> demo_tags("<root><t1>text</t1><t2 a1='foo' a2 = 'fie'>more</t2><tag3 att3='b'/></root>")
481        input data      : <root><t1>text</t1><t2 a1='foo' a2 = 'fie'>more</t2><tag3 att3='b'/></root>
482        element names   : _1111__11___________11_______________________________1111__________________
483        attribute names : _______________________11_______11________________________1111_____________
484        attribute values: __________________________11111______11111_____________________111_________
485        empty tag marks : ___________________________________________________________________1_______
486        end tags        : _______________111______________________________111__________________11111_
487        start/empty tags: _1111__11___________1111111111111111111111___________11111111111111________
488        errors          : ____________________________________________________________________________
489
490        Attributes can use double quotes.
491
492        >>> demo_tags('<dquote_atts a1="1234" attribute2="4321"/>')
493        input data      : <dquote_atts a1="1234" attribute2="4321"/>
494        element names   : _11111111111______________________________
495        attribute names : _____________11________1111111111_________
496        attribute values: ________________111111____________111111__
497        empty tag marks : _________________________________________1
498        end tags        : __________________________________________
499        start/empty tags: _1111111111111111111111111111111111111111_
500        errors          : ___________________________________________
501
502        Syntax errors of various types are identified with the error stream.
503
504        1. Element name missing errors.
505
506        >>> demo_tags("< noname='flawed'/> ")
507        input data      : < noname='flawed'/>
508        element names   : ____________________
509        attribute names : __111111____________
510        attribute values: _________11111111___
511        empty tag marks : __________________1_
512        end tags        : ____________________
513        start/empty tags: _11111111111111111__
514        errors          : _1___________________
515
516        2. Missing attribute names.
517
518        >>> demo_tags("<noatt ='flawed'/>  <one_att a1='good' = 'bad'> oops </one_att>")
519        input data      : <noatt ='flawed'/>  <one_att a1='good' = 'bad'> oops </one_att>
520        element names   : _11111_______________1111111___________________________________
521        attribute names : _____________________________11________________________________
522        attribute values: ________11111111________________111111___11111_________________
523        empty tag marks : _________________1_____________________________________________
524        end tags        : ______________________________________________________11111111_
525        start/empty tags: _1111111111111111____1111111111111111111111111_________________
526        errors          : _______1_______________________________1________________________
527
528        3. Missing or incorrect = sign.
529
530        >>> demo_tags('<errata plusforeq+"5678" noequals"90" />')
531        input data      : <errata plusforeq+"5678" noequals"90" />
532        element names   : _111111_________________________________
533        attribute names : ________111111111________11111111_______
534        attribute values: __________________111111__________111111
535        empty tag marks : ________________________________________
536        end tags        : ________________________________________
537        start/empty tags: _111111111111111111111111111111111111111
538        errors          : _________________1_______________11______
539
540        4.  Missing whitespace
541
542        >>> demo_tags("<jammed att='value'att2='v2' />")
543        input data      : <jammed att='value'att2='v2' />
544        element names   : _111111________________________
545        attribute names : ________111________1111________
546        attribute values: ____________1111111_____1111___
547        empty tag marks : ______________________________1
548        end tags        : _______________________________
549        start/empty tags: _11111111111111111111111111111_
550        errors          : ___________________1____________
551
552        5.  Extra whitespace in an empty tag.
553
554        >>> demo_tags("<extrawhite / >")
555        input data      : <extrawhite / >
556        element names   : _1111111111____
557        attribute names : _______________
558        attribute values: _______________
559        empty tag marks : _____________1_
560        end tags        : _______________
561        start/empty tags: _111111111111__
562        errors          : _____________1__
563
564        6.  Unterminated or incorrectly terminated attribute values
565
566        >>> demo_tags("<badattvalues a='blud<   b='455>   ")
567        input data      : <badattvalues a='blud<   b='455>   
568        element names   : _111111111111______________________
569        attribute names : ______________1__________1_________
570        attribute values: ________________111111_____11111111
571        empty tag marks : ___________________________________
572        end tags        : ___________________________________
573        start/empty tags: _111111111111111111111_111111111111
574        errors          : _____________________11____________1
575
576        7.  Unterminated tags
577
578        >>> demo_tags("<unterminated a='245'  ")
579        input data      : <unterminated a='245' 
580        element names   : _111111111111__________
581        attribute names : ______________1________
582        attribute values: ________________11111__
583        empty tag marks : _______________________
584        end tags        : _______________________
585        start/empty tags: _1111111111111111111111
586        errors          : _______________________1
587
588"""
589        callouts = tag_callouts()
590       
591        # Delimiters for scans.
592        DQuoteScan = ~(lex.DQuote | lex.LAngle) & EOF_mask
593        SQuoteScan = ~(lex.SQuote | lex.LAngle) & EOF_mask
594        AttListDelim = lex.Slash | lex.RAngle
595       
596        # Start the parallel parsing by inspecting the character
597        # after the opening "<" of a tag.
598        LAngleFollow = lex.LAngle_scope &~ CtCDPI_mask
599        ElemNamePositions = LAngleFollow & ~lex.Slash
600        EndTagSeconds = LAngleFollow & lex.Slash
601       
602        # Start Tag/Empty Element Tag Parsing
603
604        # Advance all cursors by scanning through the tag name.
605        ElemNameFollows = bitutil.ScanThru(ElemNamePositions, lex.NameScan)
606        # Must have at least one name character for a legal start tag.
607        # Mark any occurrences of null names as errors.
608        ParseError = ElemNamePositions & ElemNameFollows
609        callouts.ElemNames = ElemNameFollows - ElemNamePositions
610       
611        # Initialize the accumulators for attribute name and value positions.
612        AttNameStarts = 0 
613        AttNameFollows = 0
614        EqToCheck = 0
615        AttValStarts = 0
616        AttValEnds = 0
617        AttValFollows = 0
618
619        # After the element name, there may or may not be an attlist.
620        AfterWS = bitutil.ScanThru(ElemNameFollows, lex.WS)
621        AttListEnd = AfterWS & AttListDelim
622        AttNameStart = AfterWS & ~AttListDelim
623        # At least one WS character is required between ElemNames and AttNames.
624        ParseError |= ElemNameFollows & AttNameStart
625
626        #
627        # The following loop iterates through attributes within a start tag.
628        # Because all start tags are processed in parallel, the number of
629        # iterations is the maximum number of attributes found in any one
630        # start tag, plus one.
631        while AttNameStart:
632                AttNameStarts |= AttNameStart
633                AttNameFollow = bitutil.ScanThru(AttNameStart, lex.NameScan)
634                AttNameFollows |= AttNameFollow
635                # Scan through WS to the expected '=' delimiter.
636                EqExpected = bitutil.ScanThru(AttNameFollow, lex.WS)
637                EqToCheck |= EqExpected
638                AttValPos = bitutil.ScanThru(bitutil.Advance(EqExpected), lex.WS)
639                AttValStarts |= AttValPos
640                DQuoteAttVal = AttValPos & lex.DQuote
641                SQuoteAttVal = AttValPos & lex.SQuote
642                DQuoteAttEnd = bitutil.ScanThru(bitutil.Advance(DQuoteAttVal), DQuoteScan)
643                SQuoteAttEnd = bitutil.ScanThru(bitutil.Advance(SQuoteAttVal), SQuoteScan)
644                AttValEnd = DQuoteAttEnd | SQuoteAttEnd
645                AttValEnds |= AttValEnd
646                AttValFollow = bitutil.Advance(AttValEnd)
647                AttValFollows |= AttValFollow
648                AfterWS = bitutil.ScanThru(AttValFollow, lex.WS)
649                AttListEnd |= AfterWS & AttListDelim
650                AttNameStart = AfterWS & ~AttListDelim
651
652        # No more attribute values to process when AttNameStart == 0.
653
654        callouts.AttNames = AttNameFollows - AttNameStarts
655        callouts.AttVals = AttValFollows - AttValStarts
656        STagEnds = AttListEnd & lex.RAngle
657        # Mark any "/" characters found as the ends of empty element tags.
658        callouts.EmptyTagMarks = bitutil.Advance(AttListEnd & lex.Slash)
659        callouts.Tags = (STagEnds | callouts.EmptyTagMarks) - ElemNamePositions
660
661        # Check for errors.
662        ParseError |= AttValFollows & AttNameStarts # No intervening WS.
663        ParseError |= AttNameStarts & AttNameFollows # Null AttName
664        ParseError |= EqToCheck & ~lex.Equals # = not found where expected.
665        ParseError |= AttValStarts & ~ (lex.DQuote | lex.SQuote)
666        ParseError |= AttValEnds & ~ (lex.DQuote | lex.SQuote)
667        ParseError |= callouts.EmptyTagMarks & ~lex.RAngle
668
669        # End Tag Parsing
670        EndTagEnds = bitutil.ScanThru(bitutil.ScanThru(bitutil.Advance(EndTagSeconds), lex.NameScan), lex.WS)
671        ParseError |= EndTagEnds & ~lex.RAngle
672        callouts.EndTags = EndTagEnds - EndTagSeconds
673        callouts.error = ParseError
674
675        # POTENTIAL ADDITIONAL FIELDS
676        # callouts.StartTagEnds = STagEnds
677        # callouts.EmptyTagEnds = bitutil.Advance(callouts.EmptyTagMarks)
678        # callouts.EndTagEnds = EndTagEnds
679       
680        return callouts
681
682def demo_tags(u8data):
683        lgth = len(u8data)
684        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
685        (u8, control, lex) = byteclass.classify_bytes(bit)
686        lex = add_multiliterals(lex)
687        markup1 = parse_CtCDPI(lex, EOF_mask)
688        callouts = parse_tags(lex, markup1.CtCDPI_mask, EOF_mask)
689        bitutil.print_aligned_u8_byte_streams([('input data', u8data), 
690                            ('element names', bitutil.bitstream2string(callouts.ElemNames, lgth)),
691                            ('attribute names', bitutil.bitstream2string(callouts.AttNames, lgth)),
692                            ('attribute values', bitutil.bitstream2string(callouts.AttVals, lgth)),
693                            ('empty tag marks', bitutil.bitstream2string(callouts.EmptyTagMarks, lgth)),
694                            ('end tags', bitutil.bitstream2string(callouts.EndTags, lgth)),
695                            ('start/empty tags', bitutil.bitstream2string(callouts.Tags, lgth)),
696                            ('errors', bitutil.bitstream2string(callouts.error, lgth+1))])
697
698
699
700def validate_no_CD_end(lex, markup1, tags):
701        """Find illegal occurrences of ]]> in text (outside of markup).
702
703        >>> demo_validate_no_CD_end(' <!-- OK: ]]>  --> <![CDATA OK  ]]>  ]]> <tag att=" ]]> "/> ]]>  <?php ]]> ?> ')
704        input data :  <!-- OK: ]]>  --> <![CDATA OK  ]]>  ]]> <tag att=" ]]> "/> ]]>  <?php ]]> ?>
705        CtCDPI_mask: __1111111111111111__111111111111111_______________________________11111111111_
706        tags       : __________________________________________1111111111111111____________________
707        illegal ]]>: _______________________________________1______________________1_______________
708"""
709        ret = lex.CD_end & ~(markup1.CtCDPI_mask | tags.Tags)
710        return ret
711
712def demo_validate_no_CD_end(u8data):
713        lgth = len(u8data)
714        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
715        (u8, control, lex) = byteclass.classify_bytes(bit)
716        lex = add_multiliterals(lex)
717        markup1 = parse_CtCDPI(lex, EOF_mask)
718        tags = parse_tags(lex, markup1.CtCDPI_mask, EOF_mask)
719        error = validate_no_CD_end(lex, markup1, tags)
720        bitutil.print_aligned_u8_byte_streams([('input data', u8data), 
721                            ('CtCDPI_mask', bitutil.bitstream2string(markup1.CtCDPI_mask, lgth)),
722                            ('tags', bitutil.bitstream2string(tags.Tags, lgth)),
723                            ('illegal ]]>', bitutil.bitstream2string(error, lgth))])
724
725
726
727def main(u8data):
728        # Transpose to parallel bit streams and prepare an EOF mask.
729        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
730
731        # Classify bytes for UTF-8 processing, whitespace and control
732        # processing and XML lexical analysis.
733        #(u8, control, lex) = byteclass.classify_bytes(bit)
734        #(u8, control, lex) = byteclass.classify_bytes_with_shift1opt(bit)
735        #(control, lex) = classify_bytes(bit)
736
737        control = control_streams()
738        temp1 = (bit[0] | bit[1]);
739        temp2 = (bit[2] &~ bit[3]);
740        temp3 = (temp2 &~ temp1);
741        temp4 = (bit[5] &~ bit[4]);
742        temp5 = (bit[6] &~ bit[7]);
743        temp6 = (temp4 & temp5);
744        lex.RefStart = (temp3 & temp6);
745        temp7 = (bit[2] & bit[3]);
746        temp8 = (temp7 &~ temp1);
747        temp9 = (bit[4] &~ bit[5]);
748        temp10 = (bit[6] & bit[7]);
749        temp11 = (temp9 & temp10);
750        lex.Semicolon = (temp8 & temp11);
751        temp12 = (bit[4] & bit[5]);
752        temp13 = (bit[6] | bit[7]);
753        temp14 = (temp12 &~ temp13);
754        lex.LAngle = (temp8 & temp14);
755        temp15 = (temp12 & temp5);
756        lex.RAngle = (temp8 & temp15);
757        temp16 = (bit[1] &~ bit[0]);
758        temp17 = (bit[3] &~ bit[2]);
759        temp18 = (temp16 & temp17);
760        lex.LBracket = (temp18 & temp11);
761        temp19 = (bit[7] &~ bit[6]);
762        temp20 = (temp12 & temp19);
763        lex.RBracket = (temp18 & temp20);
764        temp21 = (bit[4] | bit[5]);
765        temp22 = (temp19 &~ temp21);
766        lex.Exclam = (temp3 & temp22);
767        temp23 = (temp12 & temp10);
768        lex.QMark = (temp8 & temp23);
769        lex.Hyphen = (temp3 & temp20);
770        lex.Equals = (temp8 & temp20);
771        temp24 = (temp4 & temp10);
772        lex.SQuote = (temp3 & temp24);
773        temp25 = (temp5 &~ temp21);
774        lex.DQuote = (temp3 & temp25);
775        lex.Slash = (temp3 & temp23);
776        temp26 = (temp10 &~ temp21);
777        lex.Hash = (temp3 & temp26);
778        temp27 = (temp16 & temp7);
779        temp28 = (temp9 &~ temp13);
780        lex.x = (temp27 & temp28);
781        temp29 = (temp9 & temp5);
782        lex.Colon = (temp8 & temp29);
783        temp30 = (temp18 & temp23);
784        temp31 = (temp30 | lex.Colon);
785        temp32 = (temp16 &~ bit[2]);
786        temp33 = (bit[5] | temp10);
787        temp34 = (bit[4] & temp33);
788        temp35 = (~temp34);
789        temp36 = (temp21 | temp13);
790        temp37 = ((bit[3] & temp35)|(~(bit[3]) & temp36));
791        temp38 = (temp32 & temp37);
792        temp39 = (temp31 | temp38);
793        temp40 = (temp16 & bit[2]);
794        temp41 = (temp40 & temp37);
795        lex.ASCII_name_start = (temp39 | temp41);
796        temp42 = (temp30 | lex.Hyphen);
797        temp43 = (temp3 & temp15);
798        temp44 = (temp42 | temp43);
799        temp45 = (temp8 &~ temp34);
800        temp46 = (temp44 | temp45);
801        temp47 = (temp46 | temp38);
802        lex.ASCII_name_char = (temp47 | temp41);
803        lex.NameScan = (lex.ASCII_name_char | bit[0]);
804        temp48 = (temp1 | bit[2]);
805        control.x00_x1F = (~temp48);
806        temp49 = (bit[2] | bit[3]);
807        temp50 = (temp1 | temp49);
808        control.CR = (temp20 &~ temp50);
809        control.LF = (temp29 &~ temp50);
810        temp51 = (temp9 & temp19);
811        control.HT = (temp51 &~ temp50);
812        control.SP = (temp3 &~ temp36);
813        temp52 = (temp20 | temp29);
814        temp53 = (temp52 | temp51);
815        temp54 = (temp53 &~ temp50);
816        lex.WS = (temp54 | control.SP);
817        temp55 = (bit[5] | bit[6]);
818        temp56 = (bit[4] & temp55);
819        lex.Digit = (temp8 &~ temp56);
820        temp57 = (temp16 &~ temp49);
821        temp58 = (temp57 &~ bit[4]);
822        temp59 = (~temp10);
823        temp60 = ((bit[5] & temp59)|(~(bit[5]) & temp13));
824        temp61 = (temp58 & temp60);
825        temp62 = (lex.Digit | temp61);
826        temp63 = (temp16 & temp2);
827        temp64 = (temp63 &~ bit[4]);
828        temp65 = (temp64 & temp60);
829        lex.Hex = (temp62 | temp65);
830
831
832
833        xmlchar_error = (control.x00_x1F &~ lex.WS & EOF_mask)
834
835
836        u8 = u8_streams()
837        u8.unibyte = (~bit[0]);
838        u8.suffix = 0
839
840        if bit[0]:
841                u8.prefix = (bit[0] & bit[1]);
842                u8.prefix2 = (u8.prefix &~ bit[2]);
843                u8.prefix3 = (u8.prefix & temp2);
844                u8.prefix4 = (u8.prefix & temp7);
845                u8.suffix = (bit[0] &~ bit[1]);
846                temp66 = (u8.prefix &~ temp49);
847                temp67 = (temp21 | bit[6]);
848                temp68 = (temp66 &~ temp67);
849                temp69 = (bit[5] & temp13);
850                temp70 = (bit[4] | temp69);
851                temp71 = (u8.prefix4 & temp70);
852                u8.badprefix = (temp68 | temp71);
853                xE0 = (u8.prefix3 &~ temp36);
854                xED = (u8.prefix3 & temp20);
855                xF0 = (u8.prefix4 &~ temp36);
856                temp72 = (temp4 &~ temp13);
857                xF4 = (u8.prefix4 & temp72);
858                u8.xA0_xBF = (u8.suffix & bit[2]);
859                u8.x80_x9F = (u8.suffix &~ bit[2]);
860                u8.x90_xBF = (u8.suffix & temp49);
861                u8.x80_x8F = (u8.suffix &~ temp49);
862                xEF = (u8.prefix3 & temp23);
863                temp73 = (u8.suffix & temp7);
864                u8.xBF = (temp73 & temp23);
865                u8.xBE = (temp73 & temp15);
866                u8.xE0_scope = bitutil.Advance(xE0);
867                u8.xED_scope = bitutil.Advance(xED);
868                u8.xF0_scope = bitutil.Advance(xF0);
869                u8.xF4_scope = bitutil.Advance(xF4);
870                u8.xEF_scope = bitutil.Advance(xEF);
871                u8.scope22 = bitutil.Advance(u8.prefix2)
872                u8.scope32 = bitutil.Advance(u8.prefix3)
873                u8.scope33 = bitutil.Advance(u8.scope32)
874                u8.scope42 = bitutil.Advance(u8.prefix4)
875                u8.scope43 = bitutil.Advance(u8.scope42)
876                u8.scope44 = bitutil.Advance(u8.scope43)
877
878                u8lastscope = u8.scope22 | u8.scope33 | u8.scope44
879                u8anyscope = u8lastscope | u8.scope32 | u8.scope42 | u8.scope43
880               
881                u8error1 = u8.xE0_scope & u8.x80_x9F
882                u8error2 = u8.xED_scope & u8.xA0_xBF
883                u8error3 = u8.xF0_scope & u8.x80_x8F
884                u8error4 = u8.xF4_scope & u8.x90_xBF
885       
886                u8mismatch = u8anyscope ^ u8.suffix
887
888                u8.error = u8.badprefix | u8error1 | u8error2 | u8error3 | u8error4 | u8mismatch
889
890                EF_BF_pending = bitutil.Advance(u8.xEF_scope & u8.xBF)
891
892                FFFE_FFFF = (EF_BF_pending & (u8.xBE | u8.xBF))
893
894        xmlchar_error |= FFFE_FFFF
895
896        lex.RefStart_scope = bitutil.Advance(lex.RefStart)
897        lex.LAngle_scope = bitutil.Advance(lex.LAngle)
898        lex.Hyphen_scope = bitutil.Advance(lex.Hyphen)
899        lex.QMark_scope = bitutil.Advance(lex.QMark)
900        lex.RBracket_scope = bitutil.Advance(lex.RBracket)
901
902        # Compute XML multilterals such as <?, </, --, ]]>.
903        #lex = add_multiliterals(lex)
904        lex.PI_start = lex.LAngle_scope & lex.QMark
905        lex.CtCD_start = lex.LAngle_scope & lex.Exclam
906        lex.EndTag_start = lex.LAngle_scope & lex.Slash
907        lex.CD_end = bitutil.Advance(lex.RBracket_scope & lex.RBracket) & lex.RAngle
908        lex.DoubleHyphen = lex.Hyphen_scope & lex.Hyphen
909        lex.PI_end = lex.QMark_scope & lex.RAngle
910
911       
912        # THE FOLLOWING FUNCTIONAL CALL IS MANUALLY INLINED
913        # Parse all comments, CDATA sections and processing instructions.
914        #markup1 = parse_CtCDPI(lex, EOF_mask)
915        #CT_callouts = CtCDPI_callouts()
916        PI_starts = 0
917        PI_ends = 0
918        Ct_starts = 0
919        Ct_ends = 0
920        CD_starts = 0
921        CD_ends = 0
922        CtCDPI_starts = 0
923        PI_name_ends = 0
924        # Scanning streams
925        CtCDPI_scan = ~(lex.CtCD_start | lex.PI_start) & EOF_mask
926        Ct_end_scan = ~lex.DoubleHyphen & EOF_mask
927        CD_end_scan = ~lex.CD_end & EOF_mask
928        PI_end_scan = ~lex.PI_end & EOF_mask
929        #
930        # Initiate the scan
931        CtCDPI_Cursor = 1
932        CtCDPI_Cursor = bitutil.ScanThru(CtCDPI_Cursor, CtCDPI_scan)
933        CtCDPI_Cursor &= EOF_mask
934        while CtCDPI_Cursor:
935                CtCDPI_starts |= CtCDPI_Cursor
936                PI_Cursor = CtCDPI_Cursor & lex.PI_start
937                CD_Ct_Cursor = bitutil.Advance(CtCDPI_Cursor & ~PI_Cursor)
938                CD_Cursor = CD_Ct_Cursor & lex.LBracket
939                Ct_Cursor = bitutil.Advance(CD_Ct_Cursor & lex.Hyphen) 
940                PI_starts |= PI_Cursor
941                CD_starts |= CD_Cursor
942                Ct_starts |= Ct_Cursor
943                Ct_Cursor = bitutil.Advance(Ct_Cursor)
944                Ct_end_scan |= Ct_Cursor
945                #PI_Cursor = bitutil.ScanThru(PI_Cursor, PI_end_scan)
946                PI_name_end = bitutil.ScanThru( bitutil.Advance(PI_Cursor), lex.NameScan)
947                PI_name_ends |= PI_name_end
948                CT_callouts.PI_name |= PI_name_end - PI_Cursor
949                PI_Cursor = bitutil.ScanThru(PI_name_end, PI_end_scan)
950                CD_Cursor = bitutil.ScanThru(CD_Cursor, CD_end_scan)
951                Ct_Cursor = bitutil.Advance(bitutil.ScanThru(Ct_Cursor, Ct_end_scan))
952                PI_ends |= PI_Cursor
953                CD_ends |= CD_Cursor
954                Ct_ends |= Ct_Cursor
955                CtCDPI_Cursor = PI_Cursor | CD_Cursor | Ct_Cursor
956                CtCDPI_Cursor = bitutil.ScanThru(CtCDPI_Cursor, CtCDPI_scan)
957                CtCDPI_Cursor &= EOF_mask
958        # End of loop: no remaining CtCDPI_Cursor
959        #Not needed for xmlwf
960        #CT_callouts.CD_span = CD_ends - CD_starts
961        #CT_callouts.Ct_span = Ct_ends - Ct_starts
962        #CT_callouts.PI_span = PI_ends - PI_starts
963       
964        CT_callouts.CtCDPI_mask = bitutil.Advance(CD_ends | Ct_ends | PI_ends) - CtCDPI_starts
965        CT_callouts.error = Ct_ends & ~lex.RAngle | Ct_starts & ~ lex.Hyphen
966        CT_callouts.error |= bitutil.Advance(PI_name_ends & ~ lex.WS) & ~ lex.PI_end
967        # If any of the Comment, CDATA or PI markups are unterminated, it is an error.
968        CT_callouts.error |= CT_callouts.CtCDPI_mask &~ EOF_mask
969        ########## END OF MANUAL INLINING
970       
971        # THE FOLLOWING FUNCTIONAL CALL IS MANUALLY INLINED
972        # All remaining "<" must be tag start characters; parse tags.
973        #tags = parse_tags(lex, CT_callouts.CtCDPI_mask, EOF_mask)
974
975        #callouts = tag_callouts()
976       
977        # Delimiters for scans.
978        DQuoteScan = ~(lex.DQuote | lex.LAngle) & EOF_mask
979        SQuoteScan = ~(lex.SQuote | lex.LAngle) & EOF_mask
980        AttListDelim = lex.Slash | lex.RAngle
981       
982        # Start the parallel parsing by inspecting the character
983        # after the opening "<" of a tag.
984        LAngleFollow = bitutil.Advance(lex.LAngle) &~ CT_callouts.CtCDPI_mask
985        ElemNamePositions = LAngleFollow & ~lex.Slash
986        EndTagSeconds = LAngleFollow & lex.Slash
987       
988        # Start Tag/Empty Element Tag Parsing
989
990        # Advance all cursors by scanning through the tag name.
991        ElemNameFollows = bitutil.ScanThru(ElemNamePositions, lex.NameScan)
992        # Must have at least one name character for a legal start tag.
993        # Mark any occurrences of null names as errors.
994        ParseError = ElemNamePositions & ElemNameFollows
995        callouts.ElemNames = ElemNameFollows - ElemNamePositions
996       
997        # Initialize the accumulators for attribute name and value positions.
998        AttNameStarts = 0 
999        AttNameFollows = 0
1000        EqToCheck = 0
1001        AttValStarts = 0
1002        AttValEnds = 0
1003        AttValFollows = 0
1004
1005        # After the element name, there may or may not be an attlist.
1006        AfterWS = bitutil.ScanThru(ElemNameFollows, lex.WS)
1007        AttListEnd = AfterWS & AttListDelim
1008        AttNameStart = AfterWS & ~AttListDelim
1009        # At least one WS character is required between ElemNames and AttNames.
1010        ParseError |= ElemNameFollows & AttNameStart
1011
1012        #
1013        # The following loop iterates through attributes within a start tag.
1014        # Because all start tags are processed in parallel, the number of
1015        # iterations is the maximum number of attributes found in any one
1016        # start tag, plus one.
1017        while AttNameStart:
1018                AttNameStarts |= AttNameStart
1019                AttNameFollow = bitutil.ScanThru(AttNameStart, lex.NameScan)
1020                AttNameFollows |= AttNameFollow
1021                # Scan through WS to the expected '=' delimiter.
1022                EqExpected = bitutil.ScanThru(AttNameFollow, lex.WS)
1023                EqToCheck |= EqExpected
1024                AttValPos = bitutil.ScanThru(bitutil.Advance(EqExpected), lex.WS)
1025                AttValStarts |= AttValPos
1026                DQuoteAttVal = AttValPos & lex.DQuote
1027                SQuoteAttVal = AttValPos & lex.SQuote
1028                DQuoteAttEnd = bitutil.ScanThru(bitutil.Advance(DQuoteAttVal), DQuoteScan)
1029                SQuoteAttEnd = bitutil.ScanThru(bitutil.Advance(SQuoteAttVal), SQuoteScan)
1030                AttValEnd = DQuoteAttEnd | SQuoteAttEnd
1031                AttValEnds |= AttValEnd
1032                AttValFollow = bitutil.Advance(AttValEnd)
1033                AttValFollows |= AttValFollow
1034                AfterWS = bitutil.ScanThru(AttValFollow, lex.WS)
1035                AttListEnd |= AfterWS & AttListDelim
1036                AttNameStart = AfterWS & ~AttListDelim
1037
1038        # No more attribute values to process when AttNameStart == 0.
1039        # Not needed for xmlwf
1040        callouts.AttNames = AttNameFollows - AttNameStarts
1041        #callouts.AttVals = AttValFollows - AttValStarts
1042        STagEnds = AttListEnd & lex.RAngle
1043        # Mark any "/" characters found as the ends of empty element tags.
1044        callouts.EmptyTagMarks = bitutil.Advance(AttListEnd & lex.Slash)
1045        # Not needed for xmlwf
1046        #callouts.Tags = (STagEnds | callouts.EmptyTagMarks) - ElemNamePositions
1047       
1048        # Check for errors.
1049        ParseError |= AttValFollows & AttNameStarts # No intervening WS.
1050        ParseError |= AttNameStarts & AttNameFollows # Null AttName
1051        ParseError |= EqToCheck & ~lex.Equals # = not found where expected.
1052        ParseError |= AttValStarts & ~ (lex.DQuote | lex.SQuote)
1053        ParseError |= AttValEnds & ~ (lex.DQuote | lex.SQuote)
1054        ParseError |= callouts.EmptyTagMarks & ~lex.RAngle
1055
1056        # End Tag Parsing
1057        EndTagEnds = bitutil.ScanThru(bitutil.ScanThru(bitutil.Advance(EndTagSeconds), lex.NameScan), lex.WS)
1058        ParseError |= EndTagEnds & ~lex.RAngle
1059        # Not needed for xmlwf
1060        #callouts.EndTags = EndTagEnds - EndTagSeconds
1061        callouts.error = ParseError
1062        ########## END OF MANUAL INLINING
1063
1064
1065
1066
1067        # All remaining "&" must be reference start characters; parse them.
1068        # INLINED: refs = parse_refs(lex, CT_callouts.CtCDPI_mask)
1069        refs = ref_callouts()
1070        Ref2 = lex.RefStart_scope &~ CT_callouts.CtCDPI_mask
1071        if Ref2:
1072                NumRef2 = Ref2 & lex.Hash
1073                GenRef2 = Ref2 &~ lex.Hash
1074                NumRef3 = bitutil.Advance(NumRef2)
1075                HexRef3 = NumRef3 & lex.x
1076                DecRef3 = NumRef3 &~ lex.x
1077                HexRef4 = bitutil.Advance(HexRef3) 
1078                GenRefEnds = bitutil.ScanThru(GenRef2, lex.NameScan)
1079                DecRefEnds = bitutil.ScanThru(DecRef3, lex.Digit)
1080                HexRefEnds = bitutil.ScanThru(HexRef4, lex.Hex)
1081                # Error checks
1082                # At least one digit required for DecRef, one hex digit for HexRef.
1083                error1 = DecRef3 &~ lex.Digit
1084                error2 = HexRef4 &~ lex.Hex
1085                # Semicolon terminator required (also covers unterminated at EOF).
1086                error3 = (GenRefEnds | DecRefEnds | HexRefEnds) &~ lex.Semicolon
1087                refs.GenRefs = GenRefEnds - GenRef2
1088                #refs.DecRefs = DecRefEnds - DecRef3
1089                #refs.HexRefs = HexRefEnds - HexRef4
1090                # Mark references for deletion, but leave the trailing semicolon as
1091                # the point for insertion of the "expansion" text (most often a
1092                # single character).
1093                #refs.delmask = (GenRefEnds | DecRefEnds | HexRefEnds) - lex.RefStart
1094                refs.error = error1 | error2 | error3
1095
1096
1097        # Ensure that no occurrence of ]]> occurs outside of markup.
1098        CD_end_error = validate_no_CD_end(lex, CT_callouts, callouts)
1099
1100        # Convert to UTF-16 bit streams.
1101        #(u16hi, u16lo, u16delmask) = u8u16.u8u16(u8, bit)
1102
1103        # Consolidate and check for errors
1104        error_mask = u8.error | xmlchar_error | CT_callouts.error | callouts.error | CD_end_error | refs.error
1105
1106        # Consolidate the deletion_masks
1107        #delmask = control.CRLF | refs.delmask | u16delmask # | CT_callouts.CDATA_delimiters
1108        #Not needed for xmlwf
1109        #delmask = control.CRLF | refs.delmask  # | CT_callouts.CDATA_delimiters
1110       
1111        qname_stream =  callouts.ElemNames | callouts.AttNames
1112        ncname_stream = CT_callouts.PI_name | refs.GenRefs
1113        name_stream = qname_stream | ncname_stream
1114        name_start = name_stream &~ bitutil.Advance(name_stream)
1115        name_start_check = name_start & ~lex.ASCII_name_start
1116        name_check = (name_stream &~ name_start | nmtoken_stream) & ~lex.ASCII_name_char & ~u8.suffix
1117
1118        #return (CT_callouts, callouts, refs, u16hi, u16lo, delmask, error, lex, u16delmask, EOF_mask)
1119        return (CT_callouts, callouts, refs, delmask, error, lex, EOF_mask, name_check, name_start_check, control)
1120
1121def demo_parabix(u8data):
1122
1123        lgth = len(u8data)
1124       
1125        (markup1, tags, refs, u16hi, u16lo, delmask, error, lex, u16delmask, EOF_mask) = parabix_parse(u8data)
1126        bitutil.print_aligned_u8_byte_streams([('input data', u8data), 
1127                            ('input high nybbles', bitutil.high_nybble_stream(u8data)), 
1128                            ('input low nybbles', bitutil.low_nybble_stream(u8data)),
1129                            ('CD_span', bitutil.bitstream2string(markup1.CD_span, lgth)),
1130                            ('Ct_span', bitutil.bitstream2string(markup1.Ct_span, lgth)),
1131                            ('PI_span', bitutil.bitstream2string(markup1.PI_span, lgth)),
1132                            ('CtCDPI_mask', bitutil.bitstream2string(markup1.CtCDPI_mask, lgth)),
1133                            ('entity refs', bitutil.bitstream2string(refs.GenRefs, lgth)),
1134                            ('decimal char refs', bitutil.bitstream2string(refs.DecRefs, lgth)),
1135                            ('hex char refs', bitutil.bitstream2string(refs.HexRefs, lgth)),
1136                            ('element names', bitutil.bitstream2string(tags.ElemNames, lgth)),
1137                            ('attribute names', bitutil.bitstream2string(tags.AttNames, lgth)),
1138                            ('attribute values', bitutil.bitstream2string(tags.AttVals, lgth)),
1139                            ('empty tag marks', bitutil.bitstream2string(tags.EmptyTagMarks, lgth)),
1140                            ('end tags', bitutil.bitstream2string(tags.EndTags, lgth)),
1141                            ('start/empty tags', bitutil.bitstream2string(tags.Tags, lgth)),
1142                            ('delmask', bitutil.bitstream2string(delmask, lgth)),
1143                            ('u16delmask', bitutil.bitstream2string(u16delmask, lgth)),
1144                            ('errors', bitutil.bitstream2string(error, lgth+1))])
1145
1146def demo_u16delmask(u8data):
1147
1148        u8len = len(u8data)
1149       
1150        # Transpose to parallel bit streams and prepare an EOF mask.
1151        (bit, EOF_mask) = bitutil.transpose_streams(u8data)
1152
1153        # Classify bytes for UTF-8 processing, whitespace and control
1154        # processing and XML lexical analysis.
1155        (u8, control, lex) = byteclass.classify_bytes(bit)
1156
1157        # Validate UTF-8 multibyte sequences and determine the UTF-8 scope streams.
1158        u8 = u8u16.validate_utf8(u8)   
1159       
1160        # Convert to UTF-16 bit streams.
1161        (u16hi, u16lo, delmask) = u8u16.u8u16(u8, bit)
1162       
1163        # Inverse transpose
1164        U16H = bitutil.filter_bytes(bitutil.inverse_transpose(u16hi, u8len), delmask)
1165        U16L = bitutil.filter_bytes(bitutil.inverse_transpose(u16lo, u8len), delmask)
1166       
1167        # Construct UTF-16 data buffer
1168        bytes = bitutil.merge_bytes(U16L, U16H)
1169       
1170        U16data = bytes.decode('utf16')
1171       
1172        bitutil.print_aligned_u8_byte_streams([('input data', u8data), 
1173                                ('u16delmask', bitutil.bitstream2string(delmask, u8len)),               
1174                                  ('errors', bitutil.bitstream2string(u8.error, u8len+1))])
1175        return
1176
1177if __name__ == "__main__":
1178        import doctest
1179        doctest.testmod()
1180       
1181        if len(sys.argv) > 1:
1182                u8data = bitutil.readfile(sys.argv[1]) 
1183#               demo_validate_xmlchar(u8data)
1184#               demo_line_breaks(u8data)
1185#               demo_multiliterals(u8data)
1186#               demo_CtCDPI(u8data)
1187#               demo_refs(u8data)
1188#               demo_tags(u8data)
1189#               demo_validate_no_CD_end(u8data)         
1190#               demo_u16delmask(u8data)         
1191                demo_parabix(u8data)
1192#               demo_u16delmask(u8data)
1193        else:
1194                print("Usage: python parabix2.py <file>")       
1195               
1196 
1197       
1198       
Note: See TracBrowser for help on using the repository browser.