#########################################################################
#
# Copyright 2020 by Sean Conner.  All Rights Reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# Comments, questions and criticisms can be sent to: sean@conman.org
#
########################################################################

BODY      <- flow+ !.
flow      <- block / inline

# **************************************
# INLINE tags
# **************************************

inline    <- fontstyle / phrase / special  / iINS   / formctrl / iDEL / Cinline / PCDATA
fontstyle <- TT        / I      / B        / BIG    / SMALL    / U
phrase    <- EM        / STRONG / DFN      / CODE   / SAMP     / KBD  / VAR / CITE / ABBR / ACRONYM
special   <- A         / IMG    / BR       / SCRIPT / BDO      / Q    / SUB / SUP  / SPAN / OBJECT /  FONT / MAP
formctrl  <- INPUT     / SELECT / TEXTAREA / LABEL  / BUTTON

TT        <- "<" _TT       & ET { tagi(yy,"tt");       } attrs*         S* ">" inline*           "</" _TT       ">"   { endtag(yy); }
I         <- "<" _I        & ET { tagi(yy,"i");        } attrs*         S* ">" inline*           "</" _I        ">"   { endtag(yy); }
B         <- "<" _B        & ET { tagi(yy,"b");        } attrs*         S* ">" inline*           "</" _B        ">"   { endtag(yy); }
BIG       <- "<" _BIG      & ET { tagi(yy,"big");      } attrs*         S* ">" inline*           "</" _BIG      ">"   { endtag(yy); }
SMALL     <- "<" _SMALL    & ET { tagi(yy,"small");    } attrs*         S* ">" inline*           "</" _SMALL    ">"   { endtag(yy); }
U         <- "<" _U        & ET { tagi(yy,"u");        } attrs*         S* ">" inline*           "</" _U        ">"   { endtag(yy); } # XXX non-standard
EM        <- "<" _EM       & ET { tagi(yy,"em");       } attrs*         S* ">" inline*           "</" _EM       ">"   { endtag(yy); }
STRONG    <- "<" _STRONG   & ET { tagi(yy,"strong");   } attrs*         S* ">" inline*           "</" _STRONG   ">"   { endtag(yy); }
DFN       <- "<" _DFN      & ET { tagi(yy,"dfn");      } attrs*         S* ">" inline*           "</" _DFN      ">"   { endtag(yy); }
CODE      <- "<" _CODE     & ET { tagi(yy,"code");     } attrs*         S* ">" inline*           "</" _CODE     ">"   { endtag(yy); }
SAMP      <- "<" _SAMP     & ET { tagi(yy,"samp");     } attrs*         S* ">" inline*           "</" _SAMP     ">"   { endtag(yy); }
KBD       <- "<" _KBD      & ET { tagi(yy,"kbd");      } attrs*         S* ">" inline*           "</" _KBD      ">"   { endtag(yy); }
VAR       <- "<" _VAR      & ET { tagi(yy,"var");      } attrs*         S* ">" inline*           "</" _VAR      ">"   { endtag(yy); }
CITE      <- "<" _CITE     & ET { tagi(yy,"cite");     } attrs*         S* ">" inline*           "</" _CITE     ">"   { endtag(yy); }
ABBR      <- "<" _ABBR     & ET { tagi(yy,"abbr");     } attrs*         S* ">" inline*           "</" _ABBR     ">"   { endtag(yy); }
ACRONYM   <- "<" _ACRONYM  & ET { tagi(yy,"acronym");  } attrs*         S* ">" inline*           "</" _ACRONYM  ">"   { endtag(yy); }
A         <- "<" _A        & ET { tagi(yy,"a");        } A_attr*        S* ">" (!A inline)*      "</" _A        ">"   { endtag(yy); }
IMG       <- "<" _IMG      & ET { tagi(yy,"img");      } IMG_attr*      S* ">"               (S* "</" _IMG      ">")? { endtag(yy); }
BR        <- "<" _BR       & ET { tagi(yy,"br");       } coreattrs*     S* ">"               (S* "</" _BR       ">")? { endtag(yy); }
SCRIPT    <- "<" _SCRIPT   & ET { tagi(yy,"script");   } SCRIPT_attr*   S* ">" scriptDATA        "</" _SCRIPT   ">"   { endtag(yy); }
BDO       <- "<" _BDO      & ET { tagi(yy,"bdo");      } BDO_attr*      S* ">" inline*           "</" _BDO      ">"   { endtag(yy); }
Q         <- "<" _Q        & ET { tagi(yy,"q");        } Q_attr*        S* ">" inline*           "</" _Q        ">"   { endtag(yy); }
SUB       <- "<" _SUB      & ET { tagi(yy,"sub");      } attrs*         S* ">" inline*           "</" _SUB      ">"   { endtag(yy); }
SUP       <- "<" _SUP      & ET { tagi(yy,"sup");      } attrs*         S* ">" inline*           "</" _SUP      ">"   { endtag(yy); }
SPAN      <- "<" _SPAN     & ET { tagi(yy,"span");     } attrs*         S* ">" inline*           "</" _SPAN     ">"   { endtag(yy); }
OBJECT    <- "<" _OBJECT   & ET { tagi(yy,"object");   } OBJECT_attr*   S* ">" object_flow*      "</" _OBJECT   ">"   { endtag(yy); }
PARAM     <- "<" _PARAM    & ET { tagi(yy,"param");    } PARAM_attr*    S* ">"               (S* "</" _PARAM    ">")? { endtag(yy); }
FONT      <- "<" _FONT     & ET { tagi(yy,"font");     } FONT_attr*     S* ">" inline*           "</" _FONT     ">"   { endtag(yy); }
MAP       <- "<" _MAP      & ET { tagi(yy,"map");      } MAP_attr*      S* ">" map_flow+         "</" _MAP      ">"   { endtag(yy); }
AREA      <- "<" _AREA     & ET { tagi(yy,"area");     } AREA_attr*     S* ">"               (S* "</" _AREA     ">")? { endtag(yy); }
INPUT     <- "<" _INPUT    & ET { tagi(yy,"input");    } INPUT_attr*    S* ">"               (S* "</" _INPUT    ">")? { endtag(yy); }
SELECT    <- "<" _SELECT   & ET { tagi(yy,"select");   } SELECT_attr*   S* ">" select_flow+      "</" _SELECT   ">"   { endtag(yy); }
TEXTAREA  <- "<" _TEXTAREA & ET { tagi(yy,"textarea"); } TEXTAREA_attr* S* ">" PCDATA*           "</" _TEXTAREA ">"   { endtag(yy); }
LABEL     <- "<" _LABEL    & ET { tagi(yy,"label");    } LABEL_attr*    S* ">" (! LABEL inline)* "</" _LABEL    ">"   { endtag(yy); }
BUTTON    <- "<" _BUTTON   & ET { tagi(yy,"button");   } BUTTON_attr*   S* ">" button_flow*      "</" _BUTTON   ">"   { endtag(yy); }
OPTGROUP  <- "<" _OPTGROUP & ET { tagi(yy,"optgroup"); } OPTGROUP_attr* S* ">" (OPTION / S)+     "</" _OPTGROUP ">"   { endtag(yy); }
OPTION    <- "<" _OPTION   & ET { tagi(yy,"option");   } OPTION_attr*   S* ">" PCDATA*           "</" _OPTION   ">"   { endtag(yy); }
iINS      <- "<" _INS      & ET { tagi(yy,"ins");      } INSDEL_attr*   S* ">" flow*             "</" _INS      ">"   { endtag(yy); }
iDEL      <- "<" _DEL      & ET { tagi(yy,"del");      } INSDEL_attr*   S* ">" flow*             "</" _DEL      ">"   { endtag(yy); }

