/[suikacvs]/markup/html/whatpm/Whatpm/HTML/Tokenizer.pm.src
Suika

Diff of /markup/html/whatpm/Whatpm/HTML/Tokenizer.pm.src

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.4 by wakaba, Tue Oct 14 11:46:57 2008 UTC revision 1.12 by wakaba, Wed Oct 15 12:49:49 2008 UTC
# Line 31  BEGIN { Line 31  BEGIN {
31    );    );
32  }  }
33    
34    ## NOTE: Differences from the XML5 draft are marked as "XML5:".
35    
36  ## Token types  ## Token types
37    
38  sub DOCTYPE_TOKEN () { 1 }  sub DOCTYPE_TOKEN () { 1 } ## XML5: No DOCTYPE token.
39  sub COMMENT_TOKEN () { 2 }  sub COMMENT_TOKEN () { 2 }
40  sub START_TAG_TOKEN () { 3 }  sub START_TAG_TOKEN () { 3 }
41  sub END_TAG_TOKEN () { 4 }  sub END_TAG_TOKEN () { 4 }
42  sub END_OF_FILE_TOKEN () { 5 }  sub END_OF_FILE_TOKEN () { 5 }
43  sub CHARACTER_TOKEN () { 6 }  sub CHARACTER_TOKEN () { 6 }
44  sub PI_TOKEN () { 7 } # XML5  sub PI_TOKEN () { 7 } ## NOTE: XML only.
45  sub ABORT_TOKEN () { 8 } # Not a token actually  sub ABORT_TOKEN () { 8 } ## NOTE: For internal processing.
46    
47    ## XML5: XML5 has "empty tag token".  In this implementation, it is
48    ## represented as a start tag token with $self->{self_closing} flag
49    ## set to true.
50    
51    ## XML5: XML5 has "short end tag token".  In this implementation, it
52    ## is represented as an end tag token with $token->{tag_name} flag set
53    ## to an empty string.
54    
55  package Whatpm::HTML;  package Whatpm::HTML;
56    
# Line 114  sub HEXREF_HEX_STATE () { 48 } Line 124  sub HEXREF_HEX_STATE () { 48 }
124  sub ENTITY_NAME_STATE () { 49 }  sub ENTITY_NAME_STATE () { 49 }
125  sub PCDATA_STATE () { 50 } # "data state" in the spec  sub PCDATA_STATE () { 50 } # "data state" in the spec
126    
127    ## XML-only states
128    sub PI_STATE () { 51 }
129    sub PI_TARGET_STATE () { 52 }
130    sub PI_TARGET_AFTER_STATE () { 53 }
131    sub PI_DATA_STATE () { 54 }
132    sub PI_AFTER_STATE () { 55 }
133    sub PI_DATA_AFTER_STATE () { 56 }
134    sub DOCTYPE_INTERNAL_SUBSET_STATE () { 57 }
135    sub DOCTYPE_INTERNAL_SUBSET_AFTER_STATE () { 58 }
136    
137  ## Tree constructor state constants (see Whatpm::HTML for the full  ## Tree constructor state constants (see Whatpm::HTML for the full
138  ## list and descriptions)  ## list and descriptions)
139    
# Line 178  sub _initialize_tokenizer ($) { Line 198  sub _initialize_tokenizer ($) {
198    #$self->{is_xml} (if XML)    #$self->{is_xml} (if XML)
199    
200    $self->{state} = DATA_STATE; # MUST    $self->{state} = DATA_STATE; # MUST
201    #$self->{s_kwd}; # state keyword - initialized when used    $self->{s_kwd} = ''; # Data state keyword
202      #$self->{kwd} = ''; # State-dependent keyword; initialized when used
203    #$self->{entity__value}; # initialized when used    #$self->{entity__value}; # initialized when used
204    #$self->{entity__match}; # initialized when used    #$self->{entity__match}; # initialized when used
205    $self->{content_model} = PCDATA_CONTENT_MODEL; # be    $self->{content_model} = PCDATA_CONTENT_MODEL; # be
# Line 198  sub _initialize_tokenizer ($) { Line 219  sub _initialize_tokenizer ($) {
219    
220  ## A token has:  ## A token has:
221  ##   ->{type} == DOCTYPE_TOKEN, START_TAG_TOKEN, END_TAG_TOKEN, COMMENT_TOKEN,  ##   ->{type} == DOCTYPE_TOKEN, START_TAG_TOKEN, END_TAG_TOKEN, COMMENT_TOKEN,
222  ##       CHARACTER_TOKEN, or END_OF_FILE_TOKEN  ##       CHARACTER_TOKEN, END_OF_FILE_TOKEN, PI_TOKEN, or ABORT_TOKEN
223  ##   ->{name} (DOCTYPE_TOKEN)  ##   ->{name} (DOCTYPE_TOKEN)
224  ##   ->{tag_name} (START_TAG_TOKEN, END_TAG_TOKEN)  ##   ->{tag_name} (START_TAG_TOKEN, END_TAG_TOKEN)
225    ##   ->{target} (PI_TOKEN)
226  ##   ->{pubid} (DOCTYPE_TOKEN)  ##   ->{pubid} (DOCTYPE_TOKEN)
227  ##   ->{sysid} (DOCTYPE_TOKEN)  ##   ->{sysid} (DOCTYPE_TOKEN)
228  ##   ->{quirks} == 1 or 0 (DOCTYPE_TOKEN): "force-quirks" flag  ##   ->{quirks} == 1 or 0 (DOCTYPE_TOKEN): "force-quirks" flag
# Line 208  sub _initialize_tokenizer ($) { Line 230  sub _initialize_tokenizer ($) {
230  ##        ->{name}  ##        ->{name}
231  ##        ->{value}  ##        ->{value}
232  ##        ->{has_reference} == 1 or 0  ##        ->{has_reference} == 1 or 0
233  ##   ->{data} (COMMENT_TOKEN, CHARACTER_TOKEN)  ##        ->{index}: Index of the attribute in a tag.
234    ##   ->{data} (COMMENT_TOKEN, CHARACTER_TOKEN, PI_TOKEN)
235    ##   ->{has_reference} == 1 or 0 (CHARACTER_TOKEN)
236    ##   ->{last_index} (ELEMENT_TOKEN): Next attribute's index - 1.
237    ##   ->{has_internal_subset} = 1 or 0 (DOCTYPE_TOKEN)
238    
239  ## NOTE: The "self-closing flag" is hold as |$self->{self_closing}|.  ## NOTE: The "self-closing flag" is hold as |$self->{self_closing}|.
240  ##     |->{self_closing}| is used to save the value of |$self->{self_closing}|  ##     |->{self_closing}| is used to save the value of |$self->{self_closing}|
241  ##     while the token is pushed back to the stack.  ##     while the token is pushed back to the stack.
# Line 228  my $is_space = { Line 255  my $is_space = {
255    0x0009 => 1, # CHARACTER TABULATION (HT)    0x0009 => 1, # CHARACTER TABULATION (HT)
256    0x000A => 1, # LINE FEED (LF)    0x000A => 1, # LINE FEED (LF)
257    #0x000B => 0, # LINE TABULATION (VT)    #0x000B => 0, # LINE TABULATION (VT)
258    0x000C => 1, # FORM FEED (FF)    0x000C => 1, # FORM FEED (FF) ## XML5: Not a space character.
259    #0x000D => 1, # CARRIAGE RETURN (CR)    #0x000D => 1, # CARRIAGE RETURN (CR)
260    0x0020 => 1, # SPACE (SP)    0x0020 => 1, # SPACE (SP)
261  };  };
# Line 312  sub _get_next_token ($) { Line 339  sub _get_next_token ($) {
339          }          }
340        } elsif ($self->{nc} == 0x002D) { # -        } elsif ($self->{nc} == 0x002D) { # -
341          if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA          if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
342            $self->{s_kwd} .= '-';            if ($self->{s_kwd} eq '<!-') {
             
           if ($self->{s_kwd} eq '<!--') {  
343              !!!cp (3);              !!!cp (3);
344              $self->{escape} = 1; # unless $self->{escape};              $self->{escape} = 1; # unless $self->{escape};
345              $self->{s_kwd} = '--';              $self->{s_kwd} = '--';
346              #              #
347            } elsif ($self->{s_kwd} eq '---') {            } elsif ($self->{s_kwd} eq '-') {
348              !!!cp (4);              !!!cp (4);
349              $self->{s_kwd} = '--';              $self->{s_kwd} = '--';
350              #              #
351              } elsif ($self->{s_kwd} eq '<!' or $self->{s_kwd} eq '-') {
352                !!!cp (4.1);
353                $self->{s_kwd} .= '-';
354                #
355            } else {            } else {
356              !!!cp (5);              !!!cp (5);
357                $self->{s_kwd} = '-';
358              #              #
359            }            }
360          }          }
# Line 360  sub _get_next_token ($) { Line 390  sub _get_next_token ($) {
390            if ($self->{s_kwd} eq '--') {            if ($self->{s_kwd} eq '--') {
391              !!!cp (8);              !!!cp (8);
392              delete $self->{escape};              delete $self->{escape};
393                #
394            } else {            } else {
395              !!!cp (9);              !!!cp (9);
396                #
397            }            }
398            } elsif ($self->{is_xml} and $self->{s_kwd} eq ']]') {
399              !!!cp (9.1);
400              !!!parse-error (type => 'unmatched mse', ## TODO: type
401                              line => $self->{line_prev},
402                              column => $self->{column_prev} - 1);
403              #
404          } else {          } else {
405            !!!cp (10);            !!!cp (10);
406              #
407          }          }
408                    
409          $self->{s_kwd} = '';          $self->{s_kwd} = '';
410          #          #
411          } elsif ($self->{nc} == 0x005D) { # ]
412            if ($self->{s_kwd} eq ']' or $self->{s_kwd} eq '') {
413              !!!cp (10.1);
414              $self->{s_kwd} .= ']';
415            } elsif ($self->{s_kwd} eq ']]') {
416              !!!cp (10.2);
417              #
418            } else {
419              !!!cp (10.3);
420              $self->{s_kwd} = '';
421            }
422            #
423        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
424          !!!cp (11);          !!!cp (11);
425          $self->{s_kwd} = '';          $self->{s_kwd} = '';
# Line 386  sub _get_next_token ($) { Line 437  sub _get_next_token ($) {
437                     data => chr $self->{nc},                     data => chr $self->{nc},
438                     line => $self->{line}, column => $self->{column},                     line => $self->{line}, column => $self->{column},
439                    };                    };
440        if ($self->{read_until}->($token->{data}, q[-!<>&],        if ($self->{read_until}->($token->{data}, q{-!<>&\]},
441                                  length $token->{data})) {                                  length $token->{data})) {
442          $self->{s_kwd} = '';          $self->{s_kwd} = '';
443        }        }
444    
445        ## Stay in the data state.        ## Stay in the data state.
446        if ($self->{content_model} == PCDATA_CONTENT_MODEL) {        if (not $self->{is_xml} and
447              $self->{content_model} == PCDATA_CONTENT_MODEL) {
448          !!!cp (13);          !!!cp (13);
449          $self->{state} = PCDATA_STATE;          $self->{state} = PCDATA_STATE;
450        } else {        } else {
# Line 403  sub _get_next_token ($) { Line 455  sub _get_next_token ($) {
455        !!!emit ($token);        !!!emit ($token);
456        redo A;        redo A;
457      } elsif ($self->{state} == TAG_OPEN_STATE) {      } elsif ($self->{state} == TAG_OPEN_STATE) {
458          ## XML5: "tag state".
459    
460        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
461          if ($self->{nc} == 0x002F) { # /          if ($self->{nc} == 0x002F) { # /
462            !!!cp (15);            !!!cp (15);
# Line 411  sub _get_next_token ($) { Line 465  sub _get_next_token ($) {
465            redo A;            redo A;
466          } elsif ($self->{nc} == 0x0021) { # !          } elsif ($self->{nc} == 0x0021) { # !
467            !!!cp (15.1);            !!!cp (15.1);
468            $self->{s_kwd} = '<' unless $self->{escape};            $self->{s_kwd} = $self->{escaped} ? '' : '<';
469            #            #
470          } else {          } else {
471            !!!cp (16);            !!!cp (16);
472              $self->{s_kwd} = '';
473            #            #
474          }          }
475    
# Line 463  sub _get_next_token ($) { Line 518  sub _get_next_token ($) {
518                            line => $self->{line_prev},                            line => $self->{line_prev},
519                            column => $self->{column_prev});                            column => $self->{column_prev});
520            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
521              $self->{s_kwd} = '';
522            !!!next-input-character;            !!!next-input-character;
523    
524            !!!emit ({type => CHARACTER_TOKEN, data => '<>',            !!!emit ({type => CHARACTER_TOKEN, data => '<>',
# Line 472  sub _get_next_token ($) { Line 528  sub _get_next_token ($) {
528    
529            redo A;            redo A;
530          } elsif ($self->{nc} == 0x003F) { # ?          } elsif ($self->{nc} == 0x003F) { # ?
531            !!!cp (22);            if ($self->{is_xml}) {
532            !!!parse-error (type => 'pio',              !!!cp (22.1);
533                            line => $self->{line_prev},              $self->{state} = PI_STATE;
534                            column => $self->{column_prev});              !!!next-input-character;
535            $self->{state} = BOGUS_COMMENT_STATE;              redo A;
536            $self->{ct} = {type => COMMENT_TOKEN, data => '',            } else {
537                                      line => $self->{line_prev},              !!!cp (22);
538                                      column => $self->{column_prev},              !!!parse-error (type => 'pio',
539                                     };                              line => $self->{line_prev},
540            ## $self->{nc} is intentionally left as is                              column => $self->{column_prev});
541            redo A;              $self->{state} = BOGUS_COMMENT_STATE;
542          } else {              $self->{ct} = {type => COMMENT_TOKEN, data => '',
543                               line => $self->{line_prev},
544                               column => $self->{column_prev},
545                              };
546                ## $self->{nc} is intentionally left as is
547                redo A;
548              }
549            } elsif (not $self->{is_xml} or $is_space->{$self->{nc}}) {
550            !!!cp (23);            !!!cp (23);
551            !!!parse-error (type => 'bare stago',            !!!parse-error (type => 'bare stago',
552                            line => $self->{line_prev},                            line => $self->{line_prev},
553                            column => $self->{column_prev});                            column => $self->{column_prev});
554            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
555              $self->{s_kwd} = '';
556            ## reconsume            ## reconsume
557    
558            !!!emit ({type => CHARACTER_TOKEN, data => '<',            !!!emit ({type => CHARACTER_TOKEN, data => '<',
# Line 497  sub _get_next_token ($) { Line 561  sub _get_next_token ($) {
561                     });                     });
562    
563            redo A;            redo A;
564            } else {
565              ## XML5: "<:" is a parse error.
566              !!!cp (23.1);
567              $self->{ct} = {type => START_TAG_TOKEN,
568                                        tag_name => chr ($self->{nc}),
569                                        line => $self->{line_prev},
570                                        column => $self->{column_prev}};
571              $self->{state} = TAG_NAME_STATE;
572              !!!next-input-character;
573              redo A;
574          }          }
575        } else {        } else {
576          die "$0: $self->{content_model} in tag open";          die "$0: $self->{content_model} in tag open";
# Line 505  sub _get_next_token ($) { Line 579  sub _get_next_token ($) {
579        ## NOTE: The "close tag open state" in the spec is implemented as        ## NOTE: The "close tag open state" in the spec is implemented as
580        ## |CLOSE_TAG_OPEN_STATE| and |CDATA_RCDATA_CLOSE_TAG_STATE|.        ## |CLOSE_TAG_OPEN_STATE| and |CDATA_RCDATA_CLOSE_TAG_STATE|.
581    
582          ## XML5: "end tag state".
583    
584        my ($l, $c) = ($self->{line_prev}, $self->{column_prev} - 1); # "<"of"</"        my ($l, $c) = ($self->{line_prev}, $self->{column_prev} - 1); # "<"of"</"
585        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
586          if (defined $self->{last_stag_name}) {          if (defined $self->{last_stag_name}) {
587            $self->{state} = CDATA_RCDATA_CLOSE_TAG_STATE;            $self->{state} = CDATA_RCDATA_CLOSE_TAG_STATE;
588            $self->{s_kwd} = '';            $self->{kwd} = '';
589            ## Reconsume.            ## Reconsume.
590            redo A;            redo A;
591          } else {          } else {
# Line 517  sub _get_next_token ($) { Line 593  sub _get_next_token ($) {
593            ## NOTE: See <http://krijnhoetmer.nl/irc-logs/whatwg/20070626#l-564>.            ## NOTE: See <http://krijnhoetmer.nl/irc-logs/whatwg/20070626#l-564>.
594            !!!cp (28);            !!!cp (28);
595            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
596              $self->{s_kwd} = '';
597            ## Reconsume.            ## Reconsume.
598            !!!emit ({type => CHARACTER_TOKEN, data => '</',            !!!emit ({type => CHARACTER_TOKEN, data => '</',
599                      line => $l, column => $c,                      line => $l, column => $c,
# Line 545  sub _get_next_token ($) { Line 622  sub _get_next_token ($) {
622          !!!next-input-character;          !!!next-input-character;
623          redo A;          redo A;
624        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
         !!!cp (31);  
625          !!!parse-error (type => 'empty end tag',          !!!parse-error (type => 'empty end tag',
626                          line => $self->{line_prev}, ## "<" in "</>"                          line => $self->{line_prev}, ## "<" in "</>"
627                          column => $self->{column_prev} - 1);                          column => $self->{column_prev} - 1);
628          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
629          !!!next-input-character;          $self->{s_kwd} = '';
630            if ($self->{is_xml}) {
631              !!!cp (31);
632              ## XML5: No parse error.
633              
634              ## NOTE: This parser raises a parse error, since it supports
635              ## XML1, not XML5.
636    
637              ## NOTE: A short end tag token.
638              my $ct = {type => END_TAG_TOKEN,
639                        tag_name => '',
640                        line => $self->{line_prev},
641                        column => $self->{column_prev} - 1,
642                       };
643              !!!next-input-character;
644              !!!emit ($ct);
645            } else {
646              !!!cp (31.1);
647              !!!next-input-character;
648            }
649          redo A;          redo A;
650        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
651          !!!cp (32);          !!!cp (32);
652          !!!parse-error (type => 'bare etago');          !!!parse-error (type => 'bare etago');
653            $self->{s_kwd} = '';
654          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
655          # reconsume          # reconsume
656    
# Line 563  sub _get_next_token ($) { Line 659  sub _get_next_token ($) {
659                   });                   });
660    
661          redo A;          redo A;
662        } else {        } elsif (not $self->{is_xml} or
663                   $is_space->{$self->{nc}}) {
664          !!!cp (33);          !!!cp (33);
665          !!!parse-error (type => 'bogus end tag');          !!!parse-error (type => 'bogus end tag',
666                            line => $self->{line_prev}, # "<" of "</"
667                            column => $self->{column_prev} - 1);
668          $self->{state} = BOGUS_COMMENT_STATE;          $self->{state} = BOGUS_COMMENT_STATE;
669          $self->{ct} = {type => COMMENT_TOKEN, data => '',          $self->{ct} = {type => COMMENT_TOKEN, data => '',
670                                    line => $self->{line_prev}, # "<" of "</"                                    line => $self->{line_prev}, # "<" of "</"
# Line 578  sub _get_next_token ($) { Line 677  sub _get_next_token ($) {
677          ## generated from the bogus end tag, as defined in the          ## generated from the bogus end tag, as defined in the
678          ## "bogus comment state" entry.          ## "bogus comment state" entry.
679          redo A;          redo A;
680          } else {
681            ## XML5: "</:" is a parse error.
682            !!!cp (30.1);
683            $self->{ct} = {type => END_TAG_TOKEN,
684                           tag_name => chr ($self->{nc}),
685                           line => $l, column => $c};
686            $self->{state} = TAG_NAME_STATE; ## XML5: "end tag name state".
687            !!!next-input-character;
688            redo A;
689        }        }
690      } elsif ($self->{state} == CDATA_RCDATA_CLOSE_TAG_STATE) {      } elsif ($self->{state} == CDATA_RCDATA_CLOSE_TAG_STATE) {
691        my $ch = substr $self->{last_stag_name}, length $self->{s_kwd}, 1;        my $ch = substr $self->{last_stag_name}, length $self->{kwd}, 1;
692        if (length $ch) {        if (length $ch) {
693          my $CH = $ch;          my $CH = $ch;
694          $ch =~ tr/a-z/A-Z/;          $ch =~ tr/a-z/A-Z/;
# Line 588  sub _get_next_token ($) { Line 696  sub _get_next_token ($) {
696          if ($nch eq $ch or $nch eq $CH) {          if ($nch eq $ch or $nch eq $CH) {
697            !!!cp (24);            !!!cp (24);
698            ## Stay in the state.            ## Stay in the state.
699            $self->{s_kwd} .= $nch;            $self->{kwd} .= $nch;
700            !!!next-input-character;            !!!next-input-character;
701            redo A;            redo A;
702          } else {          } else {
703            !!!cp (25);            !!!cp (25);
704            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
705              $self->{s_kwd} = '';
706            ## Reconsume.            ## Reconsume.
707            !!!emit ({type => CHARACTER_TOKEN,            !!!emit ({type => CHARACTER_TOKEN,
708                      data => '</' . $self->{s_kwd},                      data => '</' . $self->{kwd},
709                      line => $self->{line_prev},                      line => $self->{line_prev},
710                      column => $self->{column_prev} - 1 - length $self->{s_kwd},                      column => $self->{column_prev} - 1 - length $self->{kwd},
711                     });                     });
712            redo A;            redo A;
713          }          }
# Line 612  sub _get_next_token ($) { Line 721  sub _get_next_token ($) {
721            !!!cp (26);            !!!cp (26);
722            ## Reconsume.            ## Reconsume.
723            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
724              $self->{s_kwd} = '';
725            !!!emit ({type => CHARACTER_TOKEN,            !!!emit ({type => CHARACTER_TOKEN,
726                      data => '</' . $self->{s_kwd},                      data => '</' . $self->{kwd},
727                      line => $self->{line_prev},                      line => $self->{line_prev},
728                      column => $self->{column_prev} - 1 - length $self->{s_kwd},                      column => $self->{column_prev} - 1 - length $self->{kwd},
729                     });                     });
730            redo A;            redo A;
731          } else {          } else {
# Line 624  sub _get_next_token ($) { Line 734  sub _get_next_token ($) {
734                = {type => END_TAG_TOKEN,                = {type => END_TAG_TOKEN,
735                   tag_name => $self->{last_stag_name},                   tag_name => $self->{last_stag_name},
736                   line => $self->{line_prev},                   line => $self->{line_prev},
737                   column => $self->{column_prev} - 1 - length $self->{s_kwd}};                   column => $self->{column_prev} - 1 - length $self->{kwd}};
738            $self->{state} = TAG_NAME_STATE;            $self->{state} = TAG_NAME_STATE;
739            ## Reconsume.            ## Reconsume.
740            redo A;            redo A;
# Line 653  sub _get_next_token ($) { Line 763  sub _get_next_token ($) {
763            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
764          }          }
765          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
766            $self->{s_kwd} = '';
767          !!!next-input-character;          !!!next-input-character;
768    
769          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 685  sub _get_next_token ($) { Line 796  sub _get_next_token ($) {
796            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
797          }          }
798          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
799            $self->{s_kwd} = '';
800          # reconsume          # reconsume
801    
802          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 704  sub _get_next_token ($) { Line 816  sub _get_next_token ($) {
816          redo A;          redo A;
817        }        }
818      } elsif ($self->{state} == BEFORE_ATTRIBUTE_NAME_STATE) {      } elsif ($self->{state} == BEFORE_ATTRIBUTE_NAME_STATE) {
819          ## XML5: "Tag attribute name before state".
820    
821        if ($is_space->{$self->{nc}}) {        if ($is_space->{$self->{nc}}) {
822          !!!cp (45);          !!!cp (45);
823          ## Stay in the state          ## Stay in the state
# Line 725  sub _get_next_token ($) { Line 839  sub _get_next_token ($) {
839            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
840          }          }
841          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
842            $self->{s_kwd} = '';
843          !!!next-input-character;          !!!next-input-character;
844    
845          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 762  sub _get_next_token ($) { Line 877  sub _get_next_token ($) {
877            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
878          }          }
879          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
880            $self->{s_kwd} = '';
881          # reconsume          # reconsume
882    
883          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 774  sub _get_next_token ($) { Line 890  sub _get_next_token ($) {
890               0x003D => 1, # =               0x003D => 1, # =
891              }->{$self->{nc}}) {              }->{$self->{nc}}) {
892            !!!cp (55);            !!!cp (55);
893              ## XML5: Not a parse error.
894            !!!parse-error (type => 'bad attribute name');            !!!parse-error (type => 'bad attribute name');
895          } else {          } else {
896            !!!cp (56);            !!!cp (56);
897              ## XML5: ":" raises a parse error and is ignored.
898          }          }
899          $self->{ca}          $self->{ca}
900              = {name => chr ($self->{nc}),              = {name => chr ($self->{nc}),
# Line 787  sub _get_next_token ($) { Line 905  sub _get_next_token ($) {
905          redo A;          redo A;
906        }        }
907      } elsif ($self->{state} == ATTRIBUTE_NAME_STATE) {      } elsif ($self->{state} == ATTRIBUTE_NAME_STATE) {
908          ## XML5: "Tag attribute name state".
909    
910        my $before_leave = sub {        my $before_leave = sub {
911          if (exists $self->{ct}->{attributes} # start tag or end tag          if (exists $self->{ct}->{attributes} # start tag or end tag
912              ->{$self->{ca}->{name}}) { # MUST              ->{$self->{ca}->{name}}) { # MUST
# Line 797  sub _get_next_token ($) { Line 917  sub _get_next_token ($) {
917            !!!cp (58);            !!!cp (58);
918            $self->{ct}->{attributes}->{$self->{ca}->{name}}            $self->{ct}->{attributes}->{$self->{ca}->{name}}
919              = $self->{ca};              = $self->{ca};
920              $self->{ca}->{index} = ++$self->{ct}->{last_index};
921          }          }
922        }; # $before_leave        }; # $before_leave
923    
# Line 813  sub _get_next_token ($) { Line 934  sub _get_next_token ($) {
934          !!!next-input-character;          !!!next-input-character;
935          redo A;          redo A;
936        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
937            if ($self->{is_xml}) {
938              !!!cp (60.1);
939              ## XML5: Not a parse error.
940              !!!parse-error (type => 'no attr value'); ## TODO: type
941            } else {
942              !!!cp (60.2);
943            }
944    
945          $before_leave->();          $before_leave->();
946          if ($self->{ct}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
947            !!!cp (61);            !!!cp (61);
# Line 827  sub _get_next_token ($) { Line 956  sub _get_next_token ($) {
956            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
957          }          }
958          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
959            $self->{s_kwd} = '';
960          !!!next-input-character;          !!!next-input-character;
961    
962          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 841  sub _get_next_token ($) { Line 971  sub _get_next_token ($) {
971          !!!next-input-character;          !!!next-input-character;
972          redo A;          redo A;
973        } elsif ($self->{nc} == 0x002F) { # /        } elsif ($self->{nc} == 0x002F) { # /
974          !!!cp (64);          if ($self->{is_xml}) {
975              !!!cp (64);
976              ## XML5: Not a parse error.
977              !!!parse-error (type => 'no attr value'); ## TODO: type
978            } else {
979              !!!cp (64.1);
980            }
981            
982          $before_leave->();          $before_leave->();
983          $self->{state} = SELF_CLOSING_START_TAG_STATE;          $self->{state} = SELF_CLOSING_START_TAG_STATE;
984          !!!next-input-character;          !!!next-input-character;
# Line 865  sub _get_next_token ($) { Line 1002  sub _get_next_token ($) {
1002            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1003          }          }
1004          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1005            $self->{s_kwd} = '';
1006          # reconsume          # reconsume
1007    
1008          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 874  sub _get_next_token ($) { Line 1012  sub _get_next_token ($) {
1012          if ($self->{nc} == 0x0022 or # "          if ($self->{nc} == 0x0022 or # "
1013              $self->{nc} == 0x0027) { # '              $self->{nc} == 0x0027) { # '
1014            !!!cp (69);            !!!cp (69);
1015              ## XML5: Not a parse error.
1016            !!!parse-error (type => 'bad attribute name');            !!!parse-error (type => 'bad attribute name');
1017          } else {          } else {
1018            !!!cp (70);            !!!cp (70);
# Line 884  sub _get_next_token ($) { Line 1023  sub _get_next_token ($) {
1023          redo A;          redo A;
1024        }        }
1025      } elsif ($self->{state} == AFTER_ATTRIBUTE_NAME_STATE) {      } elsif ($self->{state} == AFTER_ATTRIBUTE_NAME_STATE) {
1026          ## XML5: "Tag attribute name after state".
1027          
1028        if ($is_space->{$self->{nc}}) {        if ($is_space->{$self->{nc}}) {
1029          !!!cp (71);          !!!cp (71);
1030          ## Stay in the state          ## Stay in the state
# Line 895  sub _get_next_token ($) { Line 1036  sub _get_next_token ($) {
1036          !!!next-input-character;          !!!next-input-character;
1037          redo A;          redo A;
1038        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
1039            if ($self->{is_xml}) {
1040              !!!cp (72.1);
1041              ## XML5: Not a parse error.
1042              !!!parse-error (type => 'no attr value'); ## TODO: type
1043            } else {
1044              !!!cp (72.2);
1045            }
1046    
1047          if ($self->{ct}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1048            !!!cp (73);            !!!cp (73);
1049            $self->{last_stag_name} = $self->{ct}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
# Line 911  sub _get_next_token ($) { Line 1060  sub _get_next_token ($) {
1060            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1061          }          }
1062          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1063            $self->{s_kwd} = '';
1064          !!!next-input-character;          !!!next-input-character;
1065    
1066          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 927  sub _get_next_token ($) { Line 1077  sub _get_next_token ($) {
1077          !!!next-input-character;          !!!next-input-character;
1078          redo A;          redo A;
1079        } elsif ($self->{nc} == 0x002F) { # /        } elsif ($self->{nc} == 0x002F) { # /
1080          !!!cp (77);          if ($self->{is_xml}) {
1081              !!!cp (77);
1082              ## XML5: Not a parse error.
1083              !!!parse-error (type => 'no attr value'); ## TODO: type
1084            } else {
1085              !!!cp (77.1);
1086            }
1087            
1088          $self->{state} = SELF_CLOSING_START_TAG_STATE;          $self->{state} = SELF_CLOSING_START_TAG_STATE;
1089          !!!next-input-character;          !!!next-input-character;
1090          redo A;          redo A;
# Line 948  sub _get_next_token ($) { Line 1105  sub _get_next_token ($) {
1105          } else {          } else {
1106            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1107          }          }
1108            $self->{s_kwd} = '';
1109          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1110          # reconsume          # reconsume
1111    
# Line 955  sub _get_next_token ($) { Line 1113  sub _get_next_token ($) {
1113    
1114          redo A;          redo A;
1115        } else {        } else {
1116            if ($self->{is_xml}) {
1117              !!!cp (78.1);
1118              ## XML5: Not a parse error.
1119              !!!parse-error (type => 'no attr value'); ## TODO: type
1120            } else {
1121              !!!cp (78.2);
1122            }
1123    
1124          if ($self->{nc} == 0x0022 or # "          if ($self->{nc} == 0x0022 or # "
1125              $self->{nc} == 0x0027) { # '              $self->{nc} == 0x0027) { # '
1126            !!!cp (78);            !!!cp (78);
1127              ## XML5: Not a parse error.
1128            !!!parse-error (type => 'bad attribute name');            !!!parse-error (type => 'bad attribute name');
1129          } else {          } else {
1130            !!!cp (82);            !!!cp (82);
# Line 971  sub _get_next_token ($) { Line 1138  sub _get_next_token ($) {
1138          redo A;                  redo A;        
1139        }        }
1140      } elsif ($self->{state} == BEFORE_ATTRIBUTE_VALUE_STATE) {      } elsif ($self->{state} == BEFORE_ATTRIBUTE_VALUE_STATE) {
1141          ## XML5: "Tag attribute value before state".
1142    
1143        if ($is_space->{$self->{nc}}) {        if ($is_space->{$self->{nc}}) {
1144          !!!cp (83);          !!!cp (83);
1145          ## Stay in the state          ## Stay in the state
# Line 1009  sub _get_next_token ($) { Line 1178  sub _get_next_token ($) {
1178            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1179          }          }
1180          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1181            $self->{s_kwd} = '';
1182          !!!next-input-character;          !!!next-input-character;
1183    
1184          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 1032  sub _get_next_token ($) { Line 1202  sub _get_next_token ($) {
1202            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1203          }          }
1204          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1205            $self->{s_kwd} = '';
1206          ## reconsume          ## reconsume
1207    
1208          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 1040  sub _get_next_token ($) { Line 1211  sub _get_next_token ($) {
1211        } else {        } else {
1212          if ($self->{nc} == 0x003D) { # =          if ($self->{nc} == 0x003D) { # =
1213            !!!cp (93);            !!!cp (93);
1214              ## XML5: Not a parse error.
1215            !!!parse-error (type => 'bad attribute value');            !!!parse-error (type => 'bad attribute value');
1216            } elsif ($self->{is_xml}) {
1217              !!!cp (93.1);
1218              ## XML5: No parse error.
1219              !!!parse-error (type => 'unquoted attr value'); ## TODO
1220          } else {          } else {
1221            !!!cp (94);            !!!cp (94);
1222          }          }
# Line 1050  sub _get_next_token ($) { Line 1226  sub _get_next_token ($) {
1226          redo A;          redo A;
1227        }        }
1228      } elsif ($self->{state} == ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE) {      } elsif ($self->{state} == ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE) {
1229          ## XML5: "Tag attribute value double quoted state".
1230          
1231        if ($self->{nc} == 0x0022) { # "        if ($self->{nc} == 0x0022) { # "
1232          !!!cp (95);          !!!cp (95);
1233            ## XML5: "Tag attribute name before state".
1234          $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;          $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;
1235          !!!next-input-character;          !!!next-input-character;
1236          redo A;          redo A;
1237        } elsif ($self->{nc} == 0x0026) { # &        } elsif ($self->{nc} == 0x0026) { # &
1238          !!!cp (96);          !!!cp (96);
1239            ## XML5: Not defined yet.
1240    
1241          ## NOTE: In the spec, the tokenizer is switched to the          ## NOTE: In the spec, the tokenizer is switched to the
1242          ## "entity in attribute value state".  In this implementation, the          ## "entity in attribute value state".  In this implementation, the
1243          ## tokenizer is switched to the |ENTITY_STATE|, which is an          ## tokenizer is switched to the |ENTITY_STATE|, which is an
# Line 1084  sub _get_next_token ($) { Line 1265  sub _get_next_token ($) {
1265            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1266          }          }
1267          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1268            $self->{s_kwd} = '';
1269          ## reconsume          ## reconsume
1270    
1271          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1272    
1273          redo A;          redo A;
1274        } else {        } else {
1275          !!!cp (100);          if ($self->{is_xml} and $self->{nc} == 0x003C) { # <
1276              !!!cp (100);
1277              ## XML5: Not a parse error.
1278              !!!parse-error (type => 'lt in attr value'); ## TODO: type
1279            } else {
1280              !!!cp (100.1);
1281            }
1282          $self->{ca}->{value} .= chr ($self->{nc});          $self->{ca}->{value} .= chr ($self->{nc});
1283          $self->{read_until}->($self->{ca}->{value},          $self->{read_until}->($self->{ca}->{value},
1284                                q["&],                                q["&<],
1285                                length $self->{ca}->{value});                                length $self->{ca}->{value});
1286    
1287          ## Stay in the state          ## Stay in the state
# Line 1101  sub _get_next_token ($) { Line 1289  sub _get_next_token ($) {
1289          redo A;          redo A;
1290        }        }
1291      } elsif ($self->{state} == ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE) {      } elsif ($self->{state} == ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE) {
1292          ## XML5: "Tag attribute value single quoted state".
1293    
1294        if ($self->{nc} == 0x0027) { # '        if ($self->{nc} == 0x0027) { # '
1295          !!!cp (101);          !!!cp (101);
1296            ## XML5: "Before attribute name state" (sic).
1297          $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;          $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;
1298          !!!next-input-character;          !!!next-input-character;
1299          redo A;          redo A;
1300        } elsif ($self->{nc} == 0x0026) { # &        } elsif ($self->{nc} == 0x0026) { # &
1301          !!!cp (102);          !!!cp (102);
1302            ## XML5: Not defined yet.
1303    
1304          ## NOTE: In the spec, the tokenizer is switched to the          ## NOTE: In the spec, the tokenizer is switched to the
1305          ## "entity in attribute value state".  In this implementation, the          ## "entity in attribute value state".  In this implementation, the
1306          ## tokenizer is switched to the |ENTITY_STATE|, which is an          ## tokenizer is switched to the |ENTITY_STATE|, which is an
# Line 1135  sub _get_next_token ($) { Line 1328  sub _get_next_token ($) {
1328            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1329          }          }
1330          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1331            $self->{s_kwd} = '';
1332          ## reconsume          ## reconsume
1333    
1334          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1335    
1336          redo A;          redo A;
1337        } else {        } else {
1338          !!!cp (106);          if ($self->{is_xml} and $self->{nc} == 0x003C) { # <
1339              !!!cp (106);
1340              ## XML5: Not a parse error.
1341              !!!parse-error (type => 'lt in attr value'); ## TODO: type
1342            } else {
1343              !!!cp (106.1);
1344            }
1345          $self->{ca}->{value} .= chr ($self->{nc});          $self->{ca}->{value} .= chr ($self->{nc});
1346          $self->{read_until}->($self->{ca}->{value},          $self->{read_until}->($self->{ca}->{value},
1347                                q['&],                                q['&<],
1348                                length $self->{ca}->{value});                                length $self->{ca}->{value});
1349    
1350          ## Stay in the state          ## Stay in the state
# Line 1152  sub _get_next_token ($) { Line 1352  sub _get_next_token ($) {
1352          redo A;          redo A;
1353        }        }
1354      } elsif ($self->{state} == ATTRIBUTE_VALUE_UNQUOTED_STATE) {      } elsif ($self->{state} == ATTRIBUTE_VALUE_UNQUOTED_STATE) {
1355          ## XML5: "Tag attribute value unquoted state".
1356    
1357        if ($is_space->{$self->{nc}}) {        if ($is_space->{$self->{nc}}) {
1358          !!!cp (107);          !!!cp (107);
1359            ## XML5: "Tag attribute name before state".
1360          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
1361          !!!next-input-character;          !!!next-input-character;
1362          redo A;          redo A;
1363        } elsif ($self->{nc} == 0x0026) { # &        } elsif ($self->{nc} == 0x0026) { # &
1364          !!!cp (108);          !!!cp (108);
1365    
1366            ## XML5: Not defined yet.
1367    
1368          ## NOTE: In the spec, the tokenizer is switched to the          ## NOTE: In the spec, the tokenizer is switched to the
1369          ## "entity in attribute value state".  In this implementation, the          ## "entity in attribute value state".  In this implementation, the
1370          ## tokenizer is switched to the |ENTITY_STATE|, which is an          ## tokenizer is switched to the |ENTITY_STATE|, which is an
# Line 1185  sub _get_next_token ($) { Line 1391  sub _get_next_token ($) {
1391            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1392          }          }
1393          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1394            $self->{s_kwd} = '';
1395          !!!next-input-character;          !!!next-input-character;
1396    
1397          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 1208  sub _get_next_token ($) { Line 1415  sub _get_next_token ($) {
1415            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1416          }          }
1417          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1418            $self->{s_kwd} = '';
1419          ## reconsume          ## reconsume
1420    
1421          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 1220  sub _get_next_token ($) { Line 1428  sub _get_next_token ($) {
1428               0x003D => 1, # =               0x003D => 1, # =
1429              }->{$self->{nc}}) {              }->{$self->{nc}}) {
1430            !!!cp (115);            !!!cp (115);
1431              ## XML5: Not a parse error.
1432            !!!parse-error (type => 'bad attribute value');            !!!parse-error (type => 'bad attribute value');
1433          } else {          } else {
1434            !!!cp (116);            !!!cp (116);
# Line 1256  sub _get_next_token ($) { Line 1465  sub _get_next_token ($) {
1465            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1466          }          }
1467          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1468            $self->{s_kwd} = '';
1469          !!!next-input-character;          !!!next-input-character;
1470    
1471          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 1283  sub _get_next_token ($) { Line 1493  sub _get_next_token ($) {
1493            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1494          }          }
1495          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1496            $self->{s_kwd} = '';
1497          ## Reconsume.          ## Reconsume.
1498          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1499          redo A;          redo A;
# Line 1294  sub _get_next_token ($) { Line 1505  sub _get_next_token ($) {
1505          redo A;          redo A;
1506        }        }
1507      } elsif ($self->{state} == SELF_CLOSING_START_TAG_STATE) {      } elsif ($self->{state} == SELF_CLOSING_START_TAG_STATE) {
1508          ## XML5: "Empty tag state".
1509    
1510        if ($self->{nc} == 0x003E) { # >        if ($self->{nc} == 0x003E) { # >
1511          if ($self->{ct}->{type} == END_TAG_TOKEN) {          if ($self->{ct}->{type} == END_TAG_TOKEN) {
1512            !!!cp ('124.2');            !!!cp ('124.2');
# Line 1313  sub _get_next_token ($) { Line 1526  sub _get_next_token ($) {
1526          }          }
1527    
1528          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1529            $self->{s_kwd} = '';
1530          !!!next-input-character;          !!!next-input-character;
1531    
1532          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
# Line 1334  sub _get_next_token ($) { Line 1548  sub _get_next_token ($) {
1548          } else {          } else {
1549            die "$0: $self->{ct}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1550          }          }
1551            ## XML5: "Tag attribute name before state".
1552          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1553            $self->{s_kwd} = '';
1554          ## Reconsume.          ## Reconsume.
1555          !!!emit ($self->{ct}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1556          redo A;          redo A;
# Line 1355  sub _get_next_token ($) { Line 1571  sub _get_next_token ($) {
1571        if ($self->{nc} == 0x003E) { # >        if ($self->{nc} == 0x003E) { # >
1572          !!!cp (124);          !!!cp (124);
1573          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1574            $self->{s_kwd} = '';
1575          !!!next-input-character;          !!!next-input-character;
1576    
1577          !!!emit ($self->{ct}); # comment          !!!emit ($self->{ct}); # comment
# Line 1362  sub _get_next_token ($) { Line 1579  sub _get_next_token ($) {
1579        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
1580          !!!cp (125);          !!!cp (125);
1581          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1582            $self->{s_kwd} = '';
1583          ## reconsume          ## reconsume
1584    
1585          !!!emit ($self->{ct}); # comment          !!!emit ($self->{ct}); # comment
# Line 1390  sub _get_next_token ($) { Line 1608  sub _get_next_token ($) {
1608          ## ASCII case-insensitive.          ## ASCII case-insensitive.
1609          !!!cp (130);          !!!cp (130);
1610          $self->{state} = MD_DOCTYPE_STATE;          $self->{state} = MD_DOCTYPE_STATE;
1611          $self->{s_kwd} = chr $self->{nc};          $self->{kwd} = chr $self->{nc};
1612          !!!next-input-character;          !!!next-input-character;
1613          redo A;          redo A;
1614        } elsif ((($self->{insertion_mode} & IN_FOREIGN_CONTENT_IM and        } elsif ((($self->{insertion_mode} & IN_FOREIGN_CONTENT_IM and
# Line 1399  sub _get_next_token ($) { Line 1617  sub _get_next_token ($) {
1617                 $self->{nc} == 0x005B) { # [                 $self->{nc} == 0x005B) { # [
1618          !!!cp (135.4);                          !!!cp (135.4);                
1619          $self->{state} = MD_CDATA_STATE;          $self->{state} = MD_CDATA_STATE;
1620          $self->{s_kwd} = '[';          $self->{kwd} = '[';
1621          !!!next-input-character;          !!!next-input-character;
1622          redo A;          redo A;
1623        } else {        } else {
# Line 1423  sub _get_next_token ($) { Line 1641  sub _get_next_token ($) {
1641                                    line => $self->{line_prev},                                    line => $self->{line_prev},
1642                                    column => $self->{column_prev} - 2,                                    column => $self->{column_prev} - 2,
1643                                   };                                   };
1644          $self->{state} = COMMENT_START_STATE;          $self->{state} = COMMENT_START_STATE; ## XML5: "comment state".
1645          !!!next-input-character;          !!!next-input-character;
1646          redo A;          redo A;
1647        } else {        } else {
# Line 1449  sub _get_next_token ($) { Line 1667  sub _get_next_token ($) {
1667              0x0054, # T              0x0054, # T
1668              0x0059, # Y              0x0059, # Y
1669              0x0050, # P              0x0050, # P
1670            ]->[length $self->{s_kwd}] or            ]->[length $self->{kwd}] or
1671            $self->{nc} == [            $self->{nc} == [
1672              undef,              undef,
1673              0x006F, # o              0x006F, # o
# Line 1457  sub _get_next_token ($) { Line 1675  sub _get_next_token ($) {
1675              0x0074, # t              0x0074, # t
1676              0x0079, # y              0x0079, # y
1677              0x0070, # p              0x0070, # p
1678            ]->[length $self->{s_kwd}]) {            ]->[length $self->{kwd}]) {
1679          !!!cp (131);          !!!cp (131);
1680          ## Stay in the state.          ## Stay in the state.
1681          $self->{s_kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
1682          !!!next-input-character;          !!!next-input-character;
1683          redo A;          redo A;
1684        } elsif ((length $self->{s_kwd}) == 6 and        } elsif ((length $self->{kwd}) == 6 and
1685                 ($self->{nc} == 0x0045 or # E                 ($self->{nc} == 0x0045 or # E
1686                  $self->{nc} == 0x0065)) { # e                  $self->{nc} == 0x0065)) { # e
1687          !!!cp (129);          if ($self->{is_xml} and
1688                ($self->{kwd} ne 'DOCTYP' or $self->{nc} == 0x0065)) {
1689              !!!cp (129);
1690              ## XML5: case-sensitive.
1691              !!!parse-error (type => 'lowercase keyword', ## TODO
1692                              text => 'DOCTYPE',
1693                              line => $self->{line_prev},
1694                              column => $self->{column_prev} - 5);
1695            } else {
1696              !!!cp (129.1);
1697            }
1698          $self->{state} = DOCTYPE_STATE;          $self->{state} = DOCTYPE_STATE;
1699          $self->{ct} = {type => DOCTYPE_TOKEN,          $self->{ct} = {type => DOCTYPE_TOKEN,
1700                                    quirks => 1,                                    quirks => 1,
# Line 1479  sub _get_next_token ($) { Line 1707  sub _get_next_token ($) {
1707          !!!cp (132);                  !!!cp (132);        
1708          !!!parse-error (type => 'bogus comment',          !!!parse-error (type => 'bogus comment',
1709                          line => $self->{line_prev},                          line => $self->{line_prev},
1710                          column => $self->{column_prev} - 1 - length $self->{s_kwd});                          column => $self->{column_prev} - 1 - length $self->{kwd});
1711          $self->{state} = BOGUS_COMMENT_STATE;          $self->{state} = BOGUS_COMMENT_STATE;
1712          ## Reconsume.          ## Reconsume.
1713          $self->{ct} = {type => COMMENT_TOKEN,          $self->{ct} = {type => COMMENT_TOKEN,
1714                                    data => $self->{s_kwd},                                    data => $self->{kwd},
1715                                    line => $self->{line_prev},                                    line => $self->{line_prev},
1716                                    column => $self->{column_prev} - 1 - length $self->{s_kwd},                                    column => $self->{column_prev} - 1 - length $self->{kwd},
1717                                   };                                   };
1718          redo A;          redo A;
1719        }        }
# Line 1496  sub _get_next_token ($) { Line 1724  sub _get_next_token ($) {
1724              '[CD' => 0x0041, # A              '[CD' => 0x0041, # A
1725              '[CDA' => 0x0054, # T              '[CDA' => 0x0054, # T
1726              '[CDAT' => 0x0041, # A              '[CDAT' => 0x0041, # A
1727            }->{$self->{s_kwd}}) {            }->{$self->{kwd}}) {
1728          !!!cp (135.1);          !!!cp (135.1);
1729          ## Stay in the state.          ## Stay in the state.
1730          $self->{s_kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
1731          !!!next-input-character;          !!!next-input-character;
1732          redo A;          redo A;
1733        } elsif ($self->{s_kwd} eq '[CDATA' and        } elsif ($self->{kwd} eq '[CDATA' and
1734                 $self->{nc} == 0x005B) { # [                 $self->{nc} == 0x005B) { # [
1735          !!!cp (135.2);          if ($self->{is_xml} and
1736                not $self->{tainted} and
1737                @{$self->{open_elements} or []} == 0) {
1738              !!!cp (135.2);
1739              !!!parse-error (type => 'cdata outside of root element',
1740                              line => $self->{line_prev},
1741                              column => $self->{column_prev} - 7);
1742              $self->{tainted} = 1;
1743            } else {
1744              !!!cp (135.21);
1745            }
1746    
1747          $self->{ct} = {type => CHARACTER_TOKEN,          $self->{ct} = {type => CHARACTER_TOKEN,
1748                                    data => '',                                    data => '',
1749                                    line => $self->{line_prev},                                    line => $self->{line_prev},
# Line 1516  sub _get_next_token ($) { Line 1755  sub _get_next_token ($) {
1755          !!!cp (135.3);          !!!cp (135.3);
1756          !!!parse-error (type => 'bogus comment',          !!!parse-error (type => 'bogus comment',
1757                          line => $self->{line_prev},                          line => $self->{line_prev},
1758                          column => $self->{column_prev} - 1 - length $self->{s_kwd});                          column => $self->{column_prev} - 1 - length $self->{kwd});
1759          $self->{state} = BOGUS_COMMENT_STATE;          $self->{state} = BOGUS_COMMENT_STATE;
1760          ## Reconsume.          ## Reconsume.
1761          $self->{ct} = {type => COMMENT_TOKEN,          $self->{ct} = {type => COMMENT_TOKEN,
1762                                    data => $self->{s_kwd},                                    data => $self->{kwd},
1763                                    line => $self->{line_prev},                                    line => $self->{line_prev},
1764                                    column => $self->{column_prev} - 1 - length $self->{s_kwd},                                    column => $self->{column_prev} - 1 - length $self->{kwd},
1765                                   };                                   };
1766          redo A;          redo A;
1767        }        }
# Line 1536  sub _get_next_token ($) { Line 1775  sub _get_next_token ($) {
1775          !!!cp (138);          !!!cp (138);
1776          !!!parse-error (type => 'bogus comment');          !!!parse-error (type => 'bogus comment');
1777          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1778            $self->{s_kwd} = '';
1779          !!!next-input-character;          !!!next-input-character;
1780    
1781          !!!emit ($self->{ct}); # comment          !!!emit ($self->{ct}); # comment
# Line 1545  sub _get_next_token ($) { Line 1785  sub _get_next_token ($) {
1785          !!!cp (139);          !!!cp (139);
1786          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
1787          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1788            $self->{s_kwd} = '';
1789          ## reconsume          ## reconsume
1790    
1791          !!!emit ($self->{ct}); # comment          !!!emit ($self->{ct}); # comment
# Line 1568  sub _get_next_token ($) { Line 1809  sub _get_next_token ($) {
1809          !!!cp (142);          !!!cp (142);
1810          !!!parse-error (type => 'bogus comment');          !!!parse-error (type => 'bogus comment');
1811          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1812            $self->{s_kwd} = '';
1813          !!!next-input-character;          !!!next-input-character;
1814    
1815          !!!emit ($self->{ct}); # comment          !!!emit ($self->{ct}); # comment
# Line 1577  sub _get_next_token ($) { Line 1819  sub _get_next_token ($) {
1819          !!!cp (143);          !!!cp (143);
1820          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
1821          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1822            $self->{s_kwd} = '';
1823          ## reconsume          ## reconsume
1824    
1825          !!!emit ($self->{ct}); # comment          !!!emit ($self->{ct}); # comment
# Line 1600  sub _get_next_token ($) { Line 1843  sub _get_next_token ($) {
1843          !!!cp (146);          !!!cp (146);
1844          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
1845          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1846            $self->{s_kwd} = '';
1847          ## reconsume          ## reconsume
1848    
1849          !!!emit ($self->{ct}); # comment          !!!emit ($self->{ct}); # comment
# Line 1617  sub _get_next_token ($) { Line 1861  sub _get_next_token ($) {
1861          redo A;          redo A;
1862        }        }
1863      } elsif ($self->{state} == COMMENT_END_DASH_STATE) {      } elsif ($self->{state} == COMMENT_END_DASH_STATE) {
1864          ## XML5: "comment dash state".
1865    
1866        if ($self->{nc} == 0x002D) { # -        if ($self->{nc} == 0x002D) { # -
1867          !!!cp (148);          !!!cp (148);
1868          $self->{state} = COMMENT_END_STATE;          $self->{state} = COMMENT_END_STATE;
# Line 1626  sub _get_next_token ($) { Line 1872  sub _get_next_token ($) {
1872          !!!cp (149);          !!!cp (149);
1873          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
1874          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1875            $self->{s_kwd} = '';
1876          ## reconsume          ## reconsume
1877    
1878          !!!emit ($self->{ct}); # comment          !!!emit ($self->{ct}); # comment
# Line 1642  sub _get_next_token ($) { Line 1889  sub _get_next_token ($) {
1889        if ($self->{nc} == 0x003E) { # >        if ($self->{nc} == 0x003E) { # >
1890          !!!cp (151);          !!!cp (151);
1891          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1892            $self->{s_kwd} = '';
1893          !!!next-input-character;          !!!next-input-character;
1894    
1895          !!!emit ($self->{ct}); # comment          !!!emit ($self->{ct}); # comment
# Line 1649  sub _get_next_token ($) { Line 1897  sub _get_next_token ($) {
1897          redo A;          redo A;
1898        } elsif ($self->{nc} == 0x002D) { # -        } elsif ($self->{nc} == 0x002D) { # -
1899          !!!cp (152);          !!!cp (152);
1900            ## XML5: Not a parse error.
1901          !!!parse-error (type => 'dash in comment',          !!!parse-error (type => 'dash in comment',
1902                          line => $self->{line_prev},                          line => $self->{line_prev},
1903                          column => $self->{column_prev});                          column => $self->{column_prev});
# Line 1660  sub _get_next_token ($) { Line 1909  sub _get_next_token ($) {
1909          !!!cp (153);          !!!cp (153);
1910          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
1911          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1912            $self->{s_kwd} = '';
1913          ## reconsume          ## reconsume
1914    
1915          !!!emit ($self->{ct}); # comment          !!!emit ($self->{ct}); # comment
# Line 1667  sub _get_next_token ($) { Line 1917  sub _get_next_token ($) {
1917          redo A;          redo A;
1918        } else {        } else {
1919          !!!cp (154);          !!!cp (154);
1920            ## XML5: Not a parse error.
1921          !!!parse-error (type => 'dash in comment',          !!!parse-error (type => 'dash in comment',
1922                          line => $self->{line_prev},                          line => $self->{line_prev},
1923                          column => $self->{column_prev});                          column => $self->{column_prev});
# Line 1683  sub _get_next_token ($) { Line 1934  sub _get_next_token ($) {
1934          redo A;          redo A;
1935        } else {        } else {
1936          !!!cp (156);          !!!cp (156);
1937            ## XML5: Unless EOF, swith to the bogus comment state.
1938          !!!parse-error (type => 'no space before DOCTYPE name');          !!!parse-error (type => 'no space before DOCTYPE name');
1939          $self->{state} = BEFORE_DOCTYPE_NAME_STATE;          $self->{state} = BEFORE_DOCTYPE_NAME_STATE;
1940          ## reconsume          ## reconsume
1941          redo A;          redo A;
1942        }        }
1943      } elsif ($self->{state} == BEFORE_DOCTYPE_NAME_STATE) {      } elsif ($self->{state} == BEFORE_DOCTYPE_NAME_STATE) {
1944          ## XML5: "DOCTYPE root name before state".
1945    
1946        if ($is_space->{$self->{nc}}) {        if ($is_space->{$self->{nc}}) {
1947          !!!cp (157);          !!!cp (157);
1948          ## Stay in the state          ## Stay in the state
# Line 1696  sub _get_next_token ($) { Line 1950  sub _get_next_token ($) {
1950          redo A;          redo A;
1951        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
1952          !!!cp (158);          !!!cp (158);
1953            ## XML5: No parse error.
1954          !!!parse-error (type => 'no DOCTYPE name');          !!!parse-error (type => 'no DOCTYPE name');
1955          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1956            $self->{s_kwd} = '';
1957          !!!next-input-character;          !!!next-input-character;
1958    
1959          !!!emit ($self->{ct}); # DOCTYPE (quirks)          !!!emit ($self->{ct}); # DOCTYPE (quirks)
# Line 1707  sub _get_next_token ($) { Line 1963  sub _get_next_token ($) {
1963          !!!cp (159);          !!!cp (159);
1964          !!!parse-error (type => 'no DOCTYPE name');          !!!parse-error (type => 'no DOCTYPE name');
1965          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1966            $self->{s_kwd} = '';
1967          ## reconsume          ## reconsume
1968    
1969          !!!emit ($self->{ct}); # DOCTYPE (quirks)          !!!emit ($self->{ct}); # DOCTYPE (quirks)
1970    
1971          redo A;          redo A;
1972          } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [
1973            !!!cp (159.1);
1974            !!!parse-error (type => 'no DOCTYPE name');
1975            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
1976            !!!next-input-character;
1977            redo A;
1978        } else {        } else {
1979          !!!cp (160);          !!!cp (160);
1980          $self->{ct}->{name} = chr $self->{nc};          $self->{ct}->{name} = chr $self->{nc};
# Line 1721  sub _get_next_token ($) { Line 1984  sub _get_next_token ($) {
1984          redo A;          redo A;
1985        }        }
1986      } elsif ($self->{state} == DOCTYPE_NAME_STATE) {      } elsif ($self->{state} == DOCTYPE_NAME_STATE) {
1987  ## ISSUE: Redundant "First," in the spec.        ## XML5: "DOCTYPE root name state".
1988    
1989          ## ISSUE: Redundant "First," in the spec.
1990    
1991        if ($is_space->{$self->{nc}}) {        if ($is_space->{$self->{nc}}) {
1992          !!!cp (161);          !!!cp (161);
1993          $self->{state} = AFTER_DOCTYPE_NAME_STATE;          $self->{state} = AFTER_DOCTYPE_NAME_STATE;
# Line 1730  sub _get_next_token ($) { Line 1996  sub _get_next_token ($) {
1996        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
1997          !!!cp (162);          !!!cp (162);
1998          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1999            $self->{s_kwd} = '';
2000          !!!next-input-character;          !!!next-input-character;
2001    
2002          !!!emit ($self->{ct}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
# Line 1739  sub _get_next_token ($) { Line 2006  sub _get_next_token ($) {
2006          !!!cp (163);          !!!cp (163);
2007          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2008          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2009            $self->{s_kwd} = '';
2010          ## reconsume          ## reconsume
2011    
2012          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2013          !!!emit ($self->{ct}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2014    
2015          redo A;          redo A;
2016          } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [
2017            !!!cp (163.1);
2018            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
2019            !!!next-input-character;
2020            redo A;
2021        } else {        } else {
2022          !!!cp (164);          !!!cp (164);
2023          $self->{ct}->{name}          $self->{ct}->{name}
# Line 1754  sub _get_next_token ($) { Line 2027  sub _get_next_token ($) {
2027          redo A;          redo A;
2028        }        }
2029      } elsif ($self->{state} == AFTER_DOCTYPE_NAME_STATE) {      } elsif ($self->{state} == AFTER_DOCTYPE_NAME_STATE) {
2030          ## XML5: Corresponding to XML5's "DOCTYPE root name after
2031          ## state", but implemented differently.
2032    
2033        if ($is_space->{$self->{nc}}) {        if ($is_space->{$self->{nc}}) {
2034          !!!cp (165);          !!!cp (165);
2035          ## Stay in the state          ## Stay in the state
# Line 1762  sub _get_next_token ($) { Line 2038  sub _get_next_token ($) {
2038        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2039          !!!cp (166);          !!!cp (166);
2040          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2041            $self->{s_kwd} = '';
2042          !!!next-input-character;          !!!next-input-character;
2043    
2044          !!!emit ($self->{ct}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
# Line 1771  sub _get_next_token ($) { Line 2048  sub _get_next_token ($) {
2048          !!!cp (167);          !!!cp (167);
2049          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2050          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2051            $self->{s_kwd} = '';
2052          ## reconsume          ## reconsume
2053    
2054          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
# Line 1779  sub _get_next_token ($) { Line 2057  sub _get_next_token ($) {
2057          redo A;          redo A;
2058        } elsif ($self->{nc} == 0x0050 or # P        } elsif ($self->{nc} == 0x0050 or # P
2059                 $self->{nc} == 0x0070) { # p                 $self->{nc} == 0x0070) { # p
2060            !!!cp (167.1);
2061          $self->{state} = PUBLIC_STATE;          $self->{state} = PUBLIC_STATE;
2062          $self->{s_kwd} = chr $self->{nc};          $self->{kwd} = chr $self->{nc};
2063          !!!next-input-character;          !!!next-input-character;
2064          redo A;          redo A;
2065        } elsif ($self->{nc} == 0x0053 or # S        } elsif ($self->{nc} == 0x0053 or # S
2066                 $self->{nc} == 0x0073) { # s                 $self->{nc} == 0x0073) { # s
2067            !!!cp (167.2);
2068          $self->{state} = SYSTEM_STATE;          $self->{state} = SYSTEM_STATE;
2069          $self->{s_kwd} = chr $self->{nc};          $self->{kwd} = chr $self->{nc};
2070            !!!next-input-character;
2071            redo A;
2072          } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [
2073            !!!cp (167.3);
2074            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
2075            $self->{ct}->{has_internal_subset} = 1; # DOCTYPE
2076          !!!next-input-character;          !!!next-input-character;
2077          redo A;          redo A;
2078        } else {        } else {
# Line 1806  sub _get_next_token ($) { Line 2092  sub _get_next_token ($) {
2092              0x0042, # B              0x0042, # B
2093              0x004C, # L              0x004C, # L
2094              0x0049, # I              0x0049, # I
2095            ]->[length $self->{s_kwd}] or            ]->[length $self->{kwd}] or
2096            $self->{nc} == [            $self->{nc} == [
2097              undef,              undef,
2098              0x0075, # u              0x0075, # u
2099              0x0062, # b              0x0062, # b
2100              0x006C, # l              0x006C, # l
2101              0x0069, # i              0x0069, # i
2102            ]->[length $self->{s_kwd}]) {            ]->[length $self->{kwd}]) {
2103          !!!cp (175);          !!!cp (175);
2104          ## Stay in the state.          ## Stay in the state.
2105          $self->{s_kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
2106          !!!next-input-character;          !!!next-input-character;
2107          redo A;          redo A;
2108        } elsif ((length $self->{s_kwd}) == 5 and        } elsif ((length $self->{kwd}) == 5 and
2109                 ($self->{nc} == 0x0043 or # C                 ($self->{nc} == 0x0043 or # C
2110                  $self->{nc} == 0x0063)) { # c                  $self->{nc} == 0x0063)) { # c
2111          !!!cp (168);          if ($self->{is_xml} and
2112                ($self->{kwd} ne 'PUBLI' or $self->{nc} == 0x0063)) { # c
2113              !!!cp (168.1);
2114              !!!parse-error (type => 'lowercase keyword', ## TODO: type
2115                              text => 'PUBLIC',
2116                              line => $self->{line_prev},
2117                              column => $self->{column_prev} - 4);
2118            } else {
2119              !!!cp (168);
2120            }
2121          $self->{state} = BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE;          $self->{state} = BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
2122          !!!next-input-character;          !!!next-input-character;
2123          redo A;          redo A;
# Line 1830  sub _get_next_token ($) { Line 2125  sub _get_next_token ($) {
2125          !!!cp (169);          !!!cp (169);
2126          !!!parse-error (type => 'string after DOCTYPE name',          !!!parse-error (type => 'string after DOCTYPE name',
2127                          line => $self->{line_prev},                          line => $self->{line_prev},
2128                          column => $self->{column_prev} + 1 - length $self->{s_kwd});                          column => $self->{column_prev} + 1 - length $self->{kwd});
2129          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2130    
2131          $self->{state} = BOGUS_DOCTYPE_STATE;          $self->{state} = BOGUS_DOCTYPE_STATE;
# Line 1845  sub _get_next_token ($) { Line 2140  sub _get_next_token ($) {
2140              0x0053, # S              0x0053, # S
2141              0x0054, # T              0x0054, # T
2142              0x0045, # E              0x0045, # E
2143            ]->[length $self->{s_kwd}] or            ]->[length $self->{kwd}] or
2144            $self->{nc} == [            $self->{nc} == [
2145              undef,              undef,
2146              0x0079, # y              0x0079, # y
2147              0x0073, # s              0x0073, # s
2148              0x0074, # t              0x0074, # t
2149              0x0065, # e              0x0065, # e
2150            ]->[length $self->{s_kwd}]) {            ]->[length $self->{kwd}]) {
2151          !!!cp (170);          !!!cp (170);
2152          ## Stay in the state.          ## Stay in the state.
2153          $self->{s_kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
2154          !!!next-input-character;          !!!next-input-character;
2155          redo A;          redo A;
2156        } elsif ((length $self->{s_kwd}) == 5 and        } elsif ((length $self->{kwd}) == 5 and
2157                 ($self->{nc} == 0x004D or # M                 ($self->{nc} == 0x004D or # M
2158                  $self->{nc} == 0x006D)) { # m                  $self->{nc} == 0x006D)) { # m
2159          !!!cp (171);          if ($self->{is_xml} and
2160                ($self->{kwd} ne 'SYSTE' or $self->{nc} == 0x006D)) { # m
2161              !!!cp (171.1);
2162              !!!parse-error (type => 'lowercase keyword', ## TODO: type
2163                              text => 'SYSTEM',
2164                              line => $self->{line_prev},
2165                              column => $self->{column_prev} - 4);
2166            } else {
2167              !!!cp (171);
2168            }
2169          $self->{state} = BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE;          $self->{state} = BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
2170          !!!next-input-character;          !!!next-input-character;
2171          redo A;          redo A;
# Line 1869  sub _get_next_token ($) { Line 2173  sub _get_next_token ($) {
2173          !!!cp (172);          !!!cp (172);
2174          !!!parse-error (type => 'string after DOCTYPE name',          !!!parse-error (type => 'string after DOCTYPE name',
2175                          line => $self->{line_prev},                          line => $self->{line_prev},
2176                          column => $self->{column_prev} + 1 - length $self->{s_kwd});                          column => $self->{column_prev} + 1 - length $self->{kwd});
2177          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2178    
2179          $self->{state} = BOGUS_DOCTYPE_STATE;          $self->{state} = BOGUS_DOCTYPE_STATE;
# Line 1899  sub _get_next_token ($) { Line 2203  sub _get_next_token ($) {
2203          !!!parse-error (type => 'no PUBLIC literal');          !!!parse-error (type => 'no PUBLIC literal');
2204    
2205          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2206            $self->{s_kwd} = '';
2207          !!!next-input-character;          !!!next-input-character;
2208    
2209          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
# Line 1910  sub _get_next_token ($) { Line 2215  sub _get_next_token ($) {
2215          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2216    
2217          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2218            $self->{s_kwd} = '';
2219          ## reconsume          ## reconsume
2220    
2221          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2222          !!!emit ($self->{ct}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2223    
2224          redo A;          redo A;
2225          } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [
2226            !!!cp (186.1);
2227            !!!parse-error (type => 'no PUBLIC literal');
2228            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
2229            $self->{ct}->{has_internal_subset} = 1; # DOCTYPE
2230            !!!next-input-character;
2231            redo A;
2232        } else {        } else {
2233          !!!cp (186);          !!!cp (186);
2234          !!!parse-error (type => 'string after PUBLIC');          !!!parse-error (type => 'string after PUBLIC');
# Line 1936  sub _get_next_token ($) { Line 2249  sub _get_next_token ($) {
2249          !!!parse-error (type => 'unclosed PUBLIC literal');          !!!parse-error (type => 'unclosed PUBLIC literal');
2250    
2251          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2252            $self->{s_kwd} = '';
2253          !!!next-input-character;          !!!next-input-character;
2254    
2255          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
# Line 1947  sub _get_next_token ($) { Line 2261  sub _get_next_token ($) {
2261          !!!parse-error (type => 'unclosed PUBLIC literal');          !!!parse-error (type => 'unclosed PUBLIC literal');
2262    
2263          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2264            $self->{s_kwd} = '';
2265          ## reconsume          ## reconsume
2266    
2267          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
# Line 1975  sub _get_next_token ($) { Line 2290  sub _get_next_token ($) {
2290          !!!parse-error (type => 'unclosed PUBLIC literal');          !!!parse-error (type => 'unclosed PUBLIC literal');
2291    
2292          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2293            $self->{s_kwd} = '';
2294          !!!next-input-character;          !!!next-input-character;
2295    
2296          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
# Line 1986  sub _get_next_token ($) { Line 2302  sub _get_next_token ($) {
2302          !!!parse-error (type => 'unclosed PUBLIC literal');          !!!parse-error (type => 'unclosed PUBLIC literal');
2303    
2304          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2305            $self->{s_kwd} = '';
2306          ## reconsume          ## reconsume
2307    
2308          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
# Line 2022  sub _get_next_token ($) { Line 2339  sub _get_next_token ($) {
2339          !!!next-input-character;          !!!next-input-character;
2340          redo A;          redo A;
2341        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2342          !!!cp (198);          if ($self->{is_xml}) {
2343              !!!cp (198.1);
2344              !!!parse-error (type => 'no SYSTEM literal');
2345            } else {
2346              !!!cp (198);
2347            }
2348          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2349            $self->{s_kwd} = '';
2350          !!!next-input-character;          !!!next-input-character;
2351    
2352          !!!emit ($self->{ct}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
# Line 2034  sub _get_next_token ($) { Line 2357  sub _get_next_token ($) {
2357          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2358    
2359          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2360            $self->{s_kwd} = '';
2361          ## reconsume          ## reconsume
2362    
2363          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2364          !!!emit ($self->{ct}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2365    
2366          redo A;          redo A;
2367          } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [
2368            !!!cp (200.1);
2369            !!!parse-error (type => 'no SYSTEM literal');
2370            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
2371            $self->{ct}->{has_internal_subset} = 1; # DOCTYPE
2372            !!!next-input-character;
2373            redo A;
2374        } else {        } else {
2375          !!!cp (200);          !!!cp (200);
2376          !!!parse-error (type => 'string after PUBLIC literal');          !!!parse-error (type => 'string after PUBLIC literal');
# Line 2071  sub _get_next_token ($) { Line 2402  sub _get_next_token ($) {
2402          !!!cp (204);          !!!cp (204);
2403          !!!parse-error (type => 'no SYSTEM literal');          !!!parse-error (type => 'no SYSTEM literal');
2404          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2405            $self->{s_kwd} = '';
2406          !!!next-input-character;          !!!next-input-character;
2407    
2408          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
# Line 2082  sub _get_next_token ($) { Line 2414  sub _get_next_token ($) {
2414          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2415    
2416          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2417            $self->{s_kwd} = '';
2418          ## reconsume          ## reconsume
2419    
2420          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2421          !!!emit ($self->{ct}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2422    
2423          redo A;          redo A;
2424          } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [
2425            !!!cp (206.1);
2426            !!!parse-error (type => 'no SYSTEM literal');
2427    
2428            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
2429            $self->{ct}->{has_internal_subset} = 1; # DOCTYPE
2430            !!!next-input-character;
2431            redo A;
2432        } else {        } else {
2433          !!!cp (206);          !!!cp (206);
2434          !!!parse-error (type => 'string after SYSTEM');          !!!parse-error (type => 'string after SYSTEM');
# Line 2103  sub _get_next_token ($) { Line 2444  sub _get_next_token ($) {
2444          $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;          $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
2445          !!!next-input-character;          !!!next-input-character;
2446          redo A;          redo A;
2447        } elsif ($self->{nc} == 0x003E) { # >        } elsif (not $self->{is_xml} and $self->{nc} == 0x003E) { # >
2448          !!!cp (208);          !!!cp (208);
2449          !!!parse-error (type => 'unclosed SYSTEM literal');          !!!parse-error (type => 'unclosed SYSTEM literal');
2450    
2451          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2452            $self->{s_kwd} = '';
2453          !!!next-input-character;          !!!next-input-character;
2454    
2455          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
# Line 2119  sub _get_next_token ($) { Line 2461  sub _get_next_token ($) {
2461          !!!parse-error (type => 'unclosed SYSTEM literal');          !!!parse-error (type => 'unclosed SYSTEM literal');
2462    
2463          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2464            $self->{s_kwd} = '';
2465          ## reconsume          ## reconsume
2466    
2467          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
# Line 2142  sub _get_next_token ($) { Line 2485  sub _get_next_token ($) {
2485          $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;          $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
2486          !!!next-input-character;          !!!next-input-character;
2487          redo A;          redo A;
2488        } elsif ($self->{nc} == 0x003E) { # >        } elsif (not $self->{is_xml} and $self->{nc} == 0x003E) { # >
2489          !!!cp (212);          !!!cp (212);
2490          !!!parse-error (type => 'unclosed SYSTEM literal');          !!!parse-error (type => 'unclosed SYSTEM literal');
2491    
2492          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2493            $self->{s_kwd} = '';
2494          !!!next-input-character;          !!!next-input-character;
2495    
2496          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
# Line 2158  sub _get_next_token ($) { Line 2502  sub _get_next_token ($) {
2502          !!!parse-error (type => 'unclosed SYSTEM literal');          !!!parse-error (type => 'unclosed SYSTEM literal');
2503    
2504          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2505            $self->{s_kwd} = '';
2506          ## reconsume          ## reconsume
2507    
2508          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
# Line 2184  sub _get_next_token ($) { Line 2529  sub _get_next_token ($) {
2529        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2530          !!!cp (216);          !!!cp (216);
2531          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2532            $self->{s_kwd} = '';
2533          !!!next-input-character;          !!!next-input-character;
2534    
2535          !!!emit ($self->{ct}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
# Line 2193  sub _get_next_token ($) { Line 2539  sub _get_next_token ($) {
2539          !!!cp (217);          !!!cp (217);
2540          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2541          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2542            $self->{s_kwd} = '';
2543          ## reconsume          ## reconsume
2544    
2545          $self->{ct}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2546          !!!emit ($self->{ct}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2547    
2548          redo A;          redo A;
2549          } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [
2550            !!!cp (218.1);
2551            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
2552            $self->{ct}->{has_internal_subset} = 1; # DOCTYPE
2553            !!!next-input-character;
2554            redo A;
2555        } else {        } else {
2556          !!!cp (218);          !!!cp (218);
2557          !!!parse-error (type => 'string after SYSTEM literal');          !!!parse-error (type => 'string after SYSTEM literal');
# Line 2212  sub _get_next_token ($) { Line 2565  sub _get_next_token ($) {
2565        if ($self->{nc} == 0x003E) { # >        if ($self->{nc} == 0x003E) { # >
2566          !!!cp (219);          !!!cp (219);
2567          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2568            $self->{s_kwd} = '';
2569          !!!next-input-character;          !!!next-input-character;
2570    
2571          !!!emit ($self->{ct}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2572    
2573          redo A;          redo A;
2574          } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [
2575            if ($self->{ct}->{has_internal_subset}) { # DOCTYPE
2576              !!!cp (220.2);
2577              ## Stay in the state.
2578              !!!next-input-character;
2579              redo A;
2580            } else {
2581              !!!cp (220.1);
2582              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
2583              $self->{ct}->{has_internal_subset} = 1; # DOCTYPE
2584              !!!next-input-character;
2585              redo A;
2586            }
2587        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
2588          !!!cp (220);          !!!cp (220);
2589          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2590            $self->{s_kwd} = '';
2591          ## reconsume          ## reconsume
2592    
2593          !!!emit ($self->{ct}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
# Line 2228  sub _get_next_token ($) { Line 2596  sub _get_next_token ($) {
2596        } else {        } else {
2597          !!!cp (221);          !!!cp (221);
2598          my $s = '';          my $s = '';
2599          $self->{read_until}->($s, q[>], 0);          $self->{read_until}->($s, q{>[}, 0);
2600    
2601          ## Stay in the state          ## Stay in the state
2602          !!!next-input-character;          !!!next-input-character;
# Line 2238  sub _get_next_token ($) { Line 2606  sub _get_next_token ($) {
2606        ## NOTE: "CDATA section state" in the state is jointly implemented        ## NOTE: "CDATA section state" in the state is jointly implemented
2607        ## by three states, |CDATA_SECTION_STATE|, |CDATA_SECTION_MSE1_STATE|,        ## by three states, |CDATA_SECTION_STATE|, |CDATA_SECTION_MSE1_STATE|,
2608        ## and |CDATA_SECTION_MSE2_STATE|.        ## and |CDATA_SECTION_MSE2_STATE|.
2609    
2610          ## XML5: "CDATA state".
2611                
2612        if ($self->{nc} == 0x005D) { # ]        if ($self->{nc} == 0x005D) { # ]
2613          !!!cp (221.1);          !!!cp (221.1);
# Line 2245  sub _get_next_token ($) { Line 2615  sub _get_next_token ($) {
2615          !!!next-input-character;          !!!next-input-character;
2616          redo A;          redo A;
2617        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
2618            if ($self->{is_xml}) {
2619              !!!cp (221.11);
2620              !!!parse-error (type => 'no mse'); ## TODO: type
2621            } else {
2622              !!!cp (221.12);
2623            }
2624    
2625          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2626          !!!next-input-character;          $self->{s_kwd} = '';
2627            ## Reconsume.
2628          if (length $self->{ct}->{data}) { # character          if (length $self->{ct}->{data}) { # character
2629            !!!cp (221.2);            !!!cp (221.2);
2630            !!!emit ($self->{ct}); # character            !!!emit ($self->{ct}); # character
# Line 2269  sub _get_next_token ($) { Line 2647  sub _get_next_token ($) {
2647    
2648        ## ISSUE: "text tokens" in spec.        ## ISSUE: "text tokens" in spec.
2649      } elsif ($self->{state} == CDATA_SECTION_MSE1_STATE) {      } elsif ($self->{state} == CDATA_SECTION_MSE1_STATE) {
2650          ## XML5: "CDATA bracket state".
2651    
2652        if ($self->{nc} == 0x005D) { # ]        if ($self->{nc} == 0x005D) { # ]
2653          !!!cp (221.5);          !!!cp (221.5);
2654          $self->{state} = CDATA_SECTION_MSE2_STATE;          $self->{state} = CDATA_SECTION_MSE2_STATE;
# Line 2276  sub _get_next_token ($) { Line 2656  sub _get_next_token ($) {
2656          redo A;          redo A;
2657        } else {        } else {
2658          !!!cp (221.6);          !!!cp (221.6);
2659            ## XML5: If EOF, "]" is not appended and changed to the data state.
2660          $self->{ct}->{data} .= ']';          $self->{ct}->{data} .= ']';
2661          $self->{state} = CDATA_SECTION_STATE;          $self->{state} = CDATA_SECTION_STATE; ## XML5: Stay in the state.
2662          ## Reconsume.          ## Reconsume.
2663          redo A;          redo A;
2664        }        }
2665      } elsif ($self->{state} == CDATA_SECTION_MSE2_STATE) {      } elsif ($self->{state} == CDATA_SECTION_MSE2_STATE) {
2666          ## XML5: "CDATA end state".
2667    
2668        if ($self->{nc} == 0x003E) { # >        if ($self->{nc} == 0x003E) { # >
2669          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2670            $self->{s_kwd} = '';
2671          !!!next-input-character;          !!!next-input-character;
2672          if (length $self->{ct}->{data}) { # character          if (length $self->{ct}->{data}) { # character
2673            !!!cp (221.7);            !!!cp (221.7);
# Line 2303  sub _get_next_token ($) { Line 2687  sub _get_next_token ($) {
2687          !!!cp (221.11);          !!!cp (221.11);
2688          $self->{ct}->{data} .= ']]'; # character          $self->{ct}->{data} .= ']]'; # character
2689          $self->{state} = CDATA_SECTION_STATE;          $self->{state} = CDATA_SECTION_STATE;
2690          ## Reconsume.          ## Reconsume. ## XML5: Emit.
2691          redo A;          redo A;
2692        }        }
2693      } elsif ($self->{state} == ENTITY_STATE) {      } elsif ($self->{state} == ENTITY_STATE) {
# Line 2320  sub _get_next_token ($) { Line 2704  sub _get_next_token ($) {
2704        } elsif ($self->{nc} == 0x0023) { # #        } elsif ($self->{nc} == 0x0023) { # #
2705          !!!cp (999);          !!!cp (999);
2706          $self->{state} = ENTITY_HASH_STATE;          $self->{state} = ENTITY_HASH_STATE;
2707          $self->{s_kwd} = '#';          $self->{kwd} = '#';
2708          !!!next-input-character;          !!!next-input-character;
2709          redo A;          redo A;
2710        } elsif ((0x0041 <= $self->{nc} and        } elsif ((0x0041 <= $self->{nc} and
# Line 2330  sub _get_next_token ($) { Line 2714  sub _get_next_token ($) {
2714          !!!cp (998);          !!!cp (998);
2715          require Whatpm::_NamedEntityList;          require Whatpm::_NamedEntityList;
2716          $self->{state} = ENTITY_NAME_STATE;          $self->{state} = ENTITY_NAME_STATE;
2717          $self->{s_kwd} = chr $self->{nc};          $self->{kwd} = chr $self->{nc};
2718          $self->{entity__value} = $self->{s_kwd};          $self->{entity__value} = $self->{kwd};
2719          $self->{entity__match} = 0;          $self->{entity__match} = 0;
2720          !!!next-input-character;          !!!next-input-character;
2721          redo A;          redo A;
# Line 2351  sub _get_next_token ($) { Line 2735  sub _get_next_token ($) {
2735        if ($self->{prev_state} == DATA_STATE) {        if ($self->{prev_state} == DATA_STATE) {
2736          !!!cp (997);          !!!cp (997);
2737          $self->{state} = $self->{prev_state};          $self->{state} = $self->{prev_state};
2738            $self->{s_kwd} = '';
2739          ## Reconsume.          ## Reconsume.
2740          !!!emit ({type => CHARACTER_TOKEN, data => '&',          !!!emit ({type => CHARACTER_TOKEN, data => '&',
2741                    line => $self->{line_prev},                    line => $self->{line_prev},
# Line 2361  sub _get_next_token ($) { Line 2746  sub _get_next_token ($) {
2746          !!!cp (996);          !!!cp (996);
2747          $self->{ca}->{value} .= '&';          $self->{ca}->{value} .= '&';
2748          $self->{state} = $self->{prev_state};          $self->{state} = $self->{prev_state};
2749            $self->{s_kwd} = '';
2750          ## Reconsume.          ## Reconsume.
2751          redo A;          redo A;
2752        }        }
# Line 2369  sub _get_next_token ($) { Line 2755  sub _get_next_token ($) {
2755            $self->{nc} == 0x0058) { # X            $self->{nc} == 0x0058) { # X
2756          !!!cp (995);          !!!cp (995);
2757          $self->{state} = HEXREF_X_STATE;          $self->{state} = HEXREF_X_STATE;
2758          $self->{s_kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
2759          !!!next-input-character;          !!!next-input-character;
2760          redo A;          redo A;
2761        } elsif (0x0030 <= $self->{nc} and        } elsif (0x0030 <= $self->{nc} and
2762                 $self->{nc} <= 0x0039) { # 0..9                 $self->{nc} <= 0x0039) { # 0..9
2763          !!!cp (994);          !!!cp (994);
2764          $self->{state} = NCR_NUM_STATE;          $self->{state} = NCR_NUM_STATE;
2765          $self->{s_kwd} = $self->{nc} - 0x0030;          $self->{kwd} = $self->{nc} - 0x0030;
2766          !!!next-input-character;          !!!next-input-character;
2767          redo A;          redo A;
2768        } else {        } else {
# Line 2391  sub _get_next_token ($) { Line 2777  sub _get_next_token ($) {
2777          if ($self->{prev_state} == DATA_STATE) {          if ($self->{prev_state} == DATA_STATE) {
2778            !!!cp (1019);            !!!cp (1019);
2779            $self->{state} = $self->{prev_state};            $self->{state} = $self->{prev_state};
2780              $self->{s_kwd} = '';
2781            ## Reconsume.            ## Reconsume.
2782            !!!emit ({type => CHARACTER_TOKEN,            !!!emit ({type => CHARACTER_TOKEN,
2783                      data => '&#',                      data => '&#',
# Line 2402  sub _get_next_token ($) { Line 2789  sub _get_next_token ($) {
2789            !!!cp (993);            !!!cp (993);
2790            $self->{ca}->{value} .= '&#';            $self->{ca}->{value} .= '&#';
2791            $self->{state} = $self->{prev_state};            $self->{state} = $self->{prev_state};
2792              $self->{s_kwd} = '';
2793            ## Reconsume.            ## Reconsume.
2794            redo A;            redo A;
2795          }          }
# Line 2410  sub _get_next_token ($) { Line 2798  sub _get_next_token ($) {
2798        if (0x0030 <= $self->{nc} and        if (0x0030 <= $self->{nc} and
2799            $self->{nc} <= 0x0039) { # 0..9            $self->{nc} <= 0x0039) { # 0..9
2800          !!!cp (1012);          !!!cp (1012);
2801          $self->{s_kwd} *= 10;          $self->{kwd} *= 10;
2802          $self->{s_kwd} += $self->{nc} - 0x0030;          $self->{kwd} += $self->{nc} - 0x0030;
2803                    
2804          ## Stay in the state.          ## Stay in the state.
2805          !!!next-input-character;          !!!next-input-character;
# Line 2427  sub _get_next_token ($) { Line 2815  sub _get_next_token ($) {
2815          #          #
2816        }        }
2817    
2818        my $code = $self->{s_kwd};        my $code = $self->{kwd};
2819        my $l = $self->{line_prev};        my $l = $self->{line_prev};
2820        my $c = $self->{column_prev};        my $c = $self->{column_prev};
2821        if ($charref_map->{$code}) {        if ($charref_map->{$code}) {
# Line 2447  sub _get_next_token ($) { Line 2835  sub _get_next_token ($) {
2835        if ($self->{prev_state} == DATA_STATE) {        if ($self->{prev_state} == DATA_STATE) {
2836          !!!cp (992);          !!!cp (992);
2837          $self->{state} = $self->{prev_state};          $self->{state} = $self->{prev_state};
2838            $self->{s_kwd} = '';
2839          ## Reconsume.          ## Reconsume.
2840          !!!emit ({type => CHARACTER_TOKEN, data => chr $code,          !!!emit ({type => CHARACTER_TOKEN, data => chr $code,
2841                      has_reference => 1,
2842                    line => $l, column => $c,                    line => $l, column => $c,
2843                   });                   });
2844          redo A;          redo A;
# Line 2457  sub _get_next_token ($) { Line 2847  sub _get_next_token ($) {
2847          $self->{ca}->{value} .= chr $code;          $self->{ca}->{value} .= chr $code;
2848          $self->{ca}->{has_reference} = 1;          $self->{ca}->{has_reference} = 1;
2849          $self->{state} = $self->{prev_state};          $self->{state} = $self->{prev_state};
2850            $self->{s_kwd} = '';
2851          ## Reconsume.          ## Reconsume.
2852          redo A;          redo A;
2853        }        }
# Line 2467  sub _get_next_token ($) { Line 2858  sub _get_next_token ($) {
2858          # 0..9, A..F, a..f          # 0..9, A..F, a..f
2859          !!!cp (990);          !!!cp (990);
2860          $self->{state} = HEXREF_HEX_STATE;          $self->{state} = HEXREF_HEX_STATE;
2861          $self->{s_kwd} = 0;          $self->{kwd} = 0;
2862          ## Reconsume.          ## Reconsume.
2863          redo A;          redo A;
2864        } else {        } else {
# Line 2482  sub _get_next_token ($) { Line 2873  sub _get_next_token ($) {
2873          if ($self->{prev_state} == DATA_STATE) {          if ($self->{prev_state} == DATA_STATE) {
2874            !!!cp (1005);            !!!cp (1005);
2875            $self->{state} = $self->{prev_state};            $self->{state} = $self->{prev_state};
2876              $self->{s_kwd} = '';
2877            ## Reconsume.            ## Reconsume.
2878            !!!emit ({type => CHARACTER_TOKEN,            !!!emit ({type => CHARACTER_TOKEN,
2879                      data => '&' . $self->{s_kwd},                      data => '&' . $self->{kwd},
2880                      line => $self->{line_prev},                      line => $self->{line_prev},
2881                      column => $self->{column_prev} - length $self->{s_kwd},                      column => $self->{column_prev} - length $self->{kwd},
2882                     });                     });
2883            redo A;            redo A;
2884          } else {          } else {
2885            !!!cp (989);            !!!cp (989);
2886            $self->{ca}->{value} .= '&' . $self->{s_kwd};            $self->{ca}->{value} .= '&' . $self->{kwd};
2887            $self->{state} = $self->{prev_state};            $self->{state} = $self->{prev_state};
2888              $self->{s_kwd} = '';
2889            ## Reconsume.            ## Reconsume.
2890            redo A;            redo A;
2891          }          }
# Line 2501  sub _get_next_token ($) { Line 2894  sub _get_next_token ($) {
2894        if (0x0030 <= $self->{nc} and $self->{nc} <= 0x0039) {        if (0x0030 <= $self->{nc} and $self->{nc} <= 0x0039) {
2895          # 0..9          # 0..9
2896          !!!cp (1002);          !!!cp (1002);
2897          $self->{s_kwd} *= 0x10;          $self->{kwd} *= 0x10;
2898          $self->{s_kwd} += $self->{nc} - 0x0030;          $self->{kwd} += $self->{nc} - 0x0030;
2899          ## Stay in the state.          ## Stay in the state.
2900          !!!next-input-character;          !!!next-input-character;
2901          redo A;          redo A;
2902        } elsif (0x0061 <= $self->{nc} and        } elsif (0x0061 <= $self->{nc} and
2903                 $self->{nc} <= 0x0066) { # a..f                 $self->{nc} <= 0x0066) { # a..f
2904          !!!cp (1003);          !!!cp (1003);
2905          $self->{s_kwd} *= 0x10;          $self->{kwd} *= 0x10;
2906          $self->{s_kwd} += $self->{nc} - 0x0060 + 9;          $self->{kwd} += $self->{nc} - 0x0060 + 9;
2907          ## Stay in the state.          ## Stay in the state.
2908          !!!next-input-character;          !!!next-input-character;
2909          redo A;          redo A;
2910        } elsif (0x0041 <= $self->{nc} and        } elsif (0x0041 <= $self->{nc} and
2911                 $self->{nc} <= 0x0046) { # A..F                 $self->{nc} <= 0x0046) { # A..F
2912          !!!cp (1004);          !!!cp (1004);
2913          $self->{s_kwd} *= 0x10;          $self->{kwd} *= 0x10;
2914          $self->{s_kwd} += $self->{nc} - 0x0040 + 9;          $self->{kwd} += $self->{nc} - 0x0040 + 9;
2915          ## Stay in the state.          ## Stay in the state.
2916          !!!next-input-character;          !!!next-input-character;
2917          redo A;          redo A;
# Line 2535  sub _get_next_token ($) { Line 2928  sub _get_next_token ($) {
2928          #          #
2929        }        }
2930    
2931        my $code = $self->{s_kwd};        my $code = $self->{kwd};
2932        my $l = $self->{line_prev};        my $l = $self->{line_prev};
2933        my $c = $self->{column_prev};        my $c = $self->{column_prev};
2934        if ($charref_map->{$code}) {        if ($charref_map->{$code}) {
# Line 2555  sub _get_next_token ($) { Line 2948  sub _get_next_token ($) {
2948        if ($self->{prev_state} == DATA_STATE) {        if ($self->{prev_state} == DATA_STATE) {
2949          !!!cp (988);          !!!cp (988);
2950          $self->{state} = $self->{prev_state};          $self->{state} = $self->{prev_state};
2951            $self->{s_kwd} = '';
2952          ## Reconsume.          ## Reconsume.
2953          !!!emit ({type => CHARACTER_TOKEN, data => chr $code,          !!!emit ({type => CHARACTER_TOKEN, data => chr $code,
2954                      has_reference => 1,
2955                    line => $l, column => $c,                    line => $l, column => $c,
2956                   });                   });
2957          redo A;          redo A;
# Line 2565  sub _get_next_token ($) { Line 2960  sub _get_next_token ($) {
2960          $self->{ca}->{value} .= chr $code;          $self->{ca}->{value} .= chr $code;
2961          $self->{ca}->{has_reference} = 1;          $self->{ca}->{has_reference} = 1;
2962          $self->{state} = $self->{prev_state};          $self->{state} = $self->{prev_state};
2963            $self->{s_kwd} = '';
2964          ## Reconsume.          ## Reconsume.
2965          redo A;          redo A;
2966        }        }
2967      } elsif ($self->{state} == ENTITY_NAME_STATE) {      } elsif ($self->{state} == ENTITY_NAME_STATE) {
2968        if (length $self->{s_kwd} < 30 and        if (length $self->{kwd} < 30 and
2969            ## NOTE: Some number greater than the maximum length of entity name            ## NOTE: Some number greater than the maximum length of entity name
2970            ((0x0041 <= $self->{nc} and # a            ((0x0041 <= $self->{nc} and # a
2971              $self->{nc} <= 0x005A) or # x              $self->{nc} <= 0x005A) or # x
# Line 2579  sub _get_next_token ($) { Line 2975  sub _get_next_token ($) {
2975              $self->{nc} <= 0x0039) or # 9              $self->{nc} <= 0x0039) or # 9
2976             $self->{nc} == 0x003B)) { # ;             $self->{nc} == 0x003B)) { # ;
2977          our $EntityChar;          our $EntityChar;
2978          $self->{s_kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
2979          if (defined $EntityChar->{$self->{s_kwd}}) {          if (defined $EntityChar->{$self->{kwd}}) {
2980            if ($self->{nc} == 0x003B) { # ;            if ($self->{nc} == 0x003B) { # ;
2981              !!!cp (1020);              !!!cp (1020);
2982              $self->{entity__value} = $EntityChar->{$self->{s_kwd}};              $self->{entity__value} = $EntityChar->{$self->{kwd}};
2983              $self->{entity__match} = 1;              $self->{entity__match} = 1;
2984              !!!next-input-character;              !!!next-input-character;
2985              #              #
2986            } else {            } else {
2987              !!!cp (1021);              !!!cp (1021);
2988              $self->{entity__value} = $EntityChar->{$self->{s_kwd}};              $self->{entity__value} = $EntityChar->{$self->{kwd}};
2989              $self->{entity__match} = -1;              $self->{entity__match} = -1;
2990              ## Stay in the state.              ## Stay in the state.
2991              !!!next-input-character;              !!!next-input-character;
# Line 2617  sub _get_next_token ($) { Line 3013  sub _get_next_token ($) {
3013          if ($self->{prev_state} != DATA_STATE and # in attribute          if ($self->{prev_state} != DATA_STATE and # in attribute
3014              $self->{entity__match} < -1) {              $self->{entity__match} < -1) {
3015            !!!cp (1024);            !!!cp (1024);
3016            $data = '&' . $self->{s_kwd};            $data = '&' . $self->{kwd};
3017            #            #
3018          } else {          } else {
3019            !!!cp (1025);            !!!cp (1025);
# Line 2629  sub _get_next_token ($) { Line 3025  sub _get_next_token ($) {
3025          !!!cp (1026);          !!!cp (1026);
3026          !!!parse-error (type => 'bare ero',          !!!parse-error (type => 'bare ero',
3027                          line => $self->{line_prev},                          line => $self->{line_prev},
3028                          column => $self->{column_prev} - length $self->{s_kwd});                          column => $self->{column_prev} - length $self->{kwd});
3029          $data = '&' . $self->{s_kwd};          $data = '&' . $self->{kwd};
3030          #          #
3031        }        }
3032        
# Line 2647  sub _get_next_token ($) { Line 3043  sub _get_next_token ($) {
3043        if ($self->{prev_state} == DATA_STATE) {        if ($self->{prev_state} == DATA_STATE) {
3044          !!!cp (986);          !!!cp (986);
3045          $self->{state} = $self->{prev_state};          $self->{state} = $self->{prev_state};
3046            $self->{s_kwd} = '';
3047          ## Reconsume.          ## Reconsume.
3048          !!!emit ({type => CHARACTER_TOKEN,          !!!emit ({type => CHARACTER_TOKEN,
3049                    data => $data,                    data => $data,
3050                      has_reference => $has_ref,
3051                    line => $self->{line_prev},                    line => $self->{line_prev},
3052                    column => $self->{column_prev} + 1 - length $self->{s_kwd},                    column => $self->{column_prev} + 1 - length $self->{kwd},
3053                   });                   });
3054          redo A;          redo A;
3055        } else {        } else {
# Line 2659  sub _get_next_token ($) { Line 3057  sub _get_next_token ($) {
3057          $self->{ca}->{value} .= $data;          $self->{ca}->{value} .= $data;
3058          $self->{ca}->{has_reference} = 1 if $has_ref;          $self->{ca}->{has_reference} = 1 if $has_ref;
3059          $self->{state} = $self->{prev_state};          $self->{state} = $self->{prev_state};
3060            $self->{s_kwd} = '';
3061            ## Reconsume.
3062            redo A;
3063          }
3064    
3065        ## XML-only states
3066    
3067        } elsif ($self->{state} == PI_STATE) {
3068          if ($is_space->{$self->{nc}} or
3069              $self->{nc} == 0x003F or # ? ## XML5: Same as "Anything else"
3070              $self->{nc} == -1) {
3071            !!!parse-error (type => 'bare pio', ## TODO: type
3072                            line => $self->{line_prev},
3073                            column => $self->{column_prev}
3074                                - 1 * ($self->{nc} != -1));
3075            $self->{state} = BOGUS_COMMENT_STATE;
3076            ## Reconsume.
3077            $self->{ct} = {type => COMMENT_TOKEN,
3078                           data => '?',
3079                           line => $self->{line_prev},
3080                           column => $self->{column_prev}
3081                               - 1 * ($self->{nc} != -1),
3082                          };
3083            redo A;
3084          } else {
3085            $self->{ct} = {type => PI_TOKEN,
3086                           target => chr $self->{nc},
3087                           data => '',
3088                           line => $self->{line_prev},
3089                           column => $self->{column_prev} - 1,
3090                          };
3091            $self->{state} = PI_TARGET_STATE;
3092            !!!next-input-character;
3093            redo A;
3094          }
3095        } elsif ($self->{state} == PI_TARGET_STATE) {
3096          if ($is_space->{$self->{nc}}) {
3097            $self->{state} = PI_TARGET_AFTER_STATE;
3098            !!!next-input-character;
3099            redo A;
3100          } elsif ($self->{nc} == -1) {
3101            !!!parse-error (type => 'no pic'); ## TODO: type
3102            $self->{state} = DATA_STATE;
3103            $self->{s_kwd} = '';
3104            ## Reconsume.
3105            !!!emit ($self->{ct}); # pi
3106            redo A;
3107          } elsif ($self->{nc} == 0x003F) { # ?
3108            $self->{state} = PI_AFTER_STATE;
3109            !!!next-input-character;
3110            redo A;
3111          } else {
3112            ## XML5: typo ("tag name" -> "target")
3113            $self->{ct}->{target} .= chr $self->{nc}; # pi
3114            !!!next-input-character;
3115            redo A;
3116          }
3117        } elsif ($self->{state} == PI_TARGET_AFTER_STATE) {
3118          if ($is_space->{$self->{nc}}) {
3119            ## Stay in the state.
3120            !!!next-input-character;
3121            redo A;
3122          } else {
3123            $self->{state} = PI_DATA_STATE;
3124            ## Reprocess.
3125            redo A;
3126          }
3127        } elsif ($self->{state} == PI_DATA_STATE) {
3128          if ($self->{nc} == 0x003F) { # ?
3129            $self->{state} = PI_DATA_AFTER_STATE;
3130            !!!next-input-character;
3131            redo A;
3132          } elsif ($self->{nc} == -1) {
3133            !!!parse-error (type => 'no pic'); ## TODO: type
3134            $self->{state} = DATA_STATE;
3135            $self->{s_kwd} = '';
3136            ## Reprocess.
3137            !!!emit ($self->{ct}); # pi
3138            redo A;
3139          } else {
3140            $self->{ct}->{data} .= chr $self->{nc}; # pi
3141            $self->{read_until}->($self->{ct}->{data}, q[?],
3142                                  length $self->{ct}->{data});
3143            ## Stay in the state.
3144            !!!next-input-character;
3145            ## Reprocess.
3146            redo A;
3147          }
3148        } elsif ($self->{state} == PI_AFTER_STATE) {
3149          if ($self->{nc} == 0x003E) { # >
3150            $self->{state} = DATA_STATE;
3151            $self->{s_kwd} = '';
3152            !!!next-input-character;
3153            !!!emit ($self->{ct}); # pi
3154            redo A;
3155          } elsif ($self->{nc} == 0x003F) { # ?
3156            !!!parse-error (type => 'no s after target', ## TODO: type
3157                            line => $self->{line_prev},
3158                            column => $self->{column_prev}); ## XML5: no error
3159            $self->{ct}->{data} .= '?';
3160            $self->{state} = PI_DATA_AFTER_STATE;
3161            !!!next-input-character;
3162            redo A;
3163          } else {
3164            !!!parse-error (type => 'no s after target', ## TODO: type
3165                            line => $self->{line_prev},
3166                            column => $self->{column_prev}
3167                                + 1 * ($self->{nc} == -1)); ## XML5: no error
3168            $self->{ct}->{data} .= '?'; ## XML5: not appended
3169            $self->{state} = PI_DATA_STATE;
3170            ## Reprocess.
3171            redo A;
3172          }
3173        } elsif ($self->{state} == PI_DATA_AFTER_STATE) {
3174          ## XML5: Same as "pi after state" in XML5
3175          if ($self->{nc} == 0x003E) { # >
3176            $self->{state} = DATA_STATE;
3177            $self->{s_kwd} = '';
3178            !!!next-input-character;
3179            !!!emit ($self->{ct}); # pi
3180            redo A;
3181          } elsif ($self->{nc} == 0x003F) { # ?
3182            $self->{ct}->{data} .= '?';
3183            ## Stay in the state.
3184            !!!next-input-character;
3185            redo A;
3186          } else {
3187            $self->{ct}->{data} .= '?'; ## XML5: not appended
3188            $self->{state} = PI_DATA_STATE;
3189            ## Reprocess.
3190            redo A;
3191          }
3192    
3193        } elsif ($self->{state} == DOCTYPE_INTERNAL_SUBSET_STATE) {
3194          if ($self->{nc} == 0x003C) { # <
3195            ## TODO:
3196            !!!next-input-character;
3197            redo A;
3198          } elsif ($self->{nc} == 0x0025) { # %
3199            ## XML5: Not defined yet.
3200    
3201            ## TODO:
3202            !!!next-input-character;
3203            redo A;
3204          } elsif ($self->{nc} == 0x005D) { # ]
3205            $self->{state} = DOCTYPE_INTERNAL_SUBSET_AFTER_STATE;
3206            !!!next-input-character;
3207            redo A;
3208          } elsif ($is_space->{$self->{nc}}) {
3209            ## Stay in the state.
3210            !!!next-input-character;
3211            redo A;
3212          } elsif ($self->{nc} == -1) {
3213            !!!parse-error (type => 'unclosed internal subset'); ## TODO: type
3214            $self->{state} = DATA_STATE;
3215            $self->{s_kwd} = '';
3216          ## Reconsume.          ## Reconsume.
3217            !!!emit ($self->{ct}); # DOCTYPE
3218            redo A;
3219          } else {
3220            unless ($self->{internal_subset_tainted}) {
3221              ## XML5: No parse error.
3222              !!!parse-error (type => 'string in internal subset');
3223              $self->{internal_subset_tainted} = 1;
3224            }
3225            ## Stay in the state.
3226            !!!next-input-character;
3227          redo A;          redo A;
3228        }        }
3229        } elsif ($self->{state} == DOCTYPE_INTERNAL_SUBSET_AFTER_STATE) {
3230          if ($self->{nc} == 0x003E) { # >
3231            $self->{state} = DATA_STATE;
3232            $self->{s_kwd} = '';
3233            !!!next-input-character;
3234            !!!emit ($self->{ct}); # DOCTYPE
3235            redo A;
3236          } elsif ($self->{nc} == -1) {
3237            !!!parse-error (type => 'unclosed DOCTYPE');
3238            $self->{state} = DATA_STATE;
3239            $self->{s_kwd} = '';
3240            ## Reconsume.
3241            !!!emit ($self->{ct}); # DOCTYPE
3242            redo A;
3243          } else {
3244            ## XML5: No parse error and stay in the state.
3245            !!!parse-error (type => 'string after internal subset'); ## TODO: type
3246    
3247            $self->{state} = BOGUS_DOCTYPE_STATE;
3248            !!!next-input-character;
3249            redo A;
3250          }
3251            
3252      } else {      } else {
3253        die "$0: $self->{state}: Unknown state";        die "$0: $self->{state}: Unknown state";
3254      }      }

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.12

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24