Changeset 1959


Ignore:
Timestamp:
Mar 24, 2012, 1:41:08 PM (7 years ago)
Author:
lindanl
Message:

Add prototype that can run under python and is compilable as well

Location:
proto/parabix2
Files:
2 added
1 deleted
1 edited

Legend:

Unmodified
Added
Removed
  • proto/parabix2/parabix2.py

    r845 r1959  
    44#
    55# Parallel XML Parsing with Bitstream Addition
     6#
    67# - Complete prototype for all bitstream computations in Parabix2
     8# - Optimized for compilation
     9# - Separate compilation
     10
     11# Robert D. Cameron, Dan Lin
     12# March 24, 2012
    713#
    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 
    2714import sys
    28 
    29 
    30 def validate_xmlchar(u8, control, lex, EOF_mask):
    31         r"""Compute an error stream marking characters illegal in XML:
    32         (1) Control characters in the range 0x00-0x1F except HT, LF, CR
    33         (2) OxFFFF and OxFFFE, having UTF-8 encodings 0xEF 0xBF 0XBF and 0xEF 0xBF 0xBE.
    34 
    35         >>> demo_validate_xmlchar('plaintext (good: \x09) (bad: \x03) (bad \xEF\xBF\xBF) (good \xEF\xBF\xBC)')
    36         input high nybbles: 7666676772266663202226663202226662ebb22266662ebb2
    37         input low nybbles : 0c19e4584087ff4a09908214a039082140fff9087ff40ffc9
    38         illegal XML chars : __________________________1_________1_____________
    39 """
    40         EF_BF_pending = bitutil.Advance(u8.xEF_scope & u8.xBF)
    41         return (EF_BF_pending & (u8.xBE | u8.xBF)) | (control.x00_x1F &~ lex.WS & EOF_mask)
    42 
    43 
    44 def demo_validate_xmlchar(u8data):
    45         lgth = len(u8data)
    46         (bit, EOF_mask) = bitutil.transpose_streams(u8data)
    47         (u8, control, lex) = byteclass.classify_bytes(bit)
    48         bitutil.print_aligned_streams([('input high nybbles', bitutil.high_nybble_stream(u8data)),
    49                               ('input low nybbles', bitutil.low_nybble_stream(u8data)),
    50                               ('illegal XML chars', bitutil.bitstream2string(validate_xmlchar(u8, control, lex, EOF_mask), lgth+1))])
    51 
    52 def normalize_line_breaks(control, bit):
    53         r"""Convert CRs to LFs and mark CRLF occurrences for deletion.
    54 
    55         >>> demo_line_breaks('ab \r\n  cd \r  ef \r ')
    56         input high nybbles: 662002266202266202
    57         input low nybbles : 120da00340d00560d0
    58         CR                : ___1______1_____1_
    59         LF                : ____1_____________
    60         CRLF              : ____1_____________
    61 """
    62         control.CRLF = control.CR_scope & control.LF
    63         # Convert CRs to LFs (flip bits 5, 6 and 7 with xor).
    64         bit[5] ^= control.CR
    65         bit[6] ^= control.CR
    66         bit[7] ^= control.CR
    67         return (control, bit)
    68 
    69 def demo_line_breaks(u8data):
    70         lgth = len(u8data)
    71         (bit, EOF_mask) = bitutil.transpose_streams(u8data)
    72         (u8, control, lex) = byteclass.classify_bytes(bit)
    73         (control, bit) = normalize_line_breaks(control, bit)
    74         bitutil.print_aligned_u8_byte_streams([('input high nybbles', bitutil.high_nybble_stream(u8data)),
    75                               ('input low nybbles', bitutil.low_nybble_stream(u8data)),
    76                               ('CR', bitutil.bitstream2string(control.CR, lgth)),
    77                               ('LF', bitutil.bitstream2string(control.LF, lgth)),
    78                               ('CRLF', bitutil.bitstream2string(control.CRLF, lgth))])
    79 
    80 
    81 
    82 
    83 
    84 def add_multiliterals(lex):
    85         """Extend the byte-based lexical item streams for some important
    86         multibyte literals.
    87        
    88         >>> demo_multiliterals("  <?php?>  <!--  -->  <![CDATA[  ]]> ")
    89         input data  :   <?php?>  <!--  -->  <![CDATA[  ]]>
    90         PI_start    : ___1_________________________________
    91         CtCD_start  : ____________1__________1_____________
    92         EndTag_start: _____________________________________
    93         CD_end      : ___________________________________1_
    94         DoubleHyphen: ______________1___1__________________
    95         PI_end      : ________1____________________________
    96         """
    97 
    98         lex.PI_start = lex.LAngle_scope & lex.QMark
    99         lex.CtCD_start = lex.LAngle_scope & lex.Exclam
    100         lex.EndTag_start = lex.LAngle_scope & lex.Slash
    101         lex.CD_end = bitutil.Advance(lex.RBracket_scope & lex.RBracket) & lex.RAngle
    102         lex.DoubleHyphen = lex.Hyphen_scope & lex.Hyphen
    103         lex.PI_end = lex.QMark_scope & lex.RAngle
    104         return lex
    105 
    106 def demo_multiliterals(u8data):
    107         lgth = len(u8data)
    108         (bit, EOF_mask) = bitutil.transpose_streams(u8data)
    109         (u8, control, lex) = byteclass.classify_bytes(bit)
    110         lex = add_multiliterals(lex)
    111         bitutil.print_aligned_u8_byte_streams([('input data', u8data),
    112                               ('PI_start', bitutil.bitstream2string(lex.PI_start, lgth)),
    113                               ('CtCD_start', bitutil.bitstream2string(lex.CtCD_start, lgth)),
    114                               ('EndTag_start', bitutil.bitstream2string(lex.EndTag_start, lgth)),
    115                               ('CD_end', bitutil.bitstream2string(lex.CD_end, lgth)),
    116                               ('DoubleHyphen', bitutil.bitstream2string(lex.DoubleHyphen, lgth)),
    117                               ('PI_end', bitutil.bitstream2string(lex.PI_end, lgth))])
    118 
    119 class CtCDPI_callouts:
    120         CD_span = 0
    121         Ct_span = 0
    122         PI_mask = 0
    123         PI_name = 0
    124         CtCDPI_mask = 0
    125         error = 0
    126        
    127 def parse_CtCDPI(lex, EOF_mask):
    128         """Parse all comments, CDATA sections and processing instructions.
    129        
    130         Return bitstreams marking the extent of these markup items,
    131         excluding initial and final bracketting.
    132        
    133         >>> demo_CtCDPI(' <?php?>  <!-- example -->  <![CDATA[  shift: a<<1 ]]> ')
    134         input data :  <?php?>  <!-- example -->  <![CDATA[  shift: a<<1 ]]>
    135         CD_span    : ______________________________11111111111111111111111__
    136         Ct_span    : ____________1111111111111______________________________
    137         PI_span    : __11111________________________________________________
    138         CtCDPI_mask: __111111___111111111111111___1111111111111111111111111_
    139         Misc_mask  : 111111111111111111111111111111_______11______1_11_1___1
    140         error      : ________________________________________________________
    141        
    142         Comments are terminated by double-hyphen; immediately require closing ">".
    143        
    144         >>> demo_CtCDPI(' <!--  <?php?>  --   <!-- -->')
    145         input data :  <!--  <?php?>  --   <!-- -->
    146         CD_span    : _____________________________
    147         Ct_span    : ___111111111111111_____11111_
    148         PI_span    : _____________________________
    149         CtCDPI_mask: __11111111111111111___1111111
    150         Misc_mask  : 11111111111111111111111111111
    151         error      : __________________1___________
    152 
    153         >>> demo_CtCDPI("<?PI_target??>")
    154         input data : <?PI_target??>
    155         CD_span    : ______________
    156         Ct_span    : ______________
    157         PI_span    : _111111111111_
    158         CtCDPI_mask: _1111111111111
    159         Misc_mask  : 11111111111111
    160         error      : ____________1__
    161 
    162 
    163 """
    164         callouts = CtCDPI_callouts()
    165         PI_starts = 0
    166         PI_ends = 0
     15import pablo
     16import error_tracker
     17
     18class Basis_bits():     
     19        bit_0 = 0
     20        bit_1 = 0
     21        bit_2 = 0
     22        bit_3 = 0
     23        bit_4 = 0
     24        bit_5 = 0
     25        bit_6 = 0
     26        bit_7 = 0
     27
     28
     29class U8 ():
     30        suffix = 0
     31
     32class Lex ():
     33        CR = 0
     34        LF = 0
     35        HT = 0
     36        SP = 0
     37        CRLF = 0
     38        RefStart = 0
     39        Semicolon = 0 
     40        Colon = 0
     41        LAngle = 0
     42        RAngle = 0
     43        LBracket = 0
     44        RBracket = 0
     45        Exclam = 0
     46        QMark = 0
     47        Hyphen = 0
     48        Equals = 0
     49        SQuote = 0
     50        DQuote = 0
     51        Slash = 0
     52        Hash = 0
     53        x = 0
     54        ASCII_name_start = 0
     55        ASCII_name_char = 0
     56        NameScan = 0
     57        Digit = 0
     58        Hex = 0
     59        WS = 0
     60
     61class Marker ():
     62        LAngle_scope = 0
     63        Ref_opener = 0
     64        CD_closer = 0
     65
     66class CtCDPI_Callouts():
    16767        Ct_starts = 0
    16868        Ct_ends = 0
    169         Ct_errors = 0
    17069        CD_starts = 0
    17170        CD_ends = 0
     71        PI_starts = 0
     72        PI_name_starts = 0
     73        PI_name_ends = 0
     74        PI_ends = 0
     75
     76class Ref_Callouts():
     77        GenRef_starts = 0
     78        GenRef_ends = 0
     79        DecRef_starts = 0
     80        DecRef_ends = 0
     81        HexRef_starts = 0
     82        HexRef_ends = 0
     83
     84class Tag_Callouts():
     85        ElemName_starts = 0
     86        ElemName_ends = 0
     87        AttName_starts = 0
     88        AttName_ends = 0
     89        AttVal_starts = 0
     90        AttVal_ends = 0
     91        AttVal_spans = 0
     92        EmptyTag_marks = 0
     93        EndTag_marks = 0
     94       
     95class Check_streams():
     96        misc_mask = 0
     97        non_ascii_name_starts = 0
     98        non_ascii_names = 0
     99        tag_marks = 0
     100        name_follows = 0
     101        att_refs = 0
     102
     103def Classify_bytes_Validate_utf8(basis_bits, lex, u8): 
     104        temp1 = (basis_bits.bit_0 | basis_bits.bit_1);
     105        temp2 = (basis_bits.bit_2 &~ basis_bits.bit_3);
     106        temp3 = (temp2 &~ temp1);
     107        temp4 = (basis_bits.bit_5 &~ basis_bits.bit_4);
     108        temp5 = (basis_bits.bit_6 &~ basis_bits.bit_7);
     109        temp6 = (temp4 & temp5);
     110        lex.RefStart = (temp3 & temp6);
     111        temp7 = (basis_bits.bit_2 & basis_bits.bit_3);
     112        temp8 = (temp7 &~ temp1);
     113        temp9 = (basis_bits.bit_4 &~ basis_bits.bit_5);
     114        temp10 = (basis_bits.bit_6 & basis_bits.bit_7);
     115        temp11 = (temp9 & temp10);
     116        lex.Semicolon = (temp8 & temp11);
     117        temp12 = (basis_bits.bit_4 & basis_bits.bit_5);
     118        temp13 = (basis_bits.bit_6 | basis_bits.bit_7);
     119        temp14 = (temp12 &~ temp13);
     120        lex.LAngle = (temp8 & temp14);
     121        temp15 = (temp12 & temp5);
     122        lex.RAngle = (temp8 & temp15);
     123        temp16 = (basis_bits.bit_1 &~ basis_bits.bit_0);
     124        temp17 = (basis_bits.bit_3 &~ basis_bits.bit_2);
     125        temp18 = (temp16 & temp17);
     126        lex.LBracket = (temp18 & temp11);
     127        temp19 = (basis_bits.bit_7 &~ basis_bits.bit_6);
     128        temp20 = (temp12 & temp19);
     129        lex.RBracket = (temp18 & temp20);
     130        temp21 = (basis_bits.bit_4 | basis_bits.bit_5);
     131        temp22 = (temp19 &~ temp21);
     132        lex.Exclam = (temp3 & temp22);
     133        temp23 = (temp12 & temp10);
     134        lex.QMark = (temp8 & temp23);
     135        lex.Hyphen = (temp3 & temp20);
     136        lex.Equals = (temp8 & temp20);
     137        temp24 = (temp4 & temp10);
     138        lex.SQuote = (temp3 & temp24);
     139        temp25 = (temp5 &~ temp21);
     140        lex.DQuote = (temp3 & temp25);
     141        lex.Slash = (temp3 & temp23);
     142        temp26 = (temp10 &~ temp21);
     143        lex.Hash = (temp3 & temp26);
     144        temp27 = (temp16 & temp7);
     145        temp28 = (temp9 &~ temp13);
     146        lex.x = (temp27 & temp28);
     147        temp29 = (temp9 & temp5);
     148        lex.Colon = (temp8 & temp29);
     149        temp30 = (temp18 & temp23);
     150        temp31 = (temp30 | lex.Colon);
     151        temp32 = (temp16 &~ basis_bits.bit_2);
     152        temp33 = (basis_bits.bit_5 | temp10);
     153        temp34 = (basis_bits.bit_4 & temp33);
     154        temp35 = (~temp34);
     155        temp36 = (temp21 | temp13);
     156        temp37 = ((basis_bits.bit_3 & temp35)|(~(basis_bits.bit_3) & temp36));
     157        temp38 = (temp32 & temp37);
     158        temp39 = (temp31 | temp38);
     159        temp40 = (temp16 & basis_bits.bit_2);
     160        temp41 = (temp40 & temp37);
     161        lex.ASCII_name_start = (temp39 | temp41);
     162        temp42 = (temp30 | lex.Hyphen);
     163        temp43 = (temp3 & temp15);
     164        temp44 = (temp42 | temp43);
     165        temp45 = (temp8 &~ temp34);
     166        temp46 = (temp44 | temp45);
     167        temp47 = (temp46 | temp38);
     168        lex.ASCII_name_char = (temp47 | temp41);
     169        lex.NameScan = (lex.ASCII_name_char | basis_bits.bit_0);
     170        temp48 = (temp1 | basis_bits.bit_2);
     171        x00_x1F = (~temp48);
     172        temp49 = (basis_bits.bit_2 | basis_bits.bit_3);
     173        temp50 = (temp1 | temp49);
     174        lex.CR = (temp20 &~ temp50);
     175        lex.LF = (temp29 &~ temp50);
     176        temp51 = (temp9 & temp19);
     177        lex.HT = (temp51 &~ temp50);
     178        lex.SP = (temp3 &~ temp36);
     179        temp52 = (temp20 | temp29);
     180        temp53 = (temp52 | temp51);
     181        temp54 = (temp53 &~ temp50);
     182        lex.WS = (temp54 | lex.SP);
     183        temp55 = (basis_bits.bit_5 | basis_bits.bit_6);
     184        temp56 = (basis_bits.bit_4 & temp55);
     185        lex.Digit = (temp8 &~ temp56);
     186        temp57 = (temp16 &~ temp49);
     187        temp58 = (temp57 &~ basis_bits.bit_4);
     188        temp59 = (~temp10);
     189        temp60 = ((basis_bits.bit_5 & temp59)|(~(basis_bits.bit_5) & temp13));
     190        temp61 = (temp58 & temp60);
     191        temp62 = (lex.Digit | temp61);
     192        temp63 = (temp16 & temp2);
     193        temp64 = (temp63 &~ basis_bits.bit_4);
     194        temp65 = (temp64 & temp60);
     195        lex.Hex = (temp62 | temp65);
     196        lex_error = x00_x1F &~ lex.WS
     197        if pablo.inFile(lex_error):
     198                error_tracker.NoteError("Error: illegal character", lex_error)
     199               
     200       
     201        ### Validate_utf8(basis_bits, u8):
     202        unibyte = (~basis_bits.bit_0);
     203        suffix = 0
     204        u8_error = 0
     205        u8_FFFE_FFFF = 0
     206        u8anyscope = 0 #local
     207        if basis_bits.bit_0:
     208                prefix = (basis_bits.bit_0 & basis_bits.bit_1);
     209                prefix2 = (prefix &~ basis_bits.bit_2);
     210                prefix3 = (prefix & temp2);
     211                prefix4 = (prefix & temp7);
     212                suffix = (basis_bits.bit_0 &~ basis_bits.bit_1);
     213                temp66 = (prefix &~ temp49);
     214                temp67 = (temp21 | basis_bits.bit_6);
     215                temp68 = (temp66 &~ temp67);
     216                temp69 = (basis_bits.bit_5 & temp13);
     217                temp70 = (basis_bits.bit_4 | temp69);
     218                temp71 = (prefix4 & temp70);
     219                badprefix = (temp68 | temp71);
     220                u8_error = badprefix
     221                scope22 = pablo.Advance(prefix2)
     222                u8anyscope = scope22
     223                if prefix3 | prefix4:
     224                        xE0 = (prefix3 &~ temp36);
     225                        xED = (prefix3 & temp20);
     226                        xF0 = (prefix4 &~ temp36);
     227                        temp72 = (temp4 &~ temp13);
     228                        xF4 = (prefix4 & temp72);
     229                        xA0_xBF = (suffix & basis_bits.bit_2);
     230                        x80_x9F = (suffix &~ basis_bits.bit_2);
     231                        x90_xBF = (suffix & temp49);
     232                        x80_x8F = (suffix &~ temp49);
     233                        xEF = (prefix3 & temp23);
     234                        temp73 = (suffix & temp7);
     235                        xBF = (temp73 & temp23);
     236                        xBE = (temp73 & temp15);
     237
     238                        scope32 = pablo.Advance(prefix3)
     239                        scope33 = pablo.Advance(scope32)
     240                        scope42 = pablo.Advance(prefix4)
     241                        scope43 = pablo.Advance(scope42)
     242                        scope44 = pablo.Advance(scope43)
     243
     244                        E0_F0_scope = pablo.Advance(xE0 | xF0)
     245                        ED_F4_scope = pablo.Advance(xED | xF4)
     246                        xE0_scope = scope32 & E0_F0_scope
     247                        xED_scope = scope32 & ED_F4_scope
     248                        xF0_scope = scope42 & E0_F0_scope
     249                        xF4_scope = scope42 & ED_F4_scope
     250                        xEF_scope = pablo.Advance(xEF);
     251
     252                        u8lastscope = scope22 | scope33 | scope44
     253                        u8anyscope = u8lastscope | scope32 | scope42 | scope43
     254               
     255                        u8error1 = xE0_scope & x80_x9F
     256                        u8error2 = xED_scope & xA0_xBF
     257                        u8error3 = xF0_scope & x80_x8F
     258                        u8error4 = xF4_scope & x90_xBF
     259       
     260                        u8_error |= u8error1 | u8error2 | u8error3 | u8error4
     261
     262                        EF_BF_pending = pablo.Advance(xEF_scope & xBF)
     263
     264                        u8_FFFE_FFFF = (EF_BF_pending & (xBE | xBF))
     265                u8mismatch = u8anyscope ^ suffix
     266                u8_error |= u8mismatch | u8_FFFE_FFFF
     267                if u8_error:
     268                        error_tracker.NoteError("UTF-8 error found", (u8_error))
     269                       
     270       
     271def Parse_CtCDPI(lex, marker, ctCDPI_Callouts, check_streams):
     272        ctCDPI_Callouts.Ct_starts = 0
     273        ctCDPI_Callouts.Ct_ends = 0
     274        ctCDPI_Callouts.CD_starts = 0
     275        ctCDPI_Callouts.CD_ends = 0
     276        ctCDPI_Callouts.PI_starts = 0
     277        ctCDPI_Callouts.PI_name_starts = 0
     278        ctCDPI_Callouts.PI_name_ends = 0
     279        ctCDPI_Callouts.PI_ends = 0
    172280        CtCDPI_starts = 0
    173         PI_name_ends = 0
    174         PI_namestarts = 0
    175         # Scanning streams
    176         CtCDPI_scan = ~(lex.CtCD_start | lex.PI_start) & EOF_mask
    177         Ct_end_scan = ~lex.DoubleHyphen & EOF_mask
    178         CD_end_scan = ~lex.CD_end & EOF_mask
    179         PI_end_scan = ~lex.PI_end & EOF_mask
     281        CtCDPI_ends = 0
     282        ctCDPI_mask = 0
     283
     284        v = lex.LAngle | lex.Hyphen
     285        w = lex.Hyphen | lex.QMark
     286        v1 = pablo.Advance(v)
     287        w1 = pablo.Advance(w)
     288       
     289        LAngle_scope = v1 &~ w1  #pablo.Advance(lex.LAngle)
     290        PI_opener = LAngle_scope & lex.QMark
     291        CtCD_opener= LAngle_scope & lex.Exclam
     292        CtCDPI_opener = PI_opener | CtCD_opener
     293
     294        #DoubleHyphen = 0
     295        CD_closer = 0
     296        #PI_closer = 0
     297       
     298        #if lex.Hyphen: DoubleHyphen = pablo.Advance(lex.Hyphen) & lex.Hyphen
     299        DoubleHyphen = v1 & w1 & lex.Hyphen
     300        if lex.RBracket:
     301                DoubleRBracket = pablo.Advance(lex.RBracket) & lex.RBracket
     302                CD_closer = pablo.Advance(DoubleRBracket) & lex.RAngle
     303        #if lex.QMark: PI_closer = pablo.Advance(lex.QMark) & lex.RAngle
     304        PI_closer = w1 & ~v1 & lex.RAngle
     305
    180306        #
    181307        # Initiate the scan
    182         CtCDPI_Cursor = 1
    183         CtCDPI_Cursor = bitutil.ScanThru(CtCDPI_Cursor, CtCDPI_scan)
    184         CtCDPI_Cursor &= EOF_mask
     308        CtCDPI_Cursor = pablo.ScanToFirst(CtCDPI_opener)
    185309        while CtCDPI_Cursor:
    186310                CtCDPI_starts |= CtCDPI_Cursor
    187                 PI_Cursor = CtCDPI_Cursor & lex.PI_start
    188                 CD_Ct_Cursor = bitutil.Advance(CtCDPI_Cursor & ~PI_Cursor)
     311                PI_Cursor = CtCDPI_Cursor & PI_opener
     312                CD_Ct_Cursor = pablo.Advance(CtCDPI_Cursor & ~PI_Cursor)
    189313                CD_Cursor = CD_Ct_Cursor & lex.LBracket
    190                 Ct_Cursor = CD_Ct_Cursor & lex.Hyphen
    191                 PI_starts |= PI_Cursor
    192                 CD_starts |= CD_Cursor
    193                 Ct_starts |= Ct_Cursor
    194                 Ct_Cursor = bitutil.Advance(Ct_Cursor)
    195                 Ct_errors |= Ct_Cursor & ~ lex.Hyphen
    196                 Ct_Cursor = bitutil.Advance(Ct_Cursor)
    197                 Ct_end_scan |= Ct_Cursor
    198                 #PI_Cursor = bitutil.ScanThru(PI_Cursor, PI_end_scan)
    199                 PI_Cursor = bitutil.Advance(PI_Cursor)
    200                 PI_namestarts |= PI_Cursor
    201                 PI_name_end = bitutil.ScanThru(PI_Cursor, lex.NameScan)
    202                 PI_name_ends |= PI_name_end
    203                 callouts.PI_name |= PI_name_end - PI_Cursor
    204                 PI_Cursor = bitutil.ScanThru(PI_name_end, PI_end_scan)
    205                 CD_Cursor = bitutil.ScanThru(CD_Cursor, CD_end_scan)
    206                 Ct_Cursor = bitutil.Advance(bitutil.ScanThru(Ct_Cursor, Ct_end_scan))
    207                 PI_ends |= PI_Cursor
    208                 CD_ends |= CD_Cursor
    209                 Ct_ends |= Ct_Cursor
     314                Ct_Cursor = CD_Ct_Cursor & lex.Hyphen
     315                # PI processing
     316                if PI_Cursor:
     317                        ctCDPI_Callouts.PI_starts |= PI_Cursor
     318                        PI_Cursor = pablo.Advance(PI_Cursor)
     319                        ctCDPI_Callouts.PI_name_starts |= PI_Cursor
     320                        PI_name_end = pablo.ScanThru(PI_Cursor, lex.NameScan)
     321                        PI_error = PI_Cursor & PI_name_end
     322                        PI_error |= pablo.Advance(PI_name_end & ~ lex.WS) & ~ PI_closer
     323                        if PI_error:
     324                                error_tracker.NoteError("Error in PI syntax", PI_name_end)
     325                        ctCDPI_Callouts.PI_name_ends |= PI_name_end
     326                        PI_Cursor = pablo.ScanTo(PI_name_end, PI_closer)
     327                        ctCDPI_Callouts.PI_ends |= PI_Cursor
     328                        CtCDPI_ends |= PI_Cursor
     329
     330                # CDATA section processing
     331                if CD_Cursor:
     332                        ctCDPI_Callouts.CD_starts |= CD_Cursor
     333                        CD_Cursor = pablo.ScanTo(CD_Cursor, CD_closer)
     334                        ctCDPI_Callouts.CD_ends |= CD_Cursor
     335                        CtCDPI_ends |= CD_Cursor
     336
     337                # Comment processing
     338                if Ct_Cursor:
     339                        ctCDPI_Callouts.Ct_starts |= Ct_Cursor
     340                        Ct_Cursor = pablo.Advance(Ct_Cursor) 
     341                        Ct_error = Ct_Cursor & ~ lex.Hyphen
     342                        # Advance twice past <!--, so that we don't treat <!---
     343                        # as being a terminated comment.
     344                        Ct_Cursor = pablo.Advance(pablo.Advance(Ct_Cursor))
     345                        Ct_Cursor = pablo.Advance(pablo.ScanTo(Ct_Cursor, DoubleHyphen))
     346                        Ct_error |= Ct_Cursor & ~ lex.RAngle   
     347                        ctCDPI_Callouts.Ct_ends |= Ct_Cursor
     348                        CtCDPI_ends |= Ct_Cursor
     349                        if Ct_error:
     350                                error_tracker.NoteError("Error in comment syntax", Ct_error)
     351
     352                # Common processing
    210353                CtCDPI_Cursor = PI_Cursor | CD_Cursor | Ct_Cursor
    211                 CtCDPI_Cursor = bitutil.ScanThru(CtCDPI_Cursor, CtCDPI_scan)
    212                 CtCDPI_Cursor &= EOF_mask
    213         # End of loop: no remaining CtCDPI_Cursor
    214         callouts.CD_span = CD_ends - CD_starts
    215         callouts.Ct_span = Ct_ends - Ct_starts
    216         callouts.PI_span = PI_ends - PI_starts
    217        
    218         callouts.CtCDPI_mask |= bitutil.Advance(CD_ends | Ct_ends | PI_ends) - CtCDPI_starts
    219         callouts.error = Ct_errors | Ct_ends & ~lex.RAngle
    220         callouts.error |= bitutil.Advance(PI_name_ends & ~ lex.WS) & ~ lex.PI_end
    221         callouts.error |= PI_namestarts & PI_name_ends
    222         # If any of the Comment, CDATA or PI markups are unterminated, it is an error.
    223         callouts.error |= callouts.CtCDPI_mask &~ EOF_mask
    224         callouts.Misc_mask = lex.WS | lex.LAngle | (bitutil.Advance(Ct_ends | PI_ends) - (Ct_starts | PI_starts)) | CtCDPI_starts
    225         return callouts
    226 
    227 def demo_CtCDPI(u8data):
    228         lgth = len(u8data)
    229         (bit, EOF_mask) = bitutil.transpose_streams(u8data)
    230         (u8, control, lex) = byteclass.classify_bytes(bit)
    231         lex = add_multiliterals(lex)
    232         markup = parse_CtCDPI(lex, EOF_mask)
    233         bitutil.print_aligned_u8_byte_streams([('input data', u8data),
    234                               ('CD_span', bitutil.bitstream2string(markup.CD_span, lgth)),
    235                               ('Ct_span', bitutil.bitstream2string(markup.Ct_span, lgth)),
    236                               ('PI_span', bitutil.bitstream2string(markup.PI_span, lgth)),
    237                               ('CtCDPI_mask', bitutil.bitstream2string(markup.CtCDPI_mask, lgth)),
    238                               ('Misc_mask', bitutil.bitstream2string(markup.Misc_mask, lgth)),
    239                               ('error', bitutil.bitstream2string(markup.error, lgth+1))])
    240 
    241 
    242 class ref_callouts:
    243         GenRefs = 0
    244         DecRefs = 0
    245         HexRefs = 0
    246         delmask = 0
    247         error = 0
    248 
    249 def parse_refs(lex, CtCDPI_mask):
    250         """Parse and call out all general and character references.
    251         Mark all but the closing semicolon for deletion.
    252        
    253         >>> demo_refs(" &gt;  &#13;  &#x0a;  ")
    254         input data       :  &gt;  &#13;  &#x0a; 
    255         entity refs      : __11__________________
    256         decimal char refs: _________11___________
    257         hex char refs    : _________________11___
    258         ref delmask      : _111___1111___11111___
    259         errors           : _______________________
    260 
    261         Empty numeric references are reported as errors.
    262         >>> demo_refs(" &#;       &#x; ")
    263         input data       :  &#;       &#x;
    264         entity refs      : ________________
    265         decimal char refs: ________________
    266         hex char refs    : ________________
    267         ref delmask      : _11________111__
    268         errors           : ___1__________1__
    269 
    270         Improperly terminated or unterminated references (lacking ";") are also errors.
    271         >>> demo_refs("  &gt:  &#456a;  &#xab:  &unterminated")
    272         input data       :   &gt:  &#456a;  &#xab:  &unterminated
    273         entity refs      : ___111____________________111111111111
    274         decimal char refs: __________111_________________________
    275         hex char refs    : ____________________11________________
    276         ref delmask      : __1111__11111____11111___1111111111111
    277         errors           : ______1______1________1_______________1
    278 """
    279         CallOuts = ref_callouts()
    280         Ref2 = lex.RefStart_scope &~ CtCDPI_mask
    281         NumRef2 = Ref2 & lex.Hash
    282         GenRef2 = Ref2 &~ lex.Hash
    283         NumRef3 = bitutil.Advance(NumRef2)
    284         HexRef3 = NumRef3 & lex.x
    285         DecRef3 = NumRef3 &~ lex.x
    286         HexRef4 = bitutil.Advance(HexRef3)
    287         GenRefEnds = bitutil.ScanThru(GenRef2, lex.NameScan)
    288         DecRefEnds = bitutil.ScanThru(DecRef3, lex.Digit)
    289         HexRefEnds = bitutil.ScanThru(HexRef4, lex.Hex)
    290         # Error checks
    291         # At least one digit required for DecRef, one hex digit for HexRef.
    292         error1 = DecRef3 &~ lex.Digit
    293         error2 = HexRef4 &~ lex.Hex
    294         # Semicolon terminator required (also covers unterminated at EOF).
    295         error3 = (GenRefEnds | DecRefEnds | HexRefEnds) &~ lex.Semicolon
    296         CallOuts.GenRefs = GenRefEnds - GenRef2
    297         CallOuts.DecRefs = DecRefEnds - DecRef3
    298         CallOuts.HexRefs = HexRefEnds - HexRef4
    299         # Mark references for deletion, but leave the trailing semicolon as
    300         # the point for insertion of the "expansion" text (most often a
    301         # single character).
    302         CallOuts.delmask = (GenRefEnds | DecRefEnds | HexRefEnds) - lex.RefStart
    303         CallOuts.error = error1 | error2 | error3
    304         return CallOuts
    305 
    306 def demo_refs(u8data):
    307         lgth = len(u8data)
    308         (bit, EOF_mask) = bitutil.transpose_streams(u8data)
    309         (u8, control, lex) = byteclass.classify_bytes(bit)
    310         callouts = parse_refs(lex, 0)
    311         bitutil.print_aligned_u8_byte_streams([('input data', u8data),
    312                               ('entity refs', bitutil.bitstream2string(callouts.GenRefs, lgth)),
    313                               ('decimal char refs', bitutil.bitstream2string(callouts.DecRefs, lgth)),
    314                               ('hex char refs', bitutil.bitstream2string(callouts.HexRefs, lgth)),
    315                               ('ref delmask', bitutil.bitstream2string(callouts.delmask, lgth)),
    316                               ('errors', bitutil.bitstream2string(callouts.error, lgth+1))])
    317 
    318 
    319 class tag_callouts:
    320         ElemNames = 0
    321         AttNames = 0
    322         AttVals = 0
    323         Tags = 0
    324         EmptyTagEnds = 0
    325         EndTags = 0
    326         error = 0
    327        
    328         # POTENTIAL ADDITIONAL FIELDS
    329         # StartTagEnds = 0
    330         # EmptyTagEnds = 0     
    331         # EndTagEnds = 0
    332 
    333 def parse_tags(lex, CtCDPI_mask, EOF_mask):
    334         """Parse start, empty and end tags, calling out element names, attribute
    335         names and values, empty tag positions, and tag extents.
    336 
    337         >>> demo_tags("<root><t1>text</t1><t2 a1='foo' a2 = 'fie'>more</t2><tag3 att3='b'/></root>")
    338         input data      : <root><t1>text</t1><t2 a1='foo' a2 = 'fie'>more</t2><tag3 att3='b'/></root>
    339         element names   : _1111__11___________11_______________________________1111__________________
    340         attribute names : _______________________11_______11________________________1111_____________
    341         attribute values: __________________________11111______11111_____________________111_________
    342         empty tag marks : ___________________________________________________________________1_______
    343         end tags        : _______________111______________________________111__________________11111_
    344         start/empty tags: _1111__11___________1111111111111111111111___________11111111111111________
    345         errors          : ____________________________________________________________________________
    346 
    347         Attributes can use double quotes.
    348 
    349         >>> demo_tags('<dquote_atts a1="1234" attribute2="4321"/>')
    350         input data      : <dquote_atts a1="1234" attribute2="4321"/>
    351         element names   : _11111111111______________________________
    352         attribute names : _____________11________1111111111_________
    353         attribute values: ________________111111____________111111__
    354         empty tag marks : _________________________________________1
    355         end tags        : __________________________________________
    356         start/empty tags: _1111111111111111111111111111111111111111_
    357         errors          : ___________________________________________
    358 
    359         Syntax errors of various types are identified with the error stream.
    360 
    361         1. Element name missing errors.
    362 
    363         >>> demo_tags("< noname='flawed'/> ")
    364         input data      : < noname='flawed'/>
    365         element names   : ____________________
    366         attribute names : __111111____________
    367         attribute values: _________11111111___
    368         empty tag marks : __________________1_
    369         end tags        : ____________________
    370         start/empty tags: _11111111111111111__
    371         errors          : _1___________________
    372 
    373         2. Missing attribute names.
    374 
    375         >>> demo_tags("<noatt ='flawed'/>  <one_att a1='good' = 'bad'> oops </one_att>")
    376         input data      : <noatt ='flawed'/>  <one_att a1='good' = 'bad'> oops </one_att>
    377         element names   : _11111_______________1111111___________________________________
    378         attribute names : _____________________________11________________________________
    379         attribute values: ________11111111________________111111___11111_________________
    380         empty tag marks : _________________1_____________________________________________
    381         end tags        : ______________________________________________________11111111_
    382         start/empty tags: _1111111111111111____1111111111111111111111111_________________
    383         errors          : _______1_______________________________1________________________
    384 
    385         3. Missing or incorrect = sign.
    386 
    387         >>> demo_tags('<errata plusforeq+"5678" noequals"90" />')
    388         input data      : <errata plusforeq+"5678" noequals"90" />
    389         element names   : _111111_________________________________
    390         attribute names : ________111111111________11111111_______
    391         attribute values: __________________111111__________111111
    392         empty tag marks : ________________________________________
    393         end tags        : ________________________________________
    394         start/empty tags: _111111111111111111111111111111111111111
    395         errors          : _________________1_______________11______
    396 
    397         4.  Missing whitespace
    398 
    399         >>> demo_tags("<jammed att='value'att2='v2' />")
    400         input data      : <jammed att='value'att2='v2' />
    401         element names   : _111111________________________
    402         attribute names : ________111________1111________
    403         attribute values: ____________1111111_____1111___
    404         empty tag marks : ______________________________1
    405         end tags        : _______________________________
    406         start/empty tags: _11111111111111111111111111111_
    407         errors          : ___________________1____________
    408 
    409         5.  Extra whitespace in an empty tag.
    410 
    411         >>> demo_tags("<extrawhite / >")
    412         input data      : <extrawhite / >
    413         element names   : _1111111111____
    414         attribute names : _______________
    415         attribute values: _______________
    416         empty tag marks : _____________1_
    417         end tags        : _______________
    418         start/empty tags: _111111111111__
    419         errors          : _____________1__
    420 
    421         6.  Unterminated or incorrectly terminated attribute values
    422 
    423         >>> demo_tags("<badattvalues a='blud<   b='455>   ")
    424         input data      : <badattvalues a='blud<   b='455>   
    425         element names   : _111111111111______________________
    426         attribute names : ______________1__________1_________
    427         attribute values: ________________111111_____11111111
    428         empty tag marks : ___________________________________
    429         end tags        : ___________________________________
    430         start/empty tags: _111111111111111111111_111111111111
    431         errors          : _____________________11____________1
    432 
    433         7.  Unterminated tags
    434 
    435         >>> demo_tags("<unterminated a='245'  ")
    436         input data      : <unterminated a='245' 
    437         element names   : _111111111111__________
    438         attribute names : ______________1________
    439         attribute values: ________________11111__
    440         empty tag marks : _______________________
    441         end tags        : _______________________
    442         start/empty tags: _1111111111111111111111
    443         errors          : _______________________1
    444 
    445 """
    446         callouts = tag_callouts()
     354                CtCDPI_Cursor = pablo.ScanTo(CtCDPI_Cursor, CtCDPI_opener)
     355                ctCDPI_mask |= (CtCDPI_ends - CtCDPI_starts) | CtCDPI_ends             
     356                # If any of the Comment, CDATA or PI markups are unterminated, it is an error.
     357                ctCDPI_error = pablo.atEOF(ctCDPI_mask)
     358               
     359                if ctCDPI_error:
     360                        error_tracker.NoteError("Error in comment, CDATA or processing instruction syntax", ctCDPI_error)
     361               
     362        check_streams.misc_mask = pablo.inFile((lex.WS | lex.LAngle | (pablo.Advance(ctCDPI_Callouts.Ct_ends | ctCDPI_Callouts.PI_ends) - (ctCDPI_Callouts.Ct_starts | ctCDPI_Callouts.PI_starts)) | CtCDPI_starts))
     363
     364        # Identify the remaining significant markers for XML processing.
     365        marker.LAngle_scope = LAngle_scope &~ ctCDPI_mask
     366        marker.Ref_opener = lex.RefStart &~ ctCDPI_mask
     367        marker.CD_closer = CD_closer &~ ctCDPI_mask
     368
     369def Parse_tags(lex, marker, tag_Callouts):
    447370       
    448371        # Delimiters for scans.
    449         DQuoteScan = ~(lex.DQuote | lex.LAngle) & EOF_mask
    450         SQuoteScan = ~(lex.SQuote | lex.LAngle) & EOF_mask
     372        DQuoteDelim = lex.DQuote | lex.LAngle
     373        SQuoteDelim = lex.SQuote | lex.LAngle
    451374        AttListDelim = lex.Slash | lex.RAngle
    452375       
    453376        # Start the parallel parsing by inspecting the character
    454377        # after the opening "<" of a tag.
    455         LAngleFollow = lex.LAngle_scope &~ CtCDPI_mask
    456         ElemNamePositions = LAngleFollow & ~lex.Slash
    457         EndTagSeconds = LAngleFollow & lex.Slash
     378        tag_Callouts.ElemName_starts = marker.LAngle_scope & ~lex.Slash
     379        tag_Callouts.EndTag_marks = marker.LAngle_scope & lex.Slash
    458380       
    459381        # Start Tag/Empty Element Tag Parsing
    460382
    461383        # Advance all cursors by scanning through the tag name.
    462         ElemNameFollows = bitutil.ScanThru(ElemNamePositions, lex.NameScan)
     384        tag_Callouts.ElemName_ends = pablo.ScanThru(tag_Callouts.ElemName_starts, lex.NameScan)
    463385        # Must have at least one name character for a legal start tag.
    464386        # Mark any occurrences of null names as errors.
    465         ParseError = ElemNamePositions & ElemNameFollows
    466         callouts.ElemNames = ElemNameFollows - ElemNamePositions
     387        ParseError = tag_Callouts.ElemName_starts & tag_Callouts.ElemName_ends
    467388       
    468389        # Initialize the accumulators for attribute name and value positions.
    469         AttNameStarts = 0 
    470         AttNameFollows = 0
    471         EqToCheck = 0
    472         AttValStarts = 0
    473         AttValEnds = 0
    474         AttValFollows = 0
     390        tag_Callouts.AttName_starts = 0 
     391        tag_Callouts.AttName_ends = 0
     392        tag_Callouts.AttVal_starts = 0
     393        tag_Callouts.AttVal_ends = 0
    475394
    476395        # After the element name, there may or may not be an attlist.
    477         AfterWS = bitutil.ScanThru(ElemNameFollows, lex.WS)
    478         AttListEnd = AfterWS & AttListDelim
    479         AttNameStart = AfterWS & ~AttListDelim
    480         # At least one WS character is required between ElemNames and AttNames.
    481         ParseError |= ElemNameFollows & AttNameStart
    482 
    483         #
    484         # The following loop iterates through attributes within a start tag.
    485         # Because all start tags are processed in parallel, the number of
    486         # iterations is the maximum number of attributes found in any one
    487         # start tag, plus one.
    488         while AttNameStart:
    489                 AttNameStarts |= AttNameStart
    490                 AttNameFollow = bitutil.ScanThru(AttNameStart, lex.NameScan)
    491                 AttNameFollows |= AttNameFollow
    492                 # Scan through WS to the expected '=' delimiter.
    493                 EqExpected = bitutil.ScanThru(AttNameFollow, lex.WS)
    494                 EqToCheck |= EqExpected
    495                 AttValPos = bitutil.ScanThru(bitutil.Advance(EqExpected), lex.WS)
    496                 AttValStarts |= AttValPos
    497                 DQuoteAttVal = AttValPos & lex.DQuote
    498                 SQuoteAttVal = AttValPos & lex.SQuote
    499                 DQuoteAttEnd = bitutil.ScanThru(bitutil.Advance(DQuoteAttVal), DQuoteScan)
    500                 SQuoteAttEnd = bitutil.ScanThru(bitutil.Advance(SQuoteAttVal), SQuoteScan)
    501                 AttValEnd = DQuoteAttEnd | SQuoteAttEnd
    502                 AttValEnds |= AttValEnd
    503                 AttValFollow = bitutil.Advance(AttValEnd)
    504                 AttValFollows |= AttValFollow
    505                 AfterWS = bitutil.ScanThru(AttValFollow, lex.WS)
    506                 AttListEnd |= AfterWS & AttListDelim
     396        if tag_Callouts.ElemName_ends & lex.WS:
     397                AfterWS = pablo.ScanThru(tag_Callouts.ElemName_ends, lex.WS)
     398                AttListEnd = AfterWS & AttListDelim
    507399                AttNameStart = AfterWS & ~AttListDelim
    508 
    509         # No more attribute values to process when AttNameStart == 0.
    510 
    511         callouts.AttNames = AttNameFollows - AttNameStarts
    512         callouts.AttVals = AttValFollows - AttValStarts
     400                #
     401                # The following loop iterates through attributes within a start tag.
     402                # Because all start tags are processed in parallel, the number of
     403                # iterations is the maximum number of attributes found in any one
     404                # start tag, plus one.
     405                while AttNameStart:
     406                        ParseError |= AttNameStart &~ lex.NameScan
     407                        tag_Callouts.AttName_starts |= AttNameStart
     408                        AttNameFollow = pablo.ScanThru(AttNameStart, lex.NameScan)
     409                        tag_Callouts.AttName_ends |= AttNameFollow
     410                        # Scan through WS to the expected '=' delimiter.
     411                        # EqExpected = pablo.ScanThru(AttNameFollow, lex.WS)
     412                        # But use if test to optimize.
     413                        if AttNameFollow & lex.WS:
     414                                EqExpected = pablo.ScanThru(AttNameFollow, lex.WS)
     415                        else: EqExpected = AttNameFollow
     416                        ParseError |= EqExpected &~ lex.Equals
     417                        AttValPos = pablo.ScanThru(EqExpected, EqExpected | lex.WS)
     418                        tag_Callouts.AttVal_starts |= AttValPos
     419                        DQuoteAttVal = AttValPos & lex.DQuote
     420                        SQuoteAttVal = AttValPos & lex.SQuote
     421                        DQuoteAttEnd = pablo.ScanTo(DQuoteAttVal, DQuoteDelim &~ DQuoteAttVal)
     422                        SQuoteAttEnd = pablo.ScanTo(SQuoteAttVal, SQuoteDelim &~ SQuoteAttVal)
     423                        AttValEnd = DQuoteAttEnd | SQuoteAttEnd
     424                        ParseError |= (AttValPos | AttValEnd) &~ (lex.DQuote | lex.SQuote)
     425                        AttValFollow = pablo.Advance(AttValEnd)
     426                        tag_Callouts.AttVal_ends |= AttValFollow
     427                        #  AfterWS = pablo.ScanThru(AttValFollow, lex.WS)
     428                        if AttValFollow & lex.WS:
     429                                AfterWS = pablo.ScanThru(AttValFollow, lex.WS)
     430                                AttListEnd |= AfterWS & AttListDelim
     431                                AttNameStart = AfterWS & ~AttListDelim
     432                        else:
     433                                AttListEnd |= AttValFollow & AttListDelim       
     434                                AttNameStart = 0
     435                                ParseError |= AttValFollow & ~AttListDelim
     436        else:
     437                # No WS character after ElemName; must be at the end
     438                AttListEnd = tag_Callouts.ElemName_ends & AttListDelim
     439                ParseError |= tag_Callouts.ElemName_ends & ~AttListDelim
     440
    513441        STagEnds = AttListEnd & lex.RAngle
    514442        # Mark any "/" characters found as the ends of empty element tags.
    515         callouts.EmptyTagMarks = bitutil.Advance(AttListEnd & lex.Slash)
    516         callouts.Tags = (STagEnds | callouts.EmptyTagMarks) - ElemNamePositions
    517 
    518         # Check for errors.
    519         ParseError |= AttValFollows & AttNameStarts # No intervening WS.
    520         ParseError |= AttNameStarts & AttNameFollows # Null AttName
    521         ParseError |= EqToCheck & ~lex.Equals # = not found where expected.
    522         ParseError |= AttValStarts & ~ (lex.DQuote | lex.SQuote)
    523         ParseError |= AttValEnds & ~ (lex.DQuote | lex.SQuote)
    524         ParseError |= callouts.EmptyTagMarks & ~lex.RAngle
     443        tag_Callouts.EmptyTag_marks = pablo.Advance(AttListEnd & lex.Slash)
     444       
     445        ParseError |= tag_Callouts.EmptyTag_marks & ~lex.RAngle
    525446
    526447        # End Tag Parsing
    527         EndTagEnds = bitutil.ScanThru(bitutil.ScanThru(bitutil.Advance(EndTagSeconds), lex.NameScan), lex.WS)
     448
     449        EndTagEnds = pablo.ScanThru(tag_Callouts.EndTag_marks, tag_Callouts.EndTag_marks | lex.NameScan)
     450        if EndTagEnds & lex.WS:
     451                EndTagEnds = pablo.ScanThru(EndTagEnds, lex.WS)
    528452        ParseError |= EndTagEnds & ~lex.RAngle
    529         callouts.EndTags = EndTagEnds - EndTagSeconds
    530         callouts.error = ParseError
    531 
    532         # POTENTIAL ADDITIONAL FIELDS
    533         # callouts.StartTagEnds = STagEnds
    534         # callouts.EmptyTagEnds = bitutil.Advance(callouts.EmptyTagMarks)
    535         # callouts.EndTagEnds = EndTagEnds
    536        
    537         return callouts
    538 
    539 def demo_tags(u8data):
    540         lgth = len(u8data)
    541         (bit, EOF_mask) = bitutil.transpose_streams(u8data)
    542         (u8, control, lex) = byteclass.classify_bytes(bit)
    543         lex = add_multiliterals(lex)
    544         markup1 = parse_CtCDPI(lex, EOF_mask)
    545         callouts = parse_tags(lex, markup1.CtCDPI_mask, EOF_mask)
    546         bitutil.print_aligned_u8_byte_streams([('input data', u8data),
    547                               ('element names', bitutil.bitstream2string(callouts.ElemNames, lgth)),
    548                               ('attribute names', bitutil.bitstream2string(callouts.AttNames, lgth)),
    549                               ('attribute values', bitutil.bitstream2string(callouts.AttVals, lgth)),
    550                               ('empty tag marks', bitutil.bitstream2string(callouts.EmptyTagMarks, lgth)),
    551                               ('end tags', bitutil.bitstream2string(callouts.EndTags, lgth)),
    552                               ('start/empty tags', bitutil.bitstream2string(callouts.Tags, lgth)),
    553                               ('errors', bitutil.bitstream2string(callouts.error, lgth+1))])
    554 
    555 
    556 
    557 def validate_no_CD_end(lex, markup1, tags):
    558         """Find illegal occurrences of ]]> in text (outside of markup).
    559 
    560         >>> demo_validate_no_CD_end(' <!-- OK: ]]>  --> <![CDATA OK  ]]>  ]]> <tag att=" ]]> "/> ]]>  <?php ]]> ?> ')
    561         input data :  <!-- OK: ]]>  --> <![CDATA OK  ]]>  ]]> <tag att=" ]]> "/> ]]>  <?php ]]> ?>
    562         CtCDPI_mask: __1111111111111111__111111111111111_______________________________11111111111_
    563         tags       : __________________________________________1111111111111111____________________
    564         illegal ]]>: _______________________________________1______________________1_______________
    565 """
    566         return lex.CD_end & ~(markup1.CtCDPI_mask | tags.Tags)
    567 
    568 def demo_validate_no_CD_end(u8data):
    569         lgth = len(u8data)
    570         (bit, EOF_mask) = bitutil.transpose_streams(u8data)
    571         (u8, control, lex) = byteclass.classify_bytes(bit)
    572         lex = add_multiliterals(lex)
    573         markup1 = parse_CtCDPI(lex, EOF_mask)
    574         tags = parse_tags(lex, markup1.CtCDPI_mask, EOF_mask)
    575         error = validate_no_CD_end(lex, markup1, tags)
    576         bitutil.print_aligned_u8_byte_streams([('input data', u8data),
    577                               ('CtCDPI_mask', bitutil.bitstream2string(markup1.CtCDPI_mask, lgth)),
    578                               ('tags', bitutil.bitstream2string(tags.Tags, lgth)),
    579                               ('illegal ]]>', bitutil.bitstream2string(error, lgth))])
    580 
    581 
    582 def prevalidate_names(u8, lex, name_stream, nmtoken_stream):
    583         """  Fully validate ASCII-based names and identify non-ASCII positions within names.
    584         >>> demo_prevalidate_names("<good -bad='hyphen'/><_OK/><:funny:butOK/><1problem a='b' d423='x'>")
    585         input data      : <good -bad='hyphen'/><_OK/><:funny:butOK/><1problem a='b' d423='x'>
    586         names           : _1111_1111____________111___111111111111___11111111_1_____1111_____
    587         name_start_check: ______1____________________________________1_______________________
    588         name_check      : ___________________________________________________________________
    589 """
    590         name_start = name_stream &~ bitutil.Advance(name_stream)
    591         name_start_check = name_start & ~lex.ASCII_name_start
    592         name_check = (name_stream &~ name_start | nmtoken_stream) & ~lex.ASCII_name_char & ~u8.suffix
    593         return (name_start_check, name_check)
    594 
    595 def demo_prevalidate_names(u8data):
    596         lgth = len(u8data)
    597         (bit, EOF_mask) = bitutil.transpose_streams(u8data)
    598         (u8, control, lex) = byteclass.classify_bytes(bit)
    599         lex = add_multiliterals(lex)
    600         markup1 = parse_CtCDPI(lex, EOF_mask)
    601         callouts = parse_tags(lex, markup1.CtCDPI_mask, EOF_mask)
    602         name_stream = callouts.ElemNames | callouts.AttNames
    603         (name_start_check, name_check) = prevalidate_names(u8, lex, name_stream, 0)
    604         bitutil.print_aligned_u8_byte_streams([('input data', u8data),
    605                               ('names', bitutil.bitstream2string(name_stream, lgth)),
    606                               ('name_start_check', bitutil.bitstream2string(name_start_check, lgth)),
    607                               ('name_check', bitutil.bitstream2string(name_check, lgth))])
    608 
    609 def validate_namespace_names(lex, name_stream, ncname_stream):
    610         """ Ensure that any colon (namespace separator) in a name divides the
    611         name into nonempty namespace prefix and local-part components, neither
    612         of which contain colons.
    613         >>> demo_validate_namespace_names("<a:b  xmlns: = '3' :x = '1' y: = '2'/>")
    614         input data  : <a:b  xmlns: = '3' :x = '1' y: = '2'/>
    615         names       : _111__111111_______11_______11________
    616         NCname_error: ____________1______1__________1_______
    617         >>> demo_validate_namespace_names("<a  xmlns:g = '3' a:x = '1' y::b = '2'/>")
    618         input data  : <a  xmlns:g = '3' a:x = '1' y::b = '2'/>
    619         names       : _1__1111111_______111_______1111________
    620         NCname_error: ______________________________1_________
    621         """
    622         name_cursor = name_stream & ~bitutil.Advance(name_stream)
     453        if ParseError:
     454                error_tracker.NoteError("Tag parsing error found", (ParseError))
     455               
     456               
     457        # Attribute value spans
     458        tag_Callouts.AttVal_spans = tag_Callouts.AttVal_ends - tag_Callouts.AttVal_starts
     459
     460def Parse_refs(lex, marker, ref_Callouts):
     461        ref_Callouts.GenRef_starts = 0
     462        ref_Callouts.GenRef_ends = 0
     463        ref_Callouts.DecRef_starts = 0
     464        ref_Callouts.DecRef_ends = 0
     465        ref_Callouts.HexRef_starts = 0
     466        ref_Callouts.HexRef_ends = 0
     467        ref_error = 0
     468
     469        # All remaining "&" must be reference start characters; parse them.
     470        if marker.Ref_opener:
     471                Ref_scope = pablo.Advance(marker.Ref_opener)
     472                NumRef2 = Ref_scope & lex.Hash
     473                ref_Callouts.GenRef_starts = Ref_scope &~ lex.Hash
     474                NumRef3 = pablo.Advance(NumRef2)
     475                HexRef3 = NumRef3 & lex.x
     476                ref_Callouts.DecRef_starts = NumRef3 &~ lex.x
     477                ref_Callouts.HexRef_starts = pablo.Advance(HexRef3)
     478                ref_Callouts.GenRef_ends = pablo.ScanThru(ref_Callouts.GenRef_starts, lex.NameScan)
     479                ref_Callouts.DecRef_ends = pablo.ScanThru(ref_Callouts.DecRef_starts, lex.Digit)
     480                ref_Callouts.HexRef_ends = pablo.ScanThru(ref_Callouts.HexRef_starts, lex.Hex)
     481                # Error checks
     482                # At least one digit required for DecRef, one hex digit for HexRef.
     483                ref_error1 = ref_Callouts.DecRef_starts &~ lex.Digit
     484                ref_error2 = ref_Callouts.HexRef_starts &~ lex.Hex
     485                # Semicolon terminator required (also covers unterminated at EOF).
     486                ref_ends = ref_Callouts.GenRef_ends | ref_Callouts.DecRef_ends | ref_Callouts.HexRef_ends
     487                ref_error3 = ref_ends &~ lex.Semicolon
     488                ref_error = ref_error1 | ref_error2 | ref_error3
     489                if ref_error:
     490                        error_tracker.NoteError("Reference error found", (ref_error))
     491                       
     492
     493
     494def Validate_xml_names(ctCDPI_Callouts, ref_Callouts, tag_Callouts, lex, u8, check_streams):
     495        PI_names = ctCDPI_Callouts.PI_name_ends - ctCDPI_Callouts.PI_name_starts
     496        GenRefs = ref_Callouts.GenRef_ends - ref_Callouts.GenRef_starts
     497        ElemNames = tag_Callouts.ElemName_ends - tag_Callouts.ElemName_starts
     498        AttNames = tag_Callouts.AttName_ends - tag_Callouts.AttName_starts
     499        qname_stream =  ElemNames | AttNames
     500        ncname_stream = PI_names | GenRefs
     501        name_stream = qname_stream | ncname_stream
     502        name_start = name_stream &~ pablo.Advance(name_stream)
     503        name_cursor = name_stream & ~pablo.Advance(name_stream)
    623504        void_prefix_err = name_cursor & lex.Colon
    624         namespace_sep = bitutil.ScanThru(name_cursor, lex.NameScan &~ lex.Colon) & lex.Colon
    625         local_part_start = bitutil.Advance(namespace_sep)
     505        namespace_sep = pablo.ScanThru(name_cursor, lex.NameScan &~ lex.Colon) & lex.Colon
     506        local_part_start = pablo.Advance(namespace_sep)
    626507        local_part_err = local_part_start &~ lex.NameScan
    627         colon2_err = bitutil.ScanThru(local_part_start, lex.NameScan &~ lex.Colon) & lex.Colon 
     508        colon2_err = pablo.ScanThru(local_part_start, lex.NameScan &~ lex.Colon) & lex.Colon
    628509        ncname_err = ncname_stream & lex.Colon
    629         return void_prefix_err | local_part_err | colon2_err | ncname_err
    630        
    631 def demo_validate_namespace_names(u8data):
    632         lgth = len(u8data)
    633         (bit, EOF_mask) = bitutil.transpose_streams(u8data)
    634         (u8, control, lex) = byteclass.classify_bytes(bit)
    635         lex = add_multiliterals(lex)
    636         markup1 = parse_CtCDPI(lex, EOF_mask)
    637         callouts = parse_tags(lex, markup1.CtCDPI_mask, EOF_mask)
    638         name_stream = callouts.ElemNames | callouts.AttNames
    639         #should be : ncname_stream = CT_callouts.PI_name | refs.GenRefs
    640         ncname_stream = 0
    641         name_check = validate_namespace_names(lex, name_stream, ncname_stream)
    642         bitutil.print_aligned_u8_byte_streams([('input data', u8data),
    643                               ('names', bitutil.bitstream2string(name_stream, lgth)),
    644                               ('NCname_error', bitutil.bitstream2string(name_check, lgth))])
    645 
    646 
    647 def parabix_parse(u8data):
    648         # Transpose to parallel bit streams and prepare an EOF mask.
    649         (bit, EOF_mask) = bitutil.transpose_streams(u8data)
    650 
     510        namespace_error = void_prefix_err | local_part_err | colon2_err | ncname_err
     511        if namespace_error:
     512                error_tracker.NoteError("error found", namespace_error)
     513               
     514                       
     515        check_streams.non_ascii_name_starts = name_start &~lex.ASCII_name_start
     516        check_streams.non_ascii_names = (name_stream &~ name_start) & ~lex.ASCII_name_char & ~u8.suffix
     517   
     518def Do_check_streams(marker, tag_Callouts, check_streams):
     519        CD_end_error = marker.CD_closer & ~tag_Callouts.AttVal_spans
     520        if CD_end_error:
     521                error_tracker.NoteError("Error: ]]> in text", CD_end_error)
     522        check_streams.tag_marks = tag_Callouts.EmptyTag_marks | tag_Callouts.ElemName_starts | tag_Callouts.EndTag_marks | tag_Callouts.AttName_starts
     523        check_streams.name_follows = tag_Callouts.ElemName_ends | tag_Callouts.AttName_ends
     524        check_streams.att_refs = tag_Callouts.AttVal_spans & marker.Ref_opener
     525
     526
     527def Main(basis_bits, lex, u8, xml_char, scope1, ctCDPI_Callouts, ref_Callouts, tag_Callouts, masks, xml_names, check_streams): 
     528       
    651529        # Classify bytes for UTF-8 processing, whitespace and control
    652530        # processing and XML lexical analysis.
    653         #(u8, control, lex) = byteclass.classify_bytes(bit)
    654         (u8, control, lex) = byteclass.classify_bytes_with_shift1opt(bit)
    655 
    656         # Validate UTF-8 multibyte sequences and determine the UTF-8 scope streams.
    657         u8 = u8u16.validate_utf8(u8)
    658 
    659         # Rule out the illegal characters for XML.
    660         xmlchar_error = validate_xmlchar(u8, control, lex, EOF_mask)
    661 
    662         # Find and normalize bare CR or CRLF combinations.
    663         (control, bit) = normalize_line_breaks(control, bit)
    664 
    665         # Compute XML multilterals such as <?, </, --, ]]>.
    666         lex = add_multiliterals(lex)
     531        # Classify_bytes(basis_bits, lex)
     532
     533        # Validate UTF-8 multibyte sequences and determine the UTF-8 scope streams
     534        # Validate_utf8(basis_bits, u8)
     535                               
     536        Classify_bytes_Validate_utf8(basis_bits, lex, u8)
    667537
    668538        # Parse all comments, CDATA sections and processing instructions.
    669         markup1 = parse_CtCDPI(lex, EOF_mask)
    670 
    671         # All remaining "<" must be tag start characters; parse tags.
    672         tags = parse_tags(lex, markup1.CtCDPI_mask, EOF_mask)
    673 
    674         # All remaining "&" must be reference start characters; parse them.
    675         refs = parse_refs(lex, markup1.CtCDPI_mask)
    676 
    677         # Ensure that no occurrence of ]]> occurs outside of markup.
    678         CD_end_error = validate_no_CD_end(lex, markup1, tags)
    679 
    680         # Convert to UTF-16 bit streams.
    681         (u16hi, u16lo, u16delmask) = u8u16.u8u16(u8, bit)
    682 
    683         # Consolidate and check for errors
    684         error = u8.error | xmlchar_error | markup1.error | tags.error | CD_end_error | refs.error
    685 
    686         # Consolidate the deletion_masks
    687         delmask = control.CRLF | refs.delmask | u16delmask # | markup1.CDATA_delimiters
    688 
    689         return (markup1, tags, refs, u16hi, u16lo, delmask, error, lex, u16delmask, EOF_mask)
    690 
    691 
    692 def demo_parabix(u8data):
    693 
    694         lgth = len(u8data)
    695        
    696         (markup1, tags, refs, u16hi, u16lo, delmask, error, lex, u16delmask, EOF_mask) = parabix_parse(u8data)
    697         bitutil.print_aligned_u8_byte_streams([('input data', u8data),
    698                               ('input high nybbles', bitutil.high_nybble_stream(u8data)),
    699                               ('input low nybbles', bitutil.low_nybble_stream(u8data)),
    700                               ('CD_span', bitutil.bitstream2string(markup1.CD_span, lgth)),
    701                               ('Ct_span', bitutil.bitstream2string(markup1.Ct_span, lgth)),
    702                               ('PI_span', bitutil.bitstream2string(markup1.PI_span, lgth)),
    703                               ('CtCDPI_mask', bitutil.bitstream2string(markup1.CtCDPI_mask, lgth)),
    704                               ('entity refs', bitutil.bitstream2string(refs.GenRefs, lgth)),
    705                               ('decimal char refs', bitutil.bitstream2string(refs.DecRefs, lgth)),
    706                               ('hex char refs', bitutil.bitstream2string(refs.HexRefs, lgth)),
    707                               ('element names', bitutil.bitstream2string(tags.ElemNames, lgth)),
    708                               ('attribute names', bitutil.bitstream2string(tags.AttNames, lgth)),
    709                               ('attribute values', bitutil.bitstream2string(tags.AttVals, lgth)),
    710                               ('empty tag marks', bitutil.bitstream2string(tags.EmptyTagMarks, lgth)),
    711                               ('end tags', bitutil.bitstream2string(tags.EndTags, lgth)),
    712                               ('start/empty tags', bitutil.bitstream2string(tags.Tags, lgth)),
    713                               ('delmask', bitutil.bitstream2string(delmask, lgth)),
    714                               ('u16delmask', bitutil.bitstream2string(u16delmask, lgth)),
    715                               ('errors', bitutil.bitstream2string(error, lgth+1))])
    716 
    717 def demo_u16delmask(u8data):
    718 
    719         u8len = len(u8data)
    720        
    721         # Transpose to parallel bit streams and prepare an EOF mask.
    722         (bit, EOF_mask) = bitutil.transpose_streams(u8data)
    723 
    724         # Classify bytes for UTF-8 processing, whitespace and control
    725         # processing and XML lexical analysis.
    726         (u8, control, lex) = byteclass.classify_bytes(bit)
    727 
    728         # Validate UTF-8 multibyte sequences and determine the UTF-8 scope streams.
    729         u8 = u8u16.validate_utf8(u8)   
    730        
    731         # Convert to UTF-16 bit streams.
    732         (u16hi, u16lo, delmask) = u8u16.u8u16(u8, bit)
    733        
    734         # Inverse transpose
    735         U16H = bitutil.filter_bytes(bitutil.inverse_transpose(u16hi, u8len), delmask)
    736         U16L = bitutil.filter_bytes(bitutil.inverse_transpose(u16lo, u8len), delmask)
    737        
    738         # Construct UTF-16 data buffer
    739         bytes = bitutil.merge_bytes(U16L, U16H)
    740        
    741         U16data = bytes.decode('utf16')
    742        
    743         bitutil.print_aligned_u8_byte_streams([('input data', u8data),
    744                                 ('u16delmask', bitutil.bitstream2string(delmask, u8len)),               
    745                                     ('errors', bitutil.bitstream2string(u8.error, u8len+1))])
    746         return
     539        Parse_CtCDPI(lex, marker, ctCDPI_Callouts, check_streams)
     540               
     541        # All remaining '<' must be tag start characters; parse tags.
     542        Parse_tags(lex, marker, tag_Callouts)
     543
     544        # All remaining '&' must be reference start characters; parse them.
     545        Parse_refs(lex, marker, ref_Callouts)
     546       
     547        # Validate XML namespaces and generate bit streams to post validate non-ascii range XML names
     548        Validate_xml_names(ctCDPI_Callouts, ref_Callouts, tag_Callouts, lex, u8, check_streams)
     549   
     550        Do_check_streams(marker, tag_Callouts, check_streams)
     551
     552
     553
     554basis_bits = Basis_bits()
     555lex = Lex()
     556u8 = U8()
     557marker = Marker()
     558ctCDPI_Callouts = CtCDPI_Callouts()
     559tag_Callouts = Tag_Callouts()
     560ref_Callouts = Ref_Callouts()
     561check_streams = Check_streams()
    747562
    748563if __name__ == "__main__":
    749         import doctest
    750         doctest.testmod()
    751564       
    752565        if len(sys.argv) > 1:
    753                 u8data = bitutil.readfile(sys.argv[1])
    754 #               demo_validate_xmlchar(u8data)
    755 #               demo_line_breaks(u8data)
    756 #               demo_multiliterals(u8data)
    757 #               demo_CtCDPI(u8data)
    758 #               demo_refs(u8data)
    759 #               demo_tags(u8data)
    760 #               demo_validate_no_CD_end(u8data)         
    761 #               demo_u16delmask(u8data)         
    762                 demo_parabix(u8data)
    763 #               demo_u16delmask(u8data)
     566                u8data = pablo.readfile(sys.argv[1])
     567                pablo.EOF_mask = pablo.transpose_streams(u8data, basis_bits)
     568                Classify_bytes_Validate_utf8(basis_bits, lex, u8)
     569                Parse_CtCDPI(lex, marker, ctCDPI_Callouts, check_streams)
     570                Parse_tags(lex, marker, tag_Callouts)
     571                Parse_refs(lex, marker, ref_Callouts)
     572                Validate_xml_names(ctCDPI_Callouts, ref_Callouts, tag_Callouts, lex, u8, check_streams)
     573                Do_check_streams(marker, tag_Callouts, check_streams)
    764574        else:
    765                 print("Usage: python parabix2.py <file>")       
    766                
    767  
    768        
    769        
     575                print("Usage: python parabix2.py <file>")
     576       
     577
     578
Note: See TracChangeset for help on using the changeset viewer.