object_flow     <- PARAM / flow
map_flow        <- block / AREA / S
select_flow     <- OPTGROUP / OPTION / S
button_flow     <- ! (A / formctrl / FORM / FIELDSET) flow

# *************************************
# BLOCK tags
# *************************************

block       <- P    / PRE  / DL    / NOSCRIPT / BLOCKQUOTE
            /  FORM / HR   / TABLE / FIELDSET / ADDRESS
            /  H1   / H2   / H3    / H4       / H5
            /  H6   / UL   / OL    / DIV
            /  bINS / bDEL / Cblock
            
BLOCKQUOTE  <- S* "<" _BLOCKQUOTE & ET { tagb(yy,"blockquote"); } bq_attr*     S* ">" S* bq_flow+        "</" _BLOCKQUOTE ">" S*   { endtag(yy); }
P           <- S* "<" _P          & ET { tagb(yy,"p");          } attrs*       S* ">" S* inline*        ("</" _P          ">" S*)? { endtag(yy); }
HR          <- S* "<" _HR         & ET { tagb(yy,"hr");         } attrs*       S* ">" S*                ("</" _HR         ">" S*)? { endtag(yy); }
ADDRESS     <- S* "<" _ADDRESS    & ET { tagb(yy,"address");    } attrs*       S* ">" S* inline*         "</" _ADDRESS    ">" S*   { endtag(yy); }
H1          <- S* "<" _H1         & ET { tagb(yy,"h1");         } attrs*       S* ">" S* inline*         "</" _H1         ">" S*   { endtag(yy); }
H2          <- S* "<" _H2         & ET { tagb(yy,"h2");         } attrs*       S* ">" S* inline*         "</" _H2         ">" S*   { endtag(yy); }
H3          <- S* "<" _H3         & ET { tagb(yy,"h3");         } attrs*       S* ">" S* inline*         "</" _H3         ">" S*   { endtag(yy); }
H4          <- S* "<" _H4         & ET { tagb(yy,"h4");         } attrs*       S* ">" S* inline*         "</" _H4         ">" S*   { endtag(yy); }
H5          <- S* "<" _H5         & ET { tagb(yy,"h5");         } attrs*       S* ">" S* inline*         "</" _H5         ">" S*   { endtag(yy); }
H6          <- S* "<" _H6         & ET { tagb(yy,"h6");         } attrs*       S* ">" S* inline*         "</" _H6         ">" S*   { endtag(yy); }
DIV         <- S* "<" _DIV        & ET { tagb(yy,"div");        } div_attr*    S* ">" S* flow*           "</" _DIV        ">" S*   { endtag(yy); }
DL          <- S* "<" _DL         & ET { tagb(yy,"dl");         } attrs*       S* ">" S* (DT / DD)+      "</" _DL         ">" S*   { endtag(yy); }
DT          <- S* "<" _DT         & ET { tagb(yy,"dt");         } attrs*       S* ">" S* inline*        ("</" _DT         ">" S*)? { endtag(yy); }
DD          <- S* "<" _DD         & ET { tagb(yy,"dd");         } attrs*       S* ">" S* flow*          ("</" _DD         ">" S*)? { endtag(yy); }
UL          <- S* "<" _UL         & ET { tagb(yy,"ul");         } attrs*       S* ">" S* (LI / Cblock)+  "</" _UL         ">" S*   { endtag(yy); }
OL          <- S* "<" _OL         & ET { tagb(yy,"ol");         } OL_attr*     S* ">" S* (LI / Cblock)+  "</" _OL         ">" S*   { endtag(yy); }
LI          <- S* "<" _LI         & ET { tagb(yy,"li");         } attrs*       S* ">" S* flow*          ("</" _LI         ">" S*)? { endtag(yy); }
NOSCRIPT    <- S* "<" _NOSCRIPT   & ET { tagb(yy,"noscript");   } attrs*       S* ">" S* block+          "</" _NOSCRIPT   ">" S*   { endtag(yy); }
FORM        <- S* "<" _FORM       & ET { tagb(yy,"form");       } FORM_attr*   S* ">" S* FORM_flow*      "</" _FORM       ">" S*   { endtag(yy); }
FIELDSET    <- S* "<" _FIELDSET   & ET { tagb(yy,"fieldset");   } attrs*       S* ">" S* fs_flow*        "</" _FIELDSET   ">" S*   { endtag(yy); }
LEGEND      <- S* "<" _LEGEND     & ET { tagb(yy,"legend");     } legend_attr* S* ">" S* inline*         "</" _LEGEND     ">" S*   { endtag(yy); }
TABLE       <- S* "<" _TABLE      & ET { tagb(yy,"table");      } TABLE_attr*  S* ">" S* TABLE_flow      "</" _TABLE      ">" S*   { endtag(yy); }
CAPTION     <- S* "<" _CAPTION    & ET { tagb(yy,"caption");    } attrs*       S* ">" S* inline*         "</" _CAPTION    ">" S*   { endtag(yy); }
COL         <- S* "<" _COL        & ET { tagb(yy,"col");        } col_attr*    S* ">" S*                ("</" _COL        ">" S*)? { endtag(yy); }
COLGROUP    <- S* "<" _COLGROUP   & ET { tagb(yy,"colgroup");   } col_attr*    S* ">" S* COL*           ("</" _COLGROUP   ">" S*)? { endtag(yy); }
THEAD       <- S* "<" _THEAD      & ET { tagb(yy,"thead");      } tr_attr*     S* ">" S* TR+            ("</" _THEAD      ">" S*)? { endtag(yy); }
TFOOT       <- S* "<" _TFOOT      & ET { tagb(yy,"tfoot");      } tr_attr*     S* ">" S* TR+            ("</" _TFOOT      ">" S*)? { endtag(yy); }
TR          <- S* "<" _TR         & ET { tagb(yy,"tr");         } tr_attr*     S* ">" S* (TH / TD)+     ("</" _TR         ">" S*)? { endtag(yy); }
TH          <- S* "<" _TH         & ET { tagb(yy,"th");         } THD_attr*    S* ">" S* flow*          ("</" _TH         ">" S*)? { endtag(yy); }
TD          <- S* "<" _TD         & ET { tagb(yy,"td");         } THD_attr*    S* ">" S* flow*          ("</" _TD         ">" S*)? { endtag(yy); }
bINS        <- S* "<" _INS        & ET { tagb(yy,"ins");        } INSDEL_attr* S* ">" S* flow*           "</" _INS        ">" S*   { endtag(yy); }
bDEL        <- S* "<" _DEL        & ET { tagb(yy,"del");        } INSDEL_attr* S* ">" S* flow*           "</" _DEL        ">" S*   { endtag(yy); }

        #------------------------------------------------------
        # TBODY opening and closing tag are optional.  Lovely.
        #------------------------------------------------------
        
