plugins/org.w3c.css/bin/org/w3c/css/parser/analyzer/CssParser.jj
changeset 476 20536eb3b9ff
parent 475 77edd0cbdfe0
child 477 b616697678bf
equal deleted inserted replaced
475:77edd0cbdfe0 476:20536eb3b9ff
     1 /* -*-java-extended-*-
       
     2  *
       
     3  * (c) COPYRIGHT MIT and INRIA, 1997.
       
     4  * Please first read the full copyright statement in file COPYRIGHT.html
       
     5  *
       
     6  * $Id: CssParser.jj,v 1.69 2009-10-11 09:19:37 ylafon Exp $
       
     7  *
       
     8  */
       
     9 
       
    10 options {
       
    11     IGNORE_CASE  = true;
       
    12     STATIC = false;
       
    13     UNICODE_INPUT = true;
       
    14     /*
       
    15           DEBUG_TOKEN_MANAGER = true; 
       
    16 	  DEBUG_PARSER = true;      
       
    17     */
       
    18 }
       
    19 
       
    20 PARSER_BEGIN(CssParser)
       
    21 
       
    22 package org.w3c.css.parser.analyzer;
       
    23 
       
    24 import java.io.InputStream;
       
    25 import java.io.InputStreamReader;
       
    26 import java.io.UnsupportedEncodingException;
       
    27 import java.util.Vector;
       
    28 import java.util.Enumeration;
       
    29 import java.net.URL;
       
    30 
       
    31 import org.w3c.css.values.CssValue;
       
    32 import org.w3c.css.values.CssExpression;
       
    33 import org.w3c.css.values.CssString;
       
    34 import org.w3c.css.values.CssURL;
       
    35 import org.w3c.css.values.CssLength;
       
    36 import org.w3c.css.values.CssNumber;
       
    37 import org.w3c.css.values.CssColor;
       
    38 import org.w3c.css.values.CssIdent;
       
    39 import org.w3c.css.values.CssPercentage;
       
    40 import org.w3c.css.values.CssFrequency;
       
    41 import org.w3c.css.values.CssTime;
       
    42 import org.w3c.css.values.CssDate;
       
    43 import org.w3c.css.values.CssAngle;
       
    44 import org.w3c.css.values.CssFunction;
       
    45 import org.w3c.css.values.CssUnicodeRange;
       
    46 import org.w3c.css.values.CssResolution;
       
    47 import org.w3c.css.properties.css1.CssProperty;
       
    48 import org.w3c.css.parser.Frame;
       
    49 import org.w3c.css.util.ApplContext;
       
    50 import org.w3c.css.parser.CssError;
       
    51 import org.w3c.css.parser.CssSelectors;
       
    52 import org.w3c.css.parser.CssParseException;
       
    53 import org.w3c.css.parser.AtRule;
       
    54 import org.w3c.css.parser.AtRuleMedia;
       
    55 import org.w3c.css.parser.AtRuleFontFace;
       
    56 import org.w3c.css.parser.AtRulePage;
       
    57 import org.w3c.css.parser.AtRulePreference;
       
    58 import org.w3c.css.parser.AtRulePhoneticAlphabet;
       
    59 import org.w3c.css.properties.svg.AtRuleColorProfile;
       
    60 import org.w3c.css.util.InvalidParamException;
       
    61 import org.w3c.css.util.Util;
       
    62 import org.w3c.css.util.Messages;
       
    63 import org.w3c.css.css.StyleSheetCom;
       
    64 
       
    65 import org.w3c.css.selectors.AdjacentSiblingSelector;
       
    66 import org.w3c.css.selectors.AttributeSelector;
       
    67 import org.w3c.css.selectors.ChildSelector;
       
    68 import org.w3c.css.selectors.ClassSelector;
       
    69 import org.w3c.css.selectors.DescendantSelector;
       
    70 import org.w3c.css.selectors.GeneralSiblingSelector;
       
    71 import org.w3c.css.selectors.IdSelector;
       
    72 import org.w3c.css.selectors.TypeSelector;
       
    73 import org.w3c.css.selectors.UniversalSelector;
       
    74 import org.w3c.css.selectors.attributes.AttributeAny;
       
    75 import org.w3c.css.selectors.attributes.AttributeBegin;
       
    76 import org.w3c.css.selectors.attributes.AttributeExact;
       
    77 import org.w3c.css.selectors.attributes.AttributeOneOf;
       
    78 import org.w3c.css.selectors.attributes.AttributeStart;
       
    79 import org.w3c.css.selectors.attributes.AttributeSubstr;
       
    80 import org.w3c.css.selectors.attributes.AttributeSuffix;
       
    81 
       
    82 /**
       
    83  * A CSS3 parser  
       
    84  *
       
    85  * @author Philippe Le Hegaret and Sijtsche Smeman
       
    86  * @version $Revision: 1.69 $
       
    87  */
       
    88 public abstract class CssParser {
       
    89 
       
    90     private static char hexdigits[] = { '0', '1', '2', '3',
       
    91 					'4', '5', '6', '7', 
       
    92 					'8', '9', 'a', 'b', 
       
    93 					'c', 'd', 'e', 'f' };
       
    94     // the current atRule
       
    95     protected AtRule atRule;
       
    96     protected String mediaDeclaration = "off";
       
    97 
       
    98     /**
       
    99      * The URL of the document
       
   100      */  
       
   101     protected URL url;
       
   102     
       
   103     protected ApplContext ac;
       
   104 
       
   105     protected boolean incompatible_error;
       
   106     
       
   107     /**
       
   108      * The current context recognized by the parser (for errors).
       
   109      */  
       
   110     protected Vector currentContext;
       
   111     
       
   112     /**
       
   113      * The current property recognized by the parser (for errors).
       
   114      */  
       
   115     protected String currentProperty;
       
   116     
       
   117     /**
       
   118      * <code>true</code> if the parser should recognized Aural properties, 
       
   119      * <code>false</code> otherwise.
       
   120      */  
       
   121     protected boolean mode;
       
   122 
       
   123     /**
       
   124      * <code>true</code> if the parser had recognize a rule,
       
   125      * <code>false</code> otherwise.
       
   126      */  
       
   127     protected boolean markRule;
       
   128 
       
   129     private boolean reinited = false;
       
   130     private boolean charsetdeclared = false;
       
   131 
       
   132     static StringBuilder SPACE = new StringBuilder(" ");
       
   133 
       
   134     // to be able to remove a ruleset if the selector is not valid
       
   135     protected boolean validSelector = true;
       
   136 
       
   137     /**
       
   138      * The ac for handling errors and warnings.
       
   139      * 
       
   140      * @param ac the new ac for the parser.
       
   141      */  
       
   142     public final void setApplContext(ApplContext ac) {
       
   143 	this.ac = ac;
       
   144     }
       
   145 
       
   146     /**
       
   147      * Set the attribute atRule
       
   148      *
       
   149      * @param atRule the new value for the attribute
       
   150      */
       
   151     public void setAtRule(AtRule atRule) {
       
   152         this.atRule = atRule;
       
   153     }
       
   154 
       
   155     /**
       
   156      * Set the attribute mediaDeclaration
       
   157      *
       
   158      * @param mediaDeclaration indicator if in a media expression list or not
       
   159      */
       
   160     public void setMediaDeclaration(String mediadeclaration) {
       
   161         this.mediaDeclaration = mediadeclaration;
       
   162     }
       
   163 
       
   164     /**
       
   165      * Returns the attribute mediaDeclaration
       
   166      *
       
   167      * @return the value of the attribute
       
   168      */
       
   169     public String getMediaDeclaration() {
       
   170     	return mediaDeclaration;
       
   171     }
       
   172 
       
   173     /**
       
   174      * Returns the attribute atRule
       
   175      *
       
   176      * @return the value of the attribute
       
   177      */
       
   178     public AtRule getAtRule() {
       
   179         return atRule;
       
   180     }
       
   181 
       
   182     /**
       
   183      * Reinitialized the parser.
       
   184      *
       
   185      * @param stream the stream data to parse.
       
   186      * @param ac  the new ac to use for parsing.
       
   187      */
       
   188     public void ReInitWithAc(InputStream stream, ApplContext ac, 
       
   189 			     String charset)
       
   190     {
       
   191 	InputStream is = /*new  CommentSkipperInputStream(stream);*/stream;
       
   192 	if (charset == null) {
       
   193 	    charset = "iso-8859-1";
       
   194 	}
       
   195 	InputStreamReader isr = null;
       
   196 	try {
       
   197 	    isr = new InputStreamReader(is, charset);
       
   198 	} catch (UnsupportedEncodingException uex) {
       
   199 	    isr = new InputStreamReader(is);
       
   200 	}
       
   201 	// reinit, it can not happen...
       
   202 	// ...in theory ;)
       
   203     	ReInit(isr);
       
   204 	markRule = false;
       
   205 	reinited = true;
       
   206 	setApplContext(ac);
       
   207     }
       
   208   
       
   209     /* utilities for a parser */
       
   210  
       
   211     /**
       
   212      * Call by the import statement.
       
   213      *
       
   214      * @param url  The style sheet where this import statement appears.
       
   215      * @param file the file name in the import
       
   216      */  
       
   217     public abstract void handleImport(URL url, String file, 
       
   218 				      boolean is_url, AtRuleMedia media);
       
   219 
       
   220     /**
       
   221      * Call by the namespace declaration statement.
       
   222      *
       
   223      * @param url  The style sheet where this namespace statement appears.
       
   224      * @param file the file/url name in the namespace declaration
       
   225      */  
       
   226     public abstract void handleNamespaceDeclaration(URL url, String prefix,
       
   227 						    String file, 
       
   228 						    boolean is_url);
       
   229 
       
   230     /**
       
   231      * Call by the at-rule statement.
       
   232      *
       
   233      * @param ident  The ident for this at-rule (for example: 'font-face')
       
   234      * @param string The string associate to this at-rule
       
   235      * @see          org.w3c.css.parser.Analyzer.Couple
       
   236      */  
       
   237     public abstract void handleAtRule(String ident, String string);
       
   238 
       
   239     /* added by Sijtsche Smeman */
       
   240     public abstract void addCharSet(String charset);
       
   241     public abstract void newAtRule(AtRule atRule);
       
   242     public abstract void endOfAtRule();
       
   243     public abstract void setImportant(boolean important);
       
   244     public abstract void setSelectorList(Vector selectors);
       
   245     public abstract void addProperty(Vector properties);
       
   246     public abstract void endOfRule();	
       
   247     public abstract void removeThisRule();
       
   248     public abstract void removeThisAtRule();
       
   249     
       
   250     /**
       
   251      * Assign an expression to a property.  This function create a new property
       
   252      * with <code>property</code> and assign to it the expression with the
       
   253      * importance. Don't forget to set informations too.
       
   254      * <p>
       
   255      * A subclass must provide an implementation of this method. 
       
   256      *
       
   257      * @param  property  the name of the property
       
   258      * @param  values    the expression representation of values
       
   259      * @param  important <code>true</code> if values are important
       
   260      *
       
   261      * @return           <code>null</code>or a property
       
   262      * 
       
   263      * @see              org.w3c.css.css.CssProperty
       
   264      */
       
   265     public abstract CssProperty handleDeclaration(String property, 
       
   266 						  CssExpression values, 
       
   267 						  boolean important) 
       
   268 	throws InvalidParamException;
       
   269 
       
   270     /**
       
   271      * Adds a vector of properties to a selector.
       
   272      * <p>
       
   273      * A subclass must provide an implementation of this method. 
       
   274      *
       
   275      * @param selector     the selector
       
   276      * @param declarations Properties to associate with contexts
       
   277      */  
       
   278     public abstract void handleRule(CssSelectors selector, 
       
   279 				    Vector declarations);
       
   280 
       
   281     /*Added by Sijtsche Smeman */
       
   282 
       
   283     /**
       
   284      * Returns the source file of the style sheet
       
   285      */
       
   286     public final String getSourceFile() {
       
   287 	return getURL().toString();
       
   288     }
       
   289 
       
   290     /**
       
   291      * Returns the current line in the style sheet
       
   292      */
       
   293     public final int getLine() {
       
   294 	//return token.beginLine;
       
   295 	return 0;
       
   296     }
       
   297 
       
   298     /**
       
   299      * Set the URL of the style sheet.
       
   300      *
       
   301      * @param URL The URL for the style sheet
       
   302      */
       
   303     public final void setURL(URL url) {
       
   304 	this.url = url;
       
   305     }
       
   306 
       
   307     public final URL getURL() {
       
   308 	return url;
       
   309     }
       
   310 
       
   311     /**
       
   312      * Return the next selector from the inputstream
       
   313      */    
       
   314     public CssSelectors parseSelector() throws ParseException {
       
   315 	return externalSelector();
       
   316     }
       
   317     
       
   318     /*
       
   319      * Add a value to an expression
       
   320      */
       
   321     private void setValue(CssValue v, CssExpression expr, 
       
   322 			  char operator, Token n, int token) 
       
   323 	throws ParseException {
       
   324 	if (n != null) {
       
   325 	    if (ac.getCssVersion().equals("css1") && 
       
   326 		(n.image).equals("inherit")) {
       
   327 		incompatible_error = true;
       
   328 	    }	
       
   329 	    String val = (operator == ' ') ? n.image : operator+n.image;
       
   330 
       
   331 	    if (n.kind == CssParserConstants.IDENT) {
       
   332 		v.set(convertIdent(val), ac);
       
   333 	    } else if (n.kind == CssParserConstants.STRING) {
       
   334 		v.set(val, ac); 
       
   335 	    } else {
       
   336 		v.set(val, ac); 
       
   337 	    }
       
   338 	}
       
   339 	expr.addValue(v);
       
   340     }
       
   341 
       
   342     /*
       
   343      * Error control
       
   344      */
       
   345     private void addError(Exception e, String skippedText) {
       
   346 	if (Util.onDebug) {
       
   347 	    System.err.println(e.getMessage());
       
   348 	    e.printStackTrace();
       
   349 	}
       
   350 	CssParseException ex = new CssParseException(e);
       
   351 	ex.setSkippedString(skippedText);
       
   352 	ex.setProperty(currentProperty);
       
   353 	ex.setContexts(currentContext);
       
   354 	CssError error = new CssError(getSourceFile(), getLine(), ex);
       
   355 	ac.getFrame().addError(error);
       
   356     }
       
   357     
       
   358     /*
       
   359      * Error control 2
       
   360      */
       
   361     private void addError(Exception e, CssExpression exp) {
       
   362 	if (Util.onDebug) {
       
   363 	    System.err.println(e.getMessage());
       
   364 	    e.printStackTrace();
       
   365 	}
       
   366 	
       
   367 	//	if ((exp != null) && (exp.getCount() != 0)) {
       
   368 	CssParseException ex = new CssParseException(e);
       
   369 	ex.setExp(exp);
       
   370 	ex.setProperty(currentProperty);
       
   371 	ex.setContexts(currentContext);
       
   372 	CssError error = new CssError(getSourceFile(), getLine(), ex);
       
   373 	ac.getFrame().addError(error);
       
   374 	//	}
       
   375     }
       
   376 }
       
   377 
       
   378 PARSER_END(CssParser)
       
   379 
       
   380 /*
       
   381  * The tokenizer 
       
   382  */
       
   383 
       
   384 <DEFAULT>
       
   385 SPECIAL_TOKEN :
       
   386 {
       
   387     < COMMENT : "/*" ( ~["*"] )* ( "*" )+ ( ~["/", "*"] ( ~["*"] )* ( "*" )+ )* "/" >
       
   388 } 
       
   389 
       
   390 <DEFAULT>
       
   391     TOKEN [IGNORE_CASE] : /* basic tokens */
       
   392 { 
       
   393     < #H          : ["0"-"9", "a"-"f"] > 
       
   394   | < #NONASCII   : ["\200"-"\377"] >
       
   395   | < #UNICODE    : "\\" <H> ( <H> )? ( <H> )? ( <H> )? ( <H> )? ( <H> )? 
       
   396 	            ( "\r\n" | [ " ", "\t" , "\n" , "\r", "\f" ] )? >
       
   397   | < #ESCAPE     : <UNICODE> | ( "\\" ~[ "\r", "\n", "\f", "0"-"9", "a"-"f" ] ) >
       
   398   | < #NMSTART    : [ "a"-"z", "_" ] | <NONASCII> | <ESCAPE> >
       
   399   | < #NMCHAR     : ["a"-"z", "0"-"9", "-", "_"] | <NONASCII> | <ESCAPE> >
       
   400   | < #STRING1    : "\"" ( ~[ "\n", "\r", "\f", "\\", "\"" ] | "\\" <NL> | <ESCAPE> )* "\"" >
       
   401   | < #STRING2	  : "\'" ( ~[ "\n", "\r", "\f", "\\", "\'" ] | "\\" <NL> | <ESCAPE> )* "\'" >
       
   402   | < #INVALID1   : "\"" ( ~[ "\n", "\r", "\f", "\\", "\"" ] | "\\" <NL> | <ESCAPE> )* >
       
   403   | < #INVALID2	  : "\'" ( ~[ "\n", "\r", "\f", "\\", "\'" ] | "\\" <NL> | <ESCAPE> )* >  
       
   404   | < #_IDENT     : ( <MINUS> )? <NMSTART> ( <NMCHAR> )* >
       
   405   | < #NAME       : ( <NMCHAR> )+ >
       
   406   | < #NUM        : ( ["0"-"9"] )+ | ( ["0"-"9"] )* "." ( ["0"-"9"] )+ >
       
   407   | < #_STRING    : <STRING1> | <STRING2> >
       
   408   | < #_INVALID   : <INVALID1> | <INVALID2> >
       
   409   | < #_URL       : ( [ "!", "#", "$", "%", "&", "*"-"[", "]"-"~" ] | <NONASCII> | <ESCAPE> )* >
       
   410   | < #_S         : ( [ " ", "\t" , "\n" , "\r", "\f" ] ) ( <COMMENT> | [ " ", "\t" , "\n" , "\r", "\f" ] )*  >
       
   411   | < #_W         : ( <_S> )? >
       
   412   | < #NL         : ( "\n" | "\r\n" | "\r" | "\f" ) >
       
   413 }
       
   414 /*
       
   415  * The _S definition is not  ( [ " ", "\t" , "\n" , "\r", "\f" ] ) + as we need to add support
       
   416  * for the unput(' ') (see http://www.w3.org/TR/CSS21/grammar.html#scanner )
       
   417  */
       
   418 
       
   419 <DEFAULT>
       
   420 TOKEN :
       
   421 {
       
   422   < S : ( <_S> ) >
       
   423 }
       
   424 
       
   425 <DEFAULT>
       
   426     TOKEN :
       
   427 {
       
   428     < CDO : "<!--" >
       
   429   | < CDC : "-->" >
       
   430   | < INCLUDES  : <TILDE> "=" >
       
   431   | < DASHMATCH : "|=" >
       
   432 }
       
   433 
       
   434 <DEFAULT>
       
   435 TOKEN :
       
   436 {
       
   437   < LBRACE : <_W> "{" >
       
   438   | < PLUS      : <_W>  "+" >
       
   439   | < GREATER   : <_W> ">" >
       
   440   | < COMMA     : <_W> "," >
       
   441   | < TILDE     : <_W> "~" >
       
   442 }
       
   443 
       
   444 <DEFAULT>
       
   445 TOKEN [IGNORE_CASE] :
       
   446 {
       
   447     < AND : "and" > 
       
   448 }  
       
   449 
       
   450 <DEFAULT>
       
   451 TOKEN :
       
   452 {
       
   453     <STRING    : <_STRING> >
       
   454   | <INVALID   : <_INVALID> >
       
   455   | <IDENT     : <_IDENT> >
       
   456   | <HASHIDENT : "#" <_IDENT> >
       
   457   | <HASH      : "#" <NAME> >
       
   458 }
       
   459 
       
   460 <DEFAULT>
       
   461 TOKEN :
       
   462 {
       
   463   < RBRACE : "}">
       
   464   | < PREFIXMATCH : "^=" >
       
   465   | < SUFFIXMATCH : "$=" >
       
   466   | < SUBSTRINGMATCH : "*=" >
       
   467   | < EQ        : "=" >
       
   468   | < MINUS     : "-" >
       
   469   | < SEMICOLON : ";" >
       
   470   | < DIV       : "/" >
       
   471   | < LBRACKET  : "[" >
       
   472   | < RBRACKET  : "]" >
       
   473   | < ANY       : "*" >
       
   474   | < DOT       : "." >
       
   475   | < LPARAN    : ")" >
       
   476   | < RPARAN    : "(">
       
   477 }
       
   478 
       
   479 <DEFAULT>
       
   480     TOKEN :
       
   481 {
       
   482     < COLON     : ":" >
       
   483 }
       
   484 
       
   485 <DEFAULT>
       
   486 TOKEN [IGNORE_CASE] :
       
   487 {
       
   488     < MEDIARESTRICTOR : "only" | "not" >
       
   489 }
       
   490 
       
   491 <DEFAULT>
       
   492 TOKEN [IGNORE_CASE] :
       
   493 {
       
   494   < URL         : "url(" ( <S> )* ( <STRING> | <_URL>  ) ( <S> )* ")" >
       
   495 }
       
   496 
       
   497 <DEFAULT>
       
   498 TOKEN [IGNORE_CASE] :
       
   499 {
       
   500   < LENGTH     : <NUM> "pt" 
       
   501                    | <NUM> "mm" 
       
   502 	           | <NUM> "cm" 
       
   503 	           | <NUM> "pc" 
       
   504 	           | <NUM> "in"
       
   505 	           | <NUM> "gd" 
       
   506 	           | <NUM> "px" >
       
   507   | < EMS        : <NUM> "em" >
       
   508   | < EXS        : <NUM> "ex" >
       
   509   | < ANGLE      : <NUM> ( "deg" | "grad" | "rad" ) >
       
   510   | < TIME       : <NUM> ( "ms" | "s" ) >
       
   511   | < FREQ       : <NUM> "Hz" | <NUM> "kHz" >
       
   512   | < RESOLUTION : <NUM> "dpi" | <NUM> "dpcm" >
       
   513   | < DATE       : <NUM> "/" <NUM> "/" <NUM> >
       
   514   | < DIMEN      : <NUM> <NMSTART> ( <NMCHAR> )* >
       
   515   | < PERCENTAGE : <NUM> "%" >
       
   516   | < NUMBER     : <NUM> >
       
   517 }
       
   518 
       
   519 <DEFAULT>
       
   520 TOKEN [IGNORE_CASE] :
       
   521 {  
       
   522     < IMPORTANT_SYM : "!" ( <_W> )* "important" >
       
   523 }
       
   524 
       
   525 <DEFAULT>
       
   526 TOKEN :
       
   527 {
       
   528     <PSEUDOELEMENT_SYM : "::" >
       
   529 }
       
   530 
       
   531 /* RESERVED ATRULE WORDS */
       
   532 <DEFAULT>
       
   533 TOKEN : 
       
   534 {
       
   535    < CHARSET_SYM           : "@charset" >
       
   536 }
       
   537 
       
   538 <DEFAULT>
       
   539 TOKEN [IGNORE_CASE] :
       
   540 { 
       
   541     < IMPORT_SYM            : "@import">
       
   542   | < NAMESPACE_SYM         : "@namespace">
       
   543   | < MEDIA_SYM             : "@media" >
       
   544   | < PAGE_SYM              : "@page"  >
       
   545   | < FONT_FACE_SYM         : "@font-face" >
       
   546   | < PREF_SYM              : "@preference" >
       
   547   | < COLOR_PROFILE         : "@color-profile" >
       
   548   | < ATTOP	            : "@top" >
       
   549   | < ATRIGHT               : "@right" >
       
   550   | < ATBOTTOM              : "@bottom" >
       
   551   | < ATLEFT                : "@left" >
       
   552   | < ATCOUNTER             : "@counter" >
       
   553   | < PHONETIC_ALPHABET_SYM : "@phonetic-alphabet" >
       
   554   | < ATKEYWORD             : "@" <IDENT> >
       
   555 }
       
   556 
       
   557 <DEFAULT>
       
   558 TOKEN [IGNORE_CASE] :
       
   559 {
       
   560     < #RANGE0 : <H> <H> <H> <H> <H> <H> > 
       
   561   | < #RANGE1 : <H> <H> <H> <H> <H> ( "?" )? >
       
   562   | < #RANGE2 : <H> <H> <H> <H> ( "?" )? ( "?" )? >
       
   563   | < #RANGE3 : <H> <H> <H> ( "?" )? ( "?" )? ( "?" )? >
       
   564   | < #RANGE4 : <H> <H> ( "?" )? ( "?" )? ( "?" )? ( "?" )? >
       
   565   | < #RANGE5 : <H> ( "?" )? ( "?" )? ( "?" )? ( "?" )? ( "?" )? >
       
   566   | < #RANGE6 : "?" ( "?" )? ( "?" )? ( "?" )? ( "?" )? ( "?" )? >
       
   567   | < #RANGE  : <RANGE0> | <RANGE1> | <RANGE2> 
       
   568                 | <RANGE3> | <RANGE4> | <RANGE5> | <RANGE6> >
       
   569   | < #UNI    : <H> ( <H> )? ( <H> )? ( <H> )? ( <H> )? ( <H> )? >
       
   570   | < UNICODERANGE : "U+" <RANGE> | "U+" <UNI> "-" <UNI> >
       
   571 }
       
   572 
       
   573 <DEFAULT>
       
   574     TOKEN:
       
   575 {
       
   576     < CLASS : "." <IDENT> >
       
   577 }
       
   578 
       
   579 /* FIXED, added a spacial case for lang pseudoclass */
       
   580 <DEFAULT>
       
   581 TOKEN [IGNORE_CASE] :
       
   582 {
       
   583     < FUNCTIONLANG : "lang(" >
       
   584 }
       
   585 
       
   586 <DEFAULT>
       
   587 TOKEN [IGNORE_CASE] :
       
   588 {
       
   589     < FUNCTIONNOT : ":not(" >
       
   590 }
       
   591 
       
   592 
       
   593 <DEFAULT>
       
   594     TOKEN :
       
   595 {
       
   596     < FUNCTION : <IDENT> "(" >
       
   597 }
       
   598 
       
   599 /* Quick and dirty way to catch HTML tags starting CSS documents 
       
   600   (common mistake) */
       
   601 <DEFAULT>
       
   602     TOKEN:
       
   603 {
       
   604     <HTMLSTARTTAG : "<" ( <S> )* <IDENT> ( <S> )* 
       
   605 	                ( <IDENT> "=" ( <IDENT> | <STRING> ) ( <S> )* )* 
       
   606 	            ">" >
       
   607   | <HTMLENDTAG : "</" ( <S> )* <IDENT> ( <S> )* ">" >
       
   608 }
       
   609 
       
   610 //<DEFAULT, IN_COMMENT>
       
   611 //TOKEN :
       
   612 //{ /* avoid token manager error */
       
   613 //   < UNKNOWN : ~[] >
       
   614 //}
       
   615 
       
   616 /*
       
   617  * The grammar of CSS2
       
   618  */
       
   619 
       
   620 /**
       
   621  * The main entry for the parser.
       
   622  *
       
   623  * @exception ParseException exception during the parse
       
   624  */
       
   625 void parserUnit() :
       
   626 {
       
   627     Token n = null;
       
   628 }
       
   629 {
       
   630     try {
       
   631 	// used as an error recovery for HTML tags in CSS pages
       
   632         ( ( n=<HTMLSTARTTAG> | n=<HTMLENDTAG> ) {
       
   633 	    addError (
       
   634 new ParseException(ac.getMsg().getString("generator.dontmixhtml")), n.image); 
       
   635 	}
       
   636 	    )*
       
   637 	  ( charset() )* // * instead of ? to capture the reinit part
       
   638 	    ( <S> | <CDO> | <CDC> )*
       
   639 	    ( importDeclaration() ( ignoreStatement() ) )*
       
   640 	    ( namespaceDeclaration() ( ignoreStatement() ) )*
       
   641 	    afterImportDeclaration()
       
   642 	    <EOF>
       
   643 	 } catch (TokenMgrError err) {
       
   644    addError (new ParseException(ac.getMsg().getString("generator.unrecognize")),
       
   645 	     err.getMessage());
       
   646     }
       
   647 }
       
   648 
       
   649 void charset() :
       
   650 {
       
   651     Token n = null;
       
   652     Token charsetToken = null;
       
   653     Token space1Token = null;
       
   654     Token space2Token = null;
       
   655     Token semicolonToken = null;
       
   656     int nb_S = 0;
       
   657 }
       
   658 {  
       
   659     try {
       
   660 	charsetToken=<CHARSET_SYM> ( space1Token=<S> { nb_S++;} )* 
       
   661 	    n=<STRING> ( space2Token=<S> )* semicolonToken=<SEMICOLON>
       
   662 	    {
       
   663 		if (charsetdeclared && !reinited) {
       
   664 		    throw new ParseException(
       
   665 				     ac.getMsg().getString("parser.charset"));
       
   666 		}
       
   667 		// the @charset must be at the beginning of the document
       
   668 		if(charsetToken.beginLine != 1 || 
       
   669 		   charsetToken.beginColumn != 1) {
       
   670 		    throw new ParseException(
       
   671 				  ac.getMsg().getString("parser.charset"));
       
   672 		}
       
   673 		if ("css1".equals(ac.getCssVersion())) {
       
   674 		    throw new ParseException(ac.getMsg().getString(
       
   675 							 "parser.charsetcss1"));
       
   676 		}
       
   677 	        // stricter rule for CSS21 and soon for CSS3
       
   678 		if ("css21".equals(ac.getCssVersion())) {
       
   679 		    // single space before
       
   680 		    // case sensitive
       
   681 		    // no space before ;
       
   682 		    // no comments
       
   683 		    // string must start with "
       
   684 		    if ( (nb_S != 1) ||
       
   685 			 (!"@charset".equals(charsetToken.image)) ||
       
   686 			 (!" ".equals(space1Token.image)) || 
       
   687 			 (space2Token != null && 
       
   688 			  !"".equals(space2Token.image)) ||
       
   689 			 (space1Token.specialToken != null) ||
       
   690 			 (n.specialToken != null) ||
       
   691 			 (semicolonToken.specialToken != null) ||
       
   692 			 (n.image.charAt(0) != '\"')
       
   693 			) {
       
   694 			throw new ParseException(ac.getMsg().getString(
       
   695 						     "parser.charsetspecial"));
       
   696 		    }
       
   697 		}
       
   698 		if (!charsetdeclared) {
       
   699 		    addCharSet(n.image.substring(1, n.image.length()-1));
       
   700 		    charsetdeclared = true;
       
   701 		} else {
       
   702 		    reinited = false;
       
   703 		}
       
   704 	    }
       
   705     } catch (Exception e) {
       
   706 	String skip = charsetToken +
       
   707 	    ((space1Token == null) ? "" : space1Token.image) +
       
   708 	    n +
       
   709 	    ((space2Token == null) ? "" : space2Token.image) +
       
   710 	    ";";
       
   711         addError(e, skip); 
       
   712     }
       
   713 }
       
   714 
       
   715 void afterImportDeclaration() :
       
   716 {String ret; }
       
   717 {
       
   718     ( ( ruleSet() | media() | page() | fontFace() | preference() | 
       
   719 	colorprofile() | phoneticAlphabet() | ret=skipStatement() 
       
   720 	{ if ((ret == null) || (ret.length() == 0)) {
       
   721 		return; 
       
   722 	    }
       
   723 	  // quite ugly but necessary to avoid probably a lot of changes in the
       
   724 	  // grammar, still having a beautiful error message
       
   725 	    else if (ret.startsWith("@charset")) {
       
   726 		ParseException e = 
       
   727 		new ParseException(ac.getMsg().getString("parser.charset"));
       
   728 		addError(e, ret);
       
   729 	    } else if (ret.startsWith("@import")) {
       
   730 		ParseException e = 
       
   731 		new ParseException(ac.getMsg().getString("parser.import_not_allowed"));
       
   732 		addError(e, ret);
       
   733 	    } else {
       
   734 		ParseException e = 
       
   735 	     new ParseException(ac.getMsg().getString("generator.unrecognize"));
       
   736 		addError(e, ret);
       
   737 	    }
       
   738 	}
       
   739 	) ignoreStatement() )*
       
   740 }
       
   741 
       
   742 void ignoreStatement() :
       
   743 {}
       
   744 {
       
   745     ( ( <CDO> | <CDC> | atRuleDeclaration() ) ( <S> )* )*
       
   746 }
       
   747 
       
   748 void namespaceDeclaration() :
       
   749 {
       
   750     Token n=null;
       
   751     Token v=null;
       
   752     boolean is_url; /* for formatting */
       
   753     String nsname;
       
   754     String prefix = null;
       
   755     CssValue val;
       
   756 }
       
   757 {
       
   758     // FIXME add namespaces in context to match when a definition happens
       
   759     ( <NAMESPACE_SYM> 
       
   760       ( <S> )* 
       
   761       ( n=<IDENT> {
       
   762 	  prefix = convertIdent(n.image);
       
   763       } 
       
   764 	  ( <S> )* )?
       
   765       ( v=<STRING> { 
       
   766 	      is_url = false;
       
   767 	      nsname = v.image.substring(1, v.image.length()-1);
       
   768 	  } 
       
   769 	  | v=<URL> {
       
   770 	      is_url = true;
       
   771 	      val = new CssURL(); 
       
   772 	      ((CssURL) val).set(v.image, ac, url);
       
   773 	      nsname = (String) val.get();
       
   774 	      if ((nsname.charAt(0) == '"')
       
   775 		  || (nsname.charAt(0) == '\'')) {
       
   776 		  nsname = nsname.substring(1, nsname.length()-1);
       
   777 	      }
       
   778 	  }
       
   779       ) 
       
   780       ( <S> )*
       
   781       <SEMICOLON> 
       
   782       ( <S> )*
       
   783       ) {
       
   784 	if (!ac.getCssVersion().equals("css3")) {
       
   785 	    addError(new InvalidParamException("at-rule", "@namespace", ac),
       
   786 		     (n==null)?"default":n.toString());
       
   787 	} else {
       
   788 	    if (v != null) {
       
   789 		handleNamespaceDeclaration(getURL(), prefix, nsname, is_url);
       
   790 	    }
       
   791 	}
       
   792     }
       
   793 }
       
   794 /**
       
   795  * The import statement
       
   796  *
       
   797  * @exception ParseException exception during the parse
       
   798  */
       
   799 void importDeclaration() :
       
   800 {Token n;
       
   801     AtRuleMedia media = new AtRuleMedia();
       
   802     CssValue val; 
       
   803     String importFile;
       
   804     boolean is_url = false;
       
   805 }
       
   806 {
       
   807     try {
       
   808 	<IMPORT_SYM> ( <S> )*
       
   809 	    ( n=<STRING> {
       
   810 		importFile = n.image.substring(1, n.image.length() -1);
       
   811 		is_url = false;
       
   812 	    } 
       
   813 	      | n=<URL> {
       
   814 		val = new CssURL(); 
       
   815 		((CssURL) val).set(n.image, ac, url);
       
   816 		importFile = (String) val.get();
       
   817 		if ((importFile.charAt(0) == '"')
       
   818 		    || (importFile.charAt(0) == '\'')) {
       
   819 		    importFile = importFile.substring(1, importFile.length()-1);
       
   820 		}
       
   821 		is_url = true;
       
   822 	    } 
       
   823 	    )
       
   824 	    ( <S> )*
       
   825 	    ( medium(media) 
       
   826 	      ( <COMMA> ( <S> )* medium(media) 
       
   827 		)* )? <SEMICOLON> 
       
   828 	    ( <S> )*
       
   829 	    { 
       
   830 		handleImport(getURL(), importFile, is_url, media);
       
   831 	    } 
       
   832     } catch (ParseException e) {
       
   833 	addError(e, skipStatement()); 
       
   834     }
       
   835 }
       
   836 
       
   837 /**
       
   838  * @exception ParseException exception during the parse
       
   839  */
       
   840 void media() :
       
   841 {
       
   842     AtRule old = getAtRule();
       
   843     AtRuleMedia newRule = new AtRuleMedia();
       
   844     setAtRule(newRule);
       
   845     Token n;
       
   846     CssProperty p = null;
       
   847 }
       
   848 {
       
   849     try {
       
   850 	<MEDIA_SYM> ( <S> )*
       
   851             // <CSS3>
       
   852 	    (n=<MEDIARESTRICTOR> { newRule.addMediaRestrictor(convertIdent(n.image), ac); } ( <S> )+)? 
       
   853 	    medium(newRule) 
       
   854             // </CSS3>
       
   855 	    ( <COMMA> ( <S> )* medium(newRule) )* 
       
   856             // <CSS3>
       
   857 	    (<AND> ( <S> )* <RPARAN> ( <S> )* p=mediadeclaration() { newRule.addMediaFeature(p); } <LPARAN> ( <S> )* )*
       
   858             // </CSS3>
       
   859    
       
   860 	    {
       
   861 		String media = getAtRule().toString();
       
   862 		if (ac.getMedium() != null && 
       
   863 		    !(media.equals(ac.getMedium())) &&
       
   864 		    !(ac.getMedium().equals("all"))) {
       
   865 		 
       
   866 		    ac.getFrame().addWarning("noothermedium", 
       
   867 					     getAtRule().toString());
       
   868 		}
       
   869 		if (ac.getCssVersion().equals("css1")) {
       
   870 		    skipStatement();
       
   871 		    addError(new InvalidParamException("noatruleyet", "", ac),
       
   872 			     getAtRule().toString());
       
   873 		}
       
   874 		if (!ac.getCssVersion().equals("css1")) {
       
   875 		    newAtRule(getAtRule());	
       
   876 		}
       
   877 	    }
       
   878 	<LBRACE> ( <S> )* ( ruleSet() )* <RBRACE> ( <S> )*
       
   879 	     {
       
   880 		 if (!ac.getCssVersion().equals("css1")) {
       
   881 		     endOfAtRule();
       
   882 		 }
       
   883 	     }
       
   884     } catch (ParseException e) {
       
   885 	if (!ac.getCssVersion().equals("css1")) {
       
   886 	    addError(e, skipStatement()); 
       
   887 	}
       
   888     } finally {
       
   889 	setAtRule(old);
       
   890     }
       
   891 }
       
   892 
       
   893 /**
       
   894  * @exception ParseException exception during the parse
       
   895  */
       
   896 void medium(AtRuleMedia media) : /* tv, projection, screen, ... */
       
   897 {Token n;}
       
   898 {
       
   899     n=<IDENT> ( <S> )*
       
   900     {
       
   901 	try {
       
   902 	    media.addMedia(convertIdent(n.image), ac); 
       
   903 	} catch (InvalidParamException e) {
       
   904 	    CssError error = new CssError(getSourceFile(), getLine(), e);
       
   905 	    ac.getFrame().addError(error);	
       
   906 	}
       
   907     }
       
   908 }
       
   909 
       
   910 /**
       
   911  * @exception ParseException exception during the parse
       
   912  */
       
   913 void page() :
       
   914 {
       
   915     Vector       v                              ;
       
   916     Token        n        = null                ;
       
   917     Vector       collectv = new Vector()        ;
       
   918     CssSelectors s        = new CssSelectors(ac);
       
   919     AtRule       old      = getAtRule()         ;
       
   920     AtRulePage   newRule  = new AtRulePage()    ;
       
   921     setAtRule(newRule);
       
   922     s.setAtRule(getAtRule());
       
   923 }
       
   924 {
       
   925     try {
       
   926 	<PAGE_SYM> ( <S> )*
       
   927             // FIXME <CSS3> ?
       
   928             ( n=<IDENT> { newRule.setIdent(convertIdent(n.image)); } 
       
   929 	      ( <S> )* )?
       
   930             // </CSS3>
       
   931 	    ( pseudo_page(newRule) )? <LBRACE> ( <S> )* ( v=pageContent() 
       
   932 		{ 
       
   933 		    collectv = v;
       
   934 		}
       
   935 							  ) <RBRACE> ( <S> )*
       
   936 	    {
       
   937 		if (!ac.getCssVersion().equals("css1")) {
       
   938 		    newAtRule(getAtRule());
       
   939 		}
       
   940 
       
   941 		if (!ac.getCssVersion().equals("css1")) {
       
   942 		    addProperty(collectv);
       
   943 		    endOfRule();
       
   944 		    endOfAtRule();
       
   945 		}
       
   946 		if (v == null) {
       
   947 		    ac.getFrame().addWarning("no-declaration");
       
   948 		} else {
       
   949 		    handleRule(s, collectv);
       
   950 		}
       
   951 	    }
       
   952     } catch (InvalidParamException ie) {
       
   953 	if (!ac.getCssVersion().equals("css1")) {
       
   954 	    skipStatement();
       
   955 	    removeThisAtRule();
       
   956 	    ac.getFrame().addError(new CssError(ie));
       
   957 	}
       
   958     } catch (ParseException e) {
       
   959 	if (!ac.getCssVersion().equals("css1")) {
       
   960 	    removeThisAtRule();
       
   961 	    addError(e, skipStatement()); 
       
   962 	}
       
   963     } finally {
       
   964 	setAtRule(old);
       
   965     }
       
   966 }
       
   967 
       
   968 Vector pageContent() :
       
   969 { CssProperty prop;
       
   970     Vector v = new Vector();
       
   971 }
       
   972 {
       
   973     // <CSS3> ?? FIXME
       
   974     v=prefAtRule() { return v;}
       
   975     // </CSS3>
       
   976     |
       
   977     v=declarations() { return v;} /* FIXME moved here as it can match empty string */
       
   978 }
       
   979 
       
   980 Vector prefAtRule() :
       
   981 { Token n; 
       
   982     Vector v;
       
   983 }
       
   984 {
       
   985     try {
       
   986         (n=<ATTOP> | n=<ATBOTTOM> | n=<ATLEFT> | n=<ATRIGHT> ) ( <S> )*
       
   987 	    <LBRACE> ( <S> )* v=declarations() <RBRACE> ( <S> )* 
       
   988 	    {
       
   989 		return v;
       
   990 	    }
       
   991     } catch (ParseException e) {
       
   992 	addError(e, skipStatement());
       
   993     }
       
   994 }
       
   995 
       
   996 void pseudo_page(AtRulePage page) :
       
   997 { Token n; }
       
   998 {
       
   999     ":" n=<IDENT> ( <S> )*
       
  1000     { 
       
  1001 	try {
       
  1002 	    page.setName(":" + convertIdent(n.image), ac); 
       
  1003 	} catch (InvalidParamException e) {
       
  1004 	    throw new InvalidParamException("pseudo", n.image, ac );
       
  1005 	    /*CssError error = new CssError(getSourceFile(), getLine(), e);
       
  1006 	      ac.getFrame().addError(error);	*/
       
  1007 	}
       
  1008     }
       
  1009 }
       
  1010 
       
  1011 void fontFace() :
       
  1012 {
       
  1013     Vector v;
       
  1014     AtRule old = getAtRule();
       
  1015     setAtRule(new AtRuleFontFace());
       
  1016     CssSelectors s = new CssSelectors(ac);
       
  1017     s.setAtRule(getAtRule());
       
  1018 }
       
  1019 {
       
  1020     try {
       
  1021 	<FONT_FACE_SYM> ( <S> )* 
       
  1022 	    {
       
  1023 		if (ac.getCssVersion().equals("css1")) {
       
  1024 		    skipStatement();
       
  1025 		    addError(new InvalidParamException("noatruleyet", "", ac),
       
  1026 			     getAtRule().toString());
       
  1027 		}
       
  1028 		if (!ac.getCssVersion().equals("css1")) {
       
  1029 		    newAtRule(getAtRule());	
       
  1030 		}
       
  1031 
       
  1032 	    }
       
  1033 	<LBRACE> ( <S> )* v=declarations() <RBRACE> ( <S> )*
       
  1034 	     {
       
  1035 		 if (!ac.getCssVersion().equals("css1")) {
       
  1036 		     addProperty(v);
       
  1037 		     endOfRule();
       
  1038 		     endOfAtRule();
       
  1039 		 }
       
  1040 		 if (v == null) {
       
  1041 		     ac.getFrame().addWarning("no-declaration");
       
  1042 		 } else {
       
  1043 		     handleRule(s, v);
       
  1044 		 }
       
  1045 	     }
       
  1046     } catch (ParseException e) {
       
  1047 	if (!ac.getCssVersion().equals("css1")) {
       
  1048 	    addError(e, skipStatement()); 
       
  1049         }
       
  1050     } finally {
       
  1051 	setAtRule(old);
       
  1052     }
       
  1053 }
       
  1054 
       
  1055 void colorprofile() :
       
  1056 {
       
  1057     Vector v;
       
  1058     AtRule old = getAtRule();
       
  1059     setAtRule(new AtRuleColorProfile());
       
  1060     CssSelectors s = new CssSelectors(ac);
       
  1061     s.setAtRule(getAtRule());
       
  1062 }
       
  1063 {
       
  1064     try {
       
  1065 	<COLOR_PROFILE> ( <S> )*
       
  1066 	    {
       
  1067 		if (!ac.getCssVersion().equals("svg")) {
       
  1068 		    skipStatement();
       
  1069 		    addError(new InvalidParamException("onlysvg", "", ac),
       
  1070 			     getAtRule().toString());
       
  1071 		}
       
  1072 		if (ac.getCssVersion().equals("svg")) {
       
  1073 		    newAtRule(getAtRule());	
       
  1074 		}
       
  1075 
       
  1076 	    }
       
  1077 	<LBRACE> ( <S> )* v=declarations() <RBRACE> ( <S> )*
       
  1078 	     {
       
  1079 		 if (ac.getCssVersion().equals("svg")) {
       
  1080 		     addProperty(v);
       
  1081 		     endOfRule();
       
  1082 		     endOfAtRule();
       
  1083 		 }
       
  1084 
       
  1085 		 if (v == null) {
       
  1086 		     //ac.getFrame().addWarning("medialist");
       
  1087 		 } else {
       
  1088 		     handleRule(s, v);  
       
  1089 		 }
       
  1090 	     }
       
  1091     }
       
  1092     catch (ParseException e) {
       
  1093 	if (ac.getCssVersion().equals("svg")) {
       
  1094             addError(e, skipStatement());
       
  1095 	}
       
  1096     } finally {
       
  1097 	setAtRule(old);
       
  1098     }
       
  1099 }
       
  1100 
       
  1101 
       
  1102 void preference() :
       
  1103 {
       
  1104     Vector v;
       
  1105     AtRule old = getAtRule();
       
  1106     setAtRule(new AtRulePreference());
       
  1107     CssSelectors s = new CssSelectors(ac);
       
  1108     s.setAtRule(getAtRule());
       
  1109 }
       
  1110 {
       
  1111     try {
       
  1112 	<PREF_SYM> ( <S> )*
       
  1113 	    {
       
  1114 		if (ac.getCssVersion().equals("css1")) {
       
  1115 		    skipStatement();
       
  1116 		    addError(new InvalidParamException("noatruleyet", "", ac),
       
  1117 			     getAtRule().toString());
       
  1118 		}
       
  1119 		if (!ac.getCssVersion().equals("css1")) {
       
  1120 		    newAtRule(getAtRule());	
       
  1121 		}
       
  1122 
       
  1123 	    }
       
  1124 	<LBRACE> ( <S> )* v=declarations() <RBRACE> ( <S> )*
       
  1125 	     {
       
  1126 		 if (!ac.getCssVersion().equals("css1")) {
       
  1127 		     addProperty(v);
       
  1128 		     endOfRule();
       
  1129 		     endOfAtRule();
       
  1130 		 }
       
  1131 
       
  1132 		 if (v == null) {
       
  1133 		     ac.getFrame().addWarning("medialist");
       
  1134 		 } else {
       
  1135 		     handleRule(s, v);  
       
  1136 		 }
       
  1137 	     }
       
  1138     }
       
  1139     catch (ParseException e) {
       
  1140 	if (!ac.getCssVersion().equals("css1")) {
       
  1141             addError(e, skipStatement());
       
  1142 	}
       
  1143     } finally {
       
  1144 	setAtRule(old);
       
  1145     }
       
  1146 }
       
  1147 
       
  1148 void phoneticAlphabet() :
       
  1149 {
       
  1150     Vector v;
       
  1151     AtRule old = getAtRule();
       
  1152     AtRulePhoneticAlphabet alphabetrule = new AtRulePhoneticAlphabet();
       
  1153     setAtRule(alphabetrule);
       
  1154     Token n;
       
  1155 }
       
  1156 {
       
  1157     try {
       
  1158 	<PHONETIC_ALPHABET_SYM> ( <S> )* n=<STRING> ( <S> )* ";"
       
  1159 	    {
       
  1160 		if (!ac.getCssVersion().equals("css3")) {
       
  1161 		    skipStatement();
       
  1162 		    addError(new InvalidParamException("noatruleyet", "", ac),
       
  1163 			     getAtRule().toString());
       
  1164 		}
       
  1165 
       
  1166 		alphabetrule.addAlphabet(convertIdent(n.image), ac);
       
  1167 
       
  1168 		if (!ac.getCssVersion().equals("css1") && !ac.getCssVersion().equals("css2")) {
       
  1169 		    newAtRule(getAtRule());	
       
  1170 		}
       
  1171         
       
  1172 	    }
       
  1173     } catch (ParseException e) {
       
  1174 	if (!ac.getCssVersion().equals("css1")) {
       
  1175 	    addError(e, skipStatement()); 
       
  1176         }
       
  1177     } finally {
       
  1178 	setAtRule(old);
       
  1179     }
       
  1180 }
       
  1181 
       
  1182 /**
       
  1183  * @exception ParseException exception during the parse
       
  1184  */
       
  1185 void atRuleDeclaration() :
       
  1186 {Token n;}
       
  1187 {
       
  1188     n=<ATKEYWORD>
       
  1189 	{
       
  1190 	    //ac.getFrame().addWarning("at-rule", token.toString());
       
  1191 	    ac.getFrame().addError(
       
  1192 		          new CssError(new InvalidParamException("at-rule", 
       
  1193 								 token, ac)));
       
  1194 	    skipStatement();
       
  1195 	}
       
  1196 }
       
  1197 
       
  1198 /**
       
  1199  * @exception ParseException exception during the parse
       
  1200  */
       
  1201 void operator(CssExpression expr) :
       
  1202 {}
       
  1203 {
       
  1204   ( ( <DIV> { if (expr.getCount() > 0) expr.setOperator('/'); }
       
  1205     | <COMMA> { if (expr.getCount() > 0) expr.setOperator(','); }
       
  1206     ) ( <S> )* )?
       
  1207 }
       
  1208 
       
  1209 /**
       
  1210  * @exception ParseException exception during the parse
       
  1211  */
       
  1212 char combinator() :
       
  1213 {
       
  1214     char connector = ' ';
       
  1215 }
       
  1216 {
       
  1217     ( (   <PLUS> { connector = '+' ; }
       
  1218         | <GREATER> { connector = '>' ; }
       
  1219         | <TILDE> { connector = '~' ; }
       
  1220       ) ( <S> )* 
       
  1221     | ( <S> )+ { connector = ' ' ; }
       
  1222     )
       
  1223     {
       
  1224 	return connector;
       
  1225     }
       
  1226 }
       
  1227 
       
  1228 /**
       
  1229  * @exception ParseException exception during the parse
       
  1230  */
       
  1231 char unaryOperator() :
       
  1232 {}
       
  1233 {
       
  1234     // FIXME <MINUS> | <PLUS> ? warning as <PLUS> is <_W>? "+"
       
  1235     "-" { return '-'; }
       
  1236     | <PLUS> { return '+'; }
       
  1237 }
       
  1238 
       
  1239 /**
       
  1240  * @exception ParseException exception during the parse
       
  1241  */
       
  1242 String property() :
       
  1243 {Token n; }
       
  1244 {
       
  1245     n=<IDENT> ( <S> )* { currentProperty = convertIdent(n.image); 
       
  1246 			 return currentProperty; }
       
  1247 }
       
  1248 
       
  1249 /**
       
  1250  * @exception ParseException exception during the parse
       
  1251  */
       
  1252 void ruleSet() :
       
  1253 { CssSelectors contextual;
       
  1254     Vector<CssSelectors> context_set = new Vector<CssSelectors>();
       
  1255     Vector<CssProperty> value_set = null;
       
  1256     currentContext = context_set;
       
  1257 }
       
  1258 {
       
  1259     try {
       
  1260 	contextual=selector()
       
  1261 	    { 
       
  1262 		if (contextual != null) {
       
  1263 		    context_set.addElement(contextual); 
       
  1264 		}
       
  1265 	    }
       
  1266 	
       
  1267 	( <COMMA> ( <S> )*
       
  1268 	  contextual=selector()
       
  1269 	    { 
       
  1270 		if (contextual != null) {
       
  1271 		    context_set.addElement(contextual); 
       
  1272 		}
       
  1273 	    }  
       
  1274 	  )*
       
  1275 	    <LBRACE> {
       
  1276 	    validSelector = (context_set.size() > 0);
       
  1277 	}
       
  1278 	( <S> )*
       
  1279 	    value_set=declarations()
       
  1280 	    <RBRACE> ( <S> )*
       
  1281 	    {
       
  1282 		markRule = true;
       
  1283 		
       
  1284 		/*      if (value_set == null) {
       
  1285 			ac.getFrame().addWarning("no-declaration");
       
  1286 			} else {*/
       
  1287 		if (value_set != null) {
       
  1288 		    boolean first = true;
       
  1289 		    CssSelectors sel = null;
       
  1290 		    Enumeration<CssSelectors> e = context_set.elements();
       
  1291 		    while (e.hasMoreElements()) {
       
  1292 			sel = e.nextElement();
       
  1293 			if (first) {
       
  1294 			    handleRule(sel, value_set);
       
  1295 			    first = false;
       
  1296 			} else {
       
  1297 			    // we need to duplicate properties in that case
       
  1298 			    // as property holds reference to the selectors and it interact
       
  1299 			    // badly with conflict detection
       
  1300 			    int vsize = value_set.size();
       
  1301 			    Vector<CssProperty> v = new Vector<CssProperty>(vsize);
       
  1302 			    for (int i=0; i<vsize; i++) {
       
  1303 				v.addElement(value_set.elementAt(i).duplicate());
       
  1304 			    }
       
  1305 			    handleRule(sel, v);
       
  1306 			}
       
  1307 		    }
       
  1308 		    setSelectorList(context_set);
       
  1309 		    endOfRule();
       
  1310 		}
       
  1311 		currentContext = null;
       
  1312 	    }
       
  1313     } catch (ParseException e) {
       
  1314 	if (ac.getProfile() != null) {
       
  1315 	    if (!ac.getProfile().equals("mobile") && !context_set.isEmpty()) {
       
  1316 		addError(e, skipStatement()); 
       
  1317 	    }
       
  1318 	}
       
  1319     } catch (TokenMgrError e) {
       
  1320 	addError(new ParseException(e.getMessage()), skipStatement());
       
  1321     }
       
  1322 }
       
  1323 
       
  1324 Vector<CssProperty> declarations() :
       
  1325 {
       
  1326     if(!validSelector) {        
       
  1327         validSelector = true;
       
  1328         skip_to_matching_brace();
       
  1329         return null;
       
  1330     }
       
  1331 
       
  1332     CssProperty values;
       
  1333     Vector<CssProperty> value_set   = new Vector<CssProperty>();
       
  1334     boolean wrong_value = true;
       
  1335 }
       
  1336 {    
       
  1337     ( values=declaration() 
       
  1338 	{ if (values != null) {
       
  1339 		value_set.addElement(values);
       
  1340 		wrong_value = false;
       
  1341 	    } /* else {
       
  1342 		 wrong_value = true;
       
  1343 		 } */
       
  1344 	  currentProperty = null;
       
  1345 	}
       
  1346       )? 
       
  1347 	( ";" ( <S> )*
       
  1348 	  ( values=declaration() 
       
  1349 	      { if (values != null) {
       
  1350 		      value_set.addElement(values);
       
  1351 		      wrong_value = false;
       
  1352 		  }/* else {
       
  1353 		      wrong_value = true;
       
  1354 		      }*/
       
  1355 		currentProperty = null;
       
  1356 	      }
       
  1357 	      )? )* 
       
  1358 	{  	
       
  1359 	    if (!wrong_value) {
       
  1360 		addProperty(value_set);
       
  1361 		return value_set; 
       
  1362 	    } else {
       
  1363 		return null;
       
  1364 	    }
       
  1365 	}
       
  1366 }
       
  1367 
       
  1368 /**
       
  1369  * @exception ParseException exception during the parse
       
  1370  */
       
  1371 CssSelectors selector() :
       
  1372 {   char comb;
       
  1373     CssSelectors current; }
       
  1374 {
       
  1375     try {
       
  1376 	current=simple_selector(null) 
       
  1377 	    (  
       
  1378 	      comb=combinator() { 
       
  1379 		if (ac.getProfile() != null) {
       
  1380 		    if (ac.getProfile().equals("mobile") || 
       
  1381 			getAtRule().toString().equals("@media atsc-tv") ||
       
  1382 			ac.getCssVersion().equals("css1")) {
       
  1383 			if (comb == '+')
       
  1384 			    throw new InvalidParamException("nocomb", "+", ac);
       
  1385 			if (comb == '>')
       
  1386 			    throw new InvalidParamException("nocomb", ">", ac);
       
  1387 		    } else if (ac.getProfile().equals("tv")) {
       
  1388 			if (comb == '+')
       
  1389 			    throw new InvalidParamException("nocomb", "+", ac);
       
  1390 		   
       
  1391 		    }
       
  1392 		}
       
  1393 		if (!ac.getCssVersion().equals("css3")) {
       
  1394 		    if (comb == '~') {
       
  1395 			throw new InvalidParamException("nocomb", "~", ac);
       
  1396 		    }
       
  1397 		}
       
  1398 		switch(comb) {
       
  1399 		case '+': 
       
  1400 		current.addAdjacentSibling(new AdjacentSiblingSelector());
       
  1401 		break;
       
  1402 		case '>':
       
  1403 		current.addChild(new ChildSelector());
       
  1404 		break;
       
  1405 		case '~':
       
  1406 		current.addGeneralSibling(new GeneralSiblingSelector());
       
  1407 		break;
       
  1408 		default:
       
  1409 		current.addDescendant(new DescendantSelector());
       
  1410 		}                  
       
  1411 		//current.setConnector(comb); 
       
  1412 	    }
       
  1413 	      current=simple_selector(current) 
       
  1414 	      )* 
       
  1415 	    { return current; }
       
  1416     }
       
  1417     catch (InvalidParamException ie) {    
       
  1418 	//	skipStatement();
       
  1419 	//	removeThisRule();
       
  1420 	ac.getFrame().addError(new CssError(ie));
       
  1421 	Token t = getToken(1);
       
  1422 	StringBuilder s = new StringBuilder();
       
  1423 	s.append(getToken(0).image);
       
  1424 	// eat until , { or EOF
       
  1425 	while ((t.kind != COMMA) && (t.kind != LBRACE) && (t.kind != EOF)) {
       
  1426 	    s.append(t.image);
       
  1427 	    getNextToken();
       
  1428 	    t = getToken(1);
       
  1429 	}
       
  1430 	return null;
       
  1431     }
       
  1432     catch (ParseException e) {
       
  1433 	//	validSelector = false;
       
  1434 	Token t = getToken(1);
       
  1435 	StringBuilder s = new StringBuilder("[");
       
  1436 	s.append(getToken(0).image);
       
  1437 	// eat until , { or EOF
       
  1438 	while ((t.kind != COMMA) && (t.kind != LBRACE) && (t.kind != EOF)) {
       
  1439 	    s.append(t.image);
       
  1440 	    getNextToken();
       
  1441 	    t = getToken(1);
       
  1442 	}
       
  1443 	s.append(']');
       
  1444 	//	if (validSelector) {
       
  1445 	addError(e, s.toString());
       
  1446 	    //	} else {
       
  1447 	    //  addError(e,"");
       
  1448 	    //	}
       
  1449 	validSelector = true;
       
  1450 	return null;    	
       
  1451     }
       
  1452 }
       
  1453 
       
  1454 /**
       
  1455  * I made this rule to parse a selector from a document. Combinator are avoid.
       
  1456  * @exception ParseException exception during the parse
       
  1457  */
       
  1458 CssSelectors externalSelector() :
       
  1459 {
       
  1460     CssSelectors current; }
       
  1461 {
       
  1462     current=simple_selector(null) 
       
  1463 	( ( <S> )+
       
  1464 	  current=simple_selector(current) 
       
  1465 	  )*
       
  1466 	{ return current; }
       
  1467 }
       
  1468 
       
  1469 /**
       
  1470  * @exception ParseException exception during the parse
       
  1471  */
       
  1472 CssSelectors simple_selector(CssSelectors next) :
       
  1473 { CssSelectors selector = new CssSelectors(ac, next);
       
  1474     selector.setAtRule(getAtRule());
       
  1475     //selector.setUserMedium(getUserMedium());
       
  1476 }
       
  1477 {
       
  1478 
       
  1479     element_name(selector) ( hash(selector) | _class(selector)
       
  1480 			     | attrib(selector) | pseudo(selector) 
       
  1481 			     | negation(selector) )*
       
  1482 	{   
       
  1483 	    return selector;
       
  1484 	}
       
  1485     | ( hash(selector) | _class(selector) | attrib(selector) 
       
  1486 	| pseudo(selector) | negation(selector) )+ 
       
  1487 	{
       
  1488 	    return selector;
       
  1489 	}
       
  1490 }
       
  1491 
       
  1492 /**
       
  1493  * @exception ParseException exception during the parse
       
  1494  */
       
  1495 void _class(CssSelectors s) :
       
  1496 {Token n; }
       
  1497 {
       
  1498     /*  "." n=<IDENT> { */
       
  1499     n=<CLASS> {
       
  1500 	try {
       
  1501 	    s.addClass(new ClassSelector(convertClassIdent(n.image.substring(1))));
       
  1502 	    //        s.addAttribute("class", convertIdent(n.image.substring(1)),
       
  1503 	    //           CssSelectors.ATTRIBUTE_CLASS_SEL);
       
  1504 	} catch (InvalidParamException e) {
       
  1505 	    //	    removeThisRule();
       
  1506 	     ac.getFrame().addError(new CssError(e));
       
  1507 	    throw new ParseException(e.getMessage());
       
  1508 	}
       
  1509     } 
       
  1510     /* FIXME <DOT> n=deprecated_class() ... ?? (DONE-> to be tested) */ 
       
  1511     | ( n=deprecated_class() ) {
       
  1512 	if (n.image.charAt(0) == '.') {
       
  1513 	    n.image = n.image.substring(1);
       
  1514           
       
  1515 	    // the class with the first digit escaped
       
  1516 	    String cl = "."+hexEscapeFirst(n.image);
       
  1517 
       
  1518 	    String profile = ac.getProfile();
       
  1519 	    if(profile == null || profile.equals("") || profile.equals("none")) {
       
  1520 		profile = ac.getCssVersion(); 
       
  1521 	    }     
       
  1522           
       
  1523 	    if(!profile.equals("css1")) {
       
  1524 		StringBuilder sb = new StringBuilder();
       
  1525 		Vector<String> param_err = new Vector<String>(2);
       
  1526 		param_err.add(n.image);
       
  1527 		param_err.add(cl);
       
  1528 		sb.append(ac.getMsg().getString("parser.old_class", param_err));
       
  1529 		throw new ParseException(sb.toString());
       
  1530 		//		s.addClass(new ClassSelector(n.image));                            
       
  1531 		// removeThisRule();              
       
  1532 	    }
       
  1533 	    else {
       
  1534 		CssLength length = new CssLength();
       
  1535 		boolean isLength = false;
       
  1536 		try {              
       
  1537 		    length.set(n.image, ac);
       
  1538 		    isLength = true;               
       
  1539 		}
       
  1540 		catch(Exception e) {
       
  1541 		    isLength = false;              
       
  1542 		}
       
  1543 		if(isLength) {
       
  1544 		    StringBuilder sb = new StringBuilder();
       
  1545 		    sb.append(ac.getMsg().getString("parser.class_dim"));
       
  1546 		    sb.append(n.image);
       
  1547 		    throw new ParseException(sb.toString());
       
  1548 		    //		    s.addClass(new ClassSelector(n.image));                            
       
  1549 		    // removeThisRule();
       
  1550 		}        
       
  1551 		else {
       
  1552 		    try {
       
  1553 			// for css > 1, we add the rule to have a context, 
       
  1554 			// and we then remove it
       
  1555 			s.addClass(new ClassSelector(n.image));
       
  1556 			ac.getFrame().addWarning("old_class");              
       
  1557 		    } catch (InvalidParamException e) {
       
  1558 			throw new ParseException(e.getMessage());
       
  1559 			//ac.getFrame().addError(new CssError(e));
       
  1560 			//removeThisRule();
       
  1561 		    }
       
  1562 		}
       
  1563 	    }
       
  1564 	} else {
       
  1565 	    throw new ParseException("Unrecognized ");
       
  1566 	}
       
  1567     }
       
  1568 }
       
  1569 
       
  1570 Token deprecated_class() :
       
  1571 {
       
  1572     Token n;
       
  1573 }
       
  1574 {
       
  1575     ( n=<LENGTH>
       
  1576     | n=<EMS> 
       
  1577     | n=<EXS> 
       
  1578     | n=<ANGLE>
       
  1579     | n=<TIME> 
       
  1580     | n=<FREQ> 
       
  1581     | n=<RESOLUTION>
       
  1582     | n=<DIMEN> )
       
  1583     { 
       
  1584 	return n;
       
  1585     }
       
  1586 }
       
  1587 
       
  1588 /**
       
  1589  * @exception ParseException exception during the parse
       
  1590  */
       
  1591 void element_name(CssSelectors s) :
       
  1592 {
       
  1593     Token n=null;
       
  1594     Token p=null;
       
  1595     String prefix = null;
       
  1596 }
       
  1597 {
       
  1598     ( LOOKAHEAD(2) (n=<IDENT> | n=<ANY>)? p="|" )? {
       
  1599 	// FIXME namespace, check versions of CSS in a better way.
       
  1600 	if (p != null) {
       
  1601 	    if (!ac.getCssVersion().equals("css3")) {
       
  1602 		StringBuilder sb = new StringBuilder("namespace \"");
       
  1603 		if (n != null) sb.append(n.toString());
       
  1604 		sb.append("\"");
       
  1605 		ac.getFrame().addError(new CssError(new 
       
  1606 					  InvalidParamException("notversion",
       
  1607 								"namespace",
       
  1608 							    ac.getCssVersion(),
       
  1609 								ac)));
       
  1610 		removeThisRule();
       
  1611 	    } else if (n!=null) {
       
  1612 		prefix = convertIdent(n.image);
       
  1613 		if (!ac.isNamespaceDefined(getURL(), prefix)) {
       
  1614 		    // ns is not defined
       
  1615 		    addError(new ParseException("Undefined namespace"), 
       
  1616 			     ": The namespace \""+prefix
       
  1617 			     +"\" is not defined. "
       
  1618 			     + prefix );
       
  1619 		    removeThisRule();
       
  1620 		}
       
  1621 	    } else {
       
  1622 		prefix = "";
       
  1623 	    }
       
  1624 	}
       
  1625     }
       
  1626     ( n=<IDENT> { //              s.setElement(convertIdent(n.image), ac);
       
  1627 	s.addType(new TypeSelector(prefix, convertIdent(n.image)));
       
  1628     }
       
  1629     | <ANY> { 
       
  1630         if (!ac.getCssVersion().equals("css1")) {
       
  1631 	    //          s.setElement(null);
       
  1632             s.addUniversal(new UniversalSelector(prefix));
       
  1633         } else {
       
  1634 	    ac.getFrame().addError(new CssError(new InvalidParamException("notversion",
       
  1635 									  "*", ac.getCssVersion(), ac)));
       
  1636 	}
       
  1637     }
       
  1638 	)
       
  1639 }
       
  1640 
       
  1641 /**
       
  1642  * @exception ParseException exception during the parse
       
  1643  */
       
  1644 void attrib(CssSelectors s) :
       
  1645 {
       
  1646     Token att = null;
       
  1647     Token val = null;
       
  1648     int selectorType = CssSelectors.ATTRIBUTE_ANY;
       
  1649 }
       
  1650 {
       
  1651     <LBRACKET> ( <S> )* att=<IDENT> ( <S> )*
       
  1652 	( (<EQ> { selectorType = CssSelectors.ATTRIBUTE_EXACT; }
       
  1653         | <INCLUDES> { selectorType = CssSelectors.ATTRIBUTE_ONE_OF; }
       
  1654 	| <DASHMATCH> { selectorType = CssSelectors.ATTRIBUTE_BEGIN; }
       
  1655 	| <PREFIXMATCH> { selectorType = CssSelectors.ATTRIBUTE_START; }
       
  1656 	| <SUFFIXMATCH> { selectorType = CssSelectors.ATTRIBUTE_SUFFIX; }
       
  1657 	| <SUBSTRINGMATCH> { selectorType = CssSelectors.ATTRIBUTE_SUBSTR; }
       
  1658 	 ) ( <S> )* 
       
  1659 	 ( val=<IDENT> 
       
  1660 	     { val.image = convertIdent(val.image); }
       
  1661 	   | val=<STRING> 
       
  1662 	       { val.image = convertStringIndex(val.image, 1, val.image.length() -1, false);} 
       
  1663 	   ) 
       
  1664 	   ( <S> )* )?
       
  1665   <RBRACKET>
       
  1666       {
       
  1667 	  if ("css1".equals(ac.getCssVersion())) {
       
  1668 	      StringBuilder reason;
       
  1669 	      CssParseException cp;
       
  1670 	      ParseException p;
       
  1671 	      reason = new StringBuilder(" [");
       
  1672 	      if (att != null) {
       
  1673 		  reason.append(convertIdent(att.image));
       
  1674 	      }
       
  1675 	      if (val != null ) {
       
  1676 		  reason.append('=').append(val.image);
       
  1677 	      }
       
  1678 	      reason.append(']');
       
  1679 	      p = new ParseException(ac.getMsg().getString("parser.attrcss1")+
       
  1680 				     reason.toString());
       
  1681 	      cp = new CssParseException(p);
       
  1682 	      ac.getFrame().addError(new CssError(cp));
       
  1683 	      removeThisRule();
       
  1684 	  }
       
  1685 	  if (selectorType == CssSelectors.ATTRIBUTE_ANY) {
       
  1686 	      try {
       
  1687 		  s.addAttribute(new AttributeAny(att.image.toLowerCase()));
       
  1688 //                s.addAttribute(att.image.toLowerCase(), null, selectorType);
       
  1689               } catch (InvalidParamException e) {
       
  1690 	          removeThisRule();
       
  1691 	          ac.getFrame().addError(new CssError(e));
       
  1692               }
       
  1693 	  } else {
       
  1694 	      AttributeSelector attribute;
       
  1695               switch(selectorType) {
       
  1696               case CssSelectors.ATTRIBUTE_BEGIN:
       
  1697         	  attribute = new AttributeBegin(att.image.toLowerCase(),
       
  1698         		  val.image);
       
  1699         	  break;
       
  1700               case CssSelectors.ATTRIBUTE_EXACT:
       
  1701         	  attribute = new AttributeExact(att.image.toLowerCase(),
       
  1702         		  val.image);
       
  1703         	  break;
       
  1704               case CssSelectors.ATTRIBUTE_ONE_OF:
       
  1705         	  attribute = new AttributeOneOf(att.image.toLowerCase(),
       
  1706         		  val.image);
       
  1707         	  break;
       
  1708               case CssSelectors.ATTRIBUTE_START:
       
  1709         	  attribute = new AttributeStart(att.image.toLowerCase(),
       
  1710         		  val.image);
       
  1711         	  break;
       
  1712               case CssSelectors.ATTRIBUTE_SUBSTR:
       
  1713         	  attribute = new AttributeSubstr(att.image.toLowerCase(),
       
  1714         		  val.image);
       
  1715         	  break;
       
  1716               case CssSelectors.ATTRIBUTE_SUFFIX:
       
  1717         	  attribute = new AttributeSuffix(att.image.toLowerCase(),
       
  1718         		  val.image);
       
  1719         	  break;
       
  1720               default:
       
  1721         	  attribute = new AttributeExact(att.image.toLowerCase(),
       
  1722         		  val.image);
       
  1723               	  break;
       
  1724               }
       
  1725 	      try {
       
  1726 		  s.addAttribute(attribute);
       
  1727 //	      	  s.addAttribute(att.image.toLowerCase(), val.image, 
       
  1728 //			     selectorType);
       
  1729 	      } catch (InvalidParamException e) {
       
  1730 	     	  removeThisRule();
       
  1731 	          ac.getFrame().addError(new CssError(e));
       
  1732       	      } 
       
  1733 	  }
       
  1734       }
       
  1735 }
       
  1736 
       
  1737 void negation(CssSelectors s) :
       
  1738 {
       
  1739     Token n;
       
  1740     CssSelectors ns = new CssSelectors(ac, null);
       
  1741 }
       
  1742 { // S* negation_arg S* ')'
       
  1743     // type_selector | universal | HASH | class | attrib | pseudo
       
  1744 
       
  1745     <FUNCTIONNOT> ( <S> )*
       
  1746 	(
       
  1747 	 element_name(ns) |
       
  1748 	 hash(ns) | 
       
  1749 	 _class(ns) |
       
  1750 	 attrib(ns) | 
       
  1751 	 pseudo(ns)
       
  1752 	 )
       
  1753 	( <S> )* <LPARAN>
       
  1754 	{ 
       
  1755 	    s.setPseudoFun("not", ns.toString());
       
  1756 	}
       
  1757 }
       
  1758 
       
  1759 /**
       
  1760  * @exception ParseException exception during the parse
       
  1761  */
       
  1762 void pseudo(CssSelectors s) :
       
  1763 {Token n;
       
  1764 Token language = null;
       
  1765 CssExpression param = null;
       
  1766 }
       
  1767 {
       
  1768     <PSEUDOELEMENT_SYM> ( ( n=<IDENT>
       
  1769 	{ 
       
  1770 	    try {
       
  1771 		if (ac.getCssVersion().equals("css3")) {
       
  1772 		    s.addPseudoElement(convertIdent(n.image).toLowerCase());
       
  1773 		} else {
       
  1774 		    throw new InvalidParamException("pseudo-element",
       
  1775 						    "::" + convertIdent(n.image).toLowerCase() ,
       
  1776 						    ac.getCssVersion() ,ac);
       
  1777 		}
       
  1778 	    } catch(InvalidParamException e) {
       
  1779 		//	removeThisRule();
       
  1780 		//		ac.getFrame().addError(new CssError(e));
       
  1781 		validSelector = false;
       
  1782 		throw new ParseException(e.getMessage());
       
  1783 	    }
       
  1784 	} ) )
       
  1785 	|  
       
  1786 	<COLON> ( ( n=<IDENT>
       
  1787 	    { 
       
  1788 		try {
       
  1789 		    s.addPseudoClass(convertIdent(n.image).toLowerCase());
       
  1790 		} catch(InvalidParamException e) {
       
  1791 		    removeThisRule();
       
  1792 		    ac.getFrame().addError(new CssError(e));
       
  1793 		}
       
  1794 	    } )
       
  1795 		  // FXIXME rewrite to make :lang( use a special case
       
  1796 		  | ( ( n=<FUNCTIONLANG> ( <S> )* (language=<NUMBER> | language=<IDENT> | language=<STRING> ) ( <S> )* ) {
       
  1797 		try {
       
  1798 		    s.setPseudoFun(convertStringIndex(n.image, 0,
       
  1799 						      n.image.length() -1, false).toLowerCase(),
       
  1800 				   convertIdent(language.image));
       
  1801 		} catch(InvalidParamException e) {
       
  1802 			removeThisRule();
       
  1803 			ac.getFrame().addError(new CssError(e));
       
  1804 		}
       
  1805 	    }
       
  1806 	    | ( n=<FUNCTION> ( <S> )* param=expression() ) {
       
  1807 		try {
       
  1808 		    s.setPseudoFun(convertStringIndex(n.image, 0,
       
  1809 						      n.image.length() -1, 
       
  1810 						      false).toLowerCase(),
       
  1811 				   param.toString());
       
  1812 		} catch(InvalidParamException e) {
       
  1813 		    removeThisRule();
       
  1814 		    ac.getFrame().addError(new CssError(e));
       
  1815 		} 
       
  1816 	    }
       
  1817 	    ) <LPARAN>
       
  1818 	    )
       
  1819 }
       
  1820 
       
  1821 /**
       
  1822  * @exception ParseException exception during the parse
       
  1823  */
       
  1824 void hash(CssSelectors s) :
       
  1825 {Token n; }
       
  1826 {
       
  1827   n=<HASHIDENT>  {
       
  1828       n.image = n.image.substring(1);
       
  1829       if(Character.isDigit(n.image.charAt(0))) { 
       
  1830 	  String profile = ac.getProfile();
       
  1831 	  if(profile == null || profile.equals("") || profile.equals("none")) {
       
  1832 	      profile = ac.getCssVersion(); 
       
  1833 	  }     
       
  1834 	  
       
  1835 	  if(!profile.equals("css1")) {
       
  1836 	      // the id with the first digit escaped
       
  1837 	      String cl = "\\" + Integer.toString(n.image.charAt(0), 16);
       
  1838 	      cl += n.image.substring(1);
       
  1839 	      
       
  1840 	      addError(new ParseException(ac.getMsg().getString(
       
  1841 	      	"parser.old_id")),
       
  1842 	      	"To make \"." + n.image + "\" a valid id, CSS2" +
       
  1843 	      	" requires the first digit to be escaped " +
       
  1844 	      	"(\"#" + cl + "\")");
       
  1845 	      // for css > 1, we add the rule to have a context, 
       
  1846 	      // and we then remove it
       
  1847 	      s.addId(new IdSelector(n.image));                            
       
  1848 	      removeThisRule();              
       
  1849 	  }
       
  1850 	  else {
       
  1851 	      CssLength length = new CssLength();
       
  1852 	      boolean isLength = false;
       
  1853 	      try {              
       
  1854 		  length.set(n.image, ac);
       
  1855 		  isLength = true;               
       
  1856 	      }
       
  1857 	      catch(Exception e) {
       
  1858 		  isLength = false;              
       
  1859 	      }
       
  1860 	      if(isLength) {
       
  1861 		  addError(new ParseException(ac.getMsg().getString(
       
  1862 		  "parser.id_dim")), n.image);
       
  1863 		  // we add the rule to have a context, and then we remove it
       
  1864 		  s.addId(new IdSelector(n.image));                            
       
  1865 		  removeThisRule();
       
  1866 	      }        
       
  1867 	      else {
       
  1868 		  try {
       
  1869 		      s.addId(new IdSelector(n.image));      
       
  1870 		      ac.getFrame().addWarning("old_id");              
       
  1871 		  } catch (InvalidParamException e) {
       
  1872 		      ac.getFrame().addError(new CssError(e));
       
  1873 		      removeThisRule();
       
  1874 		  }
       
  1875 	      }
       
  1876 	  }
       
  1877       }
       
  1878       else {
       
  1879 	  try {
       
  1880 	      s.addId(new IdSelector(n.image));             
       
  1881 	  } catch (InvalidParamException e) {
       
  1882 	      ac.getFrame().addError(new CssError(e));
       
  1883 	      removeThisRule();
       
  1884 	  }
       
  1885       }
       
  1886   }
       
  1887   | n=<HASH> {
       
  1888       throw new ParseException(ac.getMsg().getString("parser.invalid_id_selector"));	 
       
  1889   }
       
  1890 }
       
  1891 
       
  1892 /**
       
  1893  * @exception ParseException exception during the parse
       
  1894  */
       
  1895 CssProperty mediadeclaration() :
       
  1896 { String string_property;
       
  1897   CssExpression values = null;
       
  1898   boolean important = false;
       
  1899   setMediaDeclaration("on");
       
  1900 }
       
  1901 {
       
  1902 try {
       
  1903       string_property=property() (":" ( <S> )* 
       
  1904       values=expr() ( important=prio() )? )?
       
  1905     {
       
  1906 	
       
  1907 	try {
       
  1908 	
       
  1909 	    setImportant(important);
       
  1910 	
       
  1911 	    if (incompatible_error) {
       
  1912 		throw new InvalidParamException("notforcss1", "inherit", ac);
       
  1913 	    }
       
  1914 
       
  1915 	    CssProperty p = handleDeclaration(string_property.toLowerCase(),
       
  1916 						  values, important);
       
  1917 	    return p;
       
  1918 	    	    
       
  1919 	} catch (InvalidParamException e) {
       
  1920 		incompatible_error = false;
       
  1921 		if (null != values) {
       
  1922 			values.starts();
       
  1923 		}
       
  1924 		addError(e, (CssExpression) values);
       
  1925 	}
       
  1926 	return null;
       
  1927     }
       
  1928  } catch (NumberFormatException e) {
       
  1929      skipAfterExpression(e);
       
  1930      return null;
       
  1931  } catch (ParseException e) {
       
  1932      skipAfterExpression(e);
       
  1933      return null;
       
  1934  } finally {
       
  1935      setMediaDeclaration("off");
       
  1936  }
       
  1937 }
       
  1938 
       
  1939 
       
  1940 /**
       
  1941  * @exception ParseException exception during the parse
       
  1942  */
       
  1943 CssProperty declaration() :
       
  1944 { String string_property;
       
  1945   CssExpression values;
       
  1946   boolean important = false;
       
  1947 }
       
  1948 {
       
  1949 try {
       
  1950      string_property=property() ":" ( <S> )* 
       
  1951       values=expr() ( important=prio() )?
       
  1952     {
       
  1953 	try {
       
  1954 	
       
  1955 	    setImportant(important);
       
  1956 	
       
  1957 	    if (incompatible_error) {
       
  1958 		throw new InvalidParamException("notforcss1", "inherit", ac);
       
  1959 	    }
       
  1960 
       
  1961 	    if (values.getCount() != 0) {
       
  1962 		CssProperty p = handleDeclaration(string_property.toLowerCase(),
       
  1963 						  values, important);
       
  1964 		// Did the property recognize all values in the expression ?
       
  1965 
       
  1966 		if (!values.end() && ac.getMedium() == null) {
       
  1967 		        addError(new InvalidParamException("unrecognize", "", ac),
       
  1968 			     values);
       
  1969 		} else {
       
  1970 		    // ok, return the new property
       
  1971 		    return p;
       
  1972 		}
       
  1973 	    }
       
  1974 	} catch (InvalidParamException e) {
       
  1975 		incompatible_error = false;
       
  1976 		values.starts();
       
  1977 		addError(e, (CssExpression) values);
       
  1978 	}
       
  1979 	return null;
       
  1980     }
       
  1981  } catch (NumberFormatException e) {
       
  1982      skipAfterExpression(e);
       
  1983      return null;
       
  1984  } catch (ParseException e) {
       
  1985      skipAfterExpression(e);
       
  1986      return null;
       
  1987  } catch (NullPointerException e) {
       
  1988 	// NullPointerException happen if in handling a property
       
  1989 	// something bad happen (like setting values on sub properties
       
  1990 	// that had not been initialized (for an unknown reason yet).
       
  1991      skipAfterExpression(e);
       
  1992      return null;
       
  1993   }
       
  1994 }
       
  1995 
       
  1996 /**
       
  1997  * @exception ParseException exception during the parse
       
  1998  */
       
  1999 boolean prio() :
       
  2000 {}
       
  2001 {
       
  2002   <IMPORTANT_SYM> ( <S> )* { return true; }
       
  2003 }
       
  2004 
       
  2005 CssExpression expression() :
       
  2006 {
       
  2007     CssExpression exp = new CssExpression();
       
  2008     char operator = ' ';
       
  2009     Token n = null;
       
  2010 }
       
  2011 {
       
  2012     ( ( <PLUS> { operator = '+' ; } 
       
  2013 	| <MINUS> { operator = '-'; }
       
  2014 	| n=<NUMBER> { setValue(new CssNumber(), exp, operator, n, NUMBER); }
       
  2015 	// FIXME dimen should be a CssDimension()
       
  2016 	| n=<DIMEN> { setValue(new CssIdent(), exp, operator, n, IDENT); } 
       
  2017 	| n=<STRING> { setValue(new CssString(), exp, operator, n, STRING); } 
       
  2018 	| n=<IDENT> { setValue(new CssIdent(), exp, operator, n, IDENT); } 
       
  2019 	) ( <S> )* )+
       
  2020    { return exp; }
       
  2021 }     
       
  2022 /**
       
  2023  * @exception ParseException exception during the parse
       
  2024  */
       
  2025 CssExpression expr() :
       
  2026 {
       
  2027   CssExpression values = new CssExpression();
       
  2028 }
       
  2029 {
       
  2030   term(values) ( operator(values) term(values) )*
       
  2031   { return values; }
       
  2032 }
       
  2033 
       
  2034 /**
       
  2035  * @exception ParseException exception during the parse
       
  2036  */
       
  2037 void term(CssExpression exp) :
       
  2038 { Token n;
       
  2039   char operator = ' ';
       
  2040   CssValue func;
       
  2041 }
       
  2042 {
       
  2043   ( ( operator=unaryOperator() )?
       
  2044     ( n=<NUMBER> { setValue(new CssNumber(), exp, operator, n, NUMBER); }
       
  2045     | n=<PERCENTAGE> { setValue(new CssPercentage(), exp, operator, n, 
       
  2046 				PERCENTAGE); }
       
  2047     | n=<LENGTH> { setValue(new CssLength(), exp, operator, n, LENGTH); }
       
  2048     | n=<EMS> { setValue(new CssLength(), exp, operator, n, EMS); }
       
  2049     | n=<EXS> { setValue(new CssLength(), exp, operator, n, EXS); }
       
  2050     | n=<ANGLE> { setValue(new CssAngle(), exp, operator, n, ANGLE);}
       
  2051     | n=<TIME> { setValue(new CssTime(), exp, operator, n, TIME); }
       
  2052     | n=<FREQ> { setValue(new CssFrequency(), exp, operator, n, FREQ); }
       
  2053     | n=<RESOLUTION> { setValue(new CssResolution(), exp, operator, n, RESOLUTION); }
       
  2054     | n=<DATE> { setValue(new CssDate(), exp, operator, n, DATE); }
       
  2055     | n=<DIMEN> {  
       
  2056 	  addError(new ParseException(ac.getMsg().getString("parser.unknown-dimension")), n.image); }    
       
  2057     | func=function() { setValue(func, exp, operator, null, FUNCTION); }
       
  2058       ) ( <S> )* )
       
  2059   | (( n=<STRING> { setValue(new CssString(), exp, operator, n, STRING); }
       
  2060     | n=<IDENT> 
       
  2061     {
       
  2062 	/*
       
  2063 	 * Common error :
       
  2064 	 * H1 {
       
  2065 	 *   color : black
       
  2066 	 *   background : white
       
  2067 	 * }
       
  2068 	 */
       
  2069 	Token t = getToken(1);
       
  2070 	Token semicolon = new Token();
       
  2071 	semicolon.kind = SEMICOLON;
       
  2072 	semicolon.image = ";";
       
  2073 	if (t.kind == COLON) {
       
  2074 	    /* @@SEEME. (generate a warning?) */
       
  2075 	    /* @@SEEME if expression is a single ident, 
       
  2076 	       generate an error ? */
       
  2077 	    addError(new ParseException(ac.getMsg().getString("parser.semi-colon")),
       
  2078 		     (CssExpression) null);
       
  2079 	    rejectToken(semicolon);
       
  2080 	} else {
       
  2081 	    setValue(new CssIdent(), exp, operator, n, IDENT);
       
  2082 	}
       
  2083     }
       
  2084     | hexcolor(exp)
       
  2085     | n=<URL> { 
       
  2086 	CssURL _u = new CssURL();
       
  2087 	_u.set(n.image, ac, url);
       
  2088 	exp.addValue(_u);
       
  2089       }
       
  2090     | n=<UNICODERANGE> { setValue(new CssUnicodeRange(), exp, operator, n, 
       
  2091 				UNICODERANGE); }
       
  2092     ) ( <S> )* )
       
  2093 }
       
  2094 
       
  2095 /**
       
  2096  * @exception ParseException exception during the parse
       
  2097  */
       
  2098 CssValue function() :
       
  2099 {Token n;
       
  2100  CssExpression exp;
       
  2101  org.w3c.css.values.CssColor color = new org.w3c.css.values.CssColor();
       
  2102  org.w3c.css.values.ATSCColor colorATSC = new org.w3c.css.values.ATSCColor();
       
  2103 }
       
  2104 {
       
  2105     n=<FUNCTION> ( <S> )* exp=expr() 
       
  2106     ")" { 
       
  2107 	String funcname = n.image.toLowerCase();
       
  2108 	if (funcname.equals("rgb(")) {
       
  2109 	    if (!getAtRule().toString().equals("@media atsc-tv")) {
       
  2110 	       color.setRGBColor(exp, ac);
       
  2111 	       return color;
       
  2112             } else {
       
  2113 	       colorATSC.setRGBColor(exp, ac);
       
  2114 	       return colorATSC;
       
  2115             }
       
  2116 	} else if (n.image.toLowerCase().equals("atsc-rgba(")) {
       
  2117 	    if (getAtRule().toString().equals("@media atsc-tv")) {
       
  2118 	        colorATSC.setATSCrgba(exp, ac);
       
  2119 	        return colorATSC;
       
  2120 	    } else {
       
  2121 		addError(new InvalidParamException("onlyATSC", "", ac),
       
  2122 						 getAtRule().toString());
       
  2123 	        return null;
       
  2124 	    }
       
  2125 	} else {
       
  2126 	    CssFunction f = new CssFunction();
       
  2127 	    f.set(n.image.substring(0, n.image.length() - 1),
       
  2128 		  exp);
       
  2129 	    return f;
       
  2130 	}
       
  2131     }
       
  2132 }
       
  2133 
       
  2134 /**
       
  2135  * @exception ParseException exception during the parse
       
  2136  */
       
  2137 void hexcolor(CssExpression exp) :
       
  2138 {Token n; 
       
  2139 }
       
  2140 {
       
  2141     ( n=<HASHIDENT> | n=<HASH> ) { 
       
  2142      n.image = Util.strip(n.image);
       
  2143      setValue(new org.w3c.css.values.CssColor(), exp, ' ', n, HASH); 
       
  2144     }
       
  2145 }
       
  2146 
       
  2147 /*
       
  2148  * @@SEEME EOF
       
  2149  */
       
  2150 
       
  2151 JAVACODE
       
  2152 String skipStatement() {
       
  2153     StringBuilder s = new StringBuilder();
       
  2154     Token tok = getToken(0);
       
  2155     boolean first = true;
       
  2156 
       
  2157     if (tok.image != null) {
       
  2158 	s.append(tok.image);	
       
  2159     }
       
  2160     /* FIXME here, two option, we skip during an error, or outside
       
  2161        an error, currently both can fail with a TokenMgrError, should
       
  2162        we catch all, or only when filling message for errors? 
       
  2163        
       
  2164        -> taking the "always skip" approach.
       
  2165     */
       
  2166     while (true) {
       
  2167 	try {
       
  2168 	    tok = getToken(1);
       
  2169 	    if (tok.kind == EOF) {
       
  2170 		if (first) {
       
  2171 		    return null;
       
  2172 		} else {
       
  2173 		    break;
       
  2174 		}
       
  2175 	    } 
       
  2176 	    s.append(tok.image);
       
  2177 	    if (tok.kind == LBRACE) {
       
  2178 		getNextToken();
       
  2179 		s.append(skip_to_matching_brace());
       
  2180 		getNextToken();
       
  2181 		tok = getToken(1);
       
  2182 		break;
       
  2183 	    } else if ((tok.kind == RBRACE) || (tok.kind == SEMICOLON)) {
       
  2184 		getNextToken();
       
  2185 		tok = getToken(1);
       
  2186 		break;
       
  2187 	    }
       
  2188 	    getNextToken();
       
  2189 	} catch (TokenMgrError tokenerror) {
       
  2190 	    // read one char at a time, and loop
       
  2191 	    try {
       
  2192 	        s.append(jj_input_stream.readChar());
       
  2193 	        continue;
       
  2194             } catch (java.io.IOException ioex) { 
       
  2195 		return s.toString().trim();
       
  2196 	    }
       
  2197 	}
       
  2198 	first = false;
       
  2199     }
       
  2200     
       
  2201     // skip white space
       
  2202     while (tok.kind == S) {
       
  2203 	getNextToken();
       
  2204 	tok = getToken(1);
       
  2205     }
       
  2206     String statement = s.toString().trim();
       
  2207     return statement;
       
  2208 }
       
  2209 
       
  2210 JAVACODE
       
  2211 String skip_to_matching_brace() {
       
  2212     StringBuilder s = new StringBuilder();
       
  2213     Token tok;
       
  2214     int nesting = 1;
       
  2215     /* FIXME
       
  2216        same as above */
       
  2217     while (true) {
       
  2218 	tok = getToken(1);
       
  2219 	if (tok.kind == EOF) {
       
  2220 	    break;
       
  2221 	}
       
  2222 	s.append(tok.image);
       
  2223 	if (tok.kind == LBRACE) {
       
  2224 	    nesting++;
       
  2225 	} else if (tok.kind == RBRACE) {
       
  2226 	    nesting--;
       
  2227 	    if (nesting == 0) {
       
  2228 		break;
       
  2229 	    }
       
  2230 	}
       
  2231 	getNextToken();
       
  2232     }
       
  2233     return s.toString();
       
  2234 }
       
  2235 
       
  2236 /*
       
  2237  * @@HACK
       
  2238  * I can't insert a token into the tokens flow.
       
  2239  * It's jj_consume_token implementation dependant! :-(
       
  2240  */
       
  2241 JAVACODE
       
  2242 void rejectToken(Token t) {
       
  2243     Token fakeToken = new Token();
       
  2244     t.next = token;
       
  2245     fakeToken.next = t;
       
  2246     token = fakeToken;
       
  2247 }
       
  2248 
       
  2249 /** skip after an expression
       
  2250  */
       
  2251 JAVACODE
       
  2252 void skipAfterExpression(Exception e) {
       
  2253     StringBuilder s = new StringBuilder();
       
  2254     s.append(getToken(0).image);
       
  2255     while (true) {
       
  2256 	try {
       
  2257 	    Token t = getToken(1);
       
  2258 	    if (t.kind == LBRACE) {
       
  2259 		s.append(t.image);
       
  2260 		getNextToken();
       
  2261 		s.append(skip_to_matching_brace());
       
  2262 		getNextToken();
       
  2263 		t = getToken(1);
       
  2264 		continue;
       
  2265 	    }
       
  2266 	    if ((t.kind == SEMICOLON) || (t.kind == RBRACE) 
       
  2267 		                      || (t.kind == EOF)) {
       
  2268 		break;
       
  2269 	    }
       
  2270 	    s.append(t.image);
       
  2271 	    getNextToken();
       
  2272 	    t = getToken(1);
       
  2273 	} catch (TokenMgrError tmerr) {
       
  2274 	    try {
       
  2275 		s.append(jj_input_stream.readChar());
       
  2276 	        continue;
       
  2277 	    } catch (java.io.IOException ioex) { 
       
  2278 		ioex.printStackTrace();
       
  2279 		break;
       
  2280 	    }
       
  2281 	}
       
  2282     }
       
  2283     String statement = s.toString().trim();
       
  2284     addError(e, s.toString()); 
       
  2285 }
       
  2286 
       
  2287 JAVACODE
       
  2288 String convertStringIndex(String s, int start, int len, boolean escapeFirst) {
       
  2289     int index = start;
       
  2290     int t;
       
  2291     int maxCount = 0;
       
  2292     if ((start == 0) && (len == s.length()) && (s.indexOf('\\') == -1)) {
       
  2293 	return s;
       
  2294     }
       
  2295     StringBuilder buf = new StringBuilder(len);
       
  2296 
       
  2297     while (index < len) {
       
  2298 	char c = s.charAt(index);
       
  2299 	if (c == '\\') {
       
  2300 	    if (++index < len) {
       
  2301 		c = s.charAt(index);
       
  2302 		switch (c) {
       
  2303 		case '0': case '1': case '2': case '3': case '4':
       
  2304 		case '5': case '6': case '7': case '8': case '9':
       
  2305 		case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
       
  2306 		case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
       
  2307 		    int numValue = Character.digit(c, 16);
       
  2308 		    int count = 1;
       
  2309 		    if (maxCount == 0) {
       
  2310 			maxCount = (ac.getCssVersion().equals("css1") ? 
       
  2311 				    4 : 6);
       
  2312 		    }
       
  2313 		    while (index + 1 < len) {
       
  2314 			c = s.charAt(index+1);
       
  2315 			t = Character.digit(c, 16);
       
  2316 			if (t != -1 && count++ < maxCount) {
       
  2317 			    numValue = (numValue<<4) | t;
       
  2318 			    index++;
       
  2319 			} else {
       
  2320 			    if (c == ' ' || c == '\t' || 
       
  2321 				c == '\n' || c == '\f' ) {
       
  2322 				// skip the latest white space
       
  2323 				index++;
       
  2324 			    } else if ( c == '\r' ) {
       
  2325 				index++;
       
  2326 				// special case for \r\n
       
  2327 				if (index+1 < len) {
       
  2328 				    if (s.charAt(index + 1) == '\n') {
       
  2329 					index++;
       
  2330 				    }
       
  2331 				}
       
  2332 			    }
       
  2333 			    break;
       
  2334 			}
       
  2335 		    }
       
  2336 		    if (!escapeFirst && numValue < 255 && numValue>31) { 
       
  2337 			if (! ( (numValue>96 && numValue<123) // [a-z]
       
  2338 				|| (numValue>64 && numValue<91) // [A-Z]
       
  2339 				|| (numValue>47 && numValue<58) // [0-9]
       
  2340 				|| (numValue == 95) // _
       
  2341 				|| (numValue == 45) // -
       
  2342 				)
       
  2343 			    ) {
       
  2344 			    buf.append('\\');
       
  2345 			}
       
  2346 			buf.append((char) numValue);
       
  2347 			break;
       
  2348 		    }
       
  2349 		    char b[] = new char[maxCount];
       
  2350 		    t = maxCount;
       
  2351 		    while (t > 0) {
       
  2352 			b[--t] = hexdigits[numValue & 0xF];
       
  2353 			numValue >>>= 4;
       
  2354 		    }
       
  2355 		    buf.append('\\').append(b);
       
  2356 		    break;
       
  2357 		case '\n':
       
  2358 		case '\f':
       
  2359 		    break;
       
  2360 		case '\r':
       
  2361 		    if (index + 1 < len) {
       
  2362 			if (s.charAt(index + 1) == '\n') {
       
  2363 			    index ++;
       
  2364 			}
       
  2365 		    }
       
  2366 		    break;
       
  2367 		case '-' : case '_' : case 'g' : case 'G' :
       
  2368 		case 'h' : case 'H' : case 'i' : case 'I' :
       
  2369 		case 'j' : case 'J' : case 'k' : case 'K' :
       
  2370 		case 'l' : case 'L' : case 'm' : case 'M' :
       
  2371 		case 'n' : case 'N' : case 'o' : case 'O' :
       
  2372 		case 'p' : case 'P' : case 'q' : case 'Q' :
       
  2373 		case 'r' : case 'R' : case 's' : case 'S' :
       
  2374 		case 't' : case 'T' : case 'u' : case 'U' :
       
  2375 		case 'v' : case 'V' : case 'w' : case 'W' :
       
  2376 		case 'x' : case 'X' : case 'y' : case 'Y' :
       
  2377 		case 'z' : case 'Z' : 
       
  2378 		    buf.append(c);
       
  2379 		    break;
       
  2380 		default:
       
  2381 		    buf.append('\\').append(c);
       
  2382 		}
       
  2383 	    } else {
       
  2384 		throw new ParseException("invalid string");
       
  2385 	    }
       
  2386 	} else {
       
  2387 	    buf.append(c);
       
  2388 	}
       
  2389 	escapeFirst = false;
       
  2390 	index++;
       
  2391     }
       
  2392     return buf.toString();
       
  2393 }
       
  2394 
       
  2395 JAVACODE
       
  2396 String convertIdent(String s) {
       
  2397     return convertStringIndex(s, 0, s.length(), false);
       
  2398 }
       
  2399 
       
  2400 JAVACODE
       
  2401 String convertClassIdent(String s) {
       
  2402     return convertStringIndex(s, 0, s.length(), true);
       
  2403 }
       
  2404 
       
  2405 JAVACODE
       
  2406 String convertString(String s) {
       
  2407     return convertStringIndex(s, 0, s.length(), false);
       
  2408 }
       
  2409 
       
  2410 JAVACODE 
       
  2411 String hexEscapeFirst(String s) {
       
  2412     StringBuilder sb = new StringBuilder();
       
  2413     sb.append('\\').append(Integer.toString(s.charAt(0), 16));
       
  2414     char c = s.charAt(1);
       
  2415     if (((c >= '0') && (c <= '9')) || 
       
  2416 	((c >= 'A') && (c <= 'F')) ||
       
  2417 	((c >= 'a') && (c <= 'f'))) {
       
  2418 	sb.append(' ');
       
  2419     }
       
  2420     sb.append(s.substring(1));
       
  2421     return sb.toString();
       
  2422 }
       
  2423 /*
       
  2424  * compile-command: javacc CssParser.jj & jc CssParser.java
       
  2425  */