%%{

  machine hpricot_common;

  #
  # HTML tokens
  # (a blatant rip from HTree)
  #
  newline = '\n' @{curline += 1;} ;
  NameChar = [\-A-Za-z0-9._:?] ;
  Name = [A-Za-z_:] NameChar* ;
  StartComment = "<!--" ;
  EndComment = "-->" ;
  StartCdata = "<![CDATA[" ;
  EndCdata = "]]>" ;

  NameCap = Name >_tag %tag;
  NameAttr = NameChar+ >_akey %akey ;
  Q1Char = [^'] ;
  Q1Attr = Q1Char* >_aval %aval ;
  Q2Char = [^"] ;
  Q2Attr = Q2Char* >_aval %aval ;
  UnqAttr = ( space >_aval | [^ \t\r\n<>"'] >_aval [^ \t\r\n<>]* %aunq ) ;
  Nmtoken = NameChar+ >_akey %akey ;

  Attr =  NameAttr space* "=" space* ('"' Q2Attr '"' | "'" Q1Attr "'" | UnqAttr space+ ) space* ;
  AttrEnd = ( NameAttr space* "=" space* UnqAttr? | Nmtoken >new_attr %save_attr ) ;
  AttrSet = ( Attr >new_attr %save_attr | Nmtoken >new_attr space+ %save_attr ) ;
  StartTag = "<" NameCap space+ AttrSet* (AttrEnd >new_attr %save_attr)? ">" | "<" NameCap ">";
  EmptyTag = "<" NameCap space+ AttrSet* (AttrEnd >new_attr %save_attr)? "/>" | "<" NameCap "/>" ;

  EndTag = "</" NameCap space* ">" ;
  XmlVersionNum = [a-zA-Z0-9_.:\-]+ >_aval %xmlver ;
  XmlVersionInfo = space+ "version" space* "=" space* ("'" XmlVersionNum "'" | '"' XmlVersionNum '"' ) ;
  XmlEncName = [A-Za-z] >_aval [A-Za-z0-9._\-]* %xmlenc ;
  XmlEncodingDecl = space+ "encoding" space* "=" space* ("'" XmlEncName "'" | '"' XmlEncName '"' ) ;
  XmlYesNo = ("yes" | "no") >_aval %xmlsd ;
  XmlSDDecl = space+ "standalone" space* "=" space* ("'" XmlYesNo "'" | '"' XmlYesNo '"') ;
  XmlDecl = "<?xml" XmlVersionInfo XmlEncodingDecl? XmlSDDecl? space* "?"? ">" ;

  SystemLiteral = '"' [^"]* >_aval %sysid '"' | "'" [^']* >_aval %sysid "'" ;
  PubidLiteral = '"' [\t a-zA-Z0-9\-'()+,./:=?;!*\#@$_%]*  >_aval %pubid '"' |
    "'" [\t a-zA-Z0-9\-'()+,./:=?;!*\#@$_%]* >_aval %pubid "'" ;
  ExternalID = ( "SYSTEM" | "PUBLIC" space+ PubidLiteral ) (space+ SystemLiteral)? ;
  DocType = "<!DOCTYPE" space+ NameCap (space+ ExternalID)? space* ("[" [^\]]* "]" space*)? ">" ;
  StartXmlProcIns = "<?" Name >{ TEXT_PASS(); } space+ ;
  EndXmlProcIns = "?"? ">" ;

  html_comment := |*
    EndComment @{ EBLK(comment, 3); fgoto main; };
    any | newline { TEXT_PASS(); };
  *|;

  html_cdata := |*
    EndCdata @{ EBLK(cdata, 3); fgoto main; };
    any | newline { TEXT_PASS(); };
  *|;

  html_procins := |*
    EndXmlProcIns @{ EBLK(procins, 2); fgoto main; };
    any | newline { TEXT_PASS(); };
  *|;

  main := |*
    XmlDecl >newEle { ELE(xmldecl); };
    DocType >newEle { ELE(doctype); };
    StartXmlProcIns >newEle { fgoto html_procins; };
    StartTag >newEle { ELE(stag); };
    EndTag >newEle { ELE(etag); };
    EmptyTag >newEle { ELE(emptytag); };
    StartComment >newEle { fgoto html_comment; };
    StartCdata >newEle { fgoto html_cdata; };
    any | newline { TEXT_PASS(); };
  *|;

}%%;