TBODY       <- (S* "<" _TBODY & ET { tagb(yy,"tbody"); } tr_attr* S* ">" S* / { tagb(yy,"tbody"); })
               TR+
               (S* "</" _TBODY    ">" S*)? { endtag(yy); }
               
PRE         <- S* "<" _PRE & ET { tagb(yy,"pre"); yy->pre = true; } attrs* S* ">"
               ((" " / "\t")* "\r"? "\n")?
               PRE_flow*
               "</" _PRE ">" S* { endtag(yy); yy->pre = false; }
               
bq_flow     <- block / SCRIPT
PRE_flow    <- ! (IMG / OBJECT / BIG / SMALL / SUB / SUP) inline
FORM_flow   <- ! FORM (block / SCRIPT)
fs_flow     <- LEGEND/ flow / PCDATA
TABLE_flow  <- CAPTION? (COL / COLGROUP)* THEAD? TFOOT? TBODY+

# *******************************************
# Attributes
# *******************************************

_defval <- ( S* "=" S* _value / nil)
_value  <- '"' { luaL_buffinit(yy->L,&yy->buf); } (! '"' CHAR)* { luaL_pushresult(&yy->buf); } '"'
        /  "'" { luaL_buffinit(yy->L,&yy->buf); } (! "'" CHAR)* { luaL_pushresult(&yy->buf); } "'"
        /      { luaL_buffinit(yy->L,&yy->buf); } (! S   CHAR)* { luaL_pushresult(&yy->buf); }
        
attrs           <- coreattrs / i18n / events
coreattrs       <- attr_id / attr_class / attr_style / attr_title
i18n            <- attr_lang / attr_dir
events          <- attr_onclick    / attr_ondblclick  / attr_onmousedown
                /  attr_onmouseup  / attr_onmouseover / attr_onmousemove
                /  attr_onmouseout / attr_onkeypress  / attr_onkeydown
                /  attr_onkeyup
                
reserved        <- attr_datasrc / attr_datafld
cellhalign      <- attr_align / attr_char / attr_charoff
cellvalign      <- attr_valign

A_attr          <- attrs
                /  attr_charset  / attr_type   / attr_name     / attr_href
                /  attr_hreflang / attr_rel    / attr_rev      / attr_accesskey
                /  attr_shape    / attr_coords / attr_tabindex / attr_onfocus
                /  attr_onblur
                
IMG_attr        <- attrs
                /  attr_src    / attr_alt   / attr_longdesc / attr_name
                /  attr_height / attr_width / attr_usemap   / attr_ismap
                
BDO_attr        <- coreattrs / attr_lang / attr_dir
Q_attr          <- attrs / attr_cite
MAP_attr        <- attrs / attr_name
INSDEL_attr     <- attrs / attr_cite / attr_datetime

AREA_attr       <- attrs
                /  attr_shape     / attr_coords  / attr_href
                /  attr_nohref    / attr_alt     / attr_tabindex
                /  attr_accesskey / attr_onfocus / attr_onblur
                
FONT_attr       <- coreattrs / i18n
                /  attr_size / attr_color / attr_face
                
PARAM_attr      <-  attr_id / attr_name / attr_value / attr_valuetype
                /   attr_type
                
