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

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

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

revision 1.178 by wakaba, Sun Sep 14 11:57:41 2008 UTC revision 1.184 by wakaba, Mon Sep 15 09:02:27 2008 UTC
# Line 3  use strict; Line 3  use strict;
3  our $VERSION=do{my @r=(q$Revision$=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};  our $VERSION=do{my @r=(q$Revision$=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
4  use Error qw(:try);  use Error qw(:try);
5    
6    ## NOTE: This module don't check all HTML5 parse errors; character
7    ## encoding related parse errors are expected to be handled by relevant
8    ## modules.
9    ## Parse errors for control characters that are not allowed in HTML5
10    ## documents, for surrogate code points, and for noncharacter code
11    ## points, as well as U+FFFD substitions for characters whose code points
12    ## is higher than U+10FFFF may be detected by combining the parser with
13    ## the checker implemented by Whatpm::Charset::UnicodeChecker (for its
14    ## usage example, see |t/HTML-tree.t| in the Whatpm package or the
15    ## WebHACC::Language::HTML module in the WebHACC package).
16    
17  ## ISSUE:  ## ISSUE:
18  ## var doc = implementation.createDocument (null, null, null);  ## var doc = implementation.createDocument (null, null, null);
19  ## doc.write ('');  ## doc.write ('');
# Line 571  sub parse_byte_stream ($$$$;$$) { Line 582  sub parse_byte_stream ($$$$;$$) {
582    my $wrapped_char_stream = $get_wrapper->($char_stream);    my $wrapped_char_stream = $get_wrapper->($char_stream);
583    $wrapped_char_stream->onerror ($char_onerror);    $wrapped_char_stream->onerror ($char_onerror);
584    
585    my @args = @_; shift @args; # $s    my @args = ($_[1], $_[2]); # $doc, $onerror - $get_wrapper = undef;
586    my $return;    my $return;
587    try {    try {
588      $return = $self->parse_char_stream ($wrapped_char_stream, @args);        $return = $self->parse_char_stream ($wrapped_char_stream, @args);  
# Line 621  sub parse_char_string ($$$;$$) { Line 632  sub parse_char_string ($$$;$$) {
632    my $s = ref $_[0] ? $_[0] : \($_[0]);    my $s = ref $_[0] ? $_[0] : \($_[0]);
633    require Whatpm::Charset::DecodeHandle;    require Whatpm::Charset::DecodeHandle;
634    my $input = Whatpm::Charset::DecodeHandle::CharString->new ($s);    my $input = Whatpm::Charset::DecodeHandle::CharString->new ($s);
   if ($_[3]) {  
     $input = $_[3]->($input);  
   }  
635    return $self->parse_char_stream ($input, @_[1..$#_]);    return $self->parse_char_stream ($input, @_[1..$#_]);
636  } # parse_char_string  } # parse_char_string
637  *parse_string = \&parse_char_string; ## NOTE: Alias for backward compatibility.  *parse_string = \&parse_char_string; ## NOTE: Alias for backward compatibility.
638    
639  sub parse_char_stream ($$$;$) {  sub parse_char_stream ($$$;$$) {
640    my $self = ref $_[0] ? shift : shift->new;    my $self = ref $_[0] ? shift : shift->new;
641    my $input = $_[0];    my $input = $_[0];
642    $self->{document} = $_[1];    $self->{document} = $_[1];
# Line 641  sub parse_char_stream ($$$;$) { Line 649  sub parse_char_stream ($$$;$) {
649        if defined $self->{input_encoding};        if defined $self->{input_encoding};
650  ## TODO: |{input_encoding}| is needless?  ## TODO: |{input_encoding}| is needless?
651    
   my $i = 0;  
652    $self->{line_prev} = $self->{line} = 1;    $self->{line_prev} = $self->{line} = 1;
653    $self->{column_prev} = $self->{column} = 0;    $self->{column_prev} = -1;
654    $self->{set_next_char} = sub {    $self->{column} = 0;
655      $self->{set_nc} = sub {
656      my $self = shift;      my $self = shift;
657    
     pop @{$self->{prev_char}};  
     unshift @{$self->{prev_char}}, $self->{next_char};  
   
658      my $char = '';      my $char = '';
659      if (defined $self->{next_next_char}) {      if (defined $self->{next_nc}) {
660        $char = $self->{next_next_char};        $char = $self->{next_nc};
661        delete $self->{next_next_char};        delete $self->{next_nc};
662        $self->{next_char} = ord $char;        $self->{nc} = ord $char;
663      } else {      } else {
664          $self->{char_buffer} = '';
665          $self->{char_buffer_pos} = 0;
666    
667          my $count = $input->manakai_read_until
668             ($self->{char_buffer}, qr/[^\x00\x0A\x0D]/, $self->{char_buffer_pos});
669          if ($count) {
670            $self->{line_prev} = $self->{line};
671            $self->{column_prev} = $self->{column};
672            $self->{column}++;
673            $self->{nc}
674                = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
675            return;
676          }
677    
678        if ($input->read ($char, 1)) {        if ($input->read ($char, 1)) {
679          $self->{next_char} = ord $char;          $self->{nc} = ord $char;
680        } else {        } else {
681          $self->{next_char} = -1;          $self->{nc} = -1;
682          return;          return;
683        }        }
684      }      }
# Line 668  sub parse_char_stream ($$$;$) { Line 687  sub parse_char_stream ($$$;$) {
687          = ($self->{line}, $self->{column});          = ($self->{line}, $self->{column});
688      $self->{column}++;      $self->{column}++;
689            
690      if ($self->{next_char} == 0x000A) { # LF      if ($self->{nc} == 0x000A) { # LF
691        !!!cp ('j1');        !!!cp ('j1');
692        $self->{line}++;        $self->{line}++;
693        $self->{column} = 0;        $self->{column} = 0;
694      } elsif ($self->{next_char} == 0x000D) { # CR      } elsif ($self->{nc} == 0x000D) { # CR
695        !!!cp ('j2');        !!!cp ('j2');
696  ## TODO: support for abort/streaming  ## TODO: support for abort/streaming
697        my $next = '';        my $next = '';
698        if ($input->read ($next, 1) and $next ne "\x0A") {        if ($input->read ($next, 1) and $next ne "\x0A") {
699          $self->{next_next_char} = $next;          $self->{next_nc} = $next;
700        }        }
701        $self->{next_char} = 0x000A; # LF # MUST        $self->{nc} = 0x000A; # LF # MUST
702        $self->{line}++;        $self->{line}++;
703        $self->{column} = 0;        $self->{column} = 0;
704      } elsif ($self->{next_char} > 0x10FFFF) {      } elsif ($self->{nc} == 0x0000) { # NULL
       !!!cp ('j3');  
       $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST  
     } elsif ($self->{next_char} == 0x0000) { # NULL  
705        !!!cp ('j4');        !!!cp ('j4');
706        !!!parse-error (type => 'NULL');        !!!parse-error (type => 'NULL');
707        $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST        $self->{nc} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
     } elsif ($self->{next_char} <= 0x0008 or  
              (0x000E <= $self->{next_char} and $self->{next_char} <= 0x001F) or  
              (0x007F <= $self->{next_char} and $self->{next_char} <= 0x009F) or  
              (0xD800 <= $self->{next_char} and $self->{next_char} <= 0xDFFF) or  
              (0xFDD0 <= $self->{next_char} and $self->{next_char} <= 0xFDDF) or  
 ## ISSUE: U+FDE0-U+FDEF are not excluded  
              {  
               0xFFFE => 1, 0xFFFF => 1, 0x1FFFE => 1, 0x1FFFF => 1,  
               0x2FFFE => 1, 0x2FFFF => 1, 0x3FFFE => 1, 0x3FFFF => 1,  
               0x4FFFE => 1, 0x4FFFF => 1, 0x5FFFE => 1, 0x5FFFF => 1,  
               0x6FFFE => 1, 0x6FFFF => 1, 0x7FFFE => 1, 0x7FFFF => 1,  
               0x8FFFE => 1, 0x8FFFF => 1, 0x9FFFE => 1, 0x9FFFF => 1,  
               0xAFFFE => 1, 0xAFFFF => 1, 0xBFFFE => 1, 0xBFFFF => 1,  
               0xCFFFE => 1, 0xCFFFF => 1, 0xDFFFE => 1, 0xDFFFF => 1,  
               0xEFFFE => 1, 0xEFFFF => 1, 0xFFFFE => 1, 0xFFFFF => 1,  
               0x10FFFE => 1, 0x10FFFF => 1,  
              }->{$self->{next_char}}) {  
       !!!cp ('j5');  
       if ($self->{next_char} < 0x10000) {  
         !!!parse-error (type => 'control char',  
                         text => (sprintf 'U+%04X', $self->{next_char}));  
       } else {  
         !!!parse-error (type => 'control char',  
                         text => (sprintf 'U-%08X', $self->{next_char}));  
       }  
708      }      }
709    };    };
   $self->{prev_char} = [-1, -1, -1];  
   $self->{next_char} = -1;  
710    
711    $self->{read_until} = sub {    $self->{read_until} = sub {
712      #my ($scalar, $specials_range, $offset) = @_;      #my ($scalar, $specials_range, $offset) = @_;
713      my $specials_range = $_[1];      return 0 if defined $self->{next_nc};
714      return 0 if defined $self->{next_next_char};  
715      my $count = $input->manakai_read_until      my $pattern = qr/[^$_[1]\x00\x0A\x0D]/;
716         ($_[0],      my $offset = $_[2] || 0;
717          qr/(?![$specials_range\x{FDD0}-\x{FDDF}\x{FFFE}\x{FFFF}\x{1FFFE}\x{1FFFF}\x{2FFFE}\x{2FFFF}\x{3FFFE}\x{3FFFF}\x{4FFFE}\x{4FFFF}\x{5FFFE}\x{5FFFF}\x{6FFFE}\x{6FFFF}\x{7FFFE}\x{7FFFF}\x{8FFFE}\x{8FFFF}\x{9FFFE}\x{9FFFF}\x{AFFFE}\x{AFFFF}\x{BFFFE}\x{BFFFF}\x{CFFFE}\x{CFFFF}\x{DFFFE}\x{DFFFF}\x{EFFFE}\x{EFFFF}\x{FFFFE}\x{FFFFF}])[\x20-\x7E\xA0-\x{D7FF}\x{E000}-\x{10FFFD}]/,  
718          $_[2]);      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
719      if ($count) {        pos ($self->{char_buffer}) = $self->{char_buffer_pos};
720        $self->{column} += $count;        if ($self->{char_buffer} =~ /\G(?>$pattern)+/) {
721        $self->{column_prev} += $count;          substr ($_[0], $offset)
722        $self->{prev_char} = [-1, -1, -1];              = substr ($self->{char_buffer}, $-[0], $+[0] - $-[0]);
723        $self->{next_char} = -1;          my $count = $+[0] - $-[0];
724            if ($count) {
725              $self->{column} += $count;
726              $self->{char_buffer_pos} += $count;
727              $self->{line_prev} = $self->{line};
728              $self->{column_prev} = $self->{column} - 1;
729              $self->{nc} = -1;
730            }
731            return $count;
732          } else {
733            return 0;
734          }
735        } else {
736          my $count = $input->manakai_read_until ($_[0], $pattern, $_[2]);
737          if ($count) {
738            $self->{column} += $count;
739            $self->{line_prev} = $self->{line};
740            $self->{column_prev} = $self->{column} - 1;
741            $self->{nc} = -1;
742          }
743          return $count;
744      }      }
     return $count;  
745    }; # $self->{read_until}    }; # $self->{read_until}
746    
747    my $onerror = $_[2] || sub {    my $onerror = $_[2] || sub {
# Line 746  sub parse_char_stream ($$$;$) { Line 754  sub parse_char_stream ($$$;$) {
754      $onerror->(line => $self->{line}, column => $self->{column}, @_);      $onerror->(line => $self->{line}, column => $self->{column}, @_);
755    };    };
756    
757      my $char_onerror = sub {
758        my (undef, $type, %opt) = @_;
759        !!!parse-error (layer => 'encode',
760                        line => $self->{line}, column => $self->{column} + 1,
761                        %opt, type => $type);
762      }; # $char_onerror
763    
764      if ($_[3]) {
765        $input = $_[3]->($input);
766        $input->onerror ($char_onerror);
767      } else {
768        $input->onerror ($char_onerror) unless defined $input->onerror;
769      }
770    
771    $self->_initialize_tokenizer;    $self->_initialize_tokenizer;
772    $self->_initialize_tree_constructor;    $self->_initialize_tree_constructor;
773    $self->_construct_tree;    $self->_construct_tree;
# Line 765  sub new ($) { Line 787  sub new ($) {
787                info => 'i',                info => 'i',
788                uncertain => 'u'},                uncertain => 'u'},
789    }, $class;    }, $class;
790    $self->{set_next_char} = sub {    $self->{set_nc} = sub {
791      $self->{next_char} = -1;      $self->{nc} = -1;
792    };    };
793    $self->{parse_error} = sub {    $self->{parse_error} = sub {
794      #      #
# Line 897  sub IN_COLUMN_GROUP_IM () { 0b10 } Line 919  sub IN_COLUMN_GROUP_IM () { 0b10 }
919  sub _initialize_tokenizer ($) {  sub _initialize_tokenizer ($) {
920    my $self = shift;    my $self = shift;
921    $self->{state} = DATA_STATE; # MUST    $self->{state} = DATA_STATE; # MUST
922    #$self->{state_keyword}; # initialized when used    #$self->{s_kwd}; # state keyword - initialized when used
923    #$self->{entity__value}; # initialized when used    #$self->{entity__value}; # initialized when used
924    #$self->{entity__match}; # initialized when used    #$self->{entity__match}; # initialized when used
925    $self->{content_model} = PCDATA_CONTENT_MODEL; # be    $self->{content_model} = PCDATA_CONTENT_MODEL; # be
926    undef $self->{current_token};    undef $self->{ct}; # current token
927    undef $self->{current_attribute};    undef $self->{ca}; # current attribute
928    undef $self->{last_emitted_start_tag_name};    undef $self->{last_stag_name}; # last emitted start tag name
929    #$self->{prev_state}; # initialized when used    #$self->{prev_state}; # initialized when used
930    delete $self->{self_closing};    delete $self->{self_closing};
931    # $self->{next_char}    $self->{char_buffer} = '';
932      $self->{char_buffer_pos} = 0;
933      $self->{nc} = -1; # next input character
934      #$self->{next_nc}
935    !!!next-input-character;    !!!next-input-character;
936    $self->{token} = [];    $self->{token} = [];
937    # $self->{escape}    # $self->{escape}
# Line 917  sub _initialize_tokenizer ($) { Line 942  sub _initialize_tokenizer ($) {
942  ##       CHARACTER_TOKEN, or END_OF_FILE_TOKEN  ##       CHARACTER_TOKEN, or END_OF_FILE_TOKEN
943  ##   ->{name} (DOCTYPE_TOKEN)  ##   ->{name} (DOCTYPE_TOKEN)
944  ##   ->{tag_name} (START_TAG_TOKEN, END_TAG_TOKEN)  ##   ->{tag_name} (START_TAG_TOKEN, END_TAG_TOKEN)
945  ##   ->{public_identifier} (DOCTYPE_TOKEN)  ##   ->{pubid} (DOCTYPE_TOKEN)
946  ##   ->{system_identifier} (DOCTYPE_TOKEN)  ##   ->{sysid} (DOCTYPE_TOKEN)
947  ##   ->{quirks} == 1 or 0 (DOCTYPE_TOKEN): "force-quirks" flag  ##   ->{quirks} == 1 or 0 (DOCTYPE_TOKEN): "force-quirks" flag
948  ##   ->{attributes} isa HASH (START_TAG_TOKEN, END_TAG_TOKEN)  ##   ->{attributes} isa HASH (START_TAG_TOKEN, END_TAG_TOKEN)
949  ##        ->{name}  ##        ->{name}
# Line 944  sub _get_next_token ($) { Line 969  sub _get_next_token ($) {
969    my $self = shift;    my $self = shift;
970    
971    if ($self->{self_closing}) {    if ($self->{self_closing}) {
972      !!!parse-error (type => 'nestc', token => $self->{current_token});      !!!parse-error (type => 'nestc', token => $self->{ct});
973      ## NOTE: The |self_closing| flag is only set by start tag token.      ## NOTE: The |self_closing| flag is only set by start tag token.
974      ## In addition, when a start tag token is emitted, it is always set to      ## In addition, when a start tag token is emitted, it is always set to
975      ## |current_token|.      ## |ct|.
976      delete $self->{self_closing};      delete $self->{self_closing};
977    }    }
978    
# Line 958  sub _get_next_token ($) { Line 983  sub _get_next_token ($) {
983    
984    A: {    A: {
985      if ($self->{state} == DATA_STATE) {      if ($self->{state} == DATA_STATE) {
986        if ($self->{next_char} == 0x0026) { # &        if ($self->{nc} == 0x0026) { # &
987            delete $self->{s_kwd};
988          if ($self->{content_model} & CM_ENTITY and # PCDATA | RCDATA          if ($self->{content_model} & CM_ENTITY and # PCDATA | RCDATA
989              not $self->{escape}) {              not $self->{escape}) {
990            !!!cp (1);            !!!cp (1);
# Line 966  sub _get_next_token ($) { Line 992  sub _get_next_token ($) {
992            ## "entity data state".  In this implementation, the tokenizer            ## "entity data state".  In this implementation, the tokenizer
993            ## is switched to the |ENTITY_STATE|, which is an implementation            ## is switched to the |ENTITY_STATE|, which is an implementation
994            ## of the "consume a character reference" algorithm.            ## of the "consume a character reference" algorithm.
995            $self->{entity_additional} = -1;            $self->{entity_add} = -1;
996            $self->{prev_state} = DATA_STATE;            $self->{prev_state} = DATA_STATE;
997            $self->{state} = ENTITY_STATE;            $self->{state} = ENTITY_STATE;
998            !!!next-input-character;            !!!next-input-character;
# Line 975  sub _get_next_token ($) { Line 1001  sub _get_next_token ($) {
1001            !!!cp (2);            !!!cp (2);
1002            #            #
1003          }          }
1004        } elsif ($self->{next_char} == 0x002D) { # -        } elsif ($self->{nc} == 0x002D) { # -
1005          if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA          if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
1006            unless ($self->{escape}) {            if (defined $self->{s_kwd}) {
1007              if ($self->{prev_char}->[0] == 0x002D and # -              !!!cp (2.1);
1008                  $self->{prev_char}->[1] == 0x0021 and # !              $self->{s_kwd} .= '-';
1009                  $self->{prev_char}->[2] == 0x003C) { # <            } else {
1010                !!!cp (3);              !!!cp (2.2);
1011                $self->{escape} = 1;              $self->{s_kwd} = '-';
1012              } else {            }
1013                !!!cp (4);  
1014              }            if ($self->{s_kwd} eq '<!--') {
1015                !!!cp (3);
1016                $self->{escape} = 1; # unless $self->{escape};
1017                $self->{s_kwd} = '--';
1018                #
1019              } elsif ($self->{s_kwd} eq '---') {
1020                !!!cp (4);
1021                $self->{s_kwd} = '--';
1022                #
1023            } else {            } else {
1024              !!!cp (5);              !!!cp (5);
1025                #
1026            }            }
1027          }          }
1028                    
1029          #          #
1030        } elsif ($self->{next_char} == 0x003C) { # <        } elsif ($self->{nc} == 0x0021) { # !
1031            if (defined $self->{s_kwd}) {
1032              !!!cp (5.1);
1033              $self->{s_kwd} .= '!';
1034              #
1035            } else {
1036              !!!cp (5.2);
1037              #
1038            }
1039            #
1040          } elsif ($self->{nc} == 0x003C) { # <
1041            delete $self->{s_kwd};
1042          if ($self->{content_model} & CM_FULL_MARKUP or # PCDATA          if ($self->{content_model} & CM_FULL_MARKUP or # PCDATA
1043              (($self->{content_model} & CM_LIMITED_MARKUP) and # CDATA | RCDATA              (($self->{content_model} & CM_LIMITED_MARKUP) and # CDATA | RCDATA
1044               not $self->{escape})) {               not $self->{escape})) {
# Line 1004  sub _get_next_token ($) { Line 1050  sub _get_next_token ($) {
1050            !!!cp (7);            !!!cp (7);
1051            #            #
1052          }          }
1053        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
1054          if ($self->{escape} and          if ($self->{escape} and
1055              ($self->{content_model} & CM_LIMITED_MARKUP)) { # RCDATA | CDATA              ($self->{content_model} & CM_LIMITED_MARKUP)) { # RCDATA | CDATA
1056            if ($self->{prev_char}->[0] == 0x002D and # -            if (defined $self->{s_kwd} and $self->{s_kwd} eq '--') {
               $self->{prev_char}->[1] == 0x002D) { # -  
1057              !!!cp (8);              !!!cp (8);
1058              delete $self->{escape};              delete $self->{escape};
1059            } else {            } else {
# Line 1018  sub _get_next_token ($) { Line 1063  sub _get_next_token ($) {
1063            !!!cp (10);            !!!cp (10);
1064          }          }
1065                    
1066            delete $self->{s_kwd};
1067          #          #
1068        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
1069          !!!cp (11);          !!!cp (11);
1070            delete $self->{s_kwd};
1071          !!!emit ({type => END_OF_FILE_TOKEN,          !!!emit ({type => END_OF_FILE_TOKEN,
1072                    line => $self->{line}, column => $self->{column}});                    line => $self->{line}, column => $self->{column}});
1073          last A; ## TODO: ok?          last A; ## TODO: ok?
1074        } else {        } else {
1075          !!!cp (12);          !!!cp (12);
1076            delete $self->{s_kwd};
1077            #
1078        }        }
1079    
1080        # Anything else        # Anything else
1081        my $token = {type => CHARACTER_TOKEN,        my $token = {type => CHARACTER_TOKEN,
1082                     data => chr $self->{next_char},                     data => chr $self->{nc},
1083                     line => $self->{line}, column => $self->{column},                     line => $self->{line}, column => $self->{column},
1084                    };                    };
1085        $self->{read_until}->($token->{data}, q[-!<>&], length $token->{data});        if ($self->{read_until}->($token->{data}, q[-!<>&],
1086                                    length $token->{data})) {
1087            delete $self->{s_kwd};
1088          }
1089    
1090        ## Stay in the data state        ## Stay in the data state
1091        !!!next-input-character;        !!!next-input-character;
   
1092        !!!emit ($token);        !!!emit ($token);
   
1093        redo A;        redo A;
1094      } elsif ($self->{state} == TAG_OPEN_STATE) {      } elsif ($self->{state} == TAG_OPEN_STATE) {
1095        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
1096          if ($self->{next_char} == 0x002F) { # /          if ($self->{nc} == 0x002F) { # /
1097            !!!cp (15);            !!!cp (15);
1098            !!!next-input-character;            !!!next-input-character;
1099            $self->{state} = CLOSE_TAG_OPEN_STATE;            $self->{state} = CLOSE_TAG_OPEN_STATE;
1100            redo A;            redo A;
1101            } elsif ($self->{nc} == 0x0021) { # !
1102              !!!cp (15.1);
1103              $self->{s_kwd} = '<' unless $self->{escape};
1104              #
1105          } else {          } else {
1106            !!!cp (16);            !!!cp (16);
1107            ## reconsume            #
           $self->{state} = DATA_STATE;  
   
           !!!emit ({type => CHARACTER_TOKEN, data => '<',  
                     line => $self->{line_prev},  
                     column => $self->{column_prev},  
                    });  
   
           redo A;  
1108          }          }
1109    
1110            ## reconsume
1111            $self->{state} = DATA_STATE;
1112            !!!emit ({type => CHARACTER_TOKEN, data => '<',
1113                      line => $self->{line_prev},
1114                      column => $self->{column_prev},
1115                     });
1116            redo A;
1117        } elsif ($self->{content_model} & CM_FULL_MARKUP) { # PCDATA        } elsif ($self->{content_model} & CM_FULL_MARKUP) { # PCDATA
1118          if ($self->{next_char} == 0x0021) { # !          if ($self->{nc} == 0x0021) { # !
1119            !!!cp (17);            !!!cp (17);
1120            $self->{state} = MARKUP_DECLARATION_OPEN_STATE;            $self->{state} = MARKUP_DECLARATION_OPEN_STATE;
1121            !!!next-input-character;            !!!next-input-character;
1122            redo A;            redo A;
1123          } elsif ($self->{next_char} == 0x002F) { # /          } elsif ($self->{nc} == 0x002F) { # /
1124            !!!cp (18);            !!!cp (18);
1125            $self->{state} = CLOSE_TAG_OPEN_STATE;            $self->{state} = CLOSE_TAG_OPEN_STATE;
1126            !!!next-input-character;            !!!next-input-character;
1127            redo A;            redo A;
1128          } elsif (0x0041 <= $self->{next_char} and          } elsif (0x0041 <= $self->{nc} and
1129                   $self->{next_char} <= 0x005A) { # A..Z                   $self->{nc} <= 0x005A) { # A..Z
1130            !!!cp (19);            !!!cp (19);
1131            $self->{current_token}            $self->{ct}
1132              = {type => START_TAG_TOKEN,              = {type => START_TAG_TOKEN,
1133                 tag_name => chr ($self->{next_char} + 0x0020),                 tag_name => chr ($self->{nc} + 0x0020),
1134                 line => $self->{line_prev},                 line => $self->{line_prev},
1135                 column => $self->{column_prev}};                 column => $self->{column_prev}};
1136            $self->{state} = TAG_NAME_STATE;            $self->{state} = TAG_NAME_STATE;
1137            !!!next-input-character;            !!!next-input-character;
1138            redo A;            redo A;
1139          } elsif (0x0061 <= $self->{next_char} and          } elsif (0x0061 <= $self->{nc} and
1140                   $self->{next_char} <= 0x007A) { # a..z                   $self->{nc} <= 0x007A) { # a..z
1141            !!!cp (20);            !!!cp (20);
1142            $self->{current_token} = {type => START_TAG_TOKEN,            $self->{ct} = {type => START_TAG_TOKEN,
1143                                      tag_name => chr ($self->{next_char}),                                      tag_name => chr ($self->{nc}),
1144                                      line => $self->{line_prev},                                      line => $self->{line_prev},
1145                                      column => $self->{column_prev}};                                      column => $self->{column_prev}};
1146            $self->{state} = TAG_NAME_STATE;            $self->{state} = TAG_NAME_STATE;
1147            !!!next-input-character;            !!!next-input-character;
1148            redo A;            redo A;
1149          } elsif ($self->{next_char} == 0x003E) { # >          } elsif ($self->{nc} == 0x003E) { # >
1150            !!!cp (21);            !!!cp (21);
1151            !!!parse-error (type => 'empty start tag',            !!!parse-error (type => 'empty start tag',
1152                            line => $self->{line_prev},                            line => $self->{line_prev},
# Line 1105  sub _get_next_token ($) { Line 1160  sub _get_next_token ($) {
1160                     });                     });
1161    
1162            redo A;            redo A;
1163          } elsif ($self->{next_char} == 0x003F) { # ?          } elsif ($self->{nc} == 0x003F) { # ?
1164            !!!cp (22);            !!!cp (22);
1165            !!!parse-error (type => 'pio',            !!!parse-error (type => 'pio',
1166                            line => $self->{line_prev},                            line => $self->{line_prev},
1167                            column => $self->{column_prev});                            column => $self->{column_prev});
1168            $self->{state} = BOGUS_COMMENT_STATE;            $self->{state} = BOGUS_COMMENT_STATE;
1169            $self->{current_token} = {type => COMMENT_TOKEN, data => '',            $self->{ct} = {type => COMMENT_TOKEN, data => '',
1170                                      line => $self->{line_prev},                                      line => $self->{line_prev},
1171                                      column => $self->{column_prev},                                      column => $self->{column_prev},
1172                                     };                                     };
1173            ## $self->{next_char} is intentionally left as is            ## $self->{nc} is intentionally left as is
1174            redo A;            redo A;
1175          } else {          } else {
1176            !!!cp (23);            !!!cp (23);
# Line 1141  sub _get_next_token ($) { Line 1196  sub _get_next_token ($) {
1196    
1197        my ($l, $c) = ($self->{line_prev}, $self->{column_prev} - 1); # "<"of"</"        my ($l, $c) = ($self->{line_prev}, $self->{column_prev} - 1); # "<"of"</"
1198        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
1199          if (defined $self->{last_emitted_start_tag_name}) {          if (defined $self->{last_stag_name}) {
1200            $self->{state} = CDATA_PCDATA_CLOSE_TAG_STATE;            $self->{state} = CDATA_PCDATA_CLOSE_TAG_STATE;
1201            $self->{state_keyword} = '';            $self->{s_kwd} = '';
1202            ## Reconsume.            ## Reconsume.
1203            redo A;            redo A;
1204          } else {          } else {
# Line 1159  sub _get_next_token ($) { Line 1214  sub _get_next_token ($) {
1214          }          }
1215        }        }
1216    
1217        if (0x0041 <= $self->{next_char} and        if (0x0041 <= $self->{nc} and
1218            $self->{next_char} <= 0x005A) { # A..Z            $self->{nc} <= 0x005A) { # A..Z
1219          !!!cp (29);          !!!cp (29);
1220          $self->{current_token}          $self->{ct}
1221              = {type => END_TAG_TOKEN,              = {type => END_TAG_TOKEN,
1222                 tag_name => chr ($self->{next_char} + 0x0020),                 tag_name => chr ($self->{nc} + 0x0020),
1223                 line => $l, column => $c};                 line => $l, column => $c};
1224          $self->{state} = TAG_NAME_STATE;          $self->{state} = TAG_NAME_STATE;
1225          !!!next-input-character;          !!!next-input-character;
1226          redo A;          redo A;
1227        } elsif (0x0061 <= $self->{next_char} and        } elsif (0x0061 <= $self->{nc} and
1228                 $self->{next_char} <= 0x007A) { # a..z                 $self->{nc} <= 0x007A) { # a..z
1229          !!!cp (30);          !!!cp (30);
1230          $self->{current_token} = {type => END_TAG_TOKEN,          $self->{ct} = {type => END_TAG_TOKEN,
1231                                    tag_name => chr ($self->{next_char}),                                    tag_name => chr ($self->{nc}),
1232                                    line => $l, column => $c};                                    line => $l, column => $c};
1233          $self->{state} = TAG_NAME_STATE;          $self->{state} = TAG_NAME_STATE;
1234          !!!next-input-character;          !!!next-input-character;
1235          redo A;          redo A;
1236        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
1237          !!!cp (31);          !!!cp (31);
1238          !!!parse-error (type => 'empty end tag',          !!!parse-error (type => 'empty end tag',
1239                          line => $self->{line_prev}, ## "<" in "</>"                          line => $self->{line_prev}, ## "<" in "</>"
# Line 1186  sub _get_next_token ($) { Line 1241  sub _get_next_token ($) {
1241          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1242          !!!next-input-character;          !!!next-input-character;
1243          redo A;          redo A;
1244        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
1245          !!!cp (32);          !!!cp (32);
1246          !!!parse-error (type => 'bare etago');          !!!parse-error (type => 'bare etago');
1247          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
# Line 1201  sub _get_next_token ($) { Line 1256  sub _get_next_token ($) {
1256          !!!cp (33);          !!!cp (33);
1257          !!!parse-error (type => 'bogus end tag');          !!!parse-error (type => 'bogus end tag');
1258          $self->{state} = BOGUS_COMMENT_STATE;          $self->{state} = BOGUS_COMMENT_STATE;
1259          $self->{current_token} = {type => COMMENT_TOKEN, data => '',          $self->{ct} = {type => COMMENT_TOKEN, data => '',
1260                                    line => $self->{line_prev}, # "<" of "</"                                    line => $self->{line_prev}, # "<" of "</"
1261                                    column => $self->{column_prev} - 1,                                    column => $self->{column_prev} - 1,
1262                                   };                                   };
1263          ## NOTE: $self->{next_char} is intentionally left as is.          ## NOTE: $self->{nc} is intentionally left as is.
1264          ## Although the "anything else" case of the spec not explicitly          ## Although the "anything else" case of the spec not explicitly
1265          ## states that the next input character is to be reconsumed,          ## states that the next input character is to be reconsumed,
1266          ## it will be included to the |data| of the comment token          ## it will be included to the |data| of the comment token
# Line 1214  sub _get_next_token ($) { Line 1269  sub _get_next_token ($) {
1269          redo A;          redo A;
1270        }        }
1271      } elsif ($self->{state} == CDATA_PCDATA_CLOSE_TAG_STATE) {      } elsif ($self->{state} == CDATA_PCDATA_CLOSE_TAG_STATE) {
1272        my $ch = substr $self->{last_emitted_start_tag_name}, length $self->{state_keyword}, 1;        my $ch = substr $self->{last_stag_name}, length $self->{s_kwd}, 1;
1273        if (length $ch) {        if (length $ch) {
1274          my $CH = $ch;          my $CH = $ch;
1275          $ch =~ tr/a-z/A-Z/;          $ch =~ tr/a-z/A-Z/;
1276          my $nch = chr $self->{next_char};          my $nch = chr $self->{nc};
1277          if ($nch eq $ch or $nch eq $CH) {          if ($nch eq $ch or $nch eq $CH) {
1278            !!!cp (24);            !!!cp (24);
1279            ## Stay in the state.            ## Stay in the state.
1280            $self->{state_keyword} .= $nch;            $self->{s_kwd} .= $nch;
1281            !!!next-input-character;            !!!next-input-character;
1282            redo A;            redo A;
1283          } else {          } else {
# Line 1230  sub _get_next_token ($) { Line 1285  sub _get_next_token ($) {
1285            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
1286            ## Reconsume.            ## Reconsume.
1287            !!!emit ({type => CHARACTER_TOKEN,            !!!emit ({type => CHARACTER_TOKEN,
1288                      data => '</' . $self->{state_keyword},                      data => '</' . $self->{s_kwd},
1289                      line => $self->{line_prev},                      line => $self->{line_prev},
1290                      column => $self->{column_prev} - 1 - length $self->{state_keyword},                      column => $self->{column_prev} - 1 - length $self->{s_kwd},
1291                     });                     });
1292            redo A;            redo A;
1293          }          }
# Line 1246  sub _get_next_token ($) { Line 1301  sub _get_next_token ($) {
1301                   0x003E => 1, # >                   0x003E => 1, # >
1302                   0x002F => 1, # /                   0x002F => 1, # /
1303                   -1 => 1, # EOF                   -1 => 1, # EOF
1304                  }->{$self->{next_char}}) {                  }->{$self->{nc}}) {
1305            !!!cp (26);            !!!cp (26);
1306            ## Reconsume.            ## Reconsume.
1307            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
1308            !!!emit ({type => CHARACTER_TOKEN,            !!!emit ({type => CHARACTER_TOKEN,
1309                      data => '</' . $self->{state_keyword},                      data => '</' . $self->{s_kwd},
1310                      line => $self->{line_prev},                      line => $self->{line_prev},
1311                      column => $self->{column_prev} - 1 - length $self->{state_keyword},                      column => $self->{column_prev} - 1 - length $self->{s_kwd},
1312                     });                     });
1313            redo A;            redo A;
1314          } else {          } else {
1315            !!!cp (27);            !!!cp (27);
1316            $self->{current_token}            $self->{ct}
1317                = {type => END_TAG_TOKEN,                = {type => END_TAG_TOKEN,
1318                   tag_name => $self->{last_emitted_start_tag_name},                   tag_name => $self->{last_stag_name},
1319                   line => $self->{line_prev},                   line => $self->{line_prev},
1320                   column => $self->{column_prev} - 1 - length $self->{state_keyword}};                   column => $self->{column_prev} - 1 - length $self->{s_kwd}};
1321            $self->{state} = TAG_NAME_STATE;            $self->{state} = TAG_NAME_STATE;
1322            ## Reconsume.            ## Reconsume.
1323            redo A;            redo A;
1324          }          }
1325        }        }
1326      } elsif ($self->{state} == TAG_NAME_STATE) {      } elsif ($self->{state} == TAG_NAME_STATE) {
1327        if ($self->{next_char} == 0x0009 or # HT        if ($self->{nc} == 0x0009 or # HT
1328            $self->{next_char} == 0x000A or # LF            $self->{nc} == 0x000A or # LF
1329            $self->{next_char} == 0x000B or # VT            $self->{nc} == 0x000B or # VT
1330            $self->{next_char} == 0x000C or # FF            $self->{nc} == 0x000C or # FF
1331            $self->{next_char} == 0x0020) { # SP            $self->{nc} == 0x0020) { # SP
1332          !!!cp (34);          !!!cp (34);
1333          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
1334          !!!next-input-character;          !!!next-input-character;
1335          redo A;          redo A;
1336        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
1337          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1338            !!!cp (35);            !!!cp (35);
1339            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1340          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1341            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1342            #if ($self->{current_token}->{attributes}) {            #if ($self->{ct}->{attributes}) {
1343            #  ## NOTE: This should never be reached.            #  ## NOTE: This should never be reached.
1344            #  !!! cp (36);            #  !!! cp (36);
1345            #  !!! parse-error (type => 'end tag attribute');            #  !!! parse-error (type => 'end tag attribute');
# Line 1292  sub _get_next_token ($) { Line 1347  sub _get_next_token ($) {
1347              !!!cp (37);              !!!cp (37);
1348            #}            #}
1349          } else {          } else {
1350            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1351          }          }
1352          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1353          !!!next-input-character;          !!!next-input-character;
1354    
1355          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1356    
1357          redo A;          redo A;
1358        } elsif (0x0041 <= $self->{next_char} and        } elsif (0x0041 <= $self->{nc} and
1359                 $self->{next_char} <= 0x005A) { # A..Z                 $self->{nc} <= 0x005A) { # A..Z
1360          !!!cp (38);          !!!cp (38);
1361          $self->{current_token}->{tag_name} .= chr ($self->{next_char} + 0x0020);          $self->{ct}->{tag_name} .= chr ($self->{nc} + 0x0020);
1362            # start tag or end tag            # start tag or end tag
1363          ## Stay in this state          ## Stay in this state
1364          !!!next-input-character;          !!!next-input-character;
1365          redo A;          redo A;
1366        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
1367          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
1368          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1369            !!!cp (39);            !!!cp (39);
1370            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1371          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1372            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1373            #if ($self->{current_token}->{attributes}) {            #if ($self->{ct}->{attributes}) {
1374            #  ## NOTE: This state should never be reached.            #  ## NOTE: This state should never be reached.
1375            #  !!! cp (40);            #  !!! cp (40);
1376            #  !!! parse-error (type => 'end tag attribute');            #  !!! parse-error (type => 'end tag attribute');
# Line 1323  sub _get_next_token ($) { Line 1378  sub _get_next_token ($) {
1378              !!!cp (41);              !!!cp (41);
1379            #}            #}
1380          } else {          } else {
1381            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1382          }          }
1383          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1384          # reconsume          # reconsume
1385    
1386          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1387    
1388          redo A;          redo A;
1389        } elsif ($self->{next_char} == 0x002F) { # /        } elsif ($self->{nc} == 0x002F) { # /
1390          !!!cp (42);          !!!cp (42);
1391          $self->{state} = SELF_CLOSING_START_TAG_STATE;          $self->{state} = SELF_CLOSING_START_TAG_STATE;
1392          !!!next-input-character;          !!!next-input-character;
1393          redo A;          redo A;
1394        } else {        } else {
1395          !!!cp (44);          !!!cp (44);
1396          $self->{current_token}->{tag_name} .= chr $self->{next_char};          $self->{ct}->{tag_name} .= chr $self->{nc};
1397            # start tag or end tag            # start tag or end tag
1398          ## Stay in the state          ## Stay in the state
1399          !!!next-input-character;          !!!next-input-character;
1400          redo A;          redo A;
1401        }        }
1402      } elsif ($self->{state} == BEFORE_ATTRIBUTE_NAME_STATE) {      } elsif ($self->{state} == BEFORE_ATTRIBUTE_NAME_STATE) {
1403        if ($self->{next_char} == 0x0009 or # HT        if ($self->{nc} == 0x0009 or # HT
1404            $self->{next_char} == 0x000A or # LF            $self->{nc} == 0x000A or # LF
1405            $self->{next_char} == 0x000B or # VT            $self->{nc} == 0x000B or # VT
1406            $self->{next_char} == 0x000C or # FF            $self->{nc} == 0x000C or # FF
1407            $self->{next_char} == 0x0020) { # SP            $self->{nc} == 0x0020) { # SP
1408          !!!cp (45);          !!!cp (45);
1409          ## Stay in the state          ## Stay in the state
1410          !!!next-input-character;          !!!next-input-character;
1411          redo A;          redo A;
1412        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
1413          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1414            !!!cp (46);            !!!cp (46);
1415            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1416          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1417            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1418            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1419              !!!cp (47);              !!!cp (47);
1420              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1421            } else {            } else {
1422              !!!cp (48);              !!!cp (48);
1423            }            }
1424          } else {          } else {
1425            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1426          }          }
1427          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1428          !!!next-input-character;          !!!next-input-character;
1429    
1430          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1431    
1432          redo A;          redo A;
1433        } elsif (0x0041 <= $self->{next_char} and        } elsif (0x0041 <= $self->{nc} and
1434                 $self->{next_char} <= 0x005A) { # A..Z                 $self->{nc} <= 0x005A) { # A..Z
1435          !!!cp (49);          !!!cp (49);
1436          $self->{current_attribute}          $self->{ca}
1437              = {name => chr ($self->{next_char} + 0x0020),              = {name => chr ($self->{nc} + 0x0020),
1438                 value => '',                 value => '',
1439                 line => $self->{line}, column => $self->{column}};                 line => $self->{line}, column => $self->{column}};
1440          $self->{state} = ATTRIBUTE_NAME_STATE;          $self->{state} = ATTRIBUTE_NAME_STATE;
1441          !!!next-input-character;          !!!next-input-character;
1442          redo A;          redo A;
1443        } elsif ($self->{next_char} == 0x002F) { # /        } elsif ($self->{nc} == 0x002F) { # /
1444          !!!cp (50);          !!!cp (50);
1445          $self->{state} = SELF_CLOSING_START_TAG_STATE;          $self->{state} = SELF_CLOSING_START_TAG_STATE;
1446          !!!next-input-character;          !!!next-input-character;
1447          redo A;          redo A;
1448        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
1449          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
1450          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1451            !!!cp (52);            !!!cp (52);
1452            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1453          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1454            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1455            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1456              !!!cp (53);              !!!cp (53);
1457              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1458            } else {            } else {
1459              !!!cp (54);              !!!cp (54);
1460            }            }
1461          } else {          } else {
1462            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1463          }          }
1464          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1465          # reconsume          # reconsume
1466    
1467          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1468    
1469          redo A;          redo A;
1470        } else {        } else {
# Line 1417  sub _get_next_token ($) { Line 1472  sub _get_next_token ($) {
1472               0x0022 => 1, # "               0x0022 => 1, # "
1473               0x0027 => 1, # '               0x0027 => 1, # '
1474               0x003D => 1, # =               0x003D => 1, # =
1475              }->{$self->{next_char}}) {              }->{$self->{nc}}) {
1476            !!!cp (55);            !!!cp (55);
1477            !!!parse-error (type => 'bad attribute name');            !!!parse-error (type => 'bad attribute name');
1478          } else {          } else {
1479            !!!cp (56);            !!!cp (56);
1480          }          }
1481          $self->{current_attribute}          $self->{ca}
1482              = {name => chr ($self->{next_char}),              = {name => chr ($self->{nc}),
1483                 value => '',                 value => '',
1484                 line => $self->{line}, column => $self->{column}};                 line => $self->{line}, column => $self->{column}};
1485          $self->{state} = ATTRIBUTE_NAME_STATE;          $self->{state} = ATTRIBUTE_NAME_STATE;
# Line 1433  sub _get_next_token ($) { Line 1488  sub _get_next_token ($) {
1488        }        }
1489      } elsif ($self->{state} == ATTRIBUTE_NAME_STATE) {      } elsif ($self->{state} == ATTRIBUTE_NAME_STATE) {
1490        my $before_leave = sub {        my $before_leave = sub {
1491          if (exists $self->{current_token}->{attributes} # start tag or end tag          if (exists $self->{ct}->{attributes} # start tag or end tag
1492              ->{$self->{current_attribute}->{name}}) { # MUST              ->{$self->{ca}->{name}}) { # MUST
1493            !!!cp (57);            !!!cp (57);
1494            !!!parse-error (type => 'duplicate attribute', text => $self->{current_attribute}->{name}, line => $self->{current_attribute}->{line}, column => $self->{current_attribute}->{column});            !!!parse-error (type => 'duplicate attribute', text => $self->{ca}->{name}, line => $self->{ca}->{line}, column => $self->{ca}->{column});
1495            ## Discard $self->{current_attribute} # MUST            ## Discard $self->{ca} # MUST
1496          } else {          } else {
1497            !!!cp (58);            !!!cp (58);
1498            $self->{current_token}->{attributes}->{$self->{current_attribute}->{name}}            $self->{ct}->{attributes}->{$self->{ca}->{name}}
1499              = $self->{current_attribute};              = $self->{ca};
1500          }          }
1501        }; # $before_leave        }; # $before_leave
1502    
1503        if ($self->{next_char} == 0x0009 or # HT        if ($self->{nc} == 0x0009 or # HT
1504            $self->{next_char} == 0x000A or # LF            $self->{nc} == 0x000A or # LF
1505            $self->{next_char} == 0x000B or # VT            $self->{nc} == 0x000B or # VT
1506            $self->{next_char} == 0x000C or # FF            $self->{nc} == 0x000C or # FF
1507            $self->{next_char} == 0x0020) { # SP            $self->{nc} == 0x0020) { # SP
1508          !!!cp (59);          !!!cp (59);
1509          $before_leave->();          $before_leave->();
1510          $self->{state} = AFTER_ATTRIBUTE_NAME_STATE;          $self->{state} = AFTER_ATTRIBUTE_NAME_STATE;
1511          !!!next-input-character;          !!!next-input-character;
1512          redo A;          redo A;
1513        } elsif ($self->{next_char} == 0x003D) { # =        } elsif ($self->{nc} == 0x003D) { # =
1514          !!!cp (60);          !!!cp (60);
1515          $before_leave->();          $before_leave->();
1516          $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;          $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;
1517          !!!next-input-character;          !!!next-input-character;
1518          redo A;          redo A;
1519        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
1520          $before_leave->();          $before_leave->();
1521          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1522            !!!cp (61);            !!!cp (61);
1523            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1524          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1525            !!!cp (62);            !!!cp (62);
1526            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1527            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1528              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1529            }            }
1530          } else {          } else {
1531            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1532          }          }
1533          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1534          !!!next-input-character;          !!!next-input-character;
1535    
1536          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1537    
1538          redo A;          redo A;
1539        } elsif (0x0041 <= $self->{next_char} and        } elsif (0x0041 <= $self->{nc} and
1540                 $self->{next_char} <= 0x005A) { # A..Z                 $self->{nc} <= 0x005A) { # A..Z
1541          !!!cp (63);          !!!cp (63);
1542          $self->{current_attribute}->{name} .= chr ($self->{next_char} + 0x0020);          $self->{ca}->{name} .= chr ($self->{nc} + 0x0020);
1543          ## Stay in the state          ## Stay in the state
1544          !!!next-input-character;          !!!next-input-character;
1545          redo A;          redo A;
1546        } elsif ($self->{next_char} == 0x002F) { # /        } elsif ($self->{nc} == 0x002F) { # /
1547          !!!cp (64);          !!!cp (64);
1548          $before_leave->();          $before_leave->();
1549          $self->{state} = SELF_CLOSING_START_TAG_STATE;          $self->{state} = SELF_CLOSING_START_TAG_STATE;
1550          !!!next-input-character;          !!!next-input-character;
1551          redo A;          redo A;
1552        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
1553          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
1554          $before_leave->();          $before_leave->();
1555          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1556            !!!cp (66);            !!!cp (66);
1557            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1558          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1559            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1560            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1561              !!!cp (67);              !!!cp (67);
1562              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1563            } else {            } else {
# Line 1510  sub _get_next_token ($) { Line 1565  sub _get_next_token ($) {
1565              !!!cp (68);              !!!cp (68);
1566            }            }
1567          } else {          } else {
1568            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1569          }          }
1570          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1571          # reconsume          # reconsume
1572    
1573          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1574    
1575          redo A;          redo A;
1576        } else {        } else {
1577          if ($self->{next_char} == 0x0022 or # "          if ($self->{nc} == 0x0022 or # "
1578              $self->{next_char} == 0x0027) { # '              $self->{nc} == 0x0027) { # '
1579            !!!cp (69);            !!!cp (69);
1580            !!!parse-error (type => 'bad attribute name');            !!!parse-error (type => 'bad attribute name');
1581          } else {          } else {
1582            !!!cp (70);            !!!cp (70);
1583          }          }
1584          $self->{current_attribute}->{name} .= chr ($self->{next_char});          $self->{ca}->{name} .= chr ($self->{nc});
1585          ## Stay in the state          ## Stay in the state
1586          !!!next-input-character;          !!!next-input-character;
1587          redo A;          redo A;
1588        }        }
1589      } elsif ($self->{state} == AFTER_ATTRIBUTE_NAME_STATE) {      } elsif ($self->{state} == AFTER_ATTRIBUTE_NAME_STATE) {
1590        if ($self->{next_char} == 0x0009 or # HT        if ($self->{nc} == 0x0009 or # HT
1591            $self->{next_char} == 0x000A or # LF            $self->{nc} == 0x000A or # LF
1592            $self->{next_char} == 0x000B or # VT            $self->{nc} == 0x000B or # VT
1593            $self->{next_char} == 0x000C or # FF            $self->{nc} == 0x000C or # FF
1594            $self->{next_char} == 0x0020) { # SP            $self->{nc} == 0x0020) { # SP
1595          !!!cp (71);          !!!cp (71);
1596          ## Stay in the state          ## Stay in the state
1597          !!!next-input-character;          !!!next-input-character;
1598          redo A;          redo A;
1599        } elsif ($self->{next_char} == 0x003D) { # =        } elsif ($self->{nc} == 0x003D) { # =
1600          !!!cp (72);          !!!cp (72);
1601          $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;          $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;
1602          !!!next-input-character;          !!!next-input-character;
1603          redo A;          redo A;
1604        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
1605          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1606            !!!cp (73);            !!!cp (73);
1607            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1608          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1609            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1610            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1611              !!!cp (74);              !!!cp (74);
1612              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1613            } else {            } else {
# Line 1560  sub _get_next_token ($) { Line 1615  sub _get_next_token ($) {
1615              !!!cp (75);              !!!cp (75);
1616            }            }
1617          } else {          } else {
1618            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1619          }          }
1620          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1621          !!!next-input-character;          !!!next-input-character;
1622    
1623          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1624    
1625          redo A;          redo A;
1626        } elsif (0x0041 <= $self->{next_char} and        } elsif (0x0041 <= $self->{nc} and
1627                 $self->{next_char} <= 0x005A) { # A..Z                 $self->{nc} <= 0x005A) { # A..Z
1628          !!!cp (76);          !!!cp (76);
1629          $self->{current_attribute}          $self->{ca}
1630              = {name => chr ($self->{next_char} + 0x0020),              = {name => chr ($self->{nc} + 0x0020),
1631                 value => '',                 value => '',
1632                 line => $self->{line}, column => $self->{column}};                 line => $self->{line}, column => $self->{column}};
1633          $self->{state} = ATTRIBUTE_NAME_STATE;          $self->{state} = ATTRIBUTE_NAME_STATE;
1634          !!!next-input-character;          !!!next-input-character;
1635          redo A;          redo A;
1636        } elsif ($self->{next_char} == 0x002F) { # /        } elsif ($self->{nc} == 0x002F) { # /
1637          !!!cp (77);          !!!cp (77);
1638          $self->{state} = SELF_CLOSING_START_TAG_STATE;          $self->{state} = SELF_CLOSING_START_TAG_STATE;
1639          !!!next-input-character;          !!!next-input-character;
1640          redo A;          redo A;
1641        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
1642          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
1643          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1644            !!!cp (79);            !!!cp (79);
1645            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1646          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1647            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1648            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1649              !!!cp (80);              !!!cp (80);
1650              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1651            } else {            } else {
# Line 1598  sub _get_next_token ($) { Line 1653  sub _get_next_token ($) {
1653              !!!cp (81);              !!!cp (81);
1654            }            }
1655          } else {          } else {
1656            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1657          }          }
1658          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1659          # reconsume          # reconsume
1660    
1661          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1662    
1663          redo A;          redo A;
1664        } else {        } else {
1665          if ($self->{next_char} == 0x0022 or # "          if ($self->{nc} == 0x0022 or # "
1666              $self->{next_char} == 0x0027) { # '              $self->{nc} == 0x0027) { # '
1667            !!!cp (78);            !!!cp (78);
1668            !!!parse-error (type => 'bad attribute name');            !!!parse-error (type => 'bad attribute name');
1669          } else {          } else {
1670            !!!cp (82);            !!!cp (82);
1671          }          }
1672          $self->{current_attribute}          $self->{ca}
1673              = {name => chr ($self->{next_char}),              = {name => chr ($self->{nc}),
1674                 value => '',                 value => '',
1675                 line => $self->{line}, column => $self->{column}};                 line => $self->{line}, column => $self->{column}};
1676          $self->{state} = ATTRIBUTE_NAME_STATE;          $self->{state} = ATTRIBUTE_NAME_STATE;
# Line 1623  sub _get_next_token ($) { Line 1678  sub _get_next_token ($) {
1678          redo A;                  redo A;        
1679        }        }
1680      } elsif ($self->{state} == BEFORE_ATTRIBUTE_VALUE_STATE) {      } elsif ($self->{state} == BEFORE_ATTRIBUTE_VALUE_STATE) {
1681        if ($self->{next_char} == 0x0009 or # HT        if ($self->{nc} == 0x0009 or # HT
1682            $self->{next_char} == 0x000A or # LF            $self->{nc} == 0x000A or # LF
1683            $self->{next_char} == 0x000B or # VT            $self->{nc} == 0x000B or # VT
1684            $self->{next_char} == 0x000C or # FF            $self->{nc} == 0x000C or # FF
1685            $self->{next_char} == 0x0020) { # SP                  $self->{nc} == 0x0020) { # SP      
1686          !!!cp (83);          !!!cp (83);
1687          ## Stay in the state          ## Stay in the state
1688          !!!next-input-character;          !!!next-input-character;
1689          redo A;          redo A;
1690        } elsif ($self->{next_char} == 0x0022) { # "        } elsif ($self->{nc} == 0x0022) { # "
1691          !!!cp (84);          !!!cp (84);
1692          $self->{state} = ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE;          $self->{state} = ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE;
1693          !!!next-input-character;          !!!next-input-character;
1694          redo A;          redo A;
1695        } elsif ($self->{next_char} == 0x0026) { # &        } elsif ($self->{nc} == 0x0026) { # &
1696          !!!cp (85);          !!!cp (85);
1697          $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;          $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;
1698          ## reconsume          ## reconsume
1699          redo A;          redo A;
1700        } elsif ($self->{next_char} == 0x0027) { # '        } elsif ($self->{nc} == 0x0027) { # '
1701          !!!cp (86);          !!!cp (86);
1702          $self->{state} = ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE;          $self->{state} = ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE;
1703          !!!next-input-character;          !!!next-input-character;
1704          redo A;          redo A;
1705        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
1706          !!!parse-error (type => 'empty unquoted attribute value');          !!!parse-error (type => 'empty unquoted attribute value');
1707          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1708            !!!cp (87);            !!!cp (87);
1709            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1710          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1711            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1712            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1713              !!!cp (88);              !!!cp (88);
1714              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1715            } else {            } else {
# Line 1662  sub _get_next_token ($) { Line 1717  sub _get_next_token ($) {
1717              !!!cp (89);              !!!cp (89);
1718            }            }
1719          } else {          } else {
1720            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1721          }          }
1722          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1723          !!!next-input-character;          !!!next-input-character;
1724    
1725          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1726    
1727          redo A;          redo A;
1728        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
1729          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
1730          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1731            !!!cp (90);            !!!cp (90);
1732            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1733          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1734            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1735            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1736              !!!cp (91);              !!!cp (91);
1737              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1738            } else {            } else {
# Line 1685  sub _get_next_token ($) { Line 1740  sub _get_next_token ($) {
1740              !!!cp (92);              !!!cp (92);
1741            }            }
1742          } else {          } else {
1743            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1744          }          }
1745          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1746          ## reconsume          ## reconsume
1747    
1748          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1749    
1750          redo A;          redo A;
1751        } else {        } else {
1752          if ($self->{next_char} == 0x003D) { # =          if ($self->{nc} == 0x003D) { # =
1753            !!!cp (93);            !!!cp (93);
1754            !!!parse-error (type => 'bad attribute value');            !!!parse-error (type => 'bad attribute value');
1755          } else {          } else {
1756            !!!cp (94);            !!!cp (94);
1757          }          }
1758          $self->{current_attribute}->{value} .= chr ($self->{next_char});          $self->{ca}->{value} .= chr ($self->{nc});
1759          $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;          $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;
1760          !!!next-input-character;          !!!next-input-character;
1761          redo A;          redo A;
1762        }        }
1763      } elsif ($self->{state} == ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE) {      } elsif ($self->{state} == ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE) {
1764        if ($self->{next_char} == 0x0022) { # "        if ($self->{nc} == 0x0022) { # "
1765          !!!cp (95);          !!!cp (95);
1766          $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;          $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;
1767          !!!next-input-character;          !!!next-input-character;
1768          redo A;          redo A;
1769        } elsif ($self->{next_char} == 0x0026) { # &        } elsif ($self->{nc} == 0x0026) { # &
1770          !!!cp (96);          !!!cp (96);
1771          ## NOTE: In the spec, the tokenizer is switched to the          ## NOTE: In the spec, the tokenizer is switched to the
1772          ## "entity in attribute value state".  In this implementation, the          ## "entity in attribute value state".  In this implementation, the
1773          ## tokenizer is switched to the |ENTITY_STATE|, which is an          ## tokenizer is switched to the |ENTITY_STATE|, which is an
1774          ## implementation of the "consume a character reference" algorithm.          ## implementation of the "consume a character reference" algorithm.
1775          $self->{prev_state} = $self->{state};          $self->{prev_state} = $self->{state};
1776          $self->{entity_additional} = 0x0022; # "          $self->{entity_add} = 0x0022; # "
1777          $self->{state} = ENTITY_STATE;          $self->{state} = ENTITY_STATE;
1778          !!!next-input-character;          !!!next-input-character;
1779          redo A;          redo A;
1780        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
1781          !!!parse-error (type => 'unclosed attribute value');          !!!parse-error (type => 'unclosed attribute value');
1782          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1783            !!!cp (97);            !!!cp (97);
1784            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1785          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1786            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1787            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1788              !!!cp (98);              !!!cp (98);
1789              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1790            } else {            } else {
# Line 1737  sub _get_next_token ($) { Line 1792  sub _get_next_token ($) {
1792              !!!cp (99);              !!!cp (99);
1793            }            }
1794          } else {          } else {
1795            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1796          }          }
1797          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1798          ## reconsume          ## reconsume
1799    
1800          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1801    
1802          redo A;          redo A;
1803        } else {        } else {
1804          !!!cp (100);          !!!cp (100);
1805          $self->{current_attribute}->{value} .= chr ($self->{next_char});          $self->{ca}->{value} .= chr ($self->{nc});
1806          $self->{read_until}->($self->{current_attribute}->{value},          $self->{read_until}->($self->{ca}->{value},
1807                                q["&],                                q["&],
1808                                length $self->{current_attribute}->{value});                                length $self->{ca}->{value});
1809    
1810          ## Stay in the state          ## Stay in the state
1811          !!!next-input-character;          !!!next-input-character;
1812          redo A;          redo A;
1813        }        }
1814      } elsif ($self->{state} == ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE) {      } elsif ($self->{state} == ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE) {
1815        if ($self->{next_char} == 0x0027) { # '        if ($self->{nc} == 0x0027) { # '
1816          !!!cp (101);          !!!cp (101);
1817          $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;          $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;
1818          !!!next-input-character;          !!!next-input-character;
1819          redo A;          redo A;
1820        } elsif ($self->{next_char} == 0x0026) { # &        } elsif ($self->{nc} == 0x0026) { # &
1821          !!!cp (102);          !!!cp (102);
1822          ## NOTE: In the spec, the tokenizer is switched to the          ## NOTE: In the spec, the tokenizer is switched to the
1823          ## "entity in attribute value state".  In this implementation, the          ## "entity in attribute value state".  In this implementation, the
1824          ## tokenizer is switched to the |ENTITY_STATE|, which is an          ## tokenizer is switched to the |ENTITY_STATE|, which is an
1825          ## implementation of the "consume a character reference" algorithm.          ## implementation of the "consume a character reference" algorithm.
1826          $self->{entity_additional} = 0x0027; # '          $self->{entity_add} = 0x0027; # '
1827          $self->{prev_state} = $self->{state};          $self->{prev_state} = $self->{state};
1828          $self->{state} = ENTITY_STATE;          $self->{state} = ENTITY_STATE;
1829          !!!next-input-character;          !!!next-input-character;
1830          redo A;          redo A;
1831        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
1832          !!!parse-error (type => 'unclosed attribute value');          !!!parse-error (type => 'unclosed attribute value');
1833          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1834            !!!cp (103);            !!!cp (103);
1835            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1836          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1837            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1838            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1839              !!!cp (104);              !!!cp (104);
1840              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1841            } else {            } else {
# Line 1788  sub _get_next_token ($) { Line 1843  sub _get_next_token ($) {
1843              !!!cp (105);              !!!cp (105);
1844            }            }
1845          } else {          } else {
1846            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1847          }          }
1848          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1849          ## reconsume          ## reconsume
1850    
1851          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1852    
1853          redo A;          redo A;
1854        } else {        } else {
1855          !!!cp (106);          !!!cp (106);
1856          $self->{current_attribute}->{value} .= chr ($self->{next_char});          $self->{ca}->{value} .= chr ($self->{nc});
1857          $self->{read_until}->($self->{current_attribute}->{value},          $self->{read_until}->($self->{ca}->{value},
1858                                q['&],                                q['&],
1859                                length $self->{current_attribute}->{value});                                length $self->{ca}->{value});
1860    
1861          ## Stay in the state          ## Stay in the state
1862          !!!next-input-character;          !!!next-input-character;
1863          redo A;          redo A;
1864        }        }
1865      } elsif ($self->{state} == ATTRIBUTE_VALUE_UNQUOTED_STATE) {      } elsif ($self->{state} == ATTRIBUTE_VALUE_UNQUOTED_STATE) {
1866        if ($self->{next_char} == 0x0009 or # HT        if ($self->{nc} == 0x0009 or # HT
1867            $self->{next_char} == 0x000A or # LF            $self->{nc} == 0x000A or # LF
1868            $self->{next_char} == 0x000B or # HT            $self->{nc} == 0x000B or # HT
1869            $self->{next_char} == 0x000C or # FF            $self->{nc} == 0x000C or # FF
1870            $self->{next_char} == 0x0020) { # SP            $self->{nc} == 0x0020) { # SP
1871          !!!cp (107);          !!!cp (107);
1872          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
1873          !!!next-input-character;          !!!next-input-character;
1874          redo A;          redo A;
1875        } elsif ($self->{next_char} == 0x0026) { # &        } elsif ($self->{nc} == 0x0026) { # &
1876          !!!cp (108);          !!!cp (108);
1877          ## NOTE: In the spec, the tokenizer is switched to the          ## NOTE: In the spec, the tokenizer is switched to the
1878          ## "entity in attribute value state".  In this implementation, the          ## "entity in attribute value state".  In this implementation, the
1879          ## tokenizer is switched to the |ENTITY_STATE|, which is an          ## tokenizer is switched to the |ENTITY_STATE|, which is an
1880          ## implementation of the "consume a character reference" algorithm.          ## implementation of the "consume a character reference" algorithm.
1881          $self->{entity_additional} = -1;          $self->{entity_add} = -1;
1882          $self->{prev_state} = $self->{state};          $self->{prev_state} = $self->{state};
1883          $self->{state} = ENTITY_STATE;          $self->{state} = ENTITY_STATE;
1884          !!!next-input-character;          !!!next-input-character;
1885          redo A;          redo A;
1886        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
1887          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1888            !!!cp (109);            !!!cp (109);
1889            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1890          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1891            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1892            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1893              !!!cp (110);              !!!cp (110);
1894              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1895            } else {            } else {
# Line 1842  sub _get_next_token ($) { Line 1897  sub _get_next_token ($) {
1897              !!!cp (111);              !!!cp (111);
1898            }            }
1899          } else {          } else {
1900            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1901          }          }
1902          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1903          !!!next-input-character;          !!!next-input-character;
1904    
1905          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1906    
1907          redo A;          redo A;
1908        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
1909          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
1910          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1911            !!!cp (112);            !!!cp (112);
1912            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1913          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1914            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1915            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1916              !!!cp (113);              !!!cp (113);
1917              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1918            } else {            } else {
# Line 1865  sub _get_next_token ($) { Line 1920  sub _get_next_token ($) {
1920              !!!cp (114);              !!!cp (114);
1921            }            }
1922          } else {          } else {
1923            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1924          }          }
1925          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1926          ## reconsume          ## reconsume
1927    
1928          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1929    
1930          redo A;          redo A;
1931        } else {        } else {
# Line 1878  sub _get_next_token ($) { Line 1933  sub _get_next_token ($) {
1933               0x0022 => 1, # "               0x0022 => 1, # "
1934               0x0027 => 1, # '               0x0027 => 1, # '
1935               0x003D => 1, # =               0x003D => 1, # =
1936              }->{$self->{next_char}}) {              }->{$self->{nc}}) {
1937            !!!cp (115);            !!!cp (115);
1938            !!!parse-error (type => 'bad attribute value');            !!!parse-error (type => 'bad attribute value');
1939          } else {          } else {
1940            !!!cp (116);            !!!cp (116);
1941          }          }
1942          $self->{current_attribute}->{value} .= chr ($self->{next_char});          $self->{ca}->{value} .= chr ($self->{nc});
1943          $self->{read_until}->($self->{current_attribute}->{value},          $self->{read_until}->($self->{ca}->{value},
1944                                q["'=& >],                                q["'=& >],
1945                                length $self->{current_attribute}->{value});                                length $self->{ca}->{value});
1946    
1947          ## Stay in the state          ## Stay in the state
1948          !!!next-input-character;          !!!next-input-character;
1949          redo A;          redo A;
1950        }        }
1951      } elsif ($self->{state} == AFTER_ATTRIBUTE_VALUE_QUOTED_STATE) {      } elsif ($self->{state} == AFTER_ATTRIBUTE_VALUE_QUOTED_STATE) {
1952        if ($self->{next_char} == 0x0009 or # HT        if ($self->{nc} == 0x0009 or # HT
1953            $self->{next_char} == 0x000A or # LF            $self->{nc} == 0x000A or # LF
1954            $self->{next_char} == 0x000B or # VT            $self->{nc} == 0x000B or # VT
1955            $self->{next_char} == 0x000C or # FF            $self->{nc} == 0x000C or # FF
1956            $self->{next_char} == 0x0020) { # SP            $self->{nc} == 0x0020) { # SP
1957          !!!cp (118);          !!!cp (118);
1958          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
1959          !!!next-input-character;          !!!next-input-character;
1960          redo A;          redo A;
1961        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
1962          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1963            !!!cp (119);            !!!cp (119);
1964            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1965          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1966            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1967            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1968              !!!cp (120);              !!!cp (120);
1969              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1970            } else {            } else {
# Line 1917  sub _get_next_token ($) { Line 1972  sub _get_next_token ($) {
1972              !!!cp (121);              !!!cp (121);
1973            }            }
1974          } else {          } else {
1975            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
1976          }          }
1977          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1978          !!!next-input-character;          !!!next-input-character;
1979    
1980          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
1981    
1982          redo A;          redo A;
1983        } elsif ($self->{next_char} == 0x002F) { # /        } elsif ($self->{nc} == 0x002F) { # /
1984          !!!cp (122);          !!!cp (122);
1985          $self->{state} = SELF_CLOSING_START_TAG_STATE;          $self->{state} = SELF_CLOSING_START_TAG_STATE;
1986          !!!next-input-character;          !!!next-input-character;
1987          redo A;          redo A;
1988        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
1989          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
1990          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
1991            !!!cp (122.3);            !!!cp (122.3);
1992            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
1993          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
1994            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
1995              !!!cp (122.1);              !!!cp (122.1);
1996              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
1997            } else {            } else {
# Line 1944  sub _get_next_token ($) { Line 1999  sub _get_next_token ($) {
1999              !!!cp (122.2);              !!!cp (122.2);
2000            }            }
2001          } else {          } else {
2002            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
2003          }          }
2004          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2005          ## Reconsume.          ## Reconsume.
2006          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
2007          redo A;          redo A;
2008        } else {        } else {
2009          !!!cp ('124.1');          !!!cp ('124.1');
# Line 1958  sub _get_next_token ($) { Line 2013  sub _get_next_token ($) {
2013          redo A;          redo A;
2014        }        }
2015      } elsif ($self->{state} == SELF_CLOSING_START_TAG_STATE) {      } elsif ($self->{state} == SELF_CLOSING_START_TAG_STATE) {
2016        if ($self->{next_char} == 0x003E) { # >        if ($self->{nc} == 0x003E) { # >
2017          if ($self->{current_token}->{type} == END_TAG_TOKEN) {          if ($self->{ct}->{type} == END_TAG_TOKEN) {
2018            !!!cp ('124.2');            !!!cp ('124.2');
2019            !!!parse-error (type => 'nestc', token => $self->{current_token});            !!!parse-error (type => 'nestc', token => $self->{ct});
2020            ## TODO: Different type than slash in start tag            ## TODO: Different type than slash in start tag
2021            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
2022            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
2023              !!!cp ('124.4');              !!!cp ('124.4');
2024              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
2025            } else {            } else {
# Line 1979  sub _get_next_token ($) { Line 2034  sub _get_next_token ($) {
2034          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2035          !!!next-input-character;          !!!next-input-character;
2036    
2037          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
2038    
2039          redo A;          redo A;
2040        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2041          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
2042          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
2043            !!!cp (124.7);            !!!cp (124.7);
2044            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_stag_name} = $self->{ct}->{tag_name};
2045          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{ct}->{type} == END_TAG_TOKEN) {
2046            if ($self->{current_token}->{attributes}) {            if ($self->{ct}->{attributes}) {
2047              !!!cp (124.5);              !!!cp (124.5);
2048              !!!parse-error (type => 'end tag attribute');              !!!parse-error (type => 'end tag attribute');
2049            } else {            } else {
# Line 1996  sub _get_next_token ($) { Line 2051  sub _get_next_token ($) {
2051              !!!cp (124.6);              !!!cp (124.6);
2052            }            }
2053          } else {          } else {
2054            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{ct}->{type}: Unknown token type";
2055          }          }
2056          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2057          ## Reconsume.          ## Reconsume.
2058          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{ct}); # start tag or end tag
2059          redo A;          redo A;
2060        } else {        } else {
2061          !!!cp ('124.4');          !!!cp ('124.4');
# Line 2016  sub _get_next_token ($) { Line 2071  sub _get_next_token ($) {
2071        ## NOTE: Unlike spec's "bogus comment state", this implementation        ## NOTE: Unlike spec's "bogus comment state", this implementation
2072        ## consumes characters one-by-one basis.        ## consumes characters one-by-one basis.
2073                
2074        if ($self->{next_char} == 0x003E) { # >        if ($self->{nc} == 0x003E) { # >
2075          !!!cp (124);          !!!cp (124);
2076          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2077          !!!next-input-character;          !!!next-input-character;
2078    
2079          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{ct}); # comment
2080          redo A;          redo A;
2081        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2082          !!!cp (125);          !!!cp (125);
2083          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2084          ## reconsume          ## reconsume
2085    
2086          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{ct}); # comment
2087          redo A;          redo A;
2088        } else {        } else {
2089          !!!cp (126);          !!!cp (126);
2090          $self->{current_token}->{data} .= chr ($self->{next_char}); # comment          $self->{ct}->{data} .= chr ($self->{nc}); # comment
2091          $self->{read_until}->($self->{current_token}->{data},          $self->{read_until}->($self->{ct}->{data},
2092                                q[>],                                q[>],
2093                                length $self->{current_token}->{data});                                length $self->{ct}->{data});
2094    
2095          ## Stay in the state.          ## Stay in the state.
2096          !!!next-input-character;          !!!next-input-character;
# Line 2044  sub _get_next_token ($) { Line 2099  sub _get_next_token ($) {
2099      } elsif ($self->{state} == MARKUP_DECLARATION_OPEN_STATE) {      } elsif ($self->{state} == MARKUP_DECLARATION_OPEN_STATE) {
2100        ## (only happen if PCDATA state)        ## (only happen if PCDATA state)
2101                
2102        if ($self->{next_char} == 0x002D) { # -        if ($self->{nc} == 0x002D) { # -
2103          !!!cp (133);          !!!cp (133);
2104          $self->{state} = MD_HYPHEN_STATE;          $self->{state} = MD_HYPHEN_STATE;
2105          !!!next-input-character;          !!!next-input-character;
2106          redo A;          redo A;
2107        } elsif ($self->{next_char} == 0x0044 or # D        } elsif ($self->{nc} == 0x0044 or # D
2108                 $self->{next_char} == 0x0064) { # d                 $self->{nc} == 0x0064) { # d
2109          ## ASCII case-insensitive.          ## ASCII case-insensitive.
2110          !!!cp (130);          !!!cp (130);
2111          $self->{state} = MD_DOCTYPE_STATE;          $self->{state} = MD_DOCTYPE_STATE;
2112          $self->{state_keyword} = chr $self->{next_char};          $self->{s_kwd} = chr $self->{nc};
2113          !!!next-input-character;          !!!next-input-character;
2114          redo A;          redo A;
2115        } elsif ($self->{insertion_mode} & IN_FOREIGN_CONTENT_IM and        } elsif ($self->{insertion_mode} & IN_FOREIGN_CONTENT_IM and
2116                 $self->{open_elements}->[-1]->[1] & FOREIGN_EL and                 $self->{open_elements}->[-1]->[1] & FOREIGN_EL and
2117                 $self->{next_char} == 0x005B) { # [                 $self->{nc} == 0x005B) { # [
2118          !!!cp (135.4);                          !!!cp (135.4);                
2119          $self->{state} = MD_CDATA_STATE;          $self->{state} = MD_CDATA_STATE;
2120          $self->{state_keyword} = '[';          $self->{s_kwd} = '[';
2121          !!!next-input-character;          !!!next-input-character;
2122          redo A;          redo A;
2123        } else {        } else {
# Line 2074  sub _get_next_token ($) { Line 2129  sub _get_next_token ($) {
2129                        column => $self->{column_prev} - 1);                        column => $self->{column_prev} - 1);
2130        ## Reconsume.        ## Reconsume.
2131        $self->{state} = BOGUS_COMMENT_STATE;        $self->{state} = BOGUS_COMMENT_STATE;
2132        $self->{current_token} = {type => COMMENT_TOKEN, data => '',        $self->{ct} = {type => COMMENT_TOKEN, data => '',
2133                                  line => $self->{line_prev},                                  line => $self->{line_prev},
2134                                  column => $self->{column_prev} - 1,                                  column => $self->{column_prev} - 1,
2135                                 };                                 };
2136        redo A;        redo A;
2137      } elsif ($self->{state} == MD_HYPHEN_STATE) {      } elsif ($self->{state} == MD_HYPHEN_STATE) {
2138        if ($self->{next_char} == 0x002D) { # -        if ($self->{nc} == 0x002D) { # -
2139          !!!cp (127);          !!!cp (127);
2140          $self->{current_token} = {type => COMMENT_TOKEN, data => '',          $self->{ct} = {type => COMMENT_TOKEN, data => '',
2141                                    line => $self->{line_prev},                                    line => $self->{line_prev},
2142                                    column => $self->{column_prev} - 2,                                    column => $self->{column_prev} - 2,
2143                                   };                                   };
# Line 2096  sub _get_next_token ($) { Line 2151  sub _get_next_token ($) {
2151                          column => $self->{column_prev} - 2);                          column => $self->{column_prev} - 2);
2152          $self->{state} = BOGUS_COMMENT_STATE;          $self->{state} = BOGUS_COMMENT_STATE;
2153          ## Reconsume.          ## Reconsume.
2154          $self->{current_token} = {type => COMMENT_TOKEN,          $self->{ct} = {type => COMMENT_TOKEN,
2155                                    data => '-',                                    data => '-',
2156                                    line => $self->{line_prev},                                    line => $self->{line_prev},
2157                                    column => $self->{column_prev} - 2,                                    column => $self->{column_prev} - 2,
# Line 2105  sub _get_next_token ($) { Line 2160  sub _get_next_token ($) {
2160        }        }
2161      } elsif ($self->{state} == MD_DOCTYPE_STATE) {      } elsif ($self->{state} == MD_DOCTYPE_STATE) {
2162        ## ASCII case-insensitive.        ## ASCII case-insensitive.
2163        if ($self->{next_char} == [        if ($self->{nc} == [
2164              undef,              undef,
2165              0x004F, # O              0x004F, # O
2166              0x0043, # C              0x0043, # C
2167              0x0054, # T              0x0054, # T
2168              0x0059, # Y              0x0059, # Y
2169              0x0050, # P              0x0050, # P
2170            ]->[length $self->{state_keyword}] or            ]->[length $self->{s_kwd}] or
2171            $self->{next_char} == [            $self->{nc} == [
2172              undef,              undef,
2173              0x006F, # o              0x006F, # o
2174              0x0063, # c              0x0063, # c
2175              0x0074, # t              0x0074, # t
2176              0x0079, # y              0x0079, # y
2177              0x0070, # p              0x0070, # p
2178            ]->[length $self->{state_keyword}]) {            ]->[length $self->{s_kwd}]) {
2179          !!!cp (131);          !!!cp (131);
2180          ## Stay in the state.          ## Stay in the state.
2181          $self->{state_keyword} .= chr $self->{next_char};          $self->{s_kwd} .= chr $self->{nc};
2182          !!!next-input-character;          !!!next-input-character;
2183          redo A;          redo A;
2184        } elsif ((length $self->{state_keyword}) == 6 and        } elsif ((length $self->{s_kwd}) == 6 and
2185                 ($self->{next_char} == 0x0045 or # E                 ($self->{nc} == 0x0045 or # E
2186                  $self->{next_char} == 0x0065)) { # e                  $self->{nc} == 0x0065)) { # e
2187          !!!cp (129);          !!!cp (129);
2188          $self->{state} = DOCTYPE_STATE;          $self->{state} = DOCTYPE_STATE;
2189          $self->{current_token} = {type => DOCTYPE_TOKEN,          $self->{ct} = {type => DOCTYPE_TOKEN,
2190                                    quirks => 1,                                    quirks => 1,
2191                                    line => $self->{line_prev},                                    line => $self->{line_prev},
2192                                    column => $self->{column_prev} - 7,                                    column => $self->{column_prev} - 7,
# Line 2142  sub _get_next_token ($) { Line 2197  sub _get_next_token ($) {
2197          !!!cp (132);                  !!!cp (132);        
2198          !!!parse-error (type => 'bogus comment',          !!!parse-error (type => 'bogus comment',
2199                          line => $self->{line_prev},                          line => $self->{line_prev},
2200                          column => $self->{column_prev} - 1 - length $self->{state_keyword});                          column => $self->{column_prev} - 1 - length $self->{s_kwd});
2201          $self->{state} = BOGUS_COMMENT_STATE;          $self->{state} = BOGUS_COMMENT_STATE;
2202          ## Reconsume.          ## Reconsume.
2203          $self->{current_token} = {type => COMMENT_TOKEN,          $self->{ct} = {type => COMMENT_TOKEN,
2204                                    data => $self->{state_keyword},                                    data => $self->{s_kwd},
2205                                    line => $self->{line_prev},                                    line => $self->{line_prev},
2206                                    column => $self->{column_prev} - 1 - length $self->{state_keyword},                                    column => $self->{column_prev} - 1 - length $self->{s_kwd},
2207                                   };                                   };
2208          redo A;          redo A;
2209        }        }
2210      } elsif ($self->{state} == MD_CDATA_STATE) {      } elsif ($self->{state} == MD_CDATA_STATE) {
2211        if ($self->{next_char} == {        if ($self->{nc} == {
2212              '[' => 0x0043, # C              '[' => 0x0043, # C
2213              '[C' => 0x0044, # D              '[C' => 0x0044, # D
2214              '[CD' => 0x0041, # A              '[CD' => 0x0041, # A
2215              '[CDA' => 0x0054, # T              '[CDA' => 0x0054, # T
2216              '[CDAT' => 0x0041, # A              '[CDAT' => 0x0041, # A
2217            }->{$self->{state_keyword}}) {            }->{$self->{s_kwd}}) {
2218          !!!cp (135.1);          !!!cp (135.1);
2219          ## Stay in the state.          ## Stay in the state.
2220          $self->{state_keyword} .= chr $self->{next_char};          $self->{s_kwd} .= chr $self->{nc};
2221          !!!next-input-character;          !!!next-input-character;
2222          redo A;          redo A;
2223        } elsif ($self->{state_keyword} eq '[CDATA' and        } elsif ($self->{s_kwd} eq '[CDATA' and
2224                 $self->{next_char} == 0x005B) { # [                 $self->{nc} == 0x005B) { # [
2225          !!!cp (135.2);          !!!cp (135.2);
2226          $self->{current_token} = {type => CHARACTER_TOKEN,          $self->{ct} = {type => CHARACTER_TOKEN,
2227                                    data => '',                                    data => '',
2228                                    line => $self->{line_prev},                                    line => $self->{line_prev},
2229                                    column => $self->{column_prev} - 7};                                    column => $self->{column_prev} - 7};
# Line 2179  sub _get_next_token ($) { Line 2234  sub _get_next_token ($) {
2234          !!!cp (135.3);          !!!cp (135.3);
2235          !!!parse-error (type => 'bogus comment',          !!!parse-error (type => 'bogus comment',
2236                          line => $self->{line_prev},                          line => $self->{line_prev},
2237                          column => $self->{column_prev} - 1 - length $self->{state_keyword});                          column => $self->{column_prev} - 1 - length $self->{s_kwd});
2238          $self->{state} = BOGUS_COMMENT_STATE;          $self->{state} = BOGUS_COMMENT_STATE;
2239          ## Reconsume.          ## Reconsume.
2240          $self->{current_token} = {type => COMMENT_TOKEN,          $self->{ct} = {type => COMMENT_TOKEN,
2241                                    data => $self->{state_keyword},                                    data => $self->{s_kwd},
2242                                    line => $self->{line_prev},                                    line => $self->{line_prev},
2243                                    column => $self->{column_prev} - 1 - length $self->{state_keyword},                                    column => $self->{column_prev} - 1 - length $self->{s_kwd},
2244                                   };                                   };
2245          redo A;          redo A;
2246        }        }
2247      } elsif ($self->{state} == COMMENT_START_STATE) {      } elsif ($self->{state} == COMMENT_START_STATE) {
2248        if ($self->{next_char} == 0x002D) { # -        if ($self->{nc} == 0x002D) { # -
2249          !!!cp (137);          !!!cp (137);
2250          $self->{state} = COMMENT_START_DASH_STATE;          $self->{state} = COMMENT_START_DASH_STATE;
2251          !!!next-input-character;          !!!next-input-character;
2252          redo A;          redo A;
2253        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2254          !!!cp (138);          !!!cp (138);
2255          !!!parse-error (type => 'bogus comment');          !!!parse-error (type => 'bogus comment');
2256          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2257          !!!next-input-character;          !!!next-input-character;
2258    
2259          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{ct}); # comment
2260    
2261          redo A;          redo A;
2262        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2263          !!!cp (139);          !!!cp (139);
2264          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
2265          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2266          ## reconsume          ## reconsume
2267    
2268          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{ct}); # comment
2269    
2270          redo A;          redo A;
2271        } else {        } else {
2272          !!!cp (140);          !!!cp (140);
2273          $self->{current_token}->{data} # comment          $self->{ct}->{data} # comment
2274              .= chr ($self->{next_char});              .= chr ($self->{nc});
2275          $self->{state} = COMMENT_STATE;          $self->{state} = COMMENT_STATE;
2276          !!!next-input-character;          !!!next-input-character;
2277          redo A;          redo A;
2278        }        }
2279      } elsif ($self->{state} == COMMENT_START_DASH_STATE) {      } elsif ($self->{state} == COMMENT_START_DASH_STATE) {
2280        if ($self->{next_char} == 0x002D) { # -        if ($self->{nc} == 0x002D) { # -
2281          !!!cp (141);          !!!cp (141);
2282          $self->{state} = COMMENT_END_STATE;          $self->{state} = COMMENT_END_STATE;
2283          !!!next-input-character;          !!!next-input-character;
2284          redo A;          redo A;
2285        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2286          !!!cp (142);          !!!cp (142);
2287          !!!parse-error (type => 'bogus comment');          !!!parse-error (type => 'bogus comment');
2288          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2289          !!!next-input-character;          !!!next-input-character;
2290    
2291          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{ct}); # comment
2292    
2293          redo A;          redo A;
2294        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2295          !!!cp (143);          !!!cp (143);
2296          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
2297          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2298          ## reconsume          ## reconsume
2299    
2300          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{ct}); # comment
2301    
2302          redo A;          redo A;
2303        } else {        } else {
2304          !!!cp (144);          !!!cp (144);
2305          $self->{current_token}->{data} # comment          $self->{ct}->{data} # comment
2306              .= '-' . chr ($self->{next_char});              .= '-' . chr ($self->{nc});
2307          $self->{state} = COMMENT_STATE;          $self->{state} = COMMENT_STATE;
2308          !!!next-input-character;          !!!next-input-character;
2309          redo A;          redo A;
2310        }        }
2311      } elsif ($self->{state} == COMMENT_STATE) {      } elsif ($self->{state} == COMMENT_STATE) {
2312        if ($self->{next_char} == 0x002D) { # -        if ($self->{nc} == 0x002D) { # -
2313          !!!cp (145);          !!!cp (145);
2314          $self->{state} = COMMENT_END_DASH_STATE;          $self->{state} = COMMENT_END_DASH_STATE;
2315          !!!next-input-character;          !!!next-input-character;
2316          redo A;          redo A;
2317        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2318          !!!cp (146);          !!!cp (146);
2319          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
2320          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2321          ## reconsume          ## reconsume
2322    
2323          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{ct}); # comment
2324    
2325          redo A;          redo A;
2326        } else {        } else {
2327          !!!cp (147);          !!!cp (147);
2328          $self->{current_token}->{data} .= chr ($self->{next_char}); # comment          $self->{ct}->{data} .= chr ($self->{nc}); # comment
2329          $self->{read_until}->($self->{current_token}->{data},          $self->{read_until}->($self->{ct}->{data},
2330                                q[-],                                q[-],
2331                                length $self->{current_token}->{data});                                length $self->{ct}->{data});
2332    
2333          ## Stay in the state          ## Stay in the state
2334          !!!next-input-character;          !!!next-input-character;
2335          redo A;          redo A;
2336        }        }
2337      } elsif ($self->{state} == COMMENT_END_DASH_STATE) {      } elsif ($self->{state} == COMMENT_END_DASH_STATE) {
2338        if ($self->{next_char} == 0x002D) { # -        if ($self->{nc} == 0x002D) { # -
2339          !!!cp (148);          !!!cp (148);
2340          $self->{state} = COMMENT_END_STATE;          $self->{state} = COMMENT_END_STATE;
2341          !!!next-input-character;          !!!next-input-character;
2342          redo A;          redo A;
2343        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2344          !!!cp (149);          !!!cp (149);
2345          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
2346          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2347          ## reconsume          ## reconsume
2348    
2349          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{ct}); # comment
2350    
2351          redo A;          redo A;
2352        } else {        } else {
2353          !!!cp (150);          !!!cp (150);
2354          $self->{current_token}->{data} .= '-' . chr ($self->{next_char}); # comment          $self->{ct}->{data} .= '-' . chr ($self->{nc}); # comment
2355          $self->{state} = COMMENT_STATE;          $self->{state} = COMMENT_STATE;
2356          !!!next-input-character;          !!!next-input-character;
2357          redo A;          redo A;
2358        }        }
2359      } elsif ($self->{state} == COMMENT_END_STATE) {      } elsif ($self->{state} == COMMENT_END_STATE) {
2360        if ($self->{next_char} == 0x003E) { # >        if ($self->{nc} == 0x003E) { # >
2361          !!!cp (151);          !!!cp (151);
2362          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2363          !!!next-input-character;          !!!next-input-character;
2364    
2365          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{ct}); # comment
2366    
2367          redo A;          redo A;
2368        } elsif ($self->{next_char} == 0x002D) { # -        } elsif ($self->{nc} == 0x002D) { # -
2369          !!!cp (152);          !!!cp (152);
2370          !!!parse-error (type => 'dash in comment',          !!!parse-error (type => 'dash in comment',
2371                          line => $self->{line_prev},                          line => $self->{line_prev},
2372                          column => $self->{column_prev});                          column => $self->{column_prev});
2373          $self->{current_token}->{data} .= '-'; # comment          $self->{ct}->{data} .= '-'; # comment
2374          ## Stay in the state          ## Stay in the state
2375          !!!next-input-character;          !!!next-input-character;
2376          redo A;          redo A;
2377        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2378          !!!cp (153);          !!!cp (153);
2379          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
2380          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2381          ## reconsume          ## reconsume
2382    
2383          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{ct}); # comment
2384    
2385          redo A;          redo A;
2386        } else {        } else {
# Line 2333  sub _get_next_token ($) { Line 2388  sub _get_next_token ($) {
2388          !!!parse-error (type => 'dash in comment',          !!!parse-error (type => 'dash in comment',
2389                          line => $self->{line_prev},                          line => $self->{line_prev},
2390                          column => $self->{column_prev});                          column => $self->{column_prev});
2391          $self->{current_token}->{data} .= '--' . chr ($self->{next_char}); # comment          $self->{ct}->{data} .= '--' . chr ($self->{nc}); # comment
2392          $self->{state} = COMMENT_STATE;          $self->{state} = COMMENT_STATE;
2393          !!!next-input-character;          !!!next-input-character;
2394          redo A;          redo A;
2395        }        }
2396      } elsif ($self->{state} == DOCTYPE_STATE) {      } elsif ($self->{state} == DOCTYPE_STATE) {
2397        if ($self->{next_char} == 0x0009 or # HT        if ($self->{nc} == 0x0009 or # HT
2398            $self->{next_char} == 0x000A or # LF            $self->{nc} == 0x000A or # LF
2399            $self->{next_char} == 0x000B or # VT            $self->{nc} == 0x000B or # VT
2400            $self->{next_char} == 0x000C or # FF            $self->{nc} == 0x000C or # FF
2401            $self->{next_char} == 0x0020) { # SP            $self->{nc} == 0x0020) { # SP
2402          !!!cp (155);          !!!cp (155);
2403          $self->{state} = BEFORE_DOCTYPE_NAME_STATE;          $self->{state} = BEFORE_DOCTYPE_NAME_STATE;
2404          !!!next-input-character;          !!!next-input-character;
# Line 2356  sub _get_next_token ($) { Line 2411  sub _get_next_token ($) {
2411          redo A;          redo A;
2412        }        }
2413      } elsif ($self->{state} == BEFORE_DOCTYPE_NAME_STATE) {      } elsif ($self->{state} == BEFORE_DOCTYPE_NAME_STATE) {
2414        if ($self->{next_char} == 0x0009 or # HT        if ($self->{nc} == 0x0009 or # HT
2415            $self->{next_char} == 0x000A or # LF            $self->{nc} == 0x000A or # LF
2416            $self->{next_char} == 0x000B or # VT            $self->{nc} == 0x000B or # VT
2417            $self->{next_char} == 0x000C or # FF            $self->{nc} == 0x000C or # FF
2418            $self->{next_char} == 0x0020) { # SP            $self->{nc} == 0x0020) { # SP
2419          !!!cp (157);          !!!cp (157);
2420          ## Stay in the state          ## Stay in the state
2421          !!!next-input-character;          !!!next-input-character;
2422          redo A;          redo A;
2423        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2424          !!!cp (158);          !!!cp (158);
2425          !!!parse-error (type => 'no DOCTYPE name');          !!!parse-error (type => 'no DOCTYPE name');
2426          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2427          !!!next-input-character;          !!!next-input-character;
2428    
2429          !!!emit ($self->{current_token}); # DOCTYPE (quirks)          !!!emit ($self->{ct}); # DOCTYPE (quirks)
2430    
2431          redo A;          redo A;
2432        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2433          !!!cp (159);          !!!cp (159);
2434          !!!parse-error (type => 'no DOCTYPE name');          !!!parse-error (type => 'no DOCTYPE name');
2435          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2436          ## reconsume          ## reconsume
2437    
2438          !!!emit ($self->{current_token}); # DOCTYPE (quirks)          !!!emit ($self->{ct}); # DOCTYPE (quirks)
2439    
2440          redo A;          redo A;
2441        } else {        } else {
2442          !!!cp (160);          !!!cp (160);
2443          $self->{current_token}->{name} = chr $self->{next_char};          $self->{ct}->{name} = chr $self->{nc};
2444          delete $self->{current_token}->{quirks};          delete $self->{ct}->{quirks};
2445  ## ISSUE: "Set the token's name name to the" in the spec  ## ISSUE: "Set the token's name name to the" in the spec
2446          $self->{state} = DOCTYPE_NAME_STATE;          $self->{state} = DOCTYPE_NAME_STATE;
2447          !!!next-input-character;          !!!next-input-character;
# Line 2394  sub _get_next_token ($) { Line 2449  sub _get_next_token ($) {
2449        }        }
2450      } elsif ($self->{state} == DOCTYPE_NAME_STATE) {      } elsif ($self->{state} == DOCTYPE_NAME_STATE) {
2451  ## ISSUE: Redundant "First," in the spec.  ## ISSUE: Redundant "First," in the spec.
2452        if ($self->{next_char} == 0x0009 or # HT        if ($self->{nc} == 0x0009 or # HT
2453            $self->{next_char} == 0x000A or # LF            $self->{nc} == 0x000A or # LF
2454            $self->{next_char} == 0x000B or # VT            $self->{nc} == 0x000B or # VT
2455            $self->{next_char} == 0x000C or # FF            $self->{nc} == 0x000C or # FF
2456            $self->{next_char} == 0x0020) { # SP            $self->{nc} == 0x0020) { # SP
2457          !!!cp (161);          !!!cp (161);
2458          $self->{state} = AFTER_DOCTYPE_NAME_STATE;          $self->{state} = AFTER_DOCTYPE_NAME_STATE;
2459          !!!next-input-character;          !!!next-input-character;
2460          redo A;          redo A;
2461        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2462          !!!cp (162);          !!!cp (162);
2463          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2464          !!!next-input-character;          !!!next-input-character;
2465    
2466          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2467    
2468          redo A;          redo A;
2469        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2470          !!!cp (163);          !!!cp (163);
2471          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2472          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2473          ## reconsume          ## reconsume
2474    
2475          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2476          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2477    
2478          redo A;          redo A;
2479        } else {        } else {
2480          !!!cp (164);          !!!cp (164);
2481          $self->{current_token}->{name}          $self->{ct}->{name}
2482            .= chr ($self->{next_char}); # DOCTYPE            .= chr ($self->{nc}); # DOCTYPE
2483          ## Stay in the state          ## Stay in the state
2484          !!!next-input-character;          !!!next-input-character;
2485          redo A;          redo A;
2486        }        }
2487      } elsif ($self->{state} == AFTER_DOCTYPE_NAME_STATE) {      } elsif ($self->{state} == AFTER_DOCTYPE_NAME_STATE) {
2488        if ($self->{next_char} == 0x0009 or # HT        if ($self->{nc} == 0x0009 or # HT
2489            $self->{next_char} == 0x000A or # LF            $self->{nc} == 0x000A or # LF
2490            $self->{next_char} == 0x000B or # VT            $self->{nc} == 0x000B or # VT
2491            $self->{next_char} == 0x000C or # FF            $self->{nc} == 0x000C or # FF
2492            $self->{next_char} == 0x0020) { # SP            $self->{nc} == 0x0020) { # SP
2493          !!!cp (165);          !!!cp (165);
2494          ## Stay in the state          ## Stay in the state
2495          !!!next-input-character;          !!!next-input-character;
2496          redo A;          redo A;
2497        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2498          !!!cp (166);          !!!cp (166);
2499          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2500          !!!next-input-character;          !!!next-input-character;
2501    
2502          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2503    
2504          redo A;          redo A;
2505        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2506          !!!cp (167);          !!!cp (167);
2507          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2508          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2509          ## reconsume          ## reconsume
2510    
2511          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2512          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2513    
2514          redo A;          redo A;
2515        } elsif ($self->{next_char} == 0x0050 or # P        } elsif ($self->{nc} == 0x0050 or # P
2516                 $self->{next_char} == 0x0070) { # p                 $self->{nc} == 0x0070) { # p
2517          $self->{state} = PUBLIC_STATE;          $self->{state} = PUBLIC_STATE;
2518          $self->{state_keyword} = chr $self->{next_char};          $self->{s_kwd} = chr $self->{nc};
2519          !!!next-input-character;          !!!next-input-character;
2520          redo A;          redo A;
2521        } elsif ($self->{next_char} == 0x0053 or # S        } elsif ($self->{nc} == 0x0053 or # S
2522                 $self->{next_char} == 0x0073) { # s                 $self->{nc} == 0x0073) { # s
2523          $self->{state} = SYSTEM_STATE;          $self->{state} = SYSTEM_STATE;
2524          $self->{state_keyword} = chr $self->{next_char};          $self->{s_kwd} = chr $self->{nc};
2525          !!!next-input-character;          !!!next-input-character;
2526          redo A;          redo A;
2527        } else {        } else {
2528          !!!cp (180);          !!!cp (180);
2529          !!!parse-error (type => 'string after DOCTYPE name');          !!!parse-error (type => 'string after DOCTYPE name');
2530          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2531    
2532          $self->{state} = BOGUS_DOCTYPE_STATE;          $self->{state} = BOGUS_DOCTYPE_STATE;
2533          !!!next-input-character;          !!!next-input-character;
# Line 2480  sub _get_next_token ($) { Line 2535  sub _get_next_token ($) {
2535        }        }
2536      } elsif ($self->{state} == PUBLIC_STATE) {      } elsif ($self->{state} == PUBLIC_STATE) {
2537        ## ASCII case-insensitive        ## ASCII case-insensitive
2538        if ($self->{next_char} == [        if ($self->{nc} == [
2539              undef,              undef,
2540              0x0055, # U              0x0055, # U
2541              0x0042, # B              0x0042, # B
2542              0x004C, # L              0x004C, # L
2543              0x0049, # I              0x0049, # I
2544            ]->[length $self->{state_keyword}] or            ]->[length $self->{s_kwd}] or
2545            $self->{next_char} == [            $self->{nc} == [
2546              undef,              undef,
2547              0x0075, # u              0x0075, # u
2548              0x0062, # b              0x0062, # b
2549              0x006C, # l              0x006C, # l
2550              0x0069, # i              0x0069, # i
2551            ]->[length $self->{state_keyword}]) {            ]->[length $self->{s_kwd}]) {
2552          !!!cp (175);          !!!cp (175);
2553          ## Stay in the state.          ## Stay in the state.
2554          $self->{state_keyword} .= chr $self->{next_char};          $self->{s_kwd} .= chr $self->{nc};
2555          !!!next-input-character;          !!!next-input-character;
2556          redo A;          redo A;
2557        } elsif ((length $self->{state_keyword}) == 5 and        } elsif ((length $self->{s_kwd}) == 5 and
2558                 ($self->{next_char} == 0x0043 or # C                 ($self->{nc} == 0x0043 or # C
2559                  $self->{next_char} == 0x0063)) { # c                  $self->{nc} == 0x0063)) { # c
2560          !!!cp (168);          !!!cp (168);
2561          $self->{state} = BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE;          $self->{state} = BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
2562          !!!next-input-character;          !!!next-input-character;
# Line 2510  sub _get_next_token ($) { Line 2565  sub _get_next_token ($) {
2565          !!!cp (169);          !!!cp (169);
2566          !!!parse-error (type => 'string after DOCTYPE name',          !!!parse-error (type => 'string after DOCTYPE name',
2567                          line => $self->{line_prev},                          line => $self->{line_prev},
2568                          column => $self->{column_prev} + 1 - length $self->{state_keyword});                          column => $self->{column_prev} + 1 - length $self->{s_kwd});
2569          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2570    
2571          $self->{state} = BOGUS_DOCTYPE_STATE;          $self->{state} = BOGUS_DOCTYPE_STATE;
2572          ## Reconsume.          ## Reconsume.
# Line 2519  sub _get_next_token ($) { Line 2574  sub _get_next_token ($) {
2574        }        }
2575      } elsif ($self->{state} == SYSTEM_STATE) {      } elsif ($self->{state} == SYSTEM_STATE) {
2576        ## ASCII case-insensitive        ## ASCII case-insensitive
2577        if ($self->{next_char} == [        if ($self->{nc} == [
2578              undef,              undef,
2579              0x0059, # Y              0x0059, # Y
2580              0x0053, # S              0x0053, # S
2581              0x0054, # T              0x0054, # T
2582              0x0045, # E              0x0045, # E
2583            ]->[length $self->{state_keyword}] or            ]->[length $self->{s_kwd}] or
2584            $self->{next_char} == [            $self->{nc} == [
2585              undef,              undef,
2586              0x0079, # y              0x0079, # y
2587              0x0073, # s              0x0073, # s
2588              0x0074, # t              0x0074, # t
2589              0x0065, # e              0x0065, # e
2590            ]->[length $self->{state_keyword}]) {            ]->[length $self->{s_kwd}]) {
2591          !!!cp (170);          !!!cp (170);
2592          ## Stay in the state.          ## Stay in the state.
2593          $self->{state_keyword} .= chr $self->{next_char};          $self->{s_kwd} .= chr $self->{nc};
2594          !!!next-input-character;          !!!next-input-character;
2595          redo A;          redo A;
2596        } elsif ((length $self->{state_keyword}) == 5 and        } elsif ((length $self->{s_kwd}) == 5 and
2597                 ($self->{next_char} == 0x004D or # M                 ($self->{nc} == 0x004D or # M
2598                  $self->{next_char} == 0x006D)) { # m                  $self->{nc} == 0x006D)) { # m
2599          !!!cp (171);          !!!cp (171);
2600          $self->{state} = BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE;          $self->{state} = BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
2601          !!!next-input-character;          !!!next-input-character;
# Line 2549  sub _get_next_token ($) { Line 2604  sub _get_next_token ($) {
2604          !!!cp (172);          !!!cp (172);
2605          !!!parse-error (type => 'string after DOCTYPE name',          !!!parse-error (type => 'string after DOCTYPE name',
2606                          line => $self->{line_prev},                          line => $self->{line_prev},
2607                          column => $self->{column_prev} + 1 - length $self->{state_keyword});                          column => $self->{column_prev} + 1 - length $self->{s_kwd});
2608          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2609    
2610          $self->{state} = BOGUS_DOCTYPE_STATE;          $self->{state} = BOGUS_DOCTYPE_STATE;
2611          ## Reconsume.          ## Reconsume.
# Line 2560  sub _get_next_token ($) { Line 2615  sub _get_next_token ($) {
2615        if ({        if ({
2616              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
2617              #0x000D => 1, # HT, LF, VT, FF, SP, CR              #0x000D => 1, # HT, LF, VT, FF, SP, CR
2618            }->{$self->{next_char}}) {            }->{$self->{nc}}) {
2619          !!!cp (181);          !!!cp (181);
2620          ## Stay in the state          ## Stay in the state
2621          !!!next-input-character;          !!!next-input-character;
2622          redo A;          redo A;
2623        } elsif ($self->{next_char} eq 0x0022) { # "        } elsif ($self->{nc} eq 0x0022) { # "
2624          !!!cp (182);          !!!cp (182);
2625          $self->{current_token}->{public_identifier} = ''; # DOCTYPE          $self->{ct}->{pubid} = ''; # DOCTYPE
2626          $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE;          $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE;
2627          !!!next-input-character;          !!!next-input-character;
2628          redo A;          redo A;
2629        } elsif ($self->{next_char} eq 0x0027) { # '        } elsif ($self->{nc} eq 0x0027) { # '
2630          !!!cp (183);          !!!cp (183);
2631          $self->{current_token}->{public_identifier} = ''; # DOCTYPE          $self->{ct}->{pubid} = ''; # DOCTYPE
2632          $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE;          $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE;
2633          !!!next-input-character;          !!!next-input-character;
2634          redo A;          redo A;
2635        } elsif ($self->{next_char} eq 0x003E) { # >        } elsif ($self->{nc} eq 0x003E) { # >
2636          !!!cp (184);          !!!cp (184);
2637          !!!parse-error (type => 'no PUBLIC literal');          !!!parse-error (type => 'no PUBLIC literal');
2638    
2639          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2640          !!!next-input-character;          !!!next-input-character;
2641    
2642          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2643          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2644    
2645          redo A;          redo A;
2646        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2647          !!!cp (185);          !!!cp (185);
2648          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2649    
2650          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2651          ## reconsume          ## reconsume
2652    
2653          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2654          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2655    
2656          redo A;          redo A;
2657        } else {        } else {
2658          !!!cp (186);          !!!cp (186);
2659          !!!parse-error (type => 'string after PUBLIC');          !!!parse-error (type => 'string after PUBLIC');
2660          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2661    
2662          $self->{state} = BOGUS_DOCTYPE_STATE;          $self->{state} = BOGUS_DOCTYPE_STATE;
2663          !!!next-input-character;          !!!next-input-character;
2664          redo A;          redo A;
2665        }        }
2666      } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE) {      } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE) {
2667        if ($self->{next_char} == 0x0022) { # "        if ($self->{nc} == 0x0022) { # "
2668          !!!cp (187);          !!!cp (187);
2669          $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;          $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
2670          !!!next-input-character;          !!!next-input-character;
2671          redo A;          redo A;
2672        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2673          !!!cp (188);          !!!cp (188);
2674          !!!parse-error (type => 'unclosed PUBLIC literal');          !!!parse-error (type => 'unclosed PUBLIC literal');
2675    
2676          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2677          !!!next-input-character;          !!!next-input-character;
2678    
2679          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2680          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2681    
2682          redo A;          redo A;
2683        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2684          !!!cp (189);          !!!cp (189);
2685          !!!parse-error (type => 'unclosed PUBLIC literal');          !!!parse-error (type => 'unclosed PUBLIC literal');
2686    
2687          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2688          ## reconsume          ## reconsume
2689    
2690          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2691          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2692    
2693          redo A;          redo A;
2694        } else {        } else {
2695          !!!cp (190);          !!!cp (190);
2696          $self->{current_token}->{public_identifier} # DOCTYPE          $self->{ct}->{pubid} # DOCTYPE
2697              .= chr $self->{next_char};              .= chr $self->{nc};
2698          $self->{read_until}->($self->{current_token}->{public_identifier},          $self->{read_until}->($self->{ct}->{pubid}, q[">],
2699                                q[">],                                length $self->{ct}->{pubid});
                               length $self->{current_token}->{public_identifier});  
2700    
2701          ## Stay in the state          ## Stay in the state
2702          !!!next-input-character;          !!!next-input-character;
2703          redo A;          redo A;
2704        }        }
2705      } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE) {      } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE) {
2706        if ($self->{next_char} == 0x0027) { # '        if ($self->{nc} == 0x0027) { # '
2707          !!!cp (191);          !!!cp (191);
2708          $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;          $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
2709          !!!next-input-character;          !!!next-input-character;
2710          redo A;          redo A;
2711        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2712          !!!cp (192);          !!!cp (192);
2713          !!!parse-error (type => 'unclosed PUBLIC literal');          !!!parse-error (type => 'unclosed PUBLIC literal');
2714    
2715          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2716          !!!next-input-character;          !!!next-input-character;
2717    
2718          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2719          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2720    
2721          redo A;          redo A;
2722        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2723          !!!cp (193);          !!!cp (193);
2724          !!!parse-error (type => 'unclosed PUBLIC literal');          !!!parse-error (type => 'unclosed PUBLIC literal');
2725    
2726          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2727          ## reconsume          ## reconsume
2728    
2729          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2730          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2731    
2732          redo A;          redo A;
2733        } else {        } else {
2734          !!!cp (194);          !!!cp (194);
2735          $self->{current_token}->{public_identifier} # DOCTYPE          $self->{ct}->{pubid} # DOCTYPE
2736              .= chr $self->{next_char};              .= chr $self->{nc};
2737          $self->{read_until}->($self->{current_token}->{public_identifier},          $self->{read_until}->($self->{ct}->{pubid}, q['>],
2738                                q['>],                                length $self->{ct}->{pubid});
                               length $self->{current_token}->{public_identifier});  
2739    
2740          ## Stay in the state          ## Stay in the state
2741          !!!next-input-character;          !!!next-input-character;
# Line 2692  sub _get_next_token ($) { Line 2745  sub _get_next_token ($) {
2745        if ({        if ({
2746              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
2747              #0x000D => 1, # HT, LF, VT, FF, SP, CR              #0x000D => 1, # HT, LF, VT, FF, SP, CR
2748            }->{$self->{next_char}}) {            }->{$self->{nc}}) {
2749          !!!cp (195);          !!!cp (195);
2750          ## Stay in the state          ## Stay in the state
2751          !!!next-input-character;          !!!next-input-character;
2752          redo A;          redo A;
2753        } elsif ($self->{next_char} == 0x0022) { # "        } elsif ($self->{nc} == 0x0022) { # "
2754          !!!cp (196);          !!!cp (196);
2755          $self->{current_token}->{system_identifier} = ''; # DOCTYPE          $self->{ct}->{sysid} = ''; # DOCTYPE
2756          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
2757          !!!next-input-character;          !!!next-input-character;
2758          redo A;          redo A;
2759        } elsif ($self->{next_char} == 0x0027) { # '        } elsif ($self->{nc} == 0x0027) { # '
2760          !!!cp (197);          !!!cp (197);
2761          $self->{current_token}->{system_identifier} = ''; # DOCTYPE          $self->{ct}->{sysid} = ''; # DOCTYPE
2762          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
2763          !!!next-input-character;          !!!next-input-character;
2764          redo A;          redo A;
2765        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2766          !!!cp (198);          !!!cp (198);
2767          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2768          !!!next-input-character;          !!!next-input-character;
2769    
2770          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2771    
2772          redo A;          redo A;
2773        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2774          !!!cp (199);          !!!cp (199);
2775          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2776    
2777          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2778          ## reconsume          ## reconsume
2779    
2780          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2781          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2782    
2783          redo A;          redo A;
2784        } else {        } else {
2785          !!!cp (200);          !!!cp (200);
2786          !!!parse-error (type => 'string after PUBLIC literal');          !!!parse-error (type => 'string after PUBLIC literal');
2787          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2788    
2789          $self->{state} = BOGUS_DOCTYPE_STATE;          $self->{state} = BOGUS_DOCTYPE_STATE;
2790          !!!next-input-character;          !!!next-input-character;
# Line 2741  sub _get_next_token ($) { Line 2794  sub _get_next_token ($) {
2794        if ({        if ({
2795              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
2796              #0x000D => 1, # HT, LF, VT, FF, SP, CR              #0x000D => 1, # HT, LF, VT, FF, SP, CR
2797            }->{$self->{next_char}}) {            }->{$self->{nc}}) {
2798          !!!cp (201);          !!!cp (201);
2799          ## Stay in the state          ## Stay in the state
2800          !!!next-input-character;          !!!next-input-character;
2801          redo A;          redo A;
2802        } elsif ($self->{next_char} == 0x0022) { # "        } elsif ($self->{nc} == 0x0022) { # "
2803          !!!cp (202);          !!!cp (202);
2804          $self->{current_token}->{system_identifier} = ''; # DOCTYPE          $self->{ct}->{sysid} = ''; # DOCTYPE
2805          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
2806          !!!next-input-character;          !!!next-input-character;
2807          redo A;          redo A;
2808        } elsif ($self->{next_char} == 0x0027) { # '        } elsif ($self->{nc} == 0x0027) { # '
2809          !!!cp (203);          !!!cp (203);
2810          $self->{current_token}->{system_identifier} = ''; # DOCTYPE          $self->{ct}->{sysid} = ''; # DOCTYPE
2811          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
2812          !!!next-input-character;          !!!next-input-character;
2813          redo A;          redo A;
2814        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2815          !!!cp (204);          !!!cp (204);
2816          !!!parse-error (type => 'no SYSTEM literal');          !!!parse-error (type => 'no SYSTEM literal');
2817          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2818          !!!next-input-character;          !!!next-input-character;
2819    
2820          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2821          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2822    
2823          redo A;          redo A;
2824        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2825          !!!cp (205);          !!!cp (205);
2826          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2827    
2828          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2829          ## reconsume          ## reconsume
2830    
2831          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2832          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2833    
2834          redo A;          redo A;
2835        } else {        } else {
2836          !!!cp (206);          !!!cp (206);
2837          !!!parse-error (type => 'string after SYSTEM');          !!!parse-error (type => 'string after SYSTEM');
2838          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2839    
2840          $self->{state} = BOGUS_DOCTYPE_STATE;          $self->{state} = BOGUS_DOCTYPE_STATE;
2841          !!!next-input-character;          !!!next-input-character;
2842          redo A;          redo A;
2843        }        }
2844      } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE) {      } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE) {
2845        if ($self->{next_char} == 0x0022) { # "        if ($self->{nc} == 0x0022) { # "
2846          !!!cp (207);          !!!cp (207);
2847          $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;          $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
2848          !!!next-input-character;          !!!next-input-character;
2849          redo A;          redo A;
2850        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2851          !!!cp (208);          !!!cp (208);
2852          !!!parse-error (type => 'unclosed SYSTEM literal');          !!!parse-error (type => 'unclosed SYSTEM literal');
2853    
2854          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2855          !!!next-input-character;          !!!next-input-character;
2856    
2857          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2858          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2859    
2860          redo A;          redo A;
2861        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2862          !!!cp (209);          !!!cp (209);
2863          !!!parse-error (type => 'unclosed SYSTEM literal');          !!!parse-error (type => 'unclosed SYSTEM literal');
2864    
2865          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2866          ## reconsume          ## reconsume
2867    
2868          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2869          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2870    
2871          redo A;          redo A;
2872        } else {        } else {
2873          !!!cp (210);          !!!cp (210);
2874          $self->{current_token}->{system_identifier} # DOCTYPE          $self->{ct}->{sysid} # DOCTYPE
2875              .= chr $self->{next_char};              .= chr $self->{nc};
2876          $self->{read_until}->($self->{current_token}->{system_identifier},          $self->{read_until}->($self->{ct}->{sysid}, q[">],
2877                                q[">],                                length $self->{ct}->{sysid});
                               length $self->{current_token}->{system_identifier});  
2878    
2879          ## Stay in the state          ## Stay in the state
2880          !!!next-input-character;          !!!next-input-character;
2881          redo A;          redo A;
2882        }        }
2883      } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE) {      } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE) {
2884        if ($self->{next_char} == 0x0027) { # '        if ($self->{nc} == 0x0027) { # '
2885          !!!cp (211);          !!!cp (211);
2886          $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;          $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
2887          !!!next-input-character;          !!!next-input-character;
2888          redo A;          redo A;
2889        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2890          !!!cp (212);          !!!cp (212);
2891          !!!parse-error (type => 'unclosed SYSTEM literal');          !!!parse-error (type => 'unclosed SYSTEM literal');
2892    
2893          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2894          !!!next-input-character;          !!!next-input-character;
2895    
2896          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2897          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2898    
2899          redo A;          redo A;
2900        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2901          !!!cp (213);          !!!cp (213);
2902          !!!parse-error (type => 'unclosed SYSTEM literal');          !!!parse-error (type => 'unclosed SYSTEM literal');
2903    
2904          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2905          ## reconsume          ## reconsume
2906    
2907          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2908          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2909    
2910          redo A;          redo A;
2911        } else {        } else {
2912          !!!cp (214);          !!!cp (214);
2913          $self->{current_token}->{system_identifier} # DOCTYPE          $self->{ct}->{sysid} # DOCTYPE
2914              .= chr $self->{next_char};              .= chr $self->{nc};
2915          $self->{read_until}->($self->{current_token}->{system_identifier},          $self->{read_until}->($self->{ct}->{sysid}, q['>],
2916                                q['>],                                length $self->{ct}->{sysid});
                               length $self->{current_token}->{system_identifier});  
2917    
2918          ## Stay in the state          ## Stay in the state
2919          !!!next-input-character;          !!!next-input-character;
# Line 2872  sub _get_next_token ($) { Line 2923  sub _get_next_token ($) {
2923        if ({        if ({
2924              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
2925              #0x000D => 1, # HT, LF, VT, FF, SP, CR              #0x000D => 1, # HT, LF, VT, FF, SP, CR
2926            }->{$self->{next_char}}) {            }->{$self->{nc}}) {
2927          !!!cp (215);          !!!cp (215);
2928          ## Stay in the state          ## Stay in the state
2929          !!!next-input-character;          !!!next-input-character;
2930          redo A;          redo A;
2931        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
2932          !!!cp (216);          !!!cp (216);
2933          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2934          !!!next-input-character;          !!!next-input-character;
2935    
2936          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2937    
2938          redo A;          redo A;
2939        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2940          !!!cp (217);          !!!cp (217);
2941          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2942          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2943          ## reconsume          ## reconsume
2944    
2945          $self->{current_token}->{quirks} = 1;          $self->{ct}->{quirks} = 1;
2946          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2947    
2948          redo A;          redo A;
2949        } else {        } else {
2950          !!!cp (218);          !!!cp (218);
2951          !!!parse-error (type => 'string after SYSTEM literal');          !!!parse-error (type => 'string after SYSTEM literal');
2952          #$self->{current_token}->{quirks} = 1;          #$self->{ct}->{quirks} = 1;
2953    
2954          $self->{state} = BOGUS_DOCTYPE_STATE;          $self->{state} = BOGUS_DOCTYPE_STATE;
2955          !!!next-input-character;          !!!next-input-character;
2956          redo A;          redo A;
2957        }        }
2958      } elsif ($self->{state} == BOGUS_DOCTYPE_STATE) {      } elsif ($self->{state} == BOGUS_DOCTYPE_STATE) {
2959        if ($self->{next_char} == 0x003E) { # >        if ($self->{nc} == 0x003E) { # >
2960          !!!cp (219);          !!!cp (219);
2961          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2962          !!!next-input-character;          !!!next-input-character;
2963    
2964          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2965    
2966          redo A;          redo A;
2967        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2968          !!!cp (220);          !!!cp (220);
2969          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
2970          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2971          ## reconsume          ## reconsume
2972    
2973          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{ct}); # DOCTYPE
2974    
2975          redo A;          redo A;
2976        } else {        } else {
# Line 2936  sub _get_next_token ($) { Line 2987  sub _get_next_token ($) {
2987        ## by three states, |CDATA_SECTION_STATE|, |CDATA_SECTION_MSE1_STATE|,        ## by three states, |CDATA_SECTION_STATE|, |CDATA_SECTION_MSE1_STATE|,
2988        ## and |CDATA_SECTION_MSE2_STATE|.        ## and |CDATA_SECTION_MSE2_STATE|.
2989                
2990        if ($self->{next_char} == 0x005D) { # ]        if ($self->{nc} == 0x005D) { # ]
2991          !!!cp (221.1);          !!!cp (221.1);
2992          $self->{state} = CDATA_SECTION_MSE1_STATE;          $self->{state} = CDATA_SECTION_MSE1_STATE;
2993          !!!next-input-character;          !!!next-input-character;
2994          redo A;          redo A;
2995        } elsif ($self->{next_char} == -1) {        } elsif ($self->{nc} == -1) {
2996          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
2997          !!!next-input-character;          !!!next-input-character;
2998          if (length $self->{current_token}->{data}) { # character          if (length $self->{ct}->{data}) { # character
2999            !!!cp (221.2);            !!!cp (221.2);
3000            !!!emit ($self->{current_token}); # character            !!!emit ($self->{ct}); # character
3001          } else {          } else {
3002            !!!cp (221.3);            !!!cp (221.3);
3003            ## No token to emit. $self->{current_token} is discarded.            ## No token to emit. $self->{ct} is discarded.
3004          }                  }        
3005          redo A;          redo A;
3006        } else {        } else {
3007          !!!cp (221.4);          !!!cp (221.4);
3008          $self->{current_token}->{data} .= chr $self->{next_char};          $self->{ct}->{data} .= chr $self->{nc};
3009          $self->{read_until}->($self->{current_token}->{data},          $self->{read_until}->($self->{ct}->{data},
3010                                q<]>,                                q<]>,
3011                                length $self->{current_token}->{data});                                length $self->{ct}->{data});
3012    
3013          ## Stay in the state.          ## Stay in the state.
3014          !!!next-input-character;          !!!next-input-character;
# Line 2966  sub _get_next_token ($) { Line 3017  sub _get_next_token ($) {
3017    
3018        ## ISSUE: "text tokens" in spec.        ## ISSUE: "text tokens" in spec.
3019      } elsif ($self->{state} == CDATA_SECTION_MSE1_STATE) {      } elsif ($self->{state} == CDATA_SECTION_MSE1_STATE) {
3020        if ($self->{next_char} == 0x005D) { # ]        if ($self->{nc} == 0x005D) { # ]
3021          !!!cp (221.5);          !!!cp (221.5);
3022          $self->{state} = CDATA_SECTION_MSE2_STATE;          $self->{state} = CDATA_SECTION_MSE2_STATE;
3023          !!!next-input-character;          !!!next-input-character;
3024          redo A;          redo A;
3025        } else {        } else {
3026          !!!cp (221.6);          !!!cp (221.6);
3027          $self->{current_token}->{data} .= ']';          $self->{ct}->{data} .= ']';
3028          $self->{state} = CDATA_SECTION_STATE;          $self->{state} = CDATA_SECTION_STATE;
3029          ## Reconsume.          ## Reconsume.
3030          redo A;          redo A;
3031        }        }
3032      } elsif ($self->{state} == CDATA_SECTION_MSE2_STATE) {      } elsif ($self->{state} == CDATA_SECTION_MSE2_STATE) {
3033        if ($self->{next_char} == 0x003E) { # >        if ($self->{nc} == 0x003E) { # >
3034          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
3035          !!!next-input-character;          !!!next-input-character;
3036          if (length $self->{current_token}->{data}) { # character          if (length $self->{ct}->{data}) { # character
3037            !!!cp (221.7);            !!!cp (221.7);
3038            !!!emit ($self->{current_token}); # character            !!!emit ($self->{ct}); # character
3039          } else {          } else {
3040            !!!cp (221.8);            !!!cp (221.8);
3041            ## No token to emit. $self->{current_token} is discarded.            ## No token to emit. $self->{ct} is discarded.
3042          }          }
3043          redo A;          redo A;
3044        } elsif ($self->{next_char} == 0x005D) { # ]        } elsif ($self->{nc} == 0x005D) { # ]
3045          !!!cp (221.9); # character          !!!cp (221.9); # character
3046          $self->{current_token}->{data} .= ']'; ## Add first "]" of "]]]".          $self->{ct}->{data} .= ']'; ## Add first "]" of "]]]".
3047          ## Stay in the state.          ## Stay in the state.
3048          !!!next-input-character;          !!!next-input-character;
3049          redo A;          redo A;
3050        } else {        } else {
3051          !!!cp (221.11);          !!!cp (221.11);
3052          $self->{current_token}->{data} .= ']]'; # character          $self->{ct}->{data} .= ']]'; # character
3053          $self->{state} = CDATA_SECTION_STATE;          $self->{state} = CDATA_SECTION_STATE;
3054          ## Reconsume.          ## Reconsume.
3055          redo A;          redo A;
# Line 3007  sub _get_next_token ($) { Line 3058  sub _get_next_token ($) {
3058        if ({        if ({
3059          0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, # HT, LF, VT, FF,          0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, # HT, LF, VT, FF,
3060          0x0020 => 1, 0x003C => 1, 0x0026 => 1, -1 => 1, # SP, <, &          0x0020 => 1, 0x003C => 1, 0x0026 => 1, -1 => 1, # SP, <, &
3061          $self->{entity_additional} => 1,          $self->{entity_add} => 1,
3062        }->{$self->{next_char}}) {        }->{$self->{nc}}) {
3063          !!!cp (1001);          !!!cp (1001);
3064          ## Don't consume          ## Don't consume
3065          ## No error          ## No error
3066          ## Return nothing.          ## Return nothing.
3067          #          #
3068        } elsif ($self->{next_char} == 0x0023) { # #        } elsif ($self->{nc} == 0x0023) { # #
3069          !!!cp (999);          !!!cp (999);
3070          $self->{state} = ENTITY_HASH_STATE;          $self->{state} = ENTITY_HASH_STATE;
3071          $self->{state_keyword} = '#';          $self->{s_kwd} = '#';
3072          !!!next-input-character;          !!!next-input-character;
3073          redo A;          redo A;
3074        } elsif ((0x0041 <= $self->{next_char} and        } elsif ((0x0041 <= $self->{nc} and
3075                  $self->{next_char} <= 0x005A) or # A..Z                  $self->{nc} <= 0x005A) or # A..Z
3076                 (0x0061 <= $self->{next_char} and                 (0x0061 <= $self->{nc} and
3077                  $self->{next_char} <= 0x007A)) { # a..z                  $self->{nc} <= 0x007A)) { # a..z
3078          !!!cp (998);          !!!cp (998);
3079          require Whatpm::_NamedEntityList;          require Whatpm::_NamedEntityList;
3080          $self->{state} = ENTITY_NAME_STATE;          $self->{state} = ENTITY_NAME_STATE;
3081          $self->{state_keyword} = chr $self->{next_char};          $self->{s_kwd} = chr $self->{nc};
3082          $self->{entity__value} = $self->{state_keyword};          $self->{entity__value} = $self->{s_kwd};
3083          $self->{entity__match} = 0;          $self->{entity__match} = 0;
3084          !!!next-input-character;          !!!next-input-character;
3085          redo A;          redo A;
# Line 3056  sub _get_next_token ($) { Line 3107  sub _get_next_token ($) {
3107          redo A;          redo A;
3108        } else {        } else {
3109          !!!cp (996);          !!!cp (996);
3110          $self->{current_attribute}->{value} .= '&';          $self->{ca}->{value} .= '&';
3111          $self->{state} = $self->{prev_state};          $self->{state} = $self->{prev_state};
3112          ## Reconsume.          ## Reconsume.
3113          redo A;          redo A;
3114        }        }
3115      } elsif ($self->{state} == ENTITY_HASH_STATE) {      } elsif ($self->{state} == ENTITY_HASH_STATE) {
3116        if ($self->{next_char} == 0x0078 or # x        if ($self->{nc} == 0x0078 or # x
3117            $self->{next_char} == 0x0058) { # X            $self->{nc} == 0x0058) { # X
3118          !!!cp (995);          !!!cp (995);
3119          $self->{state} = HEXREF_X_STATE;          $self->{state} = HEXREF_X_STATE;
3120          $self->{state_keyword} .= chr $self->{next_char};          $self->{s_kwd} .= chr $self->{nc};
3121          !!!next-input-character;          !!!next-input-character;
3122          redo A;          redo A;
3123        } elsif (0x0030 <= $self->{next_char} and        } elsif (0x0030 <= $self->{nc} and
3124                 $self->{next_char} <= 0x0039) { # 0..9                 $self->{nc} <= 0x0039) { # 0..9
3125          !!!cp (994);          !!!cp (994);
3126          $self->{state} = NCR_NUM_STATE;          $self->{state} = NCR_NUM_STATE;
3127          $self->{state_keyword} = $self->{next_char} - 0x0030;          $self->{s_kwd} = $self->{nc} - 0x0030;
3128          !!!next-input-character;          !!!next-input-character;
3129          redo A;          redo A;
3130        } else {        } else {
# Line 3097  sub _get_next_token ($) { Line 3148  sub _get_next_token ($) {
3148            redo A;            redo A;
3149          } else {          } else {
3150            !!!cp (993);            !!!cp (993);
3151            $self->{current_attribute}->{value} .= '&#';            $self->{ca}->{value} .= '&#';
3152            $self->{state} = $self->{prev_state};            $self->{state} = $self->{prev_state};
3153            ## Reconsume.            ## Reconsume.
3154            redo A;            redo A;
3155          }          }
3156        }        }
3157      } elsif ($self->{state} == NCR_NUM_STATE) {      } elsif ($self->{state} == NCR_NUM_STATE) {
3158        if (0x0030 <= $self->{next_char} and        if (0x0030 <= $self->{nc} and
3159            $self->{next_char} <= 0x0039) { # 0..9            $self->{nc} <= 0x0039) { # 0..9
3160          !!!cp (1012);          !!!cp (1012);
3161          $self->{state_keyword} *= 10;          $self->{s_kwd} *= 10;
3162          $self->{state_keyword} += $self->{next_char} - 0x0030;          $self->{s_kwd} += $self->{nc} - 0x0030;
3163                    
3164          ## Stay in the state.          ## Stay in the state.
3165          !!!next-input-character;          !!!next-input-character;
3166          redo A;          redo A;
3167        } elsif ($self->{next_char} == 0x003B) { # ;        } elsif ($self->{nc} == 0x003B) { # ;
3168          !!!cp (1013);          !!!cp (1013);
3169          !!!next-input-character;          !!!next-input-character;
3170          #          #
# Line 3124  sub _get_next_token ($) { Line 3175  sub _get_next_token ($) {
3175          #          #
3176        }        }
3177    
3178        my $code = $self->{state_keyword};        my $code = $self->{s_kwd};
3179        my $l = $self->{line_prev};        my $l = $self->{line_prev};
3180        my $c = $self->{column_prev};        my $c = $self->{column_prev};
3181        if ($code == 0 or (0xD800 <= $code and $code <= 0xDFFF)) {        if ($code == 0 or (0xD800 <= $code and $code <= 0xDFFF)) {
# Line 3162  sub _get_next_token ($) { Line 3213  sub _get_next_token ($) {
3213          redo A;          redo A;
3214        } else {        } else {
3215          !!!cp (991);          !!!cp (991);
3216          $self->{current_attribute}->{value} .= chr $code;          $self->{ca}->{value} .= chr $code;
3217          $self->{current_attribute}->{has_reference} = 1;          $self->{ca}->{has_reference} = 1;
3218          $self->{state} = $self->{prev_state};          $self->{state} = $self->{prev_state};
3219          ## Reconsume.          ## Reconsume.
3220          redo A;          redo A;
3221        }        }
3222      } elsif ($self->{state} == HEXREF_X_STATE) {      } elsif ($self->{state} == HEXREF_X_STATE) {
3223        if ((0x0030 <= $self->{next_char} and $self->{next_char} <= 0x0039) or        if ((0x0030 <= $self->{nc} and $self->{nc} <= 0x0039) or
3224            (0x0041 <= $self->{next_char} and $self->{next_char} <= 0x0046) or            (0x0041 <= $self->{nc} and $self->{nc} <= 0x0046) or
3225            (0x0061 <= $self->{next_char} and $self->{next_char} <= 0x0066)) {            (0x0061 <= $self->{nc} and $self->{nc} <= 0x0066)) {
3226          # 0..9, A..F, a..f          # 0..9, A..F, a..f
3227          !!!cp (990);          !!!cp (990);
3228          $self->{state} = HEXREF_HEX_STATE;          $self->{state} = HEXREF_HEX_STATE;
3229          $self->{state_keyword} = 0;          $self->{s_kwd} = 0;
3230          ## Reconsume.          ## Reconsume.
3231          redo A;          redo A;
3232        } else {        } else {
# Line 3192  sub _get_next_token ($) { Line 3243  sub _get_next_token ($) {
3243            $self->{state} = $self->{prev_state};            $self->{state} = $self->{prev_state};
3244            ## Reconsume.            ## Reconsume.
3245            !!!emit ({type => CHARACTER_TOKEN,            !!!emit ({type => CHARACTER_TOKEN,
3246                      data => '&' . $self->{state_keyword},                      data => '&' . $self->{s_kwd},
3247                      line => $self->{line_prev},                      line => $self->{line_prev},
3248                      column => $self->{column_prev} - length $self->{state_keyword},                      column => $self->{column_prev} - length $self->{s_kwd},
3249                     });                     });
3250            redo A;            redo A;
3251          } else {          } else {
3252            !!!cp (989);            !!!cp (989);
3253            $self->{current_attribute}->{value} .= '&' . $self->{state_keyword};            $self->{ca}->{value} .= '&' . $self->{s_kwd};
3254            $self->{state} = $self->{prev_state};            $self->{state} = $self->{prev_state};
3255            ## Reconsume.            ## Reconsume.
3256            redo A;            redo A;
3257          }          }
3258        }        }
3259      } elsif ($self->{state} == HEXREF_HEX_STATE) {      } elsif ($self->{state} == HEXREF_HEX_STATE) {
3260        if (0x0030 <= $self->{next_char} and $self->{next_char} <= 0x0039) {        if (0x0030 <= $self->{nc} and $self->{nc} <= 0x0039) {
3261          # 0..9          # 0..9
3262          !!!cp (1002);          !!!cp (1002);
3263          $self->{state_keyword} *= 0x10;          $self->{s_kwd} *= 0x10;
3264          $self->{state_keyword} += $self->{next_char} - 0x0030;          $self->{s_kwd} += $self->{nc} - 0x0030;
3265          ## Stay in the state.          ## Stay in the state.
3266          !!!next-input-character;          !!!next-input-character;
3267          redo A;          redo A;
3268        } elsif (0x0061 <= $self->{next_char} and        } elsif (0x0061 <= $self->{nc} and
3269                 $self->{next_char} <= 0x0066) { # a..f                 $self->{nc} <= 0x0066) { # a..f
3270          !!!cp (1003);          !!!cp (1003);
3271          $self->{state_keyword} *= 0x10;          $self->{s_kwd} *= 0x10;
3272          $self->{state_keyword} += $self->{next_char} - 0x0060 + 9;          $self->{s_kwd} += $self->{nc} - 0x0060 + 9;
3273          ## Stay in the state.          ## Stay in the state.
3274          !!!next-input-character;          !!!next-input-character;
3275          redo A;          redo A;
3276        } elsif (0x0041 <= $self->{next_char} and        } elsif (0x0041 <= $self->{nc} and
3277                 $self->{next_char} <= 0x0046) { # A..F                 $self->{nc} <= 0x0046) { # A..F
3278          !!!cp (1004);          !!!cp (1004);
3279          $self->{state_keyword} *= 0x10;          $self->{s_kwd} *= 0x10;
3280          $self->{state_keyword} += $self->{next_char} - 0x0040 + 9;          $self->{s_kwd} += $self->{nc} - 0x0040 + 9;
3281          ## Stay in the state.          ## Stay in the state.
3282          !!!next-input-character;          !!!next-input-character;
3283          redo A;          redo A;
3284        } elsif ($self->{next_char} == 0x003B) { # ;        } elsif ($self->{nc} == 0x003B) { # ;
3285          !!!cp (1006);          !!!cp (1006);
3286          !!!next-input-character;          !!!next-input-character;
3287          #          #
# Line 3243  sub _get_next_token ($) { Line 3294  sub _get_next_token ($) {
3294          #          #
3295        }        }
3296    
3297        my $code = $self->{state_keyword};        my $code = $self->{s_kwd};
3298        my $l = $self->{line_prev};        my $l = $self->{line_prev};
3299        my $c = $self->{column_prev};        my $c = $self->{column_prev};
3300        if ($code == 0 or (0xD800 <= $code and $code <= 0xDFFF)) {        if ($code == 0 or (0xD800 <= $code and $code <= 0xDFFF)) {
# Line 3278  sub _get_next_token ($) { Line 3329  sub _get_next_token ($) {
3329          redo A;          redo A;
3330        } else {        } else {
3331          !!!cp (987);          !!!cp (987);
3332          $self->{current_attribute}->{value} .= chr $code;          $self->{ca}->{value} .= chr $code;
3333          $self->{current_attribute}->{has_reference} = 1;          $self->{ca}->{has_reference} = 1;
3334          $self->{state} = $self->{prev_state};          $self->{state} = $self->{prev_state};
3335          ## Reconsume.          ## Reconsume.
3336          redo A;          redo A;
3337        }        }
3338      } elsif ($self->{state} == ENTITY_NAME_STATE) {      } elsif ($self->{state} == ENTITY_NAME_STATE) {
3339        if (length $self->{state_keyword} < 30 and        if (length $self->{s_kwd} < 30 and
3340            ## NOTE: Some number greater than the maximum length of entity name            ## NOTE: Some number greater than the maximum length of entity name
3341            ((0x0041 <= $self->{next_char} and # a            ((0x0041 <= $self->{nc} and # a
3342              $self->{next_char} <= 0x005A) or # x              $self->{nc} <= 0x005A) or # x
3343             (0x0061 <= $self->{next_char} and # a             (0x0061 <= $self->{nc} and # a
3344              $self->{next_char} <= 0x007A) or # z              $self->{nc} <= 0x007A) or # z
3345             (0x0030 <= $self->{next_char} and # 0             (0x0030 <= $self->{nc} and # 0
3346              $self->{next_char} <= 0x0039) or # 9              $self->{nc} <= 0x0039) or # 9
3347             $self->{next_char} == 0x003B)) { # ;             $self->{nc} == 0x003B)) { # ;
3348          our $EntityChar;          our $EntityChar;
3349          $self->{state_keyword} .= chr $self->{next_char};          $self->{s_kwd} .= chr $self->{nc};
3350          if (defined $EntityChar->{$self->{state_keyword}}) {          if (defined $EntityChar->{$self->{s_kwd}}) {
3351            if ($self->{next_char} == 0x003B) { # ;            if ($self->{nc} == 0x003B) { # ;
3352              !!!cp (1020);              !!!cp (1020);
3353              $self->{entity__value} = $EntityChar->{$self->{state_keyword}};              $self->{entity__value} = $EntityChar->{$self->{s_kwd}};
3354              $self->{entity__match} = 1;              $self->{entity__match} = 1;
3355              !!!next-input-character;              !!!next-input-character;
3356              #              #
3357            } else {            } else {
3358              !!!cp (1021);              !!!cp (1021);
3359              $self->{entity__value} = $EntityChar->{$self->{state_keyword}};              $self->{entity__value} = $EntityChar->{$self->{s_kwd}};
3360              $self->{entity__match} = -1;              $self->{entity__match} = -1;
3361              ## Stay in the state.              ## Stay in the state.
3362              !!!next-input-character;              !!!next-input-character;
# Line 3313  sub _get_next_token ($) { Line 3364  sub _get_next_token ($) {
3364            }            }
3365          } else {          } else {
3366            !!!cp (1022);            !!!cp (1022);
3367            $self->{entity__value} .= chr $self->{next_char};            $self->{entity__value} .= chr $self->{nc};
3368            $self->{entity__match} *= 2;            $self->{entity__match} *= 2;
3369            ## Stay in the state.            ## Stay in the state.
3370            !!!next-input-character;            !!!next-input-character;
# Line 3333  sub _get_next_token ($) { Line 3384  sub _get_next_token ($) {
3384          if ($self->{prev_state} != DATA_STATE and # in attribute          if ($self->{prev_state} != DATA_STATE and # in attribute
3385              $self->{entity__match} < -1) {              $self->{entity__match} < -1) {
3386            !!!cp (1024);            !!!cp (1024);
3387            $data = '&' . $self->{state_keyword};            $data = '&' . $self->{s_kwd};
3388            #            #
3389          } else {          } else {
3390            !!!cp (1025);            !!!cp (1025);
# Line 3345  sub _get_next_token ($) { Line 3396  sub _get_next_token ($) {
3396          !!!cp (1026);          !!!cp (1026);
3397          !!!parse-error (type => 'bare ero',          !!!parse-error (type => 'bare ero',
3398                          line => $self->{line_prev},                          line => $self->{line_prev},
3399                          column => $self->{column_prev} - length $self->{state_keyword});                          column => $self->{column_prev} - length $self->{s_kwd});
3400          $data = '&' . $self->{state_keyword};          $data = '&' . $self->{s_kwd};
3401          #          #
3402        }        }
3403        
# Line 3367  sub _get_next_token ($) { Line 3418  sub _get_next_token ($) {
3418          !!!emit ({type => CHARACTER_TOKEN,          !!!emit ({type => CHARACTER_TOKEN,
3419                    data => $data,                    data => $data,
3420                    line => $self->{line_prev},                    line => $self->{line_prev},
3421                    column => $self->{column_prev} + 1 - length $self->{state_keyword},                    column => $self->{column_prev} + 1 - length $self->{s_kwd},
3422                   });                   });
3423          redo A;          redo A;
3424        } else {        } else {
3425          !!!cp (985);          !!!cp (985);
3426          $self->{current_attribute}->{value} .= $data;          $self->{ca}->{value} .= $data;
3427          $self->{current_attribute}->{has_reference} = 1 if $has_ref;          $self->{ca}->{has_reference} = 1 if $has_ref;
3428          $self->{state} = $self->{prev_state};          $self->{state} = $self->{prev_state};
3429          ## Reconsume.          ## Reconsume.
3430          redo A;          redo A;
# Line 3451  sub _tree_construction_initial ($) { Line 3502  sub _tree_construction_initial ($) {
3502        $doctype_name = '' unless defined $doctype_name;        $doctype_name = '' unless defined $doctype_name;
3503        $doctype_name =~ tr/a-z/A-Z/; # ASCII case-insensitive        $doctype_name =~ tr/a-z/A-Z/; # ASCII case-insensitive
3504        if (not defined $token->{name} or # <!DOCTYPE>        if (not defined $token->{name} or # <!DOCTYPE>
3505            defined $token->{system_identifier}) {            defined $token->{sysid}) {
3506          !!!cp ('t1');          !!!cp ('t1');
3507          !!!parse-error (type => 'not HTML5', token => $token);          !!!parse-error (type => 'not HTML5', token => $token);
3508        } elsif ($doctype_name ne 'HTML') {        } elsif ($doctype_name ne 'HTML') {
3509          !!!cp ('t2');          !!!cp ('t2');
3510          !!!parse-error (type => 'not HTML5', token => $token);          !!!parse-error (type => 'not HTML5', token => $token);
3511        } elsif (defined $token->{public_identifier}) {        } elsif (defined $token->{pubid}) {
3512          if ($token->{public_identifier} eq 'XSLT-compat') {          if ($token->{pubid} eq 'XSLT-compat') {
3513            !!!cp ('t1.2');            !!!cp ('t1.2');
3514            !!!parse-error (type => 'XSLT-compat', token => $token,            !!!parse-error (type => 'XSLT-compat', token => $token,
3515                            level => $self->{level}->{should});                            level => $self->{level}->{should});
# Line 3474  sub _tree_construction_initial ($) { Line 3525  sub _tree_construction_initial ($) {
3525          ($token->{name}); ## ISSUE: If name is missing (e.g. <!DOCTYPE>)?          ($token->{name}); ## ISSUE: If name is missing (e.g. <!DOCTYPE>)?
3526        ## NOTE: Default value for both |public_id| and |system_id| attributes        ## NOTE: Default value for both |public_id| and |system_id| attributes
3527        ## are empty strings, so that we don't set any value in missing cases.        ## are empty strings, so that we don't set any value in missing cases.
3528        $doctype->public_id ($token->{public_identifier})        $doctype->public_id ($token->{pubid}) if defined $token->{pubid};
3529            if defined $token->{public_identifier};        $doctype->system_id ($token->{sysid}) if defined $token->{sysid};
       $doctype->system_id ($token->{system_identifier})  
           if defined $token->{system_identifier};  
3530        ## NOTE: Other DocumentType attributes are null or empty lists.        ## NOTE: Other DocumentType attributes are null or empty lists.
3531        ## ISSUE: internalSubset = null??        ## ISSUE: internalSubset = null??
3532        $self->{document}->append_child ($doctype);        $self->{document}->append_child ($doctype);
# Line 3485  sub _tree_construction_initial ($) { Line 3534  sub _tree_construction_initial ($) {
3534        if ($token->{quirks} or $doctype_name ne 'HTML') {        if ($token->{quirks} or $doctype_name ne 'HTML') {
3535          !!!cp ('t4');          !!!cp ('t4');
3536          $self->{document}->manakai_compat_mode ('quirks');          $self->{document}->manakai_compat_mode ('quirks');
3537        } elsif (defined $token->{public_identifier}) {        } elsif (defined $token->{pubid}) {
3538          my $pubid = $token->{public_identifier};          my $pubid = $token->{pubid};
3539          $pubid =~ tr/a-z/A-z/;          $pubid =~ tr/a-z/A-z/;
3540          my $prefix = [          my $prefix = [
3541            "+//SILMARIL//DTD HTML PRO V0R11 19970101//",            "+//SILMARIL//DTD HTML PRO V0R11 19970101//",
# Line 3560  sub _tree_construction_initial ($) { Line 3609  sub _tree_construction_initial ($) {
3609            $self->{document}->manakai_compat_mode ('quirks');            $self->{document}->manakai_compat_mode ('quirks');
3610          } elsif ($pubid =~ m[^-//W3C//DTD HTML 4.01 FRAMESET//] or          } elsif ($pubid =~ m[^-//W3C//DTD HTML 4.01 FRAMESET//] or
3611                   $pubid =~ m[^-//W3C//DTD HTML 4.01 TRANSITIONAL//]) {                   $pubid =~ m[^-//W3C//DTD HTML 4.01 TRANSITIONAL//]) {
3612            if (defined $token->{system_identifier}) {            if (defined $token->{sysid}) {
3613              !!!cp ('t6');              !!!cp ('t6');
3614              $self->{document}->manakai_compat_mode ('quirks');              $self->{document}->manakai_compat_mode ('quirks');
3615            } else {            } else {
# Line 3577  sub _tree_construction_initial ($) { Line 3626  sub _tree_construction_initial ($) {
3626        } else {        } else {
3627          !!!cp ('t10');          !!!cp ('t10');
3628        }        }
3629        if (defined $token->{system_identifier}) {        if (defined $token->{sysid}) {
3630          my $sysid = $token->{system_identifier};          my $sysid = $token->{sysid};
3631          $sysid =~ tr/A-Z/a-z/;          $sysid =~ tr/A-Z/a-z/;
3632          if ($sysid eq "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {          if ($sysid eq "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
3633            ## NOTE: Ensure that |PUBLIC "(limited quirks)" "(quirks)"| is            ## NOTE: Ensure that |PUBLIC "(limited quirks)" "(quirks)"| is
# Line 7785  sub set_inner_html ($$$$;$) { Line 7834  sub set_inner_html ($$$$;$) {
7834      require Whatpm::Charset::DecodeHandle;      require Whatpm::Charset::DecodeHandle;
7835      my $input = Whatpm::Charset::DecodeHandle::CharString->new (\($_[0]));      my $input = Whatpm::Charset::DecodeHandle::CharString->new (\($_[0]));
7836      $input = $get_wrapper->($input);      $input = $get_wrapper->($input);
7837      $p->{set_next_char} = sub {      $p->{set_nc} = sub {
7838        my $self = shift;        my $self = shift;
7839    
       pop @{$self->{prev_char}};  
       unshift @{$self->{prev_char}}, $self->{next_char};  
   
7840        my $char = '';        my $char = '';
7841        if (defined $self->{next_next_char}) {        if (defined $self->{next_nc}) {
7842          $char = $self->{next_next_char};          $char = $self->{next_nc};
7843          delete $self->{next_next_char};          delete $self->{next_nc};
7844          $self->{next_char} = ord $char;          $self->{nc} = ord $char;
7845        } else {        } else {
7846            $self->{char_buffer} = '';
7847            $self->{char_buffer_pos} = 0;
7848            
7849            my $count = $input->manakai_read_until
7850                ($self->{char_buffer}, qr/[^\x00\x0A\x0D]/,
7851                 $self->{char_buffer_pos});
7852            if ($count) {
7853              $self->{line_prev} = $self->{line};
7854              $self->{column_prev} = $self->{column};
7855              $self->{column}++;
7856              $self->{nc}
7857                  = ord substr ($self->{char_buffer},
7858                                $self->{char_buffer_pos}++, 1);
7859              return;
7860            }
7861            
7862          if ($input->read ($char, 1)) {          if ($input->read ($char, 1)) {
7863            $self->{next_char} = ord $char;            $self->{nc} = ord $char;
7864          } else {          } else {
7865            $self->{next_char} = -1;            $self->{nc} = -1;
7866            return;            return;
7867          }          }
7868        }        }
# Line 7808  sub set_inner_html ($$$$;$) { Line 7870  sub set_inner_html ($$$$;$) {
7870        ($p->{line_prev}, $p->{column_prev}) = ($p->{line}, $p->{column});        ($p->{line_prev}, $p->{column_prev}) = ($p->{line}, $p->{column});
7871        $p->{column}++;        $p->{column}++;
7872    
7873        if ($self->{next_char} == 0x000A) { # LF        if ($self->{nc} == 0x000A) { # LF
7874          $p->{line}++;          $p->{line}++;
7875          $p->{column} = 0;          $p->{column} = 0;
7876          !!!cp ('i1');          !!!cp ('i1');
7877        } elsif ($self->{next_char} == 0x000D) { # CR        } elsif ($self->{nc} == 0x000D) { # CR
7878  ## TODO: support for abort/streaming  ## TODO: support for abort/streaming
7879          my $next = '';          my $next = '';
7880          if ($input->read ($next, 1) and $next ne "\x0A") {          if ($input->read ($next, 1) and $next ne "\x0A") {
7881            $self->{next_next_char} = $next;            $self->{next_nc} = $next;
7882          }          }
7883          $self->{next_char} = 0x000A; # LF # MUST          $self->{nc} = 0x000A; # LF # MUST
7884          $p->{line}++;          $p->{line}++;
7885          $p->{column} = 0;          $p->{column} = 0;
7886          !!!cp ('i2');          !!!cp ('i2');
7887        } elsif ($self->{next_char} > 0x10FFFF) {        } elsif ($self->{nc} == 0x0000) { # NULL
         $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST  
         !!!cp ('i3');  
       } elsif ($self->{next_char} == 0x0000) { # NULL  
7888          !!!cp ('i4');          !!!cp ('i4');
7889          !!!parse-error (type => 'NULL');          !!!parse-error (type => 'NULL');
7890          $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST          $self->{nc} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
       } elsif ($self->{next_char} <= 0x0008 or  
                (0x000E <= $self->{next_char} and  
                 $self->{next_char} <= 0x001F) or  
                (0x007F <= $self->{next_char} and  
                 $self->{next_char} <= 0x009F) or  
                (0xD800 <= $self->{next_char} and  
                 $self->{next_char} <= 0xDFFF) or  
                (0xFDD0 <= $self->{next_char} and  
                 $self->{next_char} <= 0xFDDF) or  
                {  
                 0xFFFE => 1, 0xFFFF => 1, 0x1FFFE => 1, 0x1FFFF => 1,  
                 0x2FFFE => 1, 0x2FFFF => 1, 0x3FFFE => 1, 0x3FFFF => 1,  
                 0x4FFFE => 1, 0x4FFFF => 1, 0x5FFFE => 1, 0x5FFFF => 1,  
                 0x6FFFE => 1, 0x6FFFF => 1, 0x7FFFE => 1, 0x7FFFF => 1,  
                 0x8FFFE => 1, 0x8FFFF => 1, 0x9FFFE => 1, 0x9FFFF => 1,  
                 0xAFFFE => 1, 0xAFFFF => 1, 0xBFFFE => 1, 0xBFFFF => 1,  
                 0xCFFFE => 1, 0xCFFFF => 1, 0xDFFFE => 1, 0xDFFFF => 1,  
                 0xEFFFE => 1, 0xEFFFF => 1, 0xFFFFE => 1, 0xFFFFF => 1,  
                 0x10FFFE => 1, 0x10FFFF => 1,  
                }->{$self->{next_char}}) {  
         !!!cp ('i4.1');  
         if ($self->{next_char} < 0x10000) {  
           !!!parse-error (type => 'control char',  
                           text => (sprintf 'U+%04X', $self->{next_char}));  
         } else {  
           !!!parse-error (type => 'control char',  
                           text => (sprintf 'U-%08X', $self->{next_char}));  
         }  
7891        }        }
7892      };      };
     $p->{prev_char} = [-1, -1, -1];  
     $p->{next_char} = -1;  
7893    
7894      $p->{read_until} = sub {      $p->{read_until} = sub {
7895        #my ($scalar, $specials_range, $offset) = @_;        #my ($scalar, $specials_range, $offset) = @_;
7896        my $specials_range = $_[1];        return 0 if defined $p->{next_nc};
7897        return 0 if defined $p->{next_next_char};  
7898        my $count = $input->manakai_read_until        my $pattern = qr/[^$_[1]\x00\x0A\x0D]/;
7899          ($_[0],        my $offset = $_[2] || 0;
7900           qr/(?![$specials_range\x{FDD0}-\x{FDDF}\x{FFFE}\x{FFFF}\x{1FFFE}\x{1FFFF}\x{2FFFE}\x{2FFFF}\x{3FFFE}\x{3FFFF}\x{4FFFE}\x{4FFFF}\x{5FFFE}\x{5FFFF}\x{6FFFE}\x{6FFFF}\x{7FFFE}\x{7FFFF}\x{8FFFE}\x{8FFFF}\x{9FFFE}\x{9FFFF}\x{AFFFE}\x{AFFFF}\x{BFFFE}\x{BFFFF}\x{CFFFE}\x{CFFFF}\x{DFFFE}\x{DFFFF}\x{EFFFE}\x{EFFFF}\x{FFFFE}\x{FFFFF}])[\x20-\x7E\xA0-\x{D7FF}\x{E000}-\x{10FFFD}]/,        
7901           $_[2]);        if ($p->{char_buffer_pos} < length $p->{char_buffer}) {
7902        if ($count) {          pos ($p->{char_buffer}) = $p->{char_buffer_pos};
7903          $p->{column} += $count;          if ($p->{char_buffer} =~ /\G(?>$pattern)+/) {
7904          $p->{column_prev} += $count;            substr ($_[0], $offset)
7905          $p->{prev_char} = [-1, -1, -1];                = substr ($p->{char_buffer}, $-[0], $+[0] - $-[0]);
7906          $p->{next_char} = -1;            my $count = $+[0] - $-[0];
7907              if ($count) {
7908                $p->{column} += $count;
7909                $p->{char_buffer_pos} += $count;
7910                $p->{line_prev} = $p->{line};
7911                $p->{column_prev} = $p->{column} - 1;
7912                $p->{nc} = -1;
7913              }
7914              return $count;
7915            } else {
7916              return 0;
7917            }
7918          } else {
7919            my $count = $input->manakai_read_until ($_[0], $pattern, $_[2]);
7920            if ($count) {
7921              $p->{column} += $count;
7922              $p->{column_prev} += $count;
7923              $p->{nc} = -1;
7924            }
7925            return $count;
7926        }        }
       return $count;  
7927      }; # $p->{read_until}      }; # $p->{read_until}
7928    
7929      my $ponerror = $onerror || sub {      my $ponerror = $onerror || sub {

Legend:
Removed from v.1.178  
changed lines
  Added in v.1.184

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24