Skip to content

Instantly share code, notes, and snippets.

@niloc132
Created June 4, 2019 15:49
Show Gist options
  • Save niloc132/91ef3a7573f896323eeb82d7123282f5 to your computer and use it in GitHub Desktop.
Save niloc132/91ef3a7573f896323eeb82d7123282f5 to your computer and use it in GitHub Desktop.
/* -*-java-extended-*-
* Copyright (c) 1999 World Wide Web Consortium
* (Massachusetts Institute of Technology, Institut National de Recherche
* en Informatique et en Automatique, Keio University).
* All Rights Reserved. http://www.w3.org/Consortium/Legal/
*
* $Id: Parser.jj,v 1.15 2000/10/27 21:09:37 plehegar Exp $
*/
options {
IGNORE_CASE = true;
STATIC = false;
USER_CHAR_STREAM = true;
/* DEBUG_TOKEN_MANAGER = true;
DEBUG_PARSER = true; */
}
PARSER_BEGIN(Parser)
package org.w3c.flute.parser;
import java.io.*;
import java.net.*;
import java.util.Locale;
import org.w3c.css.sac.ConditionFactory;
import org.w3c.css.sac.Condition;
import org.w3c.css.sac.SelectorFactory;
import org.w3c.css.sac.SelectorList;
import org.w3c.css.sac.Selector;
import org.w3c.css.sac.SimpleSelector;
import org.w3c.css.sac.DocumentHandler;
import org.w3c.css.sac.InputSource;
import org.w3c.css.sac.ErrorHandler;
import org.w3c.css.sac.CSSException;
import org.w3c.css.sac.CSSParseException;
import org.w3c.css.sac.Locator;
import org.w3c.css.sac.LexicalUnit;
import org.w3c.flute.parser.selectors.SelectorFactoryImpl;
import org.w3c.flute.parser.selectors.ConditionFactoryImpl;
import org.w3c.flute.util.Encoding;
/**
* A CSS2 parser
*
* @author Philippe Le HÈgaret
* @version $Revision: 1.15 $
*/
public class Parser implements org.w3c.css.sac.Parser {
// replaces all \t, \n, etc with this StringBuffer.
static final StringBuffer SPACE = new StringBuffer(" ");
// the document handler for the parser
protected DocumentHandler documentHandler;
// the error handler for the parser
protected ErrorHandler errorHandler;
// the input source for the parser
protected InputSource source;
protected ConditionFactory conditionFactory;
protected SelectorFactory selectorFactory;
// temporary place holder for pseudo-element ...
private String pseudoElt;
/**
* Creates a new Parser
*/
public Parser() {
this((CharStream) null);
}
/**
* @@TODO
* @exception CSSException Not yet implemented
*/
public void setLocale(Locale locale) throws CSSException {
throw new CSSException(CSSException.SAC_NOT_SUPPORTED_ERR);
}
/**
* Set the document handler for this parser
*/
public void setDocumentHandler(DocumentHandler handler) {
this.documentHandler = handler;
}
public void setSelectorFactory(SelectorFactory selectorFactory) {
this.selectorFactory = selectorFactory;
}
public void setConditionFactory(ConditionFactory conditionFactory) {
this.conditionFactory = conditionFactory;
}
/**
* Set the error handler for this parser
*/
public void setErrorHandler(ErrorHandler error) {
this.errorHandler = error;
}
/**
* Main parse methods
*
* @param source the source of the style sheet.
* @exception IOException the source can't be parsed.
* @exception CSSException the source is not CSS valid.
*/
public void parseStyleSheet(InputSource source)
throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
if (selectorFactory == null) {
selectorFactory = new SelectorFactoryImpl();
}
if (conditionFactory == null) {
conditionFactory = new ConditionFactoryImpl();
}
parserUnit();
}
/**
* Convenient method for URIs.
*
* @param systemId the fully resolved URI of the style sheet.
* @exception IOException the source can't be parsed.
* @exception CSSException the source is not CSS valid.
*/
public void parseStyleSheet(String systemId)
throws CSSException, IOException {
parseStyleSheet(new InputSource(systemId));
}
/**
* This method parses only one rule (style rule or at-rule, except @charset).
*
* @param source the source of the rule.
* @exception IOException the source can't be parsed.
* @exception CSSException the source is not CSS valid.
*/
public void parseRule(InputSource source)
throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
if (selectorFactory == null) {
selectorFactory = new SelectorFactoryImpl();
}
if (conditionFactory == null) {
conditionFactory = new ConditionFactoryImpl();
}
_parseRule();
}
/**
* This method parses a style declaration (including the surrounding curly
* braces).
*
* @param source the source of the style declaration.
* @exception IOException the source can't be parsed.
* @exception CSSException the source is not CSS valid.
*/
public void parseStyleDeclaration(InputSource source)
throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
if (selectorFactory == null) {
selectorFactory = new SelectorFactoryImpl();
}
if (conditionFactory == null) {
conditionFactory = new ConditionFactoryImpl();
}
_parseDeclarationBlock();
}
/**
* This methods returns "http://www.w3.org/TR/REC-CSS2".
* @return the string "http://www.w3.org/TR/REC-CSS2".
*/
public String getParserVersion() {
return "http://www.w3.org/TR/REC-CSS2";
}
/**
* Parse methods used by DOM Level 2 implementation.
*/
public void parseImportRule(InputSource source)
throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
if (selectorFactory == null) {
selectorFactory = new SelectorFactoryImpl();
}
if (conditionFactory == null) {
conditionFactory = new ConditionFactoryImpl();
}
_parseImportRule();
}
public void parseMediaRule(InputSource source)
throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
if (selectorFactory == null) {
selectorFactory = new SelectorFactoryImpl();
}
if (conditionFactory == null) {
conditionFactory = new ConditionFactoryImpl();
}
_parseMediaRule();
}
public SelectorList parseSelectors(InputSource source)
throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
if (selectorFactory == null) {
selectorFactory = new SelectorFactoryImpl();
}
if (conditionFactory == null) {
conditionFactory = new ConditionFactoryImpl();
}
return _parseSelectors();
}
public LexicalUnit parsePropertyValue(InputSource source)
throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
return expr();
}
public boolean parsePriority(InputSource source)
throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
return prio();
}
/**
* Convert the source into a Reader. Used only by DOM Level 2 parser methods.
*/
private Reader getReader(InputSource source) throws IOException {
if (source.getCharacterStream() != null) {
return source.getCharacterStream();
} else if (source.getByteStream() != null) {
// My DOM level 2 implementation doesn't use this case.
if (source.getEncoding() == null) {
// unknown encoding, use ASCII as default.
return new InputStreamReader(source.getByteStream(), "ASCII");
} else {
return new InputStreamReader(source.getByteStream(),
source.getEncoding());
}
} else {
// systemId
// @@TODO
throw new CSSException("not yet implemented");
}
}
/**
* Convert the source into a CharStream with encoding informations.
* The encoding can be found in the InputSource or in the CSS document.
* Since this method marks the reader and make a reset after looking for
* the charset declaration, you'll find the charset declaration into the
* stream.
*/
private CharStream getCharStreamWithLurk(InputSource source)
throws CSSException, IOException {
if (source.getCharacterStream() != null) {
// all encoding are supposed to be resolved by the user
// return the reader
return new Generic_CharStream(source.getCharacterStream(), 1, 1);
} else if (source.getByteStream() == null) {
// @@CONTINUE ME. see also getReader() with systemId
try {
source.setByteStream(new URL(source.getURI()).openStream());
} catch (Exception e) {
try {
source.setByteStream(new FileInputStream(source.getURI()));
} catch (IOException ex) {
throw new CSSException("invalid url ?");
}
}
}
String encoding = "ASCII";
InputStream input = source.getByteStream();
char c = ' ';
if (!input.markSupported()) {
input = new BufferedInputStream(input);
source.setByteStream(input);
}
input.mark(100);
c = (char) input.read();
if (c == '@') {
// hum, is it a charset ?
int size = 100;
byte[] buf = new byte[size];
input.read(buf, 0, 7);
String keyword = new String(buf, 0, 7);
if (keyword.equals("charset")) {
// Yes, this is the charset declaration !
// here I don't use the right declaration : white space are ' '.
while ((c = (char) input.read()) == ' ') {
// find the first quote
}
char endChar = c;
int i = 0;
if ((endChar != '"') && (endChar != '\'')) {
// hum this is not a quote.
throw new CSSException("invalid charset declaration");
}
while ((c = (char) input.read()) != endChar) {
buf[i++] = (byte) c;
if (i == size) {
byte[] old = buf;
buf = new byte[size + 100];
System.arraycopy(old, 0, buf, 0, size);
size += 100;
}
}
while ((c = (char) input.read()) == ' ') {
// find the next relevant character
}
if (c != ';') {
// no semi colon at the end ?
throw new CSSException("invalid charset declaration: "
+ "missing semi colon");
}
encoding = new String(buf, 0, i);
if (source.getEncoding() != null) {
// compare the two encoding informations.
// For example, I don't accept to have ASCII and after UTF-8.
// Is it really good ? That is the question.
if (!encoding.equals(source.getEncoding())) {
throw new CSSException("invalid encoding information.");
}
}
} // else no charset declaration available
}
// ok set the real encoding of this source.
source.setEncoding(encoding);
// set the real reader of this source.
source.setCharacterStream(new InputStreamReader(source.getByteStream(),
Encoding.getJavaEncoding(encoding)));
// reset the stream (leave the charset declaration in the stream).
input.reset();
return new Generic_CharStream(source.getCharacterStream(), 1, 1);
}
private LocatorImpl currentLocator;
private Locator getLocator() {
if (currentLocator == null) {
currentLocator = new LocatorImpl(this);
return currentLocator;
}
return currentLocator.reInit(this);
}
private LocatorImpl getLocator(Token save) {
if (currentLocator == null) {
currentLocator = new LocatorImpl(this, save);
return currentLocator;
}
return currentLocator.reInit(this, save);
}
private void reportError(Locator l, Exception e) {
if (errorHandler != null) {
if (e instanceof ParseException) {
// construct a clean error message.
ParseException pe = (ParseException) e;
if (pe.specialConstructor) {
StringBuffer errorM = new StringBuffer();
if (pe.currentToken != null) {
errorM.append("encountered \"")
.append(pe.currentToken.next);
}
errorM.append('"');
if (pe.expectedTokenSequences.length != 0) {
errorM.append(". Was expecting one of: ");
for (int i = 0; i < pe.expectedTokenSequences.length; i++) {
for (int j = 0; j < pe.expectedTokenSequences[i].length; j++) {
int kind = pe.expectedTokenSequences[i][j];
if (kind != S) {
errorM.append(pe.tokenImage[kind]);
errorM.append(' ');
}
}
}
}
errorHandler.error(new CSSParseException(errorM.toString(),
l, e));
} else {
errorHandler.error(new CSSParseException(e.getMessage(),
l, e));
}
} else if (e == null) {
errorHandler.error(new CSSParseException("error", l, null));
} else {
errorHandler.error(new CSSParseException(e.getMessage(), l, e));
}
}
}
private void reportWarningSkipText(Locator l, String text) {
if (errorHandler != null && text != null) {
errorHandler.warning(new CSSParseException("Skipping: " + text, l));
}
}
}
PARSER_END(Parser)
/*
* The tokenizer
*/
<DEFAULT>
TOKEN :
{
< S : ( [ " ", "\t" , "\n" , "\r", "\f" ] )+ >
{ image = Parser.SPACE; }
}
<DEFAULT>
MORE : /* Comments */
{
< "/*" > : IN_COMMENT
}
<IN_COMMENT>
SKIP :
{
< "*/" > : DEFAULT
}
<IN_COMMENT>
MORE :
{
< ~[] > : IN_COMMENT
}
<DEFAULT>
TOKEN :
{
< CDO : "<!--" >
| < CDC : "-->" >
| < LBRACE : "{" >
| < RBRACE : "}">
| < DASHMATCH : "|=" >
| < INCLUDES : "~=" >
| < EQ : "=" >
| < PLUS : "+" >
| < MINUS : "-" >
| < COMMA : "," >
| < SEMICOLON : ";" >
| < PRECEDES : ">" >
| < DIV : "/" >
| < LBRACKET : "[" >
| < RBRACKET : "]" >
| < ANY : "*" >
| < DOT : "." >
| < LPARAN : ")" >
| < RPARAN : "(">
}
<DEFAULT>
TOKEN :
{
< COLON : ":" >
}
<DEFAULT>
TOKEN : /* basic tokens */
{
< NONASCII : ["\200"-"\377"] >
| < #H : ["0"-"9", "a"-"f"] >
| < #UNICODE : "\\" <H> ( <H> )? /* I can't say {1,6} */
( <H> )? ( <H> )?
( <H> )? ( <H> )?
( [ " ", "\t" , "\n" , "\r", "\f" ] )? >
| < #ESCAPE : <UNICODE> | ( "\\" [ " "-"~","\200"-"\377" ] ) >
| < #NMSTART : [ "a"-"z", "_" ] | <NONASCII> | <ESCAPE> >
| < #NMCHAR : ["a"-"z", "0"-"9", "-", "_"] | <NONASCII> | <ESCAPE> >
| < #STRINGCHAR : [ "\t"," ","!","#","$","%","&","("-"~" ]
| "\\\n" | "\\\r\n" | "\\\r" | "\\\f"
| <NONASCII> | <ESCAPE> >
| < #D : ["0"-"9"] >
| < #NAME : ( <NMCHAR> )+ >
}
<DEFAULT>
TOKEN :
{
< STRING : ( "\"" ( <STRINGCHAR> | "'" )* "\"" ) |
( "'" ( <STRINGCHAR> | "\"" )* "'" ) >
| < IDENT : ("-")? <NMSTART> ( <NMCHAR> )* >
| < NUMBER : ( <D> )+ | ( <D> )* "." ( <D> )+ >
| < #_URL : [ "!","#","$","%","&","*"-"~" ] | <NONASCII> | <ESCAPE> >
| < URL : "url(" ( <S> )*
( <STRING> | ( <_URL> )* ) ( <S> )* ")" >
}
<DEFAULT>
TOKEN :
{
< PERCENTAGE : <NUMBER> "%" >
| < PT : <NUMBER> "pt" >
| < MM : <NUMBER> "mm" >
| < CM : <NUMBER> "cm" >
| < PC : <NUMBER> "pc" >
| < IN : <NUMBER> "in" >
| < PX : <NUMBER> "px" >
| < EMS : <NUMBER> "em" >
| < EXS : <NUMBER> "ex" >
| < DEG : <NUMBER> "deg" >
| < RAD : <NUMBER> "rad" >
| < GRAD : <NUMBER> "grad" >
| < MS : <NUMBER> "ms" >
| < SECOND : <NUMBER> "s" >
| < HZ : <NUMBER> "Hz" >
| < KHZ : <NUMBER> "kHz" >
| < DIMEN : <NUMBER> <IDENT> >
}
<DEFAULT>
TOKEN :
{
< HASH : "#" <NAME> >
}
/* RESERVED ATRULE WORDS */
<DEFAULT>
TOKEN :
{
< IMPORT_SYM : "@import">
| < MEDIA_SYM : "@media" >
| < CHARSET_SYM : "@charset" >
| < PAGE_SYM : "@page" >
| < FONT_FACE_SYM: "@font-face" >
| < ATKEYWORD : "@" <IDENT> >
}
<DEFAULT>
TOKEN :
{
< IMPORTANT_SYM : "!" ( <S> )? "important" >
}
<DEFAULT>
TOKEN :
{
< #RANGE0 : <H> <H> <H> <H> <H> >
| < #RANGE1 : <H> <H> <H> <H> <H> ( "?" )? >
| < #RANGE2 : <H> <H> <H> <H> ( "?" )? ( "?" )? >
| < #RANGE3 : <H> <H> <H> ( "?" )? ( "?" )? ( "?" )? >
| < #RANGE4 : <H> <H> ( "?" )? ( "?" )? ( "?" )? ( "?" )? >
| < #RANGE5 : <H> ( "?" )? ( "?" )? ( "?" )? ( "?" )? ( "?" )? >
| < #RANGE6 : "?" ( "?" )? ( "?" )? ( "?" )? ( "?" )? ( "?" )? >
| < #RANGE : <RANGE0> | <RANGE1> | <RANGE2>
| <RANGE3> | <RANGE4> | <RANGE5> | <RANGE6> >
| < #UNI : <H> ( <H> )? ( <H> )? ( <H> )? ( <H> )? ( <H> )? >
| < UNICODERANGE : "U+" <RANGE>
| "U+" <UNI> "-" <UNI> >
}
<DEFAULT>
TOKEN :
{
< FUNCTION : <IDENT> "(" >
}
<DEFAULT, IN_COMMENT>
TOKEN :
{ /* avoid token manager error */
< UNKNOWN : ~[] >
}
/*
* The grammar of CSS2
*/
/**
* The main entry for the parser.
*
* @exception ParseException exception during the parse
*/
void parserUnit() :
{}
{
try {
{ documentHandler.startDocument(source); }
( charset() )?
( <S> | ignoreStatement() )*
( importDeclaration() ( ignoreStatement() ( <S> )* )* )*
afterImportDeclaration()
<EOF>
} finally {
documentHandler.endDocument(source);
}
}
void charset() :
{ Token n; }
{
try {
<CHARSET_SYM> ( <S> )* n=<STRING> ( <S> )* ";"
} catch (ParseException e) {
reportError(getLocator(e.currentToken.next), e);
skipStatement();
// reportWarningSkipText(getLocator(), skipStatement());
} catch (Exception e) {
reportError(getLocator(), e);
skipStatement();
// reportWarningSkipText(getLocator(), skipStatement());
}
}
void afterImportDeclaration() :
{String ret;
Locator l;
}
{
( ( styleRule() | media() | page() | fontFace()
| { l = getLocator(); } ret=skipStatement()
{
if ((ret == null) || (ret.length() == 0)) {
return;
}
reportWarningSkipText(l, ret);
if (ret.charAt(0) == '@') {
documentHandler.ignorableAtRule(ret);
}
}
)
( ignoreStatement() ( <S> )* )* )*
}
void ignoreStatement() :
{}
{
<CDO> | <CDC> | atRuleDeclaration()
}
/**
* The import statement
*
* @exception ParseException exception during the parse
*/
void importDeclaration() :
{Token n;
String uri;
MediaListImpl ml = new MediaListImpl();
}
{
try {
<IMPORT_SYM>
( <S> )* ( n=<STRING> { uri = convertStringIndex(n.image, 1,
n.image.length() -1); }
| n=<URL>
{
uri = n.image.substring(4, n.image.length()-1).trim();
if ((uri.charAt(0) == '"')
|| (uri.charAt(0) == '\'')) {
uri = uri.substring(1, uri.length()-1);
}
}
)
( <S> )* ( mediaStatement(ml) )? ";"
( <S> )*
{
if (ml.getLength() == 0) {
// see section 6.3 of the CSS2 recommandation.
ml.addItem("all");
}
documentHandler.importStyle(uri, ml, null);
}
} catch (ParseException e) {
reportError(getLocator(), e);
skipStatement();
// reportWarningSkipText(getLocator(), skipStatement());
}
}
/**
* @exception ParseException exception during the parse
*/
void media() :
{
boolean start = false;
String ret;
MediaListImpl ml = new MediaListImpl();
}
{
try {
<MEDIA_SYM> ( <S> )*
mediaStatement(ml)
{ start = true; documentHandler.startMedia(ml); }
<LBRACE> ( <S> )* ( styleRule() | skipUnknownRule() )* <RBRACE> ( <S> )*
} catch (ParseException e) {
reportError(getLocator(), e);
skipStatement();
// reportWarningSkipText(getLocator(), skipStatement());
} finally {
if (start) {
documentHandler.endMedia(ml);
}
}
}
void mediaStatement(MediaListImpl ml) :
{
String m;
}
{
m=medium() ( <COMMA> ( <S> )* { ml.addItem(m); } m=medium() )*
{ ml.addItem(m); }
}
/**
* @exception ParseException exception during the parse
*/
String medium() : /* tv, projection, screen, ... */
{Token n;}
{
n=<IDENT> ( <S> )* { return convertIdent(n.image); }
}
/**
* @exception ParseException exception during the parse
*/
void page() :
{
boolean start = false;
Token n = null;
String page = null;
String pseudo = null;
}
{
try {
<PAGE_SYM> ( <S> )* ( n=<IDENT> ( <S> )* )?
( pseudo=pseudo_page() )?
{
if (n != null) {
page = convertIdent(n.image);
}
}
<LBRACE> (<S>)*
{
start = true;
documentHandler.startPage(page, pseudo);
}
( declaration() )? ( ";" ( <S> )* ( declaration() )? )*
<RBRACE> (<S>)*
} catch (ParseException e) {
if (errorHandler != null) {
LocatorImpl li = new LocatorImpl(this,
e.currentToken.next.beginLine,
e.currentToken.next.beginColumn-1);
reportError(li, e);
skipStatement();
// reportWarningSkipText(li, skipStatement());
} else {
skipStatement();
}
} finally {
if (start) {
documentHandler.endPage(page, pseudo);
}
}
}
String pseudo_page() :
{ Token n; }
{
":" n=<IDENT> ( <S> )* { return convertIdent(n.image); }
}
void fontFace() :
{
boolean start = false;
}
{
try {
<FONT_FACE_SYM> ( <S> )*
<LBRACE> (<S>)*
{ start = true; documentHandler.startFontFace(); }
( declaration() )? ( ";" ( <S> )* ( declaration() )? )*
<RBRACE> (<S>)*
} catch (ParseException e) {
reportError(getLocator(), e);
skipStatement();
// reportWarningSkipText(getLocator(), skipStatement());
} finally {
if (start) {
documentHandler.endFontFace();
}
}
}
/**
* @exception ParseException exception during the parse
*/
void atRuleDeclaration() :
{Token n;
String ret;
}
{
n=<ATKEYWORD>
{
ret=skipStatement();
reportWarningSkipText(getLocator(), ret);
if ((ret != null) && (ret.charAt(0) == '@')) {
documentHandler.ignorableAtRule(ret);
}
}
}
void skipUnknownRule() :
{ Token n;}
{
( n=<ATKEYWORD>
| n=<CDO>
| n=<CHARSET_SYM>
| n=<COMMA>
| n=<DASHMATCH>
| n=<FONT_FACE_SYM>
| n=<FUNCTION>
| n=<IMPORTANT_SYM>
| n=<IMPORT_SYM>
| n=<INCLUDES>
| n=<LBRACE>
| n=<MEDIA_SYM>
| n=<NONASCII>
| n=<NUMBER>
| n=<PAGE_SYM>
| n=<PERCENTAGE>
| n=<STRING>
| n=<UNICODERANGE>
| n=<URL>
| n=";"
| n="+"
| n=">"
| n="-"
| n=<UNKNOWN>
) {
String ret;
Locator loc = getLocator();
ret=skipStatement();
reportWarningSkipText(loc, ret);
if ((ret != null) && (n.image.charAt(0) == '@')) {
documentHandler.ignorableAtRule(ret);
}
}
}
/**
* @exception ParseException exception during the parse
*/
char combinator() :
{
char connector = ' ';
}
{
"+" ( <S> )* { return '+'; }
| ">" ( <S> )* { return '>'; }
| <S> ( ( "+" { connector = '+'; }
| ">" { connector = '>'; } )
( <S> )* )? { return connector; }
}
/**
* @exception ParseException exception during the parse
*/
String property() :
{Token n; }
{
n=<IDENT> ( <S> )* { return convertIdent(n.image); }
}
/**
* @exception ParseException exception during the parse
*/
void styleRule() :
{
boolean start = false;
SelectorList l = null;
Token save;
Locator loc;
}
{
try {
l=selectorList() { save = token; } <LBRACE> (<S>)*
{
start = true;
documentHandler.startSelector(l);
}
( declaration() )? ( ";" ( <S> )* ( declaration() )? )*
<RBRACE> (<S>)*
} catch (ThrowedParseException e) {
if (errorHandler != null) {
LocatorImpl li = new LocatorImpl(this,
e.e.currentToken.next.beginLine,
e.e.currentToken.next.beginColumn-1);
reportError(li, e.e);
}
} catch (ParseException e) {
reportError(getLocator(), e);
skipStatement();
// reportWarningSkipText(getLocator(), skipStatement());
} catch (TokenMgrError e) {
reportWarningSkipText(getLocator(), skipStatement());
} finally {
if (start) {
documentHandler.endSelector(l);
}
}
}
SelectorList selectorList() :
{
SelectorListImpl selectors = new SelectorListImpl();
Selector selector;
}
{
selector=selector() ( <COMMA> (<S>)* { selectors.addSelector(selector); }
selector=selector() )*
{ selectors.addSelector(selector);
return selectors;
}
}
/**
* @exception ParseException exception during the parse
*/
Selector selector() :
{
Selector selector;
char comb;
}
{
try {
selector=simple_selector(null, ' ')
( LOOKAHEAD(2) comb=combinator()
selector=simple_selector(selector, comb) )* (<S>)*
{
return selector;
}
} catch (ParseException e) {
/*
Token t = getToken(1);
StringBuffer s = new StringBuffer();
s.append(getToken(0).image);
while ((t.kind != COMMA) && (t.kind != SEMICOLON)
&& (t.kind != LBRACE) && (t.kind != EOF)) {
s.append(t.image);
getNextToken();
t = getToken(1);
}
reportWarningSkipText(getLocator(), s.toString());
*/
Token t = getToken(1);
while ((t.kind != COMMA) && (t.kind != SEMICOLON)
&& (t.kind != LBRACE) && (t.kind != EOF)) {
getNextToken();
t = getToken(1);
}
throw new ThrowedParseException(e);
}
}
/**
* @exception ParseException exception during the parse
*/
Selector simple_selector(Selector selector, char comb) :
{
SimpleSelector simple_current = null;
Condition cond = null;
pseudoElt = null;
}
{
( simple_current=element_name()
( cond=hash(cond) | cond=_class(cond)
| cond=attrib(cond) | cond=pseudo(cond) )*
| cond=hash(cond) ( cond=_class(cond)
| cond=attrib(cond) | cond=pseudo(cond) )*
| cond=_class(cond) ( cond=hash(cond) | cond=_class(cond)
| cond=attrib(cond) | cond=pseudo(cond) )*
| cond=pseudo(cond) ( cond=hash(cond) | cond=_class(cond)
| cond=attrib(cond) | cond=pseudo(cond) )*
| cond=attrib(cond) ( cond=hash(cond) | cond=_class(cond)
| cond=attrib(cond) | cond=pseudo(cond) )*
)
{
if (simple_current == null) {
simple_current = selectorFactory.createElementSelector(null, null);
}
if (cond != null) {
simple_current = selectorFactory.createConditionalSelector(simple_current,
cond);
}
if (selector != null) {
switch (comb) {
case ' ':
selector = selectorFactory.createDescendantSelector(selector,
simple_current);
break;
case '+':
selector =
selectorFactory.createDirectAdjacentSelector((short) 1,
selector,
simple_current);
break;
case '>':
selector = selectorFactory.createChildSelector(selector,
simple_current);
break;
default:
throw new ParseException("invalid state. send a bug report");
}
} else {
selector= simple_current;
}
if (pseudoElt != null) {
selector = selectorFactory.createChildSelector(selector,
selectorFactory.createPseudoElementSelector(null, pseudoElt));
}
return selector;
}
}
/**
* @exception ParseException exception during the parse
*/
Condition _class(Condition pred) :
{Token n;
Condition c;
}
{
"." n=<IDENT>
{
c = conditionFactory.createClassCondition(null, n.image);
if (pred == null) {
return c;
} else {
return conditionFactory.createAndCondition(pred, c);
}
}
}
/**
* @exception ParseException exception during the parse
*/
SimpleSelector element_name() :
{Token n; }
{
n=<IDENT>
{
return selectorFactory.createElementSelector(null, convertIdent(n.image));
}
| "*"
{ return selectorFactory.createElementSelector(null, null); }
}
/**
* @exception ParseException exception during the parse
*/
Condition attrib(Condition pred) :
{
int cases = 0;
Token att = null;
Token val = null;
String attValue = null;
}
{
"[" ( <S> )* att=<IDENT> ( <S> )*
( ( "=" { cases = 1; }
| <INCLUDES> { cases = 2; }
| <DASHMATCH> { cases = 3; } ) ( <S> )*
( val=<IDENT> { attValue = val.image; }
| val=<STRING> { attValue = convertStringIndex(val.image, 1,
val.image.length() -1);}
)
( <S> )* )?
"]"
{
String name = convertIdent(att.image);
Condition c;
switch (cases) {
case 0:
c = conditionFactory.createAttributeCondition(name, null, false, null);
break;
case 1:
c = conditionFactory.createAttributeCondition(name, null, false,
attValue);
break;
case 2:
c = conditionFactory.createOneOfAttributeCondition(name, null, false,
attValue);
break;
case 3:
c = conditionFactory.createBeginHyphenAttributeCondition(name, null,
false,
attValue);
break;
default:
// never reached.
c = null;
}
if (pred == null) {
return c;
} else {
return conditionFactory.createAndCondition(pred, c);
}
}
}
/**
* @exception ParseException exception during the parse
*/
Condition pseudo(Condition pred) :
{Token n; Token t1 = null;
Token language;
}
{
":" [(t1 = <COLON>)] ( n=<IDENT>
{
String prefix = (t1 != null) ? ":" : "";
String s = prefix + convertIdent(n.image);
if (s.equals("first-letter") || s.equals("first-line")) {
if (pseudoElt != null) {
throw new CSSParseException("duplicate pseudo element definition "
+ s, getLocator());
} else {
pseudoElt = s;
return pred;
}
} else {
Condition c =
conditionFactory.createPseudoClassCondition(null, s);
if (pred == null) {
return c;
} else {
return conditionFactory.createAndCondition(pred, c);
}
}
}
| ( n=<FUNCTION> ( <S> )* language=<IDENT> ( <S> )* ")"
{
String f = convertIdent(n.image);
if (f.equals("lang(")) {
Condition d =
conditionFactory.createLangCondition(convertIdent(language.image));
if (pred == null) {
return d;
} else {
return conditionFactory.createAndCondition(pred, d);
}
} else {
throw new CSSParseException("invalid pseudo function name "
+ f, getLocator());
}
}
)
)
}
/**
* @exception ParseException exception during the parse
*/
Condition hash(Condition pred) :
{Token n; }
{
n=<HASH>
{
Condition d =
conditionFactory.createIdCondition(n.image.substring(1));
if (pred == null) {
return d;
} else {
return conditionFactory.createAndCondition(pred, d);
}
}
}
/**
* @exception ParseException exception during the parse
*/
void declaration() :
{ boolean important = false;
String name;
LexicalUnit exp;
Token save;
}
{
try {
name=property()
{ save = token; }
":" ( <S> )* exp=expr() ( important=prio() )?
{
documentHandler.property(name, exp, important);
}
} catch (JumpException e) {
skipAfterExpression();
// reportWarningSkipText(getLocator(), skipAfterExpression());
} catch (NumberFormatException e) {
if (errorHandler != null) {
errorHandler.error(new CSSParseException("Invalid number "
+ e.getMessage(),
getLocator(),
e));
}
reportWarningSkipText(getLocator(), skipAfterExpression());
} catch (ParseException e) {
if (errorHandler != null) {
if (e.currentToken != null) {
LocatorImpl li = new LocatorImpl(this,
e.currentToken.next.beginLine,
e.currentToken.next.beginColumn-1);
reportError(li, e);
} else {
reportError(getLocator(), e);
}
skipAfterExpression();
/*
LocatorImpl loc = (LocatorImpl) getLocator();
loc.column--;
reportWarningSkipText(loc, skipAfterExpression());
*/
} else {
skipAfterExpression();
}
}
}
/**
* @exception ParseException exception during the parse
*/
boolean prio() :
{}
{
<IMPORTANT_SYM> ( <S> )* { return true; }
}
/**
* @exception ParseException exception during the parse
*/
LexicalUnitImpl operator(LexicalUnitImpl prev) :
{Token n;}
{
n="/" ( <S> )* { return LexicalUnitImpl.createSlash(n.beginLine,
n.beginColumn,
prev); }
| n="," ( <S> )* { return LexicalUnitImpl.createComma(n.beginLine,
n.beginColumn,
prev); }
}
/**
* @exception ParseException exception during the parse
*/
LexicalUnit expr() :
{
LexicalUnitImpl first, res;
char op;
}
{
first=term(null) { res = first; }
( ( res=operator(res) )? res=term(res) )*
{ return first; }
}
/**
* @exception ParseException exception during the parse
*/
char unaryOperator() :
{}
{
"-" { return '-'; }
| "+" { return '+'; }
}
/**
* @exception ParseException exception during the parse
*/
LexicalUnitImpl term(LexicalUnitImpl prev) :
{ LexicalUnitImpl result = null;
Token n = null;
char op = ' ';
}
{
( ( ( op=unaryOperator() )?
( n=<NUMBER>
{ result = LexicalUnitImpl.createNumber(n.beginLine, n.beginColumn,
prev, number(op, n, 0)); }
| n=<PERCENTAGE>
{ result = LexicalUnitImpl.createPercentage(n.beginLine, n.beginColumn,
prev, number(op, n, 1)); }
| n=<PT>
{ result = LexicalUnitImpl.createPT(n.beginLine, n.beginColumn,
prev, number(op, n, 2)); }
| n=<CM>
{ result = LexicalUnitImpl.createCM(n.beginLine, n.beginColumn,
prev, number(op, n, 2)); }
| n=<MM>
{ result = LexicalUnitImpl.createMM(n.beginLine, n.beginColumn,
prev, number(op, n, 2)); }
| n=<PC>
{ result = LexicalUnitImpl.createPC(n.beginLine, n.beginColumn,
prev, number(op, n, 2)); }
| n=<IN>
{ result = LexicalUnitImpl.createIN(n.beginLine, n.beginColumn,
prev, number(op, n, 2)); }
| n=<PX>
{ result = LexicalUnitImpl.createPX(n.beginLine, n.beginColumn,
prev, number(op, n, 2)); }
| n=<EMS>
{ result = LexicalUnitImpl.createEMS(n.beginLine, n.beginColumn,
prev, number(op, n, 2)); }
| n=<EXS>
{ result = LexicalUnitImpl.createEXS(n.beginLine, n.beginColumn,
prev, number(op, n, 2)); }
| n=<DEG>
{ result = LexicalUnitImpl.createDEG(n.beginLine, n.beginColumn,
prev, number(op, n, 3)); }
| n=<RAD>
{ result = LexicalUnitImpl.createRAD(n.beginLine, n.beginColumn,
prev, number(op, n, 3)); }
| n=<GRAD>
{ result = LexicalUnitImpl.createGRAD(n.beginLine, n.beginColumn,
prev, number(op, n, 3)); }
| n=<SECOND>
{ result = LexicalUnitImpl.createS(n.beginLine, n.beginColumn,
prev, number(op, n, 1)); }
| n=<MS>
{ result = LexicalUnitImpl.createMS(n.beginLine, n.beginColumn,
prev, number(op, n, 2)); }
| n=<HZ>
{ result = LexicalUnitImpl.createHZ(n.beginLine, n.beginColumn,
prev, number(op, n, 2)); }
| n=<KHZ>
{ result = LexicalUnitImpl.createKHZ(n.beginLine, n.beginColumn,
prev, number(op, n, 3)); }
| n=<DIMEN>
{
String s = n.image;
int i = 0;
while (i < s.length()
&& (Character.isDigit(s.charAt(i)) || (s.charAt(i) == '.'))) {
i++;
}
result = LexicalUnitImpl.createDimen(n.beginLine, n.beginColumn, prev,
Float.valueOf(s.substring(0, i)).floatValue(),
s.substring(i));
}
| result=function(op, prev) ) )
| ( n=<STRING>
{ result =
LexicalUnitImpl.createString(n.beginLine, n.beginColumn, prev,
convertStringIndex(n.image, 1,
n.image.length() -1));}
| n=<IDENT>
{ String s = convertIdent(n.image);
if ("inherit".equals(s)) {
result = LexicalUnitImpl.createInherit(n.beginLine, n.beginColumn,
prev);
} else {
result = LexicalUnitImpl.createIdent(n.beginLine, n.beginColumn,
prev, convertIdent(n.image));
}
/* /
Auto correction code used in the CSS Validator but must not
be used by a conformant CSS2 parser.
* Common error :
* H1 {
* color : black
* background : white
* }
*
Token t = getToken(1);
Token semicolon = new Token();
semicolon.kind = SEMICOLON;
semicolon.image = ";";
if (t.kind == COLON) {
// @@SEEME. (generate a warning?)
// @@SEEME if expression is a single ident,
generate an error ?
rejectToken(semicolon);
result = prev;
}
/ */
}
| result=hexcolor(prev)
| result=url(prev)
| result=unicode(prev)
) ) ( <S> )*
{
return result;
}
}
/**
* Handle all CSS2 functions.
* @exception ParseException exception during the parse
*/
LexicalUnitImpl function(char operator, LexicalUnitImpl prev) :
{Token n;
LexicalUnit params = null;
}
{
n=<FUNCTION> ( <S> )* ( params=expr() )? ")"
{
if (operator != ' ') {
throw new CSSParseException("invalid operator before a function.",
getLocator());
}
String f = convertIdent(n.image);
LexicalUnitImpl l = (LexicalUnitImpl) params;
boolean loop = true;
if ("rgb(".equals(f)) {
// this is a RGB declaration (e.g. rgb(255, 50%, 0) )
int i = 0;
while (loop && l != null && i < 5) {
switch (i) {
case 0:
case 2:
case 4:
if ((l.getLexicalUnitType() != LexicalUnit.SAC_INTEGER)
&& (l.getLexicalUnitType() != LexicalUnit.SAC_PERCENTAGE)) {
loop = false;
}
break;
case 1:
case 3:
if (l.getLexicalUnitType() != LexicalUnit.SAC_OPERATOR_COMMA) {
loop = false;
}
break;
default:
throw new ParseException("implementation error");
}
if (loop) {
l = (LexicalUnitImpl) l.getNextLexicalUnit();
i ++;
}
}
if ((i == 5) && loop && (l == null)) {
return LexicalUnitImpl.createRGBColor(n.beginLine,
n.beginColumn,
prev, params);
} else {
if (errorHandler != null) {
String errorText;
Locator loc;
if (i < 5) {
if (params == null) {
loc = new LocatorImpl(this, n.beginLine,
n.beginColumn-1);
errorText = "not enough parameters.";
} else if (l == null) {
loc = new LocatorImpl(this, n.beginLine,
n.beginColumn-1);
errorText = "not enough parameters: "
+ params.toString();
} else {
loc = new LocatorImpl(this, l.getLineNumber(),
l.getColumnNumber());
errorText = "invalid parameter: "
+ l.toString();
}
} else {
loc = new LocatorImpl(this, l.getLineNumber(),
l.getColumnNumber());
errorText = "too many parameters: "
+ l.toString();
}
errorHandler.error(new CSSParseException(errorText, loc));
}
throw new JumpException();
}
} else if ("counter".equals(f)) {
int i = 0;
while (loop && l != null && i < 3) {
switch (i) {
case 0:
case 2:
if (l.getLexicalUnitType() != LexicalUnit.SAC_IDENT) {
loop = false;
}
break;
case 1:
if (l.getLexicalUnitType() != LexicalUnit.SAC_OPERATOR_COMMA) {
loop = false;
}
break;
default:
throw new ParseException("implementation error");
}
l = (LexicalUnitImpl) l.getNextLexicalUnit();
i ++;
}
if (((i == 1) || (i == 3)) && loop && (l == null)) {
return LexicalUnitImpl.createCounter(n.beginLine, n.beginColumn,
prev, params);
}
} else if ("counters(".equals(f)) {
int i = 0;
while (loop && l != null && i < 5) {
switch (i) {
case 0:
case 4:
if (l.getLexicalUnitType() != LexicalUnit.SAC_IDENT) {
loop = false;
}
break;
case 2:
if (l.getLexicalUnitType() != LexicalUnit.SAC_STRING_VALUE) {
loop = false;
}
break;
case 1:
case 3:
if (l.getLexicalUnitType() != LexicalUnit.SAC_OPERATOR_COMMA) {
loop = false;
}
break;
default:
throw new ParseException("implementation error");
}
l = (LexicalUnitImpl) l.getNextLexicalUnit();
i ++;
}
if (((i == 3) || (i == 5)) && loop && (l == null)) {
return LexicalUnitImpl.createCounters(n.beginLine, n.beginColumn,
prev, params);
}
} else if ("attr(".equals(f)) {
if ((l != null)
&& (l.getNextLexicalUnit() == null)
&& (l.getLexicalUnitType() == LexicalUnit.SAC_IDENT)) {
return LexicalUnitImpl.createAttr(l.getLineNumber(),
l.getColumnNumber(),
prev, l.getStringValue());
}
} else if ("rect(".equals(f)) {
int i = 0;
while (loop && l != null && i < 7) {
switch (i) {
case 0:
case 2:
case 4:
case 6:
switch (l.getLexicalUnitType()) {
case LexicalUnit.SAC_INTEGER:
if (l.getIntegerValue() != 0) {
loop = false;
}
break;
case LexicalUnit.SAC_IDENT:
if (!l.getStringValue().equals("auto")) {
loop = false;
}
break;
case LexicalUnit.SAC_EM:
case LexicalUnit.SAC_EX:
case LexicalUnit.SAC_PIXEL:
case LexicalUnit.SAC_CENTIMETER:
case LexicalUnit.SAC_MILLIMETER:
case LexicalUnit.SAC_INCH:
case LexicalUnit.SAC_POINT:
case LexicalUnit.SAC_PICA:
// nothing
break;
default:
loop = false;
}
break;
case 1:
case 3:
case 5:
if (l.getLexicalUnitType() != LexicalUnit.SAC_OPERATOR_COMMA) {
loop = false;
}
break;
default:
throw new ParseException("implementation error");
}
l = (LexicalUnitImpl) l.getNextLexicalUnit();
i ++;
}
if ((i == 7) && loop && (l == null)) {
return LexicalUnitImpl.createRect(n.beginLine, n.beginColumn,
prev, params);
}
}
return LexicalUnitImpl.createFunction(n.beginLine, n.beginColumn, prev,
f.substring(0,
f.length() -1),
params);
}
}
LexicalUnitImpl unicode(LexicalUnitImpl prev) :
{ Token n;
}
{
n=<UNICODERANGE>
{
LexicalUnitImpl params = null;
String s = n.image.substring(2);
int index = s.indexOf('-');
if (index == -1) {
params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
params, Integer.parseInt(s, 16));
} else {
String s1 = s.substring(0, index);
String s2 = s.substring(index);
params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
params, Integer.parseInt(s1, 16));
params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
params, Integer.parseInt(s2, 16));
}
return LexicalUnitImpl.createUnicodeRange(n.beginLine, n.beginColumn,
prev, params);
}
}
LexicalUnitImpl url(LexicalUnitImpl prev) :
{ Token n;
}
{
n=<URL>
{
String urlname = n.image.substring(4, n.image.length()-1).trim();
if (urlname.charAt(0) == '"'
|| urlname.charAt(0) == '\'') {
urlname = urlname.substring(1, urlname.length()-1);
}
return LexicalUnitImpl.createURL(n.beginLine, n.beginColumn, prev, urlname);
}
}
/**
* @exception ParseException exception during the parse
*/
LexicalUnitImpl hexcolor(LexicalUnitImpl prev) :
{Token n;
}
{
n=<HASH>
{
int r;
LexicalUnitImpl first, params = null;
String s = n.image.substring(1);
if (s.length() == 3) {
String sh = s.substring(0,1);
r = Integer.parseInt(sh+sh, 16);
first = params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
params, r);
params = LexicalUnitImpl.createComma(n.beginLine, n.beginColumn,
params);
sh = s.substring(1,2);
r = Integer.parseInt(sh+sh, 16);
params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
params, r);
params = LexicalUnitImpl.createComma(n.beginLine, n.beginColumn,
params);
sh = s.substring(2,3);
r = Integer.parseInt(sh+sh, 16);
params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
params, r);
} else if (s.length() == 6) {
r = Integer.parseInt(s.substring(0,2), 16);
first = params = LexicalUnitImpl.createInteger(n.beginLine,
n.beginColumn,
params, r);
params = LexicalUnitImpl.createComma(n.beginLine, n.beginColumn,
params);
r = Integer.parseInt(s.substring(2,4), 16);
params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
params, r);
params = LexicalUnitImpl.createComma(n.beginLine, n.beginColumn,
params);
r = Integer.parseInt(s.substring(4,6), 16);
params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
params, r);
} else {
first = null;
throw new CSSParseException("invalid hexadecimal notation for RGB: " + s,
getLocator());
}
return LexicalUnitImpl.createRGBColor(n.beginLine, n.beginColumn,
prev, first);
}
}
JAVACODE
float number(char operator, Token n, int lengthUnit) {
String image = n.image;
float f = 0;
if (lengthUnit != 0) {
image = image.substring(0, image.length() - lengthUnit);
}
f = Float.valueOf(image).floatValue();
return (operator == '-')? -f: f;
}
JAVACODE
String skipStatement() {
StringBuffer s = new StringBuffer();
Token tok = getToken(0);
if (tok.image != null) {
s.append(tok.image);
}
while (true) {
tok = getToken(1);
if (tok.kind == EOF) {
return null;
}
s.append(tok.image);
if (tok.kind == LBRACE) {
getNextToken();
s.append(skip_to_matching_brace());
getNextToken();
tok = getToken(1);
break;
} else if (tok.kind == RBRACE) {
getNextToken();
tok = getToken(1);
break;
} else if (tok.kind == SEMICOLON) {
getNextToken();
tok = getToken(1);
break;
}
getNextToken();
}
// skip white space
while (true) {
if (tok.kind != S) {
break;
}
tok = getNextToken();
tok = getToken(1);
}
return s.toString().trim();
}
JAVACODE
String skip_to_matching_brace() {
StringBuffer s = new StringBuffer();
Token tok;
int nesting = 1;
while (true) {
tok = getToken(1);
if (tok.kind == EOF) {
break;
}
s.append(tok.image);
if (tok.kind == LBRACE) {
nesting++;
} else if (tok.kind == RBRACE) {
nesting--;
if (nesting == 0) {
break;
}
}
getNextToken();
}
return s.toString();
}
/*
* Here I handle all CSS2 unicode character stuffs.
* I convert all \XXXXXX character into a single character.
* Don't forget that the parser has recognize the token before.
* (So IDENT won't contain newline and stuffs like this).
*/
JAVACODE
String convertStringIndex(String s, int start, int len) {
StringBuffer buf = new StringBuffer(len);
int index = start;
while (index < len) {
char c = s.charAt(index);
if (c == '\\') {
if (++index < len) {
c = s.charAt(index);
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
int numValue = Character.digit(c, 16);
int count = 0;
int p = 16;
while (index + 1 < len && count < 6) {
c = s.charAt(index+1);
if (Character.digit(c, 16) != -1) {
numValue = (numValue * 16) + Character.digit(c, 16);
p *= 16;
index++;
} else {
if (c == ' ') {
// skip the latest white space
index++;
}
break;
}
}
buf.append((char) numValue);
break;
case '\n':
case '\f':
break;
case '\r':
if (index + 1 < len) {
if (s.charAt(index + 1) == '\n') {
index ++;
}
}
break;
default:
buf.append(c);
}
} else {
throw new CSSParseException("invalid string " + s, getLocator());
}
} else {
buf.append(c);
}
index++;
}
return buf.toString();
}
JAVACODE
String convertIdent(String s) {
return convertStringIndex(s, 0, s.length());
}
JAVACODE
String convertString(String s) {
return convertStringIndex(s, 0, s.length());
}
/*
* @@HACK
* I can't insert a token into the tokens flow.
* It's jj_consume_token implementation dependant! :-(
*/
JAVACODE
void rejectToken(Token t) {
Token fakeToken = new Token();
t.next = token;
fakeToken.next = t;
token = fakeToken;
}
/**
* skip after an expression
*/
JAVACODE
String skipAfterExpression() {
Token t = getToken(1);
StringBuffer s = new StringBuffer();
s.append(getToken(0).image);
while ((t.kind != RBRACE) && (t.kind != SEMICOLON) && (t.kind != EOF)) {
s.append(t.image);
getNextToken();
t = getToken(1);
}
return s.toString();
}
/**
* The following functions are useful for a DOM CSS implementation only and are
* not part of the general CSS2 parser.
*/
void _parseRule() :
{String ret = null;
}
{
( <S> )*
( importDeclaration() | styleRule() | media() | page()
| fontFace() | ret=skipStatement()
{
if ((ret == null) || (ret.length() == 0)) {
return;
}
if (ret.charAt(0) == '@') {
documentHandler.ignorableAtRule(ret);
} else {
throw new CSSParseException("unrecognize rule: " + ret,
getLocator());
}
}
)
}
void _parseImportRule() :
{
}
{
( <S> )* importDeclaration()
}
void _parseMediaRule() :
{
}
{
( <S> )* media()
}
void _parseDeclarationBlock() :
{
}
{
( <S> )*
( declaration() )? ( ";" ( <S> )* ( declaration() )? )*
}
SelectorList _parseSelectors() :
{ SelectorList p = null;
}
{
try {
( <S> )* p = selectorList()
{ return p; }
} catch (ThrowedParseException e) {
throw (ParseException) e.e.fillInStackTrace();
}
}
/*
* Local Variables:
* compile-command: javacc Parser.jj & javac Parser.java
* End:
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment