# /=====================================================================\ #
# |  LaTeXML::MathGrammar                                         | #
# | LaTeXML's Math Grammar for postprocessing                           | #
# |=====================================================================| #
# | Part of LaTeXML:                                                    | #
# |  Public domain software, produced as part of work done by the       | #
# |  United States Government & not subject to copyright in the US.     | #
# |---------------------------------------------------------------------| #
# | Bruce Miller <bruce.miller@nist.gov>                        #_#     | #
# | http://dlmf.nist.gov/LaTeXML/                              (o o)    | #
# \=========================================================ooo==U==ooo=/ #
# ================================================================================
# LaTeXML's MathGrammar.
# To compile :
#      perl -MParse::RecDescent - MathGrammar LaTeXML::MathGrammar
# ================================================================================
# Startup actions: import the constructors
{ BEGIN{ use LaTeXML::MathParser qw(:constructors); 
#$::RD_TRACE=1;
}}
  
# Rules section
# ========================================
# Naming Conventions:
#   UPPERCASE   : is for terminals, ie. classes of TeX tokens.
#   Initial Cap : for non-terminal rules that can possibly be invoked externally.
#   Initial lowercase : internal rules.
# ========================================
# For internal rules
#   moreFoos[$foo] : Looks for more Foo's w/appropriate punctuation or operators, 
#     whatever is appropriate, and combines it with whatever was passed in as pattern arg.
#   addFoo[$bar]  : Check for a following Foo and add it, as appropriate to the $bar.
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Top Level expressions; Just about anything?
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Start	: Anything /^\Z/			{ $item[1]; }

Anything : Formulae 
	 | OPEN Formulae CLOSE		  { Fence($item[1],$item[2],$item[3]); }
	 | modifierFormula
	 | OPEN modifierFormula CLOSE	  { Fence($item[1],$item[2],$item[3]); }
	 | anyop

# a top level rule for sub and superscripts that can accept all sorts of junk.
Subscript   : Formulae | relop | ADDOP | MULOP
Superscript : Formulae | relop | ADDOP | MULOP | supops

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Formulae  (relations or grouping of expressions or relations)
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# This maze attempts to recognize the various meaningful(?) alternations of
# Expression(s) separated by punctuation, relational operators or metarelational operators
# [Think of     $a=b=c$ vs $a=b, c=d$  vs. $a=b,c,d$  .. ]
# and group them into Formulae (collections of relations), including relations which have
# punctuated collections of Expression(s) on either the LHS or RHS, 
# as well as `MultiRelation' like a = b = c, or simply punctuated collections of Expression(s)
# NOTE: also constraints [parenthesized modifier formulae like (>0)] could be sprinkled throughout.
#  I'm trying to figure out _where_; they probably should `end' a formula in some sense?
#  If I can fit it in here, perhaps addConstraint shouldn't be used on the lower level patterns?
#  BUT, the constraint presumably only applies to the preceding RHS?
# HOWEVER: sometimes such a thing would mean an alternative, or "respectively": Consider $a < 0 (> 0)$!!!

Formulae : Formula moreFormulae[$item[1]]

# moreFormulae[$formula]; Got a Formula, what can follow?
moreFormulae : (PUNCT Formula { [$item[1],$item[2]]; })(s) { NewFormulae($arg[0],map(@$_,@{$item[1]})); }
	     | METARELOP Formula                           { Apply($item[1],$arg[0],$item[2]); }
             |         	                                   { $arg[0]; }

Formula : Expression extendFormula[$item[1]]

# extendFormula[$expression] ; expression might be followed by punct Expression... 
#   or relop Expression... or arrow Expression or nothing.
extendFormula : 
	  punctExpr(s) maybeRHS[$arg[0],map(@$_,@{$item[1]})]
	| relop Expression moreRHS[$arg[0],$item[1],$item[2]]
	| { $arg[0]; }

# maybeRHS[$expr,(punct,$expr)*]; 
#    Could have RELOP Expression (which means the (collected LHS) relation RHS)
#    or done (just collection)
maybeRHS : relop Expression                     { NewFormula(NewCollection(@arg), $item[1], $item[2]); }
	|   	                                { NewCollection(@arg); }
# --- either line could be followed by (>0)
# For the latter, does a,b,c (<0) mean c<0 or all of them are <0 ????

