# 'checkit_tiff' is a conformance checker for baseline TIFFs
#
# author: Andreas Romeyke, 2015-2022
# licensed under conditions of libtiff
# (see http://libtiff.maptools.org/misc.html)
#
#
#
# compile grammar with 'peg' by piumarta
#
start           <- ( Line )+ EndOfFile
Line            <- LineType EndOfLine
                 / < [^\r\n]+ > EndOfLine                      {fprintf(stderr, "grammar parser error at line %i (error at '%s')\n", parser_state.lineno-1, yytext); exit(EXIT_FAILURE); }
LineType        <- TagLine
                 / ModeLine
                 / IncludeLine
                 / CommentLine
                 / SpaceLine
CommentLine     <- '#' < ( !EndOfLine .)* >                        { commentline(); }

IncludeLine     <- 'include' OpenBracket < Path > ClosingBracket   { set_include ( yytext ); }

SlashorBackslash           <- '/'
                / '\\'

Path            <- ( Subpath )+

Subpath         <- [A-Z]
                / [a-z]
                / [0-9]
                / '.'
                / '_'
                / '-'
                / SlashorBackslash 
                

ModeLine        <- 'mode' OpenBracket < Mode > ClosingBracket  { unsigned int i = i_pop(); set_mode( i );  }
LogicalOr       <- 'logical_or' LogicalOrOpen LogicalOrList LogicalOrClose

LogicalOrOpen   <- OpenBracket                                 { set_rule_logical_open();}
LogicalOrClose  <- ClosingBracket                              { }

LogicalOrListElement   <- Any                                  { v_push( any ); incr_logical_elements();}
                 / Range                                       { v_push( range); incr_logical_elements();}
                 / Only                                        { v_push( only ); incr_logical_elements();}
                 / Number                                      { v_push( only ); incr_logical_elements();}
                 / NTupel                                      { v_push( ntupel); incr_logical_elements();}
                 / RegEx                                       { v_push( regex ); incr_logical_elements();}
                 / FullAscii                                   { v_push( full_ascii); incr_logical_elements();}
                 / PrintableAscii                              { v_push( printable_ascii ); incr_logical_elements();}
LogicalOrList   <- LogicalOrListElement (Colon LogicalOrListElement)*

Mode            <- 'baseline'                                  { i_push(mode_baseline ); }
                 / 'enable_type_checks'                        { i_push(mode_enable_type_checks); }
                 / 'enable_offset_checks'                      { i_push(mode_enable_offset_checks); }
                 / 'enable_ifd_checks'                         { i_push(mode_enable_ifd_checks); }
                 / 'enable_deep_geotiff_checks'                { i_push(mode_enable_deep_geotiff_checks); }
                 / 'enhanced'                                  #/* TODO: later if all types of TIFF are supported */

TagLine         <- Tag Semicolon Requirements Semicolon Content { rule_addtag_config();  }
                 / Tag Semicolon Requirements Semicolon LogicalOr { set_rule_logical_close(); }
Tag             <- < Number >                                  {
                        unsigned int tag = i_pop();
                        /* rule_tagorder_in_dsl( tag ); */
                        if (tag < 254) set_parse_error("wrong tag (should be >253)", yytext);
                        else if (tag > 65535) set_parse_error("wrong tag (should be <65536)", yytext);
                        else settag( tag );
                }
TagReference    <- < Number >                                  {
                        unsigned int tag = i_pop();
                        if (tag < 254) set_parse_error("wrong tagreference (should be >253)", yytext);
                        else if (tag > 65535) set_parse_error("wrong tagreference (should be <65536)", yytext);
                        else settagref( tag );
                }
Semicolon       <- ';' ( Space )*
Requirements    <- 'mandatory'                                 { set_mandatory(); }
                 / IfDepends                                   { set_ifdepends(); }
                 / OptDepends                                  { set_optdepends(); }
                 / 'optional'                                  { set_optional(); }
IfDepends       <- 'depends' OpenBracket TagReference Dot ValueReference ClosingBracket

OptDepends      <- 'optdepends' OpenBracket TagReference Dot ValueReference ClosingBracket


Content          <- Any                                         { v_push( any ); }
                 / Range                                       { v_push( range); }
                 / Only                                        { v_push( only ); }
                 / NTupel                                      { v_push( ntupel ); reset_valuelist() }
                 / RegEx                                       { v_push( regex ); }
                 / PrintableAscii                              { v_push( printable_ascii ); }
                 / FullAscii                                   { v_push( full_ascii ); }
                 / Datetime                                    { v_push( datetime ); }
                 / Iccprofile                                  { v_push( iccprofile ); }
#                 / SBit                                        { v_push( sbit ); }

Range           <- 'range' OpenBracket Number Colon Number ClosingBracket

Number          <- < '0x' [0-9a-f]+ >                      { i_push(strtoul(yytext, NULL, 16) ); }
                 / '2^' < ( Digit )+ >                         { i_push((unsigned long)2 <<atoul(yytext) ); }
                 / < ( Digit )+ >                              { i_push(atoul(yytext) );}

Colon           <- ',' (Space )*
Dot             <- '.' (Space )*
OpenBracket     <- '('
ClosingBracket     <- ')'

ValueList       <- Value (Colon Value)*
Value           <- Number                                      { incr_values(); }
NTupel          <- 'ntupel' OpenBracket ValueList ClosingBracket {unsigned int v=parser_state.valuelist; i_push(v); reset_valuelist(); }
ValueReference  <- Any                                         { parser_state.any_reference = any_ref; }
                 / Number                                      { parser_state.any_reference = only_ref; i_push(atoul(yytext) );}
                 / RegEx                                       { parser_state.any_reference = regex_ref; }
                 / Range                                       { parser_state.any_reference = range_ref; }
                 / NTupel                                      { parser_state.any_reference = ntupel_ref; }
                 / Only                                        { parser_state.any_reference = only_ref; }
Only            <- 'only' OpenBracket Number ClosingBracket    {  }
#SBit            <- 'sbit'  OpenBracket < Digit > ClosingBracket{  i_push(atoul(yytext) ); }
#                 / 'sbit'  OpenBracket Digit                   { set_parse_error("'sbit' expects a closing bracket", yytext); }
#                 / 'sbit'  OpenBracket                         { set_parse_error("'sbit' expects a digit", yytext); }
#                 / 'sbit'                                      { set_parse_error("'sbit' expects an open bracket", yytext); }
RegEx           <- 'regex' OpenBracket '"' < ( PCRE )* > '"' ClosingBracket { regex_push ( yytext ); }
Datetime        <- 'datetime'
Iccprofile      <- 'iccprofile'
PrintableAscii  <- 'printascii'
FullAscii       <- 'fullascii'
SpaceLine       <- ( Space )*
Space           <- ' ' / '\t'
Any             <- 'any'
Digit           <- [0-9]
EndOfLine       <- [\r\n]                                      {incrlineno();}
EndOfFile       <- !.
PCRE            <- EscapedPCRE
                 / [^"\\]
# FIXME: unescape char in yybuffer
EscapedPCRE     <- '\\' '\\'
                 / '\\' '"'