OBJECT_attr     <- attrs
                /  attr_declare  / attr_classid  / attr_codebase / attr_data
                /  attr_type     / attr_codetype / attr_archive  / attr_standby
                /  attr_height   / attr_width    / attr_usemap   / attr_name
                /  attr_tabindex / reserved
                
SCRIPT_attr     <- events
                /  attr_charset / attr_type / attr_src
                /  attr_defer   / attr_for  / attr_event
                
INPUT_attr      <- attrs
                /  attr_type     / attr_name      / attr_value   / attr_checked
                /  attr_disabled / attr_readonly  / attr_size    / attr_maxlength
                /  attr_src      / attr_alt       / attr_usemap  / attr_ismap
                /  attr_tabindex / attr_accesskey / attr_onfocus / attr_onblur
                /  attr_onselect / attr_onchange  / attr_accept  / reserved
                
SELECT_attr     <- attrs
                /  attr_name     / attr_size    / attr_multiple / attr_disabled
                /  attr_tabindex / attr_onfocus / attr_onblur   / attr_onchange
                /  reserved
                
TEXTAREA_attr   <- attrs
                /  attr_name     / attr_rows     / attr_cols      / attr_disabled
                /  attr_readonly / attr_tabindex / attr_accesskey / attr_onfocus
                /  attr_onblur   / attr_onselect / attr_onchange  / reserved
                
LABEL_attr      <- attrs
                /  attr_for / attr_accesskey / attr_onfocus / attr_onblur
                
BUTTON_attr     <- attrs
                /  attr_name     / attr_value    / attr_type2
                /  attr_disabled / attr_tabindex / attr_accesskey
                /  attr_onfocus  / attr_onblur   / reserved
                
OPTGROUP_attr   <- attrs / attr_disabled / attr_label OPTION_attr <- attrs
                /  attr_selected / attr_disabled / attr_label / attr_value
                
FORM_attr       <- attrs
                /  attr_action / attr_method   / attr_enctype / attr_accept
                /  attr_name   / attr_onsubmit / attr_onreset / attr_accept_charset
                
TABLE_attr      <- attrs
                /  attr_abbr    / attr_axis    / attr_headers / attr_scope
                /  attr_rowspan / attr_colspan / cellhalign   / cellvalign
                /  attr_summary / attr_rules   / attr_frame   / attr_datapagesize
                /  attr_cellspacing / attr_cellpadding / attr_border
                
bq_attr         <- attrs / attr_cite
div_attr        <- attrs / reserved
OL_attr         <- attrs / attr_start / attr_type
legend_attr     <- attrs / attr_accesskey
col_attr        <- attrs / attr_span / attr_width / cellhalign / cellvalign
tr_attr         <- attrs / cellhalign / cellvalign

THD_attr        <- attrs
                /  attr_abbr    / attr_axis    / attr_headers / attr_scope
                /  attr_rowspan / attr_colspan / cellhalign   / cellvalign
                
ET     <- " " / "\t" / "\r" / "\n" / ">" # end tag
EA     <- " " / "\t" / "\r" / "\n" / "=" / ">" # end attribute

EQ      <- S* "=" S*

_vDIR   <- EQ ('"' _LTR '"' / "'" _LTR "'" / _LTR) { lua_pushliteral(yy->L,"ltr"); }
        /  EQ ('"' _RTL '"' / "'" _RTL "'" / _RTL) { lua_pushliteral(yy->L,"rtl"); }
        
_vALIGN <- EQ ('"' _ALIGN   '"' / "'" _ALIGN   "'" / _ALIGN  ) { lua_pushliteral(yy->L,"align");   }
        /  EQ ('"' _LEFT    '"' / "'" _LEFT    "'" / _LEFT   ) { lua_pushliteral(yy->L,"left");    }
        /  EQ ('"' _CENTER  '"' / "'" _CENTER  "'" / _CENTER ) { lua_pushliteral(yy->L,"center");  }
        /  EQ ('"' _RIGHT   '"' / "'" _RIGHT   "'" / _RIGHT  ) { lua_pushliteral(yy->L,"right");   }
        /  EQ ('"' _JUSTIFY '"' / "'" _JUSTIFY "'" / _JUSTIFY) { lua_pushliteral(yy->L,"justify"); }
        /  EQ ('"' _CHAR    '"' / "'" _CHAR    "'" / _CHAR   ) { lua_pushliteral(yy->L,"char");    }
        
_vCHECKED   <- EQ ('"' _CHECKED '"' / "'" _CHECKED "'" / _CHECKED) { lua_pushliteral(yy->L,"checked"); }
            /  { lua_pushliteral(yy->L,"checked"); }
_vDECLARE   <- EQ ('"' _DECLARE '"' / "'" _DECLARE "'" / _DECLARE) { lua_pushliteral(yy->L,"declare"); }
            /  { lua_pushliteral(yy->L,"declare"); }
_vDEFER     <- EQ ('"' _DEFER '"' / "'" _DEFER "'" / _DEFER) { lua_pushliteral(yy->L,"defer"); }
            /  { lua_pushliteral(yy->L,"defer"); }
_vDISABLED  <- EQ ('"' _DISABLED '"' / "'" _DISABLED "'" / _DISABLED) { lua_pushliteral(yy->L,"disabled"); }
            /  { lua_pushliteral(yy->L,"disabled"); }
            
_vFRAME     <- EQ ('"' _VOID   '"' / "'" _VOID   "'" / _VOID  ) { lua_pushliteral(yy->L,"void");   }
            /  EQ ('"' _ABOVE  '"' / "'" _ABOVE  "'" / _ABOVE ) { lua_pushliteral(yy->L,"above");  }
            /  EQ ('"' _BELOW  '"' / "'" _BELOW  "'" / _BELOW ) { lua_pushliteral(yy->L,"below");  }
            /  EQ ('"' _HSIDES '"' / "'" _HSIDES "'" / _HSIDES) { lua_pushliteral(yy->L,"hsides"); }
            /  EQ ('"' _LHS    '"' / "'" _LHS    "'" / _LHS   ) { lua_pushliteral(yy->L,"lhs");    }
            /  EQ ('"' _RHS    '"' / "'" _RHS    "'" / _RHS   ) { lua_pushliteral(yy->L,"rhs");    }
            /  EQ ('"' _VSIDES '"' / "'" _VSIDES "'" / _VSIDES) { lua_pushliteral(yy->L,"vsides"); }
            /  EQ ('"' _BOX    '"' / "'" _BOX    "'" / _BOX   ) { lua_pushliteral(yy->L,"box");    }
            /  EQ ('"' _BORDER '"' / "'" _BORDER "'" / _BORDER) { lua_pushliteral(yy->L,"border"); }
            