# moreRHS[$expr,$relop,$expr]; Could have more (relop Expression) or (punct Expression)*
moreRHS : PUNCT Expression maybeColRHS[@arg,$item[1],$item[2]]
	| relopExpr(s?)		{ NewFormula($arg[0],$arg[1],$arg[2],map(@$_,@{$item[1]})); }
# --- 1st line could be preceded by (>0) IF it ends up end of formula
# --- 2nd line could be followed by (>0)

# maybeColRHS[$expr,$relop,$expr,(punct, $expr)*];
#    Could be done, get punct (collection) or rel Expression (another formula)
maybeColRHS :
        relop Expression moreRHS[$arg[$#arg],$item[1],$item[2]]
	 { NewFormulae(NewFormula($arg[0],$arg[1],NewCollection(@arg[2..$#arg-2])),$arg[$#arg-1],$item[3]); }
	| PUNCT Expression maybeColRHS[@arg,$item[1],$item[2]]
	| 	     { NewFormula($arg[0],$arg[1],NewCollection(@arg[2..$#arg])); }
# --- 1st line handles it through more RHS ???
# --- 2nd line could be preceded by (>0) if it ends formula
# --- 3rd line could be followed by (>0)


punctExpr : PUNCT Expression			{ [$item[1],$item[2]]; }
relopExpr : relop Expression			{ [$item[1],$item[2]]; }

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# `Modifier' formula, things like $<0$, that might follow another formula or text.
# Empty is a placeholder for the missing thing... (?)

modifierFormula : relopExpr(s) { NewFormula(New('Empty'),map(@{$_},@{$item[1]})); }

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Expressions; sums of terms
# Abstractly, things combined by operators binding tighter than relations
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Expressions : Expression punctExpr(s?)		{ NewCollection($item[1],map(@$_,@{$item[2]})); }

Expression  : SignedTerm moreTerms[[],$item[1]]

# moreTerms[ [($term,$addop)*], $term];  Check for more addop & term's
moreTerms    : ADDOP moreTerms2[$arg[0],$arg[1],$item[1]]
	    | { LeftRec(@{$arg[0]},$arg[1]); }

# moreTerms2[ [($term,$addop)*], $term, $addop]; Check if addop is followed by another term,
#   or if not, it presumably represents a limiting form like "a+" (ie a from above)
moreTerms2   : Term moreTerms[ [@{$arg[0]},$arg[1],$arg[2]],$item[1] ]
	    | { LeftRec(@{$arg[0]},Apply(New('LimitFrom'),$arg[1],$arg[2])); }

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Terms: products of factors
# Abstractly, things combined by operators binding tighter than addition
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

SignedTerm : ADDOP Term				{ Apply($item[1],$item[2]); }
        | Term
Term	: Factor (MULOP(?) Factor { [$item[1]->[0] || InvisibleTimes(), $item[2]]; })(s?)
						{ LeftRec($item[1],map(@$_,@{$item[2]})); }

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Factors: function applications, postfix on atoms, etc.
# Abstractly, things combined by operators binding tighter than multiplication
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Factor	: 
	  preScripted['FUNCTION'] addArgs[$item[1]]
	| preScripted['ATOM_OR_ID'] maybeArgs[$item[1]]
	| preScripted['UNKNOWN'] doubtArgs[$item[1]]
	| NUMBER   addScripts[$item[1]]
	| OPEN factorOpen[$item[1]]
#	| bigop addScripts[$item[1]] Term   { Apply($item[2],$item[3]); }
	| bigop addScripts[$item[1]] addTerm[$item[2]]
	| VERTBAR Expression VERTBAR addScripts[Fence($item[1],$item[2],$item[3])]
#	| OPERATOR addScripts[$item[1]] addOperatorArg[$item[2]]
	| OPERATOR addScripts[$item[1]] nestOperators[$item[2]] addArgs[$item[3]]
        | DIFF addScripts[$item[1]]

ATOM_OR_ID : ATOM | ID

# A restricted sort of Factor for the unparenthesized argument to a function.
# Note f g h => f*g*h, but f g h x => f(g(h(x)))  Seems like what people mean...
# Should there be a special case for trigs?
barearg	: 
	  preScripted['FUNCTION'] APPLYOP(?) requireArgs[$item[1]]
	| preScripted['ATOM_OR_ID'] maybeArgs[$item[1]]
	| preScripted['UNKNOWN'] doubtArgs[$item[1]]
	| NUMBER   addScripts[$item[1]]

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Adding pre|post sub|super scripts to various things.
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

# addScripts[$base] ; adds any following sub/super scripts to $base.
addScripts :
          POSTSUBSCRIPT   addScriptsA[$arg[0],$item[1]]
	| POSTSUPERSCRIPT addScriptsB[$arg[0],$item[1]]
	| POSTFIX addScripts[Apply($item[1],$arg[0])]
	| VERTBAR POSTSUBSCRIPT { Apply(New('AT'),$arg[0],Arg($item[2],0)); }
#        | PRIME  addScripts[Apply($item[1],$arg[0])]
	| { $arg[0]; }

# addScriptsA[$base,$sub]
addScriptsA : POSTSUPERSCRIPT addScripts[NewScripts($arg[0],$arg[1],$item[1])]
	|                     addScripts[NewScripts($arg[0],$arg[1],undef)]
# addScriptsB[$base,$sup]
addScriptsB : POSTSUBSCRIPT   addScripts[NewScripts($arg[0],$item[1],$arg[1])]
	|                     addScripts[NewScripts($arg[0],'',      $arg[1])]

# ================================================================================
# preScripted['RULE']; match a RULE possibly preceded by sub/super prescripts,
#  possibly followed by sub/superscripts

preScripted : FLOATINGSUBSCRIPT   preScriptedA[$arg[0],$item[1]]
        |     FLOATINGSUPERSCRIPT preScriptedB[$arg[0],$item[1]]
        |     <matchrule:$arg[0]> addScripts[$item[1]]
# preScriptedA[rule,$presub]
preScriptedA : FLOATINGSUPERSCRIPT <matchrule:$arg[0]> moreScripts[$item[2],$arg[1],$item[1]]
        |                     <matchrule:$arg[0]> moreScripts[$item[1],$arg[1],''      ]
# preScriptedB[rule,$presup]
preScriptedB : FLOATINGSUBSCRIPT   <matchrule:$arg[0]> moreScripts[$item[2],$item[1],$arg[1]]
        |                     <matchrule:$arg[0]> moreScripts[$item[1],'',      $arg[1]]

# moreScripts[base,presub,presup];
moreScripts : POSTSUBSCRIPT   moreScriptsA[$arg[0],$arg[1],$arg[2],$item[1]]
	|     POSTSUPERSCRIPT moreScriptsB[$arg[0],$arg[1],$arg[2],$item[1]]
        |     { NewScripts($arg[0],'',      '',      $arg[1],$arg[2]); }
# moreScriptsA[base,presub,presup,sub]
moreScriptsA : POSTSUPERSCRIPT addScripts[NewScripts($arg[0],$arg[3],$item[1],$arg[1],$arg[2])]
	|                      addScripts[NewScripts($arg[0],$arg[3],'',      $arg[1],$arg[2])]
# moreScriptsB[base,presub,presup,sup]
moreScriptsB : POSTSUBSCRIPT   addScripts[NewScripts($arg[0],$item[1],$arg[3],$arg[1],$arg[2])]
	|                      addScripts[NewScripts($arg[0],'',      $arg[3],$arg[1],$arg[2])]

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Parenthetical: Things wrapped in OPEN .. CLOSE
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

# ================================================================================
# Factors that begin with OPEN; grouped expressions and objects like sets, intervals, etc.
# factorOpen[$open] : Dealing with various things that start with an open.
factorOpen : ADDOP balancedClose[$arg[0]] addScripts[Fence($arg[0],$item[1],$item[2])] # For (-) !?!?
        # Parenthesized differential op possibly w/scripts
        | bigop addScripts[$item[1]] balancedClose[$arg[0]] 
	  	 addScripts[Fence($arg[0],$item[2],$item[3])] Factor
            { Apply($item[4],$item[5]); }
	# Parenthesized differential op including a pre-factor
	| Factor bigop addScripts[$item[2]] balancedClose[$arg[0]] 
	     addScripts[Fence($arg[0],Apply(InvisibleTimes(),$item[1],$item[3]),$item[4])] Factor
          { Apply($item[5],$item[6]); }
	# read expression too? match subcases.
        | Expression factorOpenExpr[$arg[0],$item[1]]

# factorOpenExpr[$open,$expr];  Try to recognize various things that start this way.
#     Need some extra productions for sets (w/possible middle '|' )and vectors; all n-ary.
factorOpenExpr :
	# 2nd expression; some kind of pair, interval, set, whatever
         (PUNCT Expression { [$item[1],$item[2]]; })(s)  CLOSE
		  addScripts[Fence($arg[0],$arg[1],map(@$_,@{$item[1]}),$item[2])]
        # A conditionalized set
	| MIDDLE Formulae CLOSE 
	  {  ApplyDelimited(New('Set',undef,role=>'FENCED'),
	                    $arg[0], $arg[1], $item[1], $item[2], $item[3]); }
	# parenthesized expression.
	| balancedClose[$arg[0]] addScripts[Fence($arg[0],$arg[1],$item[1])]

# ================================================================================
# Function args, etc.

# maybeArgs[$function] ; Add arguments to an identifier, if made explict.
maybeArgs : APPLYOP requireArgs[$arg[0]]
 	  | OPEN addConstraint[$arg[0],$item[1]]
	  | { $arg[0]; }

# doubtArgs[$unknown]; Check for apparent arguments following an Unknown (unclassified) item.
#    If an explicit APPLYOP follows, it's probably OK, otherwise Warn if there seems to be an arglist.
doubtArgs : APPLYOP requireArgs[$arg[0]]
	  | OPEN forbidArgs[$arg[0],$item[1]]
	  | { $arg[0]; }

# forbidArgs[$unknown,$open]; Got a suspicious pattern: an unknown and open. 
#    If the following seems to be an argument list, warn.
forbidArgs : Expression (PUNCT Expression)(s) balancedClose[$arg[1]] { MaybeFunction($arg[0]); undef; }
	| Term balancedClose[$arg[1]]		{ MaybeFunction($arg[0]); undef; }
	| addConstraint[$arg[0],$arg[1]]

# requireArgs[$function]; Add arguments following a function, failing if it isn't there!
requireArgs : OPEN Expression (argPunct Expression {[$item[1],$item[2]];})(s?) balancedClose[$item[1]]
 	  	  { ApplyDelimited($arg[0],$item[1],$item[2],map(@$_,@{$item[3]}),$item[4]); }
	| barearg				{ Apply($arg[0],$item[1]); }

# addArgs[$function]; Add following arguments to a function, if present.
addArgs : APPLYOP(?) OPEN Expression (argPunct Expression {[$item[1],$item[2]];})(s?) balancedClose[$item[2]]
 	  	  { ApplyDelimited($arg[0],$item[2],$item[3],map(@$_,@{$item[4]}),$item[5]); }
	| APPLYOP(?) barearg				{ Apply($arg[0],$item[2]); }
	| { $arg[0]; }

# addTerm[$bigop]; Add following Term to a bigop, if present.
addTerm : APPLYOP(?) Term				{ Apply($arg[0],$item[2]); }
	| { $arg[0]; }

# Punctuation separating function arguments; things marked MIDDLE could also separate arguments
argPunct : PUNCT | MIDDLE

# ================================================================================
# Function args, etc.

# addOperatorArg[$operator]; Add arguments to an operator, if present.
addOperatorArg :
	  OPERATOR addScripts[$item[1]] addOperatorArg[Apply($arg[0],$item[2])]
	| FUNCTION addScripts[$item[1]] addArgs[Apply($arg[0],$item[2])]
	| OPEN Expression balancedClose[$item[1]] addArgs[ApplyDelimited($arg[0],$item[1],$item[2],$item[3])]
	| { $arg[0]; }

# nestOperators[$operator*]; Nest a possible sequence of operators
nestOperators :
	  OPERATOR addScripts[$item[1]] nestOperators[@arg,$item[2]]
	| FUNCTION addScripts[$item[1]] { recApply(@arg,$item[2]); }
	| OPEN Expression balancedClose[$item[1]] 
               { recApply(@arg[0..$#arg-1],ApplyDelimited($arg[$#arg],$item[1],$item[2],$item[3])); }
	| { recApply(@arg); }

# ================================================================================

# addConstraint[$expr,$open]; An open followed expr, check if it is a `constraint'
#   of the form (>0) or (a>b)
addConstraint :
	  relop Expression balancedClose[$arg[1]]
	    { Apply(New('Annotated'),$arg[0],
 		    Fence($arg[1], Apply($item[1],New('Empty'),$item[2]),$item[3])); }
        | Expression relop Expression moreRHS[$item[1],$item[2],$item[3]] balancedClose[$arg[1]]
            { Apply(New('Annotated'),$arg[0],Fence($arg[1],$item[4],$item[5])); }

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Pseudo-Terminals. 
#  Useful combinations of terminals.
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#anyop   : relop | METARELOP | ARROW | ADDOP | MULOP | BIGOP | LIMITOP | INTOP | DIFFOP
anyop   : relop | METARELOP | ARROW | ADDOP | MULOP 
	| bigop addScripts[$item[1]] 
	| OPERATOR addScripts[$item[1]]

QOp     : relop | ADDOP | MULOP | ATOM		{ $item[1]; }

relop	: RELOP | ARROW

# Check out whether diffop should be treated as bigop or operator
# It depends on the binding 
bigop   : BIGOP | SUMOP | INTOP | LIMITOP | DIFFOP
operator: OPERATOR

supops   : SUPOP(s)				{ New('prime'.scalar(@{$item[1]}),
	   					      join('',map($_->textContent,@{$item[1]}))); }

# Match a CLOSE that `corresponds' to the OPEN
balancedClose : CLOSE { isMatchingClose($arg[0],$item[1]) && $item[1]; }

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Terminals.
#   These correspond to the TeX tokens.
# The Lexer strings are of the form TYPE:NAME:NUMBER where
#    TYPE is the grammatical role, or part of speech,
#    NAME is the specific name (semantic or presentation) of the token 
#    NUMBER is the position of the specific token in the current token sequence.
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ATOM     	: /ATOM:\S*:\d+/            { Lookup($item[1]); }
UNKNOWN		: /UNKNOWN:\S*:\d+/ 	    { Lookup($item[1]); }
ID		: /ID:\S*:\d+/ 		    { Lookup($item[1]); }
PUNCT		: /PUNCT:\S*:\d+/ 	    { Lookup($item[1]); }
APPLYOP		: /APPLYOP:\S*:\d+/ 	    { Lookup($item[1]); }
RELOP		: /RELOP:\S*:\d+/ 	    { Lookup($item[1]); }
METARELOP	: /METARELOP:\S*:\d+/ 	    { Lookup($item[1]); }
ARROW		: /ARROW:\S*:\d+/ 	    { Lookup($item[1]); }
ADDOP		: /ADDOP:\S*:\d+/ 	    { Lookup($item[1]); }
MULOP		: /MULOP:\S*:\d+/ 	    { Lookup($item[1]); }
SUPOP		: /SUPOP:\S*:\d+/ 	    { Lookup($item[1]); }
OPEN		: /OPEN:\S*:\d+/ 	    { Lookup($item[1]); }
CLOSE		: /CLOSE:\S*:\d+/ 	    { Lookup($item[1]); }
MIDDLE		: /MIDDLE:\S*:\d+/ 	    { Lookup($item[1]); }
BIGOP		: /BIGOP:\S*:\d+/ 	    { Lookup($item[1]); }
SUMOP		: /SUMOP:\S*:\d+/ 	    { Lookup($item[1]); }
INTOP		: /INTOP:\S*:\d+/ 	    { Lookup($item[1]); }
LIMITOP		: /LIMITOP:\S*:\d+/ 	    { Lookup($item[1]); }
OPERATOR	: /OPERATOR:\S*:\d+/ 	    { Lookup($item[1]); }
DIFF		: /DIFF:\S*:\d+/ 	    { Lookup($item[1]); }
VERTBAR		: /VERTBAR:\S*:\d+/ 	    { Lookup($item[1]); }
FUNCTION        : /FUNCTION:\S*:\d+/ 	    { Lookup($item[1]); }
NUMBER      	: /NUMBER:\S*:\d+/ 	    { Lookup($item[1]); }
POSTSUPERSCRIPT : /POSTSUPERSCRIPT:\S*:\d+/ { Lookup($item[1]); }
POSTSUBSCRIPT   : /POSTSUBSCRIPT:\S*:\d+/   { Lookup($item[1]); }
FLOATINGSUPERSCRIPT  : /FLOATINGSUPERSCRIPT:\S*:\d+/  { Lookup($item[1]); }
FLOATINGSUBSCRIPT    : /FLOATINGSUBSCRIPT:\S*:\d+/    { Lookup($item[1]); }
POSTFIX		: /POSTFIX:\S*:\d+/ 	    { Lookup($item[1]); }
PRIME		: /PRIME:\S*:\d+/ 	    { Lookup($item[1]); }
DIFFOP		: /DIFFOP:\S*:\d+/ 	    { Lookup($item[1]); }

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
