/*******************************************************************************
* Copyright (c) 2008 SAP
* see https://research.qkal.sap.corp/mediawiki/index.php/CoMONET
*
* Date: $Date: 2009-04-23 14:54:43 +0200 (Do, 23 Apr 2009) $
* @version $Revision: 6272 $
* @author: $Author: c5106462 $
*******************************************************************************/
package com.sap.furcas.parsergenerator.tcs.t2m.grammar;
import java.util.Collection;
import java.util.Iterator;
import com.sap.furcas.metamodel.FURCAS.TCS.ClassPattern;
import com.sap.furcas.metamodel.FURCAS.TCS.EndOfLineRule;
import com.sap.furcas.metamodel.FURCAS.TCS.MultiLineRule;
import com.sap.furcas.metamodel.FURCAS.TCS.OrPattern;
import com.sap.furcas.metamodel.FURCAS.TCS.Rule;
import com.sap.furcas.metamodel.FURCAS.TCS.RulePattern;
import com.sap.furcas.metamodel.FURCAS.TCS.SimplePattern;
import com.sap.furcas.metamodel.FURCAS.TCS.StringPattern;
import com.sap.furcas.metamodel.FURCAS.TCS.Token;
import com.sap.furcas.metamodel.FURCAS.TCS.WordRule;
import com.sap.furcas.parsergenerator.tcs.t2m.grammar.rules.SimpleProductionRule;
/**
* The Class TokenHandler.
*/
public class TokenHandler {
/** The writer. */
private final ANTLR3GrammarWriter writer;
private final SemanticErrorBucket errorBucket;
/**
* Instantiates a new token handler.
*
* @param writer the writer
*/
TokenHandler(ANTLR3GrammarWriter writer, SemanticErrorBucket errorBucket) {
super();
this.writer = writer;
this.errorBucket = errorBucket;
}
/**
* @param handlerConfig
*/
public TokenHandler(SyntaxElementHandlerConfigurationBean<?> handlerConfig) {
this(handlerConfig.getWriter(), handlerConfig.getErrorBucket());
}
/**
* Adds a rule for the token.
*
* @param token the token
*/
public void addToken(Token token) {
OrPattern pat = token.getPattern();
StringBuilder rulebody = new StringBuilder();
rulebody.append(" ");
Collection<SimplePattern> simPatList = pat.getSimplePatterns();
addSimplePatterns(rulebody, simPatList);
if (token.isOmitted()) {
rulebody.append("{$channel=HIDDEN;}");
}
writer.addRule(new SimpleProductionRule(token.getName(), rulebody.toString()));
}
/**
* adds simple patterns, can be called recursively.
* @param rulebody
* @param simPatList
*/
private void addSimplePatterns(StringBuilder rulebody, Collection<SimplePattern> simPatList) {
if (simPatList == null) {
return;
}
rulebody.append('(');
for (Iterator<SimplePattern> patternIterator = simPatList.iterator(); patternIterator.hasNext();) {
SimplePattern simplePattern = patternIterator.next();
if (simplePattern instanceof RulePattern) {
RulePattern rulePat = (RulePattern) simplePattern;
addRulePattern(rulebody, rulePat);
} else if (simplePattern instanceof ClassPattern) {
ClassPattern cPat = (ClassPattern) simplePattern;
String name = cPat.getName();
if ("alnum".equals(name)) {
rulebody.append("('A' .. 'Z'| 'a' .. 'z'| '0' .. '9')");
} else if ("alpha".equals(name)) {
rulebody.append("('A' .. 'Z'| 'a' .. 'z')");
} else {
errorBucket.addError("ClassPattern name unknown: " + name, simplePattern);
}
} else if (simplePattern instanceof StringPattern) {
StringPattern sPat = (StringPattern) simplePattern;
String name = sPat.getName();
if (name == null) {
errorBucket.addError("SimplePattern name cannot be null", simplePattern);
}
rulebody.append('\'').append(escapeString(name)).append('\'');
} else {
errorBucket.addError(simplePattern.getClass() + " is unknown SimplePattern instance", simplePattern);
}
if (patternIterator.hasNext()) {
rulebody.append(" | ");
}
} // end for patterns
rulebody.append(')');
}
/**
* adds to the antlr Grammar rulebody regarding any known rule type in TCS
* @param rulebody
* @param rulePat
*/
private void addRulePattern(StringBuilder rulebody, RulePattern rulePat) {
Rule rule = rulePat.getRule();
if (rule instanceof EndOfLineRule) {
EndOfLineRule eolRule = (EndOfLineRule) rule;
if (eolRule.isDropStart()) {
throw new RuntimeException(rule.getClass() + " dropStart to grammar not implemented yet");
}
StringPattern startPat = eolRule.getStart();
rulebody.append("(('" + escapeString(startPat.getName()) + "' (~('\\r'| '\\n'))*))");
// TODO: Create Regex Pattern from model?
} else if (rule instanceof MultiLineRule) {
MultiLineRule eolRule = (MultiLineRule) rule;
if (eolRule.isDropStart()) {
throw new RuntimeException(rule.getClass() + " dropStart to grammar not implemented yet");
}
if (eolRule.isDropEnd()) {
throw new RuntimeException(rule.getClass() + " dropEnd to grammar not implemented yet");
}
if (eolRule.getEsc() != null) {
throw new RuntimeException(rule.getClass() + " Esc to grammar not implemented yet");
}
if (eolRule.getEscMappings() != null && eolRule.getEscMappings().size() > 0) {
throw new RuntimeException(rule.getClass() + " EscMappings to grammar not implemented yet");
}
StringPattern startPat = eolRule.getStart();
StringPattern endPat = eolRule.getEnd();
rulebody.append("(('" + escapeString(startPat.getName()) + "' (options {greedy = false;} : (\'\\n\'| ~ \'\\n\'))* '"
+ escapeString(endPat.getName()) + "'))");
} else if (rule instanceof WordRule) {
// word rules have a beginning patter, a middle "part" pattern that can be repeated * times, and an end pattern
WordRule wRule = (WordRule) rule;
OrPattern start = wRule.getStart();
OrPattern part = wRule.getPart();
OrPattern end = wRule.getEnd();
if (start == null && end == null) {
errorBucket.addError("Either start or end must be defined for word() rule", rule);
}
// recursive calls
if (start != null && start.getSimplePatterns() != null && start.getSimplePatterns().size() != 0) {
addSimplePatterns(rulebody, start.getSimplePatterns());
if (part != null || end != null) {
rulebody.append(" \n");
}
}
if (part != null && part.getSimplePatterns() != null && part.getSimplePatterns().size() != 0) {
rulebody.append('(');
addSimplePatterns(rulebody, part.getSimplePatterns());
rulebody.append(")*");
if (end != null) {
rulebody.append(" \n");
}
}
if (end != null) {
addSimplePatterns(rulebody, end.getSimplePatterns());
}
} else {
// should never happen, as TCS only defines EOL, Multiline and word rules
throw new RuntimeException(rule.getClass() + " to grammar not implemented yet");
}
}
private static String escapeString(String source) {
if (source != null) {
return source.replaceAll("\\'", "\\\\\'");
}
return null;
}
}