_vISMAP     <- EQ ('"' _ISMAP '"' / "'" _ISMAP "'" / _ISMAP) { lua_pushliteral(yy->L,"ismap"); }
            /  { lua_pushliteral(yy->L,"ismap"); }
            
_vMETHOD    <- EQ ('"' _GET  '"' / "'" _GET "'"  / _GET ) { lua_pushliteral(yy->L,"GET");  }
            /  EQ ('"' _POST '"' / "'" _POST "'" / _POST) { lua_pushliteral(yy->L,"POST"); }
            
_vMULTIPLE  <- EQ ('"' _MULTIPLE '"' / "'" _MULTIPLE "'" / _MULTIPLE) { lua_pushliteral(yy->L,"multiple"); }
            /  { lua_pushliteral(yy->L,"multiple"); }
            
_vNOHREF    <- EQ ('"' _NOHREF '"' / "'" _NOHREF "'" / _NOHREF) { lua_pushliteral(yy->L,"nohref"); }
            /  { lua_pushliteral(yy->L,"nohref"); }
            
_vREADONLY  <- EQ ('"' _READONLY '"' / "'" _READONLY "'" / _READONLY) { lua_pushliteral(yy->L,"readonly"); }
            /  { lua_pushliteral(yy->L,"readonly"); }
            
_vRULES     <- EQ ('"' _NONE   '"' / "'" _NONE   "'" / _NONE  ) { lua_pushliteral(yy->L,"none");   }
            /  EQ ('"' _GROUPS '"' / "'" _GROUPS "'" / _GROUPS) { lua_pushliteral(yy->L,"groups"); }
            /  EQ ('"' _ROWS   '"' / "'" _ROWS   "'" / _ROWS  ) { lua_pushliteral(yy->L,"rows");   }
            /  EQ ('"' _COLS   '"' / "'" _COLS   "'" / _COLS  ) { lua_pushliteral(yy->L,"cols");   }
            /  EQ ('"' _ALL    '"' / "'" _ALL    "'" / _ALL   ) { lua_pushliteral(yy->L,"all");    }
            
_vSELECTED  <- EQ ('"' _SELECTED '"' / "'" _SELECTED "'" / _SELECTED) { lua_pushliteral(yy->L,"selected"); }
            /  { lua_pushliteral(yy->L,"selected"); }
            
_vTYPE2     <- EQ ('"' _BUTTON '"' / "'" _BUTTON "'" / _BUTTON) { lua_pushliteral(yy->L,"button"); }
            /  EQ ('"' _SUBMIT '"' / "'" _SUBMIT "'" / _SUBMIT) { lua_pushliteral(yy->L,"submit"); }
            /  EQ ('"' _RESET  '"' / "'" _RESET  "'" / _RESET ) { lua_pushliteral(yy->L,"reset");  }
            
_vVALIGN    <- EQ ('"' _TOP      '"' / "'" _TOP      "'" / _TOP     ) { lua_pushliteral(yy->L,"top");      }
            /  EQ ('"' _MIDDLE   '"' / "'" _MIDDLE   "'" / _MIDDLE  ) { lua_pushliteral(yy->L,"middle");   }
            /  EQ ('"' _BOTTOM   '"' / "'" _BOTTOM   "'" / _BOTTOM  ) { lua_pushliteral(yy->L,"bottom");   }
            /  EQ ('"' _BASELINE '"' / "'" _BASELINE "'" / _BASELINE) { lua_pushliteral(yy->L,"baseline"); }
            
_vVALUETYPE <- EQ ('"' _DATA   '"' / "'" _DATA   "'" / _DATA  ) { lua_pushliteral(yy->L,"DATA");   }
            /  EQ ('"' _REF    '"' / "'" _REF    "'" / _REF   ) { lua_pushliteral(yy->L,"REF");    }
            /  EQ ('"' _OBJECT '"' / "'" _OBJECT "'" / _OBJECT) { lua_pushliteral(yy->L,"OBJECT"); }
            
_vnum       <- EQ '"' < [0-9]+ > '"' { lua_pushinteger(yy->L,strtoul(yytext,NULL,10)); }
            /  EQ "'" < [0-9]+ > "'" { lua_pushinteger(yy->L,strtoul(yytext,NULL,10)); }
            /  EQ       [0-9]+ >     { lua_pushinteger(yy->L,strtoul(yytext,NULL,10)); }
            
attr_abbr               <- S+ _ABBR              & EA _defval     { setfield(yy,"abbr"); }
attr_accept             <- S+ _ACCEPT            & EA _defval     { setfield(yy,"accept"); }
attr_accept_charset     <- S+ _ACCEPT_CHARSET    & EA _defval     { setfield(yy,"accept_charset"); }
attr_accesskey          <- S+ _ACCESSKEY         & EA _defval     { setfield(yy,"accesskey"); }
attr_action             <- S+ _ACTION            & EA _defval     { setfield(yy,"action"); }
attr_align              <- S+ _ALIGN             & EA _vALIGN     { setfield(yy,"align"); }
attr_alt                <- S+ _ALT               & EA _defval     { setfield(yy,"alt"); }
attr_archive            <- S+ _ARCHIVE           & EA _defval     { setfield(yy,"archive"); }
attr_axis               <- S+ _AXIS              & EA _defval     { setfield(yy,"axis"); }
attr_border             <- S+ _BORDER            & EA _defval     { setfield(yy,"border"); }
attr_cellpadding        <- S+ _CELLPADDING       & EA _defval     { setfield(yy,"cellpadding"); }
attr_cellspacing        <- S+ _CELLSPACING       & EA _defval     { setfield(yy,"cellspacing"); }
attr_char               <- S+ _CHAR              & EA _defval     { setfield(yy,"char"); }
attr_charoff            <- S+ _CHAROFF           & EA _defval     { setfield(yy,"charoff"); }
attr_charset            <- S+ _CHARSET           & EA _defval     { setfield(yy,"charset"); }
attr_checked            <- S+ _CHECKED           & EA _vCHECKED   { setfield(yy,"checked"); }
attr_cite               <- S+ _CITE              & EA _defval     { setfield(yy,"cite"); }
attr_class              <- S+ _CLASS             & EA _defval     { setfield(yy,"class"); }
attr_classid            <- S+ _CLASSID           & EA _defval     { setfield(yy,"classid"); }
attr_codebase           <- S+ _CODEBASE          & EA _defval     { setfield(yy,"codebase"); }
attr_codetype           <- S+ _CODETYPE          & EA _defval     { setfield(yy,"codetype"); }
attr_color              <- S+ _COLOR             & EA _defval     { setfield(yy,"color"); }
attr_cols               <- S+ _COLS              & EA _vnum       { setfield(yy,"cols"); }
attr_colspan            <- S+ _COLSPAN           & EA _vnum       { setfield(yy,"colspan"); }
attr_coords             <- S+ _COORDS            & EA _defval     { setfield(yy,"coords"); }
attr_data               <- S+ _DATA              & EA _defval     { setfield(yy,"data"); }
attr_datafld            <- S+ _DATAFLD           & EA _defval     { setfield(yy,"datafld"); }
attr_datapagesize       <- S+ _DATAPAGESIZE      & EA _defval     { setfield(yy,"datapagesize"); }
attr_datasrc            <- S+ _DATASRC           & EA _defval     { setfield(yy,"datasrc"); }
attr_datetime           <- S+ _DATETIME          & EA _defval     { setfield(yy,"datetime"); }
attr_declare            <- S+ _DECLARE           & EA _vDECLARE   { setfield(yy,"declare"); }
attr_defer              <- S+ _DEFER             & EA _vDEFER     { setfield(yy,"defer"); }
attr_dir                <- S+ _DIR               & EA _vDIR       { setfield(yy,"dir"); }
attr_disabled           <- S+ _DISABLED          & EA _vDISABLED  { setfield(yy,"disabled"); }
attr_enctype            <- S+ _ENCTYPE           & EA _defval     { setfield(yy,"enctype"); }
attr_event              <- S+ _EVENT             & EA _defval     { setfield(yy,"event"); }
attr_face               <- S+ _FACE              & EA _defval     { setfield(yy,"face"); }
attr_for                <- S+ _FOR               & EA _defval     { setfield(yy,"for"); }
attr_frame              <- S+ _FRAME             & EA _vFRAME     { setfield(yy,"frame"); }
attr_headers            <- S+ _HEADERS           & EA _defval     { setfield(yy,"headers"); }
attr_height             <- S+ _HEIGHT            & EA _defval     { setfield(yy,"height"); }
attr_href               <- S+ _HREF              & EA _defval     { setfield(yy,"href"); }
attr_hreflang           <- S+ _HREFLANG          & EA _defval     { setfield(yy,"hreflang"); }
attr_id                 <- S+ _ID                & EA _defval     { setfield(yy,"id"); }
attr_ismap              <- S+ _ISMAP             & EA _vISMAP     { setfield(yy,"ismap"); }
attr_label              <- S+ _LABEL             & EA _defval     { setfield(yy,"label"); }
attr_lang               <- S+ _LANG              & EA _defval     { setfield(yy,"lang"); }
attr_longdesc           <- S+ _LONGDESC          & EA _defval     { setfield(yy,"longdesc"); }
attr_maxlength          <- S+ _MAXLENGTH         & EA _vnum       { setfield(yy,"maxlength"); }
attr_method             <- S+ _METHOD            & EA _vMETHOD    { setfield(yy,"method"); }
attr_multiple           <- S+ _MULTIPLE          & EA _vMULTIPLE  { setfield(yy,"multiple"); }
attr_name               <- S+ _NAME              & EA _defval     { setfield(yy,"name"); }
attr_nohref             <- S+ _NOHREF            & EA _vNOHREF    { setfield(yy,"nohref"); }
attr_onblur             <- S+ _ONBLUR            & EA _defval     { setfield(yy,"onblur"); }
attr_onchange           <- S+ _ONCHANGE          & EA _defval     { setfield(yy,"onchange"); }
attr_onclick            <- S+ _ONCLICK           & EA _defval     { setfield(yy,"onclick"); }
attr_ondblclick         <- S+ _ONDBLCLICK        & EA _defval     { setfield(yy,"ondblclick"); }
attr_onfocus            <- S+ _ONFOCUS           & EA _defval     { setfield(yy,"onfocus"); }
attr_onkeydown          <- S+ _ONKEYDOWN         & EA _defval     { setfield(yy,"onkeydown"); }
attr_onkeypress         <- S+ _ONKEYPRESS        & EA _defval     { setfield(yy,"onkeypress"); }
attr_onkeyup            <- S+ _ONKEYUP           & EA _defval     { setfield(yy,"onkeyup"); }
attr_onmousedown        <- S+ _ONMOUSEDOWN       & EA _defval     { setfield(yy,"onmousedown"); }
attr_onmousemove        <- S+ _ONMOUSEMOVE       & EA _defval     { setfield(yy,"onmousemove"); }
attr_onmouseout         <- S+ _ONMOUSEOUT        & EA _defval     { setfield(yy,"onmouseout"); }
attr_onmouseover        <- S+ _ONMOUSEOVER       & EA _defval     { setfield(yy,"onmouseover"); }
attr_onmouseup          <- S+ _ONMOUSEUP         & EA _defval     { setfield(yy,"onmouseup"); }
attr_onreset            <- S+ _ONRESET           & EA _defval     { setfield(yy,"onreset"); }
attr_onselect           <- S+ _ONSELECT          & EA _defval     { setfield(yy,"onselect"); }
attr_onsubmit           <- S+ _ONSUBMIT          & EA _defval     { setfield(yy,"onsubmit"); }
attr_readonly           <- S+ _READONLY          & EA _vREADONLY  { setfield(yy,"readonly"); }
attr_rel                <- S+ _REL               & EA _defval     { setfield(yy,"rel"); }
attr_rev                <- S+ _REV               & EA _defval     { setfield(yy,"rev"); }
attr_rows               <- S+ _ROWS              & EA _vnum       { setfield(yy,"rows"); }
attr_rowspan            <- S+ _ROWSPAN           & EA _vnum       { setfield(yy,"rowspan"); }
attr_rules              <- S+ _RULES             & EA _vRULES     { setfield(yy,"rules"); }
attr_scope              <- S+ _SCOPE             & EA _defval     { setfield(yy,"scope"); }
attr_selected           <- S+ _SELECTED          & EA _vSELECTED  { setfield(yy,"selected"); }
attr_shape              <- S+ _SHAPE             & EA _defval     { setfield(yy,"shape"); }
attr_size               <- S+ _SIZE              & EA _defval     { setfield(yy,"size"); }
attr_span               <- S+ _SPAN              & EA _vnum       { setfield(yy,"span"); }
attr_src                <- S+ _SRC               & EA _defval     { setfield(yy,"src"); }
attr_standby            <- S+ _STANDBY           & EA _defval     { setfield(yy,"standby"); }
attr_start              <- S+ _START             & EA _vnum       { setfield(yy,"start"); }
attr_style              <- S+ _STYLE             & EA _defval     { setfield(yy,"style"); }
attr_summary            <- S+ _SUMMARY           & EA _defval     { setfield(yy,"summary"); }
attr_tabindex           <- S+ _TABINDEX          & EA _vnum       { setfield(yy,"tabindex"); }
attr_title              <- S+ _TITLE             & EA _defval     { setfield(yy,"title"); }
attr_type               <- S+ _TYPE              & EA _defval     { setfield(yy,"type"); }
attr_type2              <- S+ _TYPE2             & EA _vTYPE2     { setfield(yy,"type2"); }
attr_usemap             <- S+ _USEMAP            & EA _defval     { setfield(yy,"usemap"); }
attr_valign             <- S+ _VALIGN            & EA _vVALIGN    { setfield(yy,"valign"); }
attr_value              <- S+ _VALUE             & EA _defval     { setfield(yy,"value"); }
attr_valuetype          <- S+ _VALUETYPE         & EA _vVALUETYPE { setfield(yy,"valuetype"); }
attr_width              <- S+ _WIDTH             & EA _defval     { setfield(yy,"width"); }

# ****************************

_A                 <- `a`
_ABBR              <- `abbr`
_ABOVE             <- `above`
_ACCEPT            <- `accept`
_ACCEPT_CHARSET    <- `accept_charset`
_ACCESSKEY         <- `accesskey`
_ACRONYM           <- `acronym`
_ACTION            <- `action`
_ADDRESS           <- `address`
_ALIGN             <- `align`
_ALL               <- `all`
_ALT               <- `alt`
_ARCHIVE           <- `archive`
_AREA              <- `area`
_AXIS              <- `axis`
_B                 <- `b`
_BASELINE          <- `baseline`
_BDO               <- `bdo`
_BELOW             <- `below`
_BIG               <- `big`
_BLOCKQUOTE        <- `blockquote`
_BORDER            <- `border`
_BOTTOM            <- `bottom`
_BOX               <- `box`
_BR                <- `br`
_BUTTON            <- `button`
_CAPTION           <- `caption`
_CELLPADDING       <- `cellpadding`
_CELLSPACING       <- `cellspacing`
_CENTER            <- `center`
_CHAR              <- `char`
_CHAROFF           <- `charoff`
_CHARSET           <- `charset`
_CHECKED           <- `checked`
_CITE              <- `cite`
_CLASS             <- `class`
_CLASSID           <- `classid`
_CODE              <- `code`
_CODEBASE          <- `codebase`
_CODETYPE          <- `codetype`
_COL               <- `col`
_COLGROUP          <- `colgroup`
_COLOR             <- `color`
_COLS              <- `cols`
_COLSPAN           <- `colspan`
_COORDS            <- `coords`
_DATA              <- `data`
_DATAFLD           <- `datafld`
_DATAPAGESIZE      <- `datapagesize`
_DATASRC           <- `datasrc`
_DATETIME          <- `datetime`
_DD                <- `dd`
_DECLARE           <- `declare`
_DEFER             <- `defer`
_DEL               <- `del`
_DFN               <- `dfn`
_DIR               <- `dir`
_DISABLED          <- `disabled`
_DIV               <- `div`
_DL                <- `dl`
_DT                <- `dt`
_EM                <- `em`
_ENCTYPE           <- `enctype`
_EVENT             <- `event`
_FACE              <- `face`
_FIELDSET          <- `fieldset`
_FONT              <- `font`
_FOR               <- `for`
_FORM              <- `form`
_FRAME             <- `frame`
_GET               <- `get`
_GROUPS            <- `groups`
_H1                <- `h1`
_H2                <- `h2`
_H3                <- `h3`
_H4                <- `h4`
_H5                <- `h5`
_H6                <- `h6`
_HEADERS           <- `headers`
_HEIGHT            <- `height`
_HR                <- `hr`
_HREF              <- `href`
_HREFLANG          <- `hreflang`
_HSIDES            <- `hsides`
_I                 <- `i`
_ID                <- `id`
_IMG               <- `img`
_INPUT             <- `input`
_INS               <- `ins`
_ISMAP             <- `ismap`
_JUSTIFY           <- `justify`
_KBD               <- `kbd`
_LABEL             <- `label`
_LANG              <- `lang`
_LEFT              <- `left`
_LEGEND            <- `legend`
_LHS               <- `lhs`
_LI                <- `li`
_LONGDESC          <- `longdesc`
_LTR               <- `ltr`
_MAP               <- `map`
_MAXLENGTH         <- `maxlength`
_METHOD            <- `method`
_MIDDLE            <- `middle`
_MULTIPLE          <- `multiple`
_NAME              <- `name`
_NOHREF            <- `nohref`
_NONE              <- `none`
_NOSCRIPT          <- `noscript`
_OBJECT            <- `object`
_OL                <- `ol`
_ONBLUR            <- `onblur`
_ONCHANGE          <- `onchange`
_ONCLICK           <- `onclick`
_ONDBLCLICK        <- `ondblclick`
_ONFOCUS           <- `onfocus`
_ONKEYDOWN         <- `onkeydown`
_ONKEYPRESS        <- `onkeypress`
_ONKEYUP           <- `onkeyup`
_ONMOUSEDOWN       <- `onmousedown`
_ONMOUSEMOVE       <- `onmousemove`
_ONMOUSEOUT        <- `onmouseout`
_ONMOUSEOVER       <- `onmouseover`
_ONMOUSEUP         <- `onmouseup`
_ONRESET           <- `onreset`
_ONSELECT          <- `onselect`
_ONSUBMIT          <- `onsubmit`
_OPTGROUP          <- `optgroup`
_OPTION            <- `option`
_P                 <- `p`
_PARAM             <- `param`
_POST              <- `post`
_PRE               <- `pre`
_Q                 <- `q`
_READONLY          <- `readonly`
_REF               <- `ref`
_REL               <- `rel`
_RESET             <- `reset`
_REV               <- `rev`
_RHS               <- `rhs`
_RIGHT             <- `right`
_ROWS              <- `rows`
_ROWSPAN           <- `rowspan`
_RTL               <- `rtl`
_RULES             <- `rules`
_SAMP              <- `samp`
_SCOPE             <- `scope`
_SCRIPT            <- `script`
_SELECT            <- `select`
_SELECTED          <- `selected`
_SHAPE             <- `shape`
_SIZE              <- `size`
_SMALL             <- `small`
_SPAN              <- `span`
_SRC               <- `src`
_STANDBY           <- `standby`
_START             <- `start`
_STRONG            <- `strong`
_STYLE             <- `style`
_SUB               <- `sub`
_SUBMIT            <- `submit`
_SUMMARY           <- `summary`
_SUP               <- `sup`
_TABINDEX          <- `tabindex`
_TABLE             <- `table`
_TBODY             <- `tbody`
_TD                <- `td`
_TEXTAREA          <- `textarea`
_TFOOT             <- `tfoot`
_TH                <- `th`
_THEAD             <- `thead`
_TITLE             <- `title`
_TOP               <- `top`
_TR                <- `tr`
_TT                <- `tt`
_TYPE              <- `type`
_TYPE2             <- `type2`
_U                 <- `u`
_UL                <- `ul`
_USEMAP            <- `usemap`
_VALIGN            <- `valign`
_VALUE             <- `value`
_VALUETYPE         <- `valuetype`
_VAR               <- `var`
_VOID              <- `void`
_VSIDES            <- `vsides`
_WIDTH             <- `width`

# ***********************************
# Misc definitions
# ***********************************

Cinline <-     S* "<!--" ___comment_start ___comment_data* ___comment_stop
Cblock  <-     S* "<!--" ___comment_start ___comment_data* ___comment_stop S*
        
___comment_start <- {
                      lua_createtable(yy->L,0,0);
                      luaL_buffinit(yy->L,&yy->buf);
                    }
___comment_data  <- < ! "-->" . > { luaL_addchar(&yy->buf,*yytext); }
___comment_stop  <- "-->"
                    {
                      luaL_pushresult(&yy->buf);
                      lua_setfield(yy->L,-2,"comment");
                      lua_pushinteger(yy->L,luaL_len(yy->L,-2) + 1);
                      lua_insert(yy->L,-2);
                      lua_settable(yy->L,-3);
                    }
                    
PCDATA  <- {
             luaL_buffinit(yy->L,&yy->buf);
           }
           (! "<" CHAR)+
           {
             luaL_pushresult(&yy->buf);
             lua_pushinteger(yy->L,luaL_len(yy->L,-2) + 1);
             lua_insert(yy->L,-2);
             lua_settable(yy->L,-3);
           }
           
scriptDATA <- {
                luaL_buffinit(yy->L,&yy->buf);
              }
              (!("</" _SCRIPT ">") CHAR)*
              {
                luaL_pushresult(&yy->buf);
                lua_pushinteger(yy->L,luaL_len(yy->L,-2) + 1);
                lua_insert(yy->L,-2);
                lua_settable(yy->L,-3);
              }
              
CHAR    <- "&#x" < HEXDIG+      > ";" { deentifyn(yy,yytext,16); }
        /  "&#X" < HEXDIG+      > ";" { deentifyn(yy,yytext,16); }
        /  "&#"  < DIGIT+       > ";" { deentifyn(yy,yytext,10); }
        /  "&"   < [A-Za-z0-9]+ > ";" { deentify(yy,yytext); }
        /  < S+ > {
                    if (yy->pre)
                      luaL_addlstring(&yy->buf,yytext,yyleng);
                    else
                      luaL_addchar(&yy->buf,' ');
                  } # handle PRE
        / < . >  { luaL_addchar(&yy->buf,*yytext); }
        
DIGIT   <- [0-9]
HEXDIG  <- [0-9A-Fa-f]
nil     <- { lua_pushliteral(yy->L,""); }
S       <- " " / "\t" / "\r" / "\n" &{ linecnt(yy) }