Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/.classpath
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/.classpath	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/.classpath	(revision 5)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" path="src-gen"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/.project
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/.project	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/.project	(revision 5)
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>de.ugoe.cs.swe.bnftools.ebnf</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
+	</natures>
+</projectDescription>
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/META-INF/MANIFEST.MF
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/META-INF/MANIFEST.MF	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/META-INF/MANIFEST.MF	(revision 5)
@@ -0,0 +1,34 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: bnftools core
+Bundle-Vendor: Software Engineering for Distributed Systems Group, University of Göttingen
+Bundle-Version: 1.0.0.qualifier
+Bundle-SymbolicName: de.ugoe.cs.swe.bnftools.ebnf; singleton:=true
+Bundle-ActivationPolicy: lazy
+Require-Bundle: org.eclipse.xtext,
+ org.eclipse.xtext.generator;resolution:=optional,
+ de.itemis.xtext.antlr;resolution:=optional,
+ org.apache.commons.logging;resolution:=optional,
+ org.eclipse.emf.codegen.ecore;resolution:=optional,
+ org.eclipse.emf.mwe.utils;resolution:=optional,
+ org.eclipse.emf.mwe2.launch;resolution:=optional,
+ com.ibm.icu;resolution:=optional,
+ org.eclipse.xtext.xtend;resolution:=optional,
+ org.eclipse.xtext.util,
+ org.eclipse.emf.ecore,
+ org.eclipse.emf.common,
+ org.antlr.runtime
+Import-Package: org.apache.log4j
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Export-Package: de.ugoe.cs.swe.bnftools,
+ de.ugoe.cs.swe.bnftools.analysis,
+ de.ugoe.cs.swe.bnftools.ebnf,
+ de.ugoe.cs.swe.bnftools.ebnf.impl,
+ de.ugoe.cs.swe.bnftools.ebnf.util,
+ de.ugoe.cs.swe.bnftools.parseTreeConstruction,
+ de.ugoe.cs.swe.bnftools.parser.antlr,
+ de.ugoe.cs.swe.bnftools.parser.antlr.internal,
+ de.ugoe.cs.swe.bnftools.services,
+ de.ugoe.cs.swe.bnftools.utils,
+ de.ugoe.cs.swe.bnftools.validation,
+ de.ugoe.cs.swe.bnftools.valueconverter
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/build.properties
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/build.properties	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/build.properties	(revision 5)
@@ -0,0 +1,4 @@
+source.. = src/,src-gen/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/plugin.xml
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/plugin.xml	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/plugin.xml	(revision 5)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+
+<plugin>
+
+  <extension point="org.eclipse.emf.ecore.generated_package">
+    <package 
+       uri = "http://www.ugoe.de/cs/swe/bnftools/Ebnf" 
+       class = "de.ugoe.cs.swe.bnftools.ebnf.EbnfPackage"
+       genModel = "de/ugoe/cs/swe/bnftools/Ebnf.genmodel" /> 
+	
+  </extension>
+
+
+
+
+
+</plugin>
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/Ebnf.properties
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/Ebnf.properties	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/Ebnf.properties	(revision 5)
@@ -0,0 +1,3 @@
+grammarURI=classpath:/de/ugoe/cs/swe/bnftools/Ebnf.xtext
+file.extensions=bnf
+projectName=de.ugoe.cs.swe.bnftools.ebnf
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/Ebnf.xtext
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/Ebnf.xtext	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/Ebnf.xtext	(revision 5)
@@ -0,0 +1,122 @@
+grammar de.ugoe.cs.swe.bnftools.Ebnf hidden(WS, ML_COMMENT, SL_COMMENT)
+
+import "http://www.eclipse.org/emf/2002/Ecore" as ecore
+
+generate ebnf "http://www.ugoe.de/cs/swe/bnftools/Ebnf"
+
+// -----------------------------------------------------------------------------------------------
+// Parser Rules
+// -----------------------------------------------------------------------------------------------
+EtsiBnf:
+	'grammar' name=ID
+	(	type='/bnf'? ';' 
+		(imports+=Import)* 
+		(rule+=Rule | sectionheader+=SectionHeading)+ 
+	)
+	| 
+	(	type='/delta' ';'
+		(imports+=Import)* 
+		(rule+=Rule | sectionheader+=SectionHeading | extRule+=ExtRule)*
+	)
+	| 
+	(	type='/merge' ';' 
+		(imports+=Import)* 
+		(sectionheader+=SectionHeading | mergeRule+=MergeRule)* 
+	)
+;
+
+
+SectionHeading:
+	{SectionHeading}
+	sectionHeader=SECTIONHEADER
+;
+
+
+Import :
+ 	'import' importURI=STRING 
+ 	('/' (grammarType='core' | grammarType='package' | grammarType='update'))?
+ 	('label:' label=ID)? ';'
+;
+
+Rule:
+	(rulenumber=INT (rulevariant=ID)? '.')?  name=ID  '::=' (definitionList=DefinitionList)? ';'? 
+;
+
+ExtRule:
+	(rulenumber=INT (rulevariant=ID)? '.')?  name=ID ('(' ruleext=INT ')') '<-' 
+	(elements+=Atom | ')' | ']' | '}' | '|' | '(' | '[' | '{' | '*' | '+')* ';'? 
+;
+
+MergeRule:
+	GlobalCombinator
+	| RuleCombinator
+	| HookCombinator
+;
+	
+GlobalCombinator:
+('global' 'combinator:') logic=LOGIC ';'?
+;	
+
+RuleCombinator:
+('rule' 'combinator:' name=ID ) logic=LOGIC ('(' LABEL+=STRING ')')* ';'?
+;
+
+HookCombinator:
+'hook' 'combinator:' name=ID '(' ruleext=INT ')' (logic=LOGIC)? ('(' LABEL+=STRING ')')+ ';'?
+;
+
+DefinitionList:
+	singleDefinition+=SingleDefinition ('|' singleDefinition+=SingleDefinition)*
+;
+
+SingleDefinition:
+	(terms+=Term)+
+;
+
+Term:
+	termAtom=Atom
+	| termGroupedSequence=GroupedSequence
+	| termOptionalSequence=OptionalSequence
+	| termRepeatedSequence=RepeatedSequence
+;
+
+Atom:
+	atomStringRule=StringRule
+	| atomRuleReference=RuleReference
+;
+
+RuleReference:
+	ruleref=[Rule]
+;
+
+StringRule:
+	literal=STRING
+	| colon=COLON
+;
+
+GroupedSequence:
+	'(' definitionList+=DefinitionList ')'
+;
+
+OptionalSequence:
+	'[' definitionList+=DefinitionList ']'
+;
+
+RepeatedSequence:
+	'{' definitions+=DefinitionList '}' morethanonce?='+'?
+;
+
+// -----------------------------------------------------------------------------------------------
+// Lexer Rules
+// -----------------------------------------------------------------------------------------------
+
+terminal ID  		: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')* ;
+terminal INT 		returns ecore::EInt: ('0'..'9')+;
+terminal WS			: (' '|'\t'|'\r'? '\n')+;
+terminal COLON		: '"' '"' '"';
+terminal STRING		: '"' !('"')* '"' | "'" !("'")*"'";
+terminal SECTIONHEADER: ('a'..'z'|'A'..'Z') ('.'|('0'..'9'))+ (' '|'\t') !('\n'|'\r')* '\r'? '\n';
+terminal SL_COMMENT	: '//' !('\n'|'\r')* ('\r'? '\n')?;
+terminal ML_COMMENT	: '/*' -> '*/';
+//TODO: a more intuitive notation
+terminal LOGIC		: '/and' | '/or' | '/andr' | '/orr' | '/any' | '/together' ;
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/EbnfRuntimeModule.java
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/EbnfRuntimeModule.java	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/EbnfRuntimeModule.java	(revision 5)
@@ -0,0 +1,29 @@
+/*
+ * generated by Xtext
+ */
+package de.ugoe.cs.swe.bnftools;
+
+import org.eclipse.xtext.scoping.impl.ImportUriGlobalScopeProvider;
+import org.eclipse.xtext.validation.INamesAreUniqueValidationHelper;
+
+import de.ugoe.cs.swe.bnftools.validation.EbnfNamesAreUniqueValidationHelper;
+import de.ugoe.cs.swe.bnftools.valueconverter.EbnfTerminalConverters;
+
+/**
+ * Use this class to register components to be used within the IDE.
+ */
+public class EbnfRuntimeModule extends de.ugoe.cs.swe.bnftools.AbstractEbnfRuntimeModule {
+
+	public Class<? extends org.eclipse.xtext.conversion.IValueConverterService> bindIValueConverterService() {
+		return EbnfTerminalConverters.class;
+	}
+	
+	public Class<? extends org.eclipse.xtext.scoping.IGlobalScopeProvider> bindIGlobalScopeProvider() {
+		return ImportUriGlobalScopeProvider.class;
+	}
+	
+	public Class<? extends INamesAreUniqueValidationHelper> bindINamesAreUniqueValidationHelper() {
+		return EbnfNamesAreUniqueValidationHelper.class;
+	}
+
+}
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/EbnfStandaloneSetup.java
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/EbnfStandaloneSetup.java	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/EbnfStandaloneSetup.java	(revision 5)
@@ -0,0 +1,14 @@
+
+package de.ugoe.cs.swe.bnftools;
+
+/**
+ * Initialization support for running Xtext languages 
+ * without equinox extension registry
+ */
+public class EbnfStandaloneSetup extends EbnfStandaloneSetupGenerated{
+
+	public static void doSetup() {
+		new EbnfStandaloneSetup().createInjectorAndDoEMFRegistration();
+	}
+}
+
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/GenerateEbnf.mwe2
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/GenerateEbnf.mwe2	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/GenerateEbnf.mwe2	(revision 5)
@@ -0,0 +1,114 @@
+module de.ugoe.cs.swe.bnftools.Ebnf
+
+import org.eclipse.emf.mwe.utils.*
+import org.eclipse.xtext.generator.*
+import org.eclipse.xtext.ui.generator.*
+
+var grammarURI = "classpath:/de/ugoe/cs/swe/bnftools/Ebnf.xtext"
+var file.extensions = "bnf"
+var projectName = "de.ugoe.cs.swe.bnftools.ebnf"
+var runtimeProject = "../${projectName}"
+
+Workflow {
+    bean = StandaloneSetup {
+		platformUri = "${runtimeProject}/.."
+	}
+	
+	component = DirectoryCleaner {
+		directory = "${runtimeProject}/src-gen"
+	}
+	
+	component = DirectoryCleaner {
+		directory = "${runtimeProject}.ui/src-gen"
+	}
+	
+	component = Generator {
+		pathRtProject = runtimeProject
+		pathUiProject = "${runtimeProject}.ui"
+		projectNameRt = projectName
+		projectNameUi = "${projectName}.ui"
+		
+		language = {
+			uri = grammarURI
+			fileExtensions = file.extensions
+			
+			// Java API to access grammar elements (required by several other fragments)
+			fragment = grammarAccess.GrammarAccessFragment {}
+			
+			// generates Java API for the generated EPackages 
+			fragment = ecore.EcoreGeneratorFragment {
+			// referencedGenModels = "uri to genmodel, uri to next genmodel"
+			}
+			
+			// the serialization component
+			fragment = parseTreeConstructor.ParseTreeConstructorFragment {}
+			
+			// a custom ResourceFactory for use with EMF 
+			fragment = resourceFactory.ResourceFactoryFragment {
+				fileExtensions = file.extensions
+			}
+				
+			// the following fragment tries to use the Antlr Generator fragment which can be installed via update manager from http://download.itemis.com/updates/
+			fragment = AntlrDelegatingFragment {}
+			
+			/*
+			If you don't want to use the Antlr fragment for some reason, remove the antlr fragment and uncomment the packrat parser fragment below.
+			fragment = parser.PackratParserFragment {}
+			*/
+			
+			// check-based API for validation
+			/*
+			fragment = validation.CheckFragment {}
+			*/
+			 
+			// java-based API for validation 
+			fragment = validation.JavaValidatorFragment {
+                composedCheck = "org.eclipse.xtext.validation.ImportUriValidator"
+                composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
+            }
+            
+			// scoping and exporting API
+			fragment = scoping.ImportURIScopingFragment {}
+			fragment = exporting.SimpleNamesFragment {}
+			
+			// scoping and exporting API 
+			//fragment = scoping.ImportNamespacesScopingFragment {}
+			//fragment = exporting.QualifiedNamesFragment {}
+			
+			// formatter API 
+			fragment = formatting.FormatterFragment {}
+
+			// labeling API 
+			fragment = labeling.LabelProviderFragment {}
+
+			// outline API 
+			fragment = outline.TransformerFragment {}
+			fragment = outline.OutlineNodeAdapterFactoryFragment {}
+			fragment = outline.QuickOutlineFragment {}
+
+			// java-based API for content assistance 
+			fragment = contentAssist.JavaBasedContentAssistFragment {}
+			
+			// the following fragment tries to use the Antlr based content assist 
+			//     fragment which can be downloaded from http://www.itemis.com 
+			//     and will be ignored if it's not available. 
+			fragment = DelegatingGeneratorFragment { 
+				delegate = "de.itemis.xtext.antlr.XtextAntlrUiGeneratorFragment"
+				message="You are generating without ANTLR. "
+			}
+
+			fragment = builder.BuilderIntegrationFragment {}
+
+			// project wizard (optional) 
+			/*
+			fragment = projectWizard.SimpleProjectWizardFragment {
+				generatorProjectName = "${projectName}.generator" 
+				modelFileExtension = file.extensions
+			}
+			*/
+			
+			// quickfix API 
+			fragment = quickfix.QuickfixProviderFragment {}			
+		}
+	}
+}
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/analysis/EbnfAnalysisUtils.java
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/analysis/EbnfAnalysisUtils.java	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/analysis/EbnfAnalysisUtils.java	(revision 5)
@@ -0,0 +1,130 @@
+package de.ugoe.cs.swe.bnftools.analysis;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.xtext.resource.IReferenceDescription;
+import org.eclipse.xtext.resource.IResourceDescription;
+import org.eclipse.xtext.resource.IResourceDescriptions;
+
+import de.ugoe.cs.swe.bnftools.ebnf.Atom;
+import de.ugoe.cs.swe.bnftools.ebnf.DefinitionList;
+import de.ugoe.cs.swe.bnftools.ebnf.Rule;
+import de.ugoe.cs.swe.bnftools.ebnf.RuleReference;
+import de.ugoe.cs.swe.bnftools.ebnf.SingleDefinition;
+import de.ugoe.cs.swe.bnftools.ebnf.StringRule;
+import de.ugoe.cs.swe.bnftools.ebnf.Term;
+
+public class EbnfAnalysisUtils {
+
+	//----------------------------------------------------------------------------------------------------
+
+	static public boolean isPassthroughRule(Rule rule) {
+		DefinitionList definitionList = rule.getDefinitionList();
+		if (definitionList == null)
+			return false;
+		
+		if (rule.getDefinitionList().getSingleDefinition().size() == 1) {
+			SingleDefinition element = rule.getDefinitionList().getSingleDefinition().get(0);
+			if (element.getTerms().size() == 1) {
+				Term first = element.getTerms().get(0);
+				if (first.getTermAtom() != null) {
+					Atom atom = (Atom) first.getTermAtom();
+					if (atom.getAtomRuleReference() != null)
+						return true;
+				}
+			}
+		}
+
+		return false;
+	}
+
+	//----------------------------------------------------------------------------------------------------
+
+	static public RuleReference getPassthroughRuleReference(Rule rule) {
+		DefinitionList definitionList = rule.getDefinitionList();
+		if (definitionList == null)
+			return null;
+		
+		if (rule.getDefinitionList().getSingleDefinition().size() == 1) {
+			SingleDefinition element = rule.getDefinitionList().getSingleDefinition().get(0);
+			if (element.getTerms().size() == 1) {
+				Term first = element.getTerms().get(0);
+				if (first.getTermAtom() != null) {
+					Atom atom = (Atom) first.getTermAtom();
+					if (atom.getAtomRuleReference() != null)
+						return atom.getAtomRuleReference();
+				}
+			}
+		}
+
+		return null;
+	}
+	
+	//----------------------------------------------------------------------------------------------------
+
+	static public boolean isTokenRule(Rule rule) {
+		DefinitionList definitionList = rule.getDefinitionList();
+		if (definitionList == null)
+			return false;
+		
+		if (rule.getDefinitionList().getSingleDefinition().size() == 1) {
+			SingleDefinition element = rule.getDefinitionList().getSingleDefinition().get(0);
+			if (element.getTerms().size() == 1) {
+				Term first = element.getTerms().get(0);
+				Atom atom = first.getTermAtom();
+				if (atom != null && atom.getAtomStringRule() != null)  {
+					return true;
+				}
+			}
+		}
+
+		return false;
+	}
+
+	//----------------------------------------------------------------------------------------------------
+
+	static public StringRule getTokenRuleTerminal(Rule rule) {
+		DefinitionList definitionList = rule.getDefinitionList();
+		if (definitionList == null)
+			return null;
+		
+		if (rule.getDefinitionList().getSingleDefinition().size() == 1) {
+			SingleDefinition element = rule.getDefinitionList().getSingleDefinition().get(0);
+			if (element.getTerms().size() == 1) {
+				Term first = element.getTerms().get(0);
+				if ((first.getTermAtom() != null) && (first.getTermAtom().getAtomStringRule() != null)) {
+					StringRule stringRule = first.getTermAtom().getAtomStringRule();
+					return stringRule;
+				}
+			}
+		}
+
+		return null;
+	}
+
+	//----------------------------------------------------------------------------------------------------
+
+	static public List<Rule> findReferences(Rule rule, IResourceDescriptions resourceDescriptions) {
+		List<Rule> ruleReferences = new ArrayList<Rule>();
+		
+		final String ruleURIF = rule.eResource().getURIFragment(rule);
+		
+		for (IResourceDescription resourceDescription : resourceDescriptions
+				.getAllResourceDescriptions()) {
+			if (!resourceDescription.getURI().equals(rule.eResource().getURI()))
+				continue;
+			
+			for (IReferenceDescription referenceDescription : resourceDescription
+					.getReferenceDescriptions()) {
+				if (ruleURIF.equals(referenceDescription.getTargetEObjectUri()
+						.fragment())) {
+					ruleReferences.add((Rule) rule.eResource().getEObject(referenceDescription.getTargetEObjectUri().fragment()));
+				}
+
+			}
+		}
+		return ruleReferences;
+	}
+
+}
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/formatting/EbnfFormatter.java
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/formatting/EbnfFormatter.java	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/formatting/EbnfFormatter.java	(revision 5)
@@ -0,0 +1,45 @@
+/*
+ * generated by Xtext
+ */
+package de.ugoe.cs.swe.bnftools.formatting;
+
+import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter;
+import org.eclipse.xtext.formatting.impl.FormattingConfig;
+
+/**
+ * This class contains custom formatting description.
+ * 
+ * see : http://www.eclipse.org/Xtext/documentation/latest/xtext.html#formatting
+ * on how and when to use it 
+ * 
+ * Also see {@link org.eclipse.xtext.xtext.XtextFormattingTokenSerializer} as an example
+ */
+public class EbnfFormatter extends AbstractDeclarativeFormatter {
+	
+	@Override
+	protected void configureFormatting(FormattingConfig c) {
+		de.ugoe.cs.swe.bnftools.services.EbnfGrammarAccess f = (de.ugoe.cs.swe.bnftools.services.EbnfGrammarAccess) getGrammarAccess();
+
+		c.setIndentationSpace(" ");
+		c.setNoLinewrap();
+		c.setAutoLinewrap(10000000);
+		c.setLinewrap(2).before(f.getSectionHeadingRule());
+		c.setLinewrap(2).after(f.getSectionHeadingRule());
+		
+		
+		c.setNoSpace().after(f.getRuleAccess().getRulenumberINTTerminalRuleCall_0_0_0());
+		c.setNoSpace().after(f.getRuleAccess().getRulevariantIDTerminalRuleCall_0_1_0());
+
+		c.setLinewrap().before(f.getRuleAccess().getRulenumberINTTerminalRuleCall_0_0_0());
+		c.setNoSpace().before(f.getRuleAccess().getSemicolonKeyword_4());
+//		c.setNoSpace().before(f.getRuleAccess().getNameIDTerminalRuleCall_1_0());
+
+//		c.setLinewrap().after(f.getRuleAccess().getDefinitionListDefinitionListParserRuleCall_3_0());
+		c.setLinewrap().after(f.getRuleAccess().getDefinitionListAssignment_3());
+
+		c.setLinewrap(2).before(f.getSL_COMMENTRule());
+		c.setNoLinewrap().after(f.getSL_COMMENTRule());
+		c.setLinewrap(2).before(f.getML_COMMENTRule());	
+	}
+	
+}
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/scoping/EbnfScopeProvider.java
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/scoping/EbnfScopeProvider.java	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/scoping/EbnfScopeProvider.java	(revision 5)
@@ -0,0 +1,17 @@
+/*
+ * generated by Xtext
+ */
+package de.ugoe.cs.swe.bnftools.scoping;
+
+import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider;
+
+/**
+ * This class contains custom scoping description.
+ * 
+ * see : http://www.eclipse.org/Xtext/documentation/latest/xtext.html#scoping
+ * on how and when to use it 
+ *
+ */
+public class EbnfScopeProvider extends AbstractDeclarativeScopeProvider {//extends SimpleLocalScopeProvider { 
+
+}
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/utils/EObjectResolver.java
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/utils/EObjectResolver.java	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/utils/EObjectResolver.java	(revision 5)
@@ -0,0 +1,49 @@
+package de.ugoe.cs.swe.bnftools.utils;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.xtext.resource.IEObjectDescription;
+import org.eclipse.xtext.resource.IResourceDescription;
+import org.eclipse.xtext.resource.IResourceDescriptions;
+import org.eclipse.xtext.resource.XtextResource;
+import org.eclipse.xtext.util.concurrent.IUnitOfWork;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+public class EObjectResolver implements
+		IUnitOfWork<IEObjectDescription, XtextResource> {
+	private IResourceDescriptions resourceDescriptions;
+	private EObject element;
+
+	public EObjectResolver(EObject element,
+			IResourceDescriptions resourceDescriptions) {
+		this.element = element;
+		this.resourceDescriptions = resourceDescriptions;
+	}
+
+	public IEObjectDescription exec(XtextResource state) throws Exception {
+		if (element != null) {
+			final URI eObjectURI = EcoreUtil.getURI(element);
+			IResourceDescription resourceDescription = resourceDescriptions
+					.getResourceDescription(eObjectURI.trimFragment());
+			if (resourceDescription != null) {
+				Iterator<IEObjectDescription> eObjectDescriptions = Iterables
+						.filter(resourceDescription.getExportedObjects(),
+								new Predicate<IEObjectDescription>() {
+									public boolean apply(
+											IEObjectDescription input) {
+										return input.getEObjectURI().equals(
+												eObjectURI);
+									}
+								}).iterator();
+				if (eObjectDescriptions.hasNext()) {
+					return eObjectDescriptions.next();
+				}
+			}
+		}
+		return null;
+	}
+}
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/validation/EbnfJavaValidator.java
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/validation/EbnfJavaValidator.java	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/validation/EbnfJavaValidator.java	(revision 5)
@@ -0,0 +1,395 @@
+package de.ugoe.cs.swe.bnftools.validation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtext.parsetree.AbstractNode;
+import org.eclipse.xtext.parsetree.CompositeNode;
+import org.eclipse.xtext.parsetree.LeafNode;
+import org.eclipse.xtext.parsetree.NodeUtil;
+import org.eclipse.xtext.resource.IResourceDescriptions;
+import org.eclipse.xtext.resource.XtextResource;
+import org.eclipse.xtext.resource.XtextResourceSet;
+import org.eclipse.xtext.validation.Check;
+import org.eclipse.xtext.validation.CheckType;
+
+import com.google.inject.Inject;
+
+import de.ugoe.cs.swe.bnftools.analysis.EbnfAnalysisUtils;
+import de.ugoe.cs.swe.bnftools.ebnf.DefinitionList;
+import de.ugoe.cs.swe.bnftools.ebnf.EtsiBnf;
+import de.ugoe.cs.swe.bnftools.ebnf.ExtRule;
+import de.ugoe.cs.swe.bnftools.ebnf.Import;
+import de.ugoe.cs.swe.bnftools.ebnf.Rule;
+import de.ugoe.cs.swe.bnftools.ebnf.SingleDefinition;
+
+public class EbnfJavaValidator extends AbstractEbnfJavaValidator {
+
+	@Inject
+	IResourceDescriptions resourceDescriptions;
+
+	public static final String ruleReferencedOneDescription = "The rule is only referenced by one other rule";
+	public static final String passthroughRuleDescription = "The rule is a passthrough rule";
+	public static final String unreferencedPassthroughRuleDescription = "The rule is an unreferenced passthrough rule";
+	public static final String unusedRuleDescription = "The rule is not referenced anywhere";
+	public static final String equalAlternativeDescription = "The rule contains equal alternatives";
+	public static final String duplicateRulesDescription = "The rule is a duplicate";
+	public static final String duplicateSubRulesDescription = "A part of rule is a duplicate";
+	public static final String packageConsistencyCheckRuleMissingDescription = "Rule has been removed or renamed in the updated grammar. The package rule is therefore now an additional rule instead of a replacement rule. The package rule might therefore be inconsistent with the updated core grammar.";
+	public static final String packageConsistencyCheckRuleDifferentDescription = "Corresponding core grammar rule has been changed in updated grammar. The package rule might have become inconsistent with the updated core grammar.";
+	public static final String packageConsistencyCheckCorrespondingRuleMissingDescription = "Corresponding rule is missing in core grammar. Rule has been manually altered in the delta grammar (delta grammar is outdated) or the /core and /update flags are somehow switched.";
+
+	public static boolean checkReferencedOnlyOnce = false;
+	public static boolean checkPassthroughRule = false;
+	public static boolean checkUnusedRule = false;
+	public static boolean checkEqualAlternative = false;
+	public static boolean checkDuplicateRules = false;
+	public static boolean checkSubruleDuplicates = false;
+	public static boolean checkUpdatedGrammarConsistency = false;
+
+	// ----------------------------------------------------------------------------------------------------
+
+	@Check(CheckType.EXPENSIVE)
+	public void checkUpdateGrammarConsistency(EtsiBnf bnf) {
+		if (!checkUpdatedGrammarConsistency)
+			return;
+
+		CompositeNode compNode = NodeUtil.getRootNode(bnf);
+		XtextResourceSet set = new XtextResourceSet();
+		URI uri = compNode.getElement().eResource().getURI();
+		Iterable<AbstractNode> allNodes = NodeUtil.getAllContents(compNode);
+		if(!bnf.getType().equals("/delta"))
+			return;
+		
+		Resource coreRes = null;
+		Resource updatedRes = null;
+		EList<Import> imports = bnf.getImports();
+
+		for(int j=0; j<imports.size(); j++) {
+			if(imports.get(j).getGrammarType().equals("core")) {
+				String packageUri = uri.trimSegments(1).toPlatformString(true);
+				String fullUri = packageUri + "/" +imports.get(j).getImportURI();
+				coreRes= set.getResource( URI.createPlatformResourceURI(fullUri, true), true);
+			}
+			if(imports.get(j).getGrammarType().equals("update")) {
+				String packageUri = uri.trimSegments(1).toPlatformString(true);
+				String fullUri = packageUri + "/" +imports.get(j).getImportURI();
+				updatedRes= set.getResource( URI.createPlatformResourceURI(fullUri, true), true);
+			}
+		}
+		
+		if( (coreRes==null) || (updatedRes==null))
+			return;
+
+		XtextResource coreResource = null;
+		XtextResource updatedResource = null;
+
+		if(coreRes instanceof XtextResource)
+			coreResource = (XtextResource) coreRes;
+		if(updatedRes instanceof XtextResource)
+			updatedResource = (XtextResource) updatedRes;
+
+		/*
+		 * the idea: get the core grammar and the updated grammar
+		 * for each extension rule in the delta grammar,
+		 * 		find the corresponding rule in the updated grammar and the core grammar
+		 * 		if it doesn't exist in the updated grammar write the inconsistency
+		 * 		if it exists, compare to the rule in the core grammar
+		 */
+		for(AbstractNode node: allNodes) {
+			if(node.getElement() instanceof ExtRule) {
+				checkForConsistency(node, coreResource, updatedResource, compNode);
+			}
+		}
+	}
+	
+	private boolean checkForConsistency(AbstractNode node, XtextResource coreResource, XtextResource updatedResource, CompositeNode compNode) {
+		//updated grammar:
+		AbstractNode updatedRule = null;
+		AbstractNode coreRule = null;
+		Rule currentRule = null;
+		for(AbstractNode uNode : NodeUtil.getAllContents(updatedResource.getParseResult().getRootNode())) {
+			if (uNode.getElement() instanceof Rule) {
+				currentRule  = (Rule) uNode.getElement();
+				if (currentRule.getName().equals(((ExtRule) node.getElement()).getName())) {
+					updatedRule = uNode;
+					break;
+				}
+			}
+		}
+		
+		if(updatedRule == null) {
+			warning(EbnfJavaValidator.packageConsistencyCheckRuleMissingDescription, node.getElement(), 1);
+			return false;
+		} else { //core grammar
+			for(AbstractNode cNode : NodeUtil.getAllContents(coreResource.getParseResult().getRootNode())) {
+				if(cNode.getElement() instanceof Rule)
+					if(((Rule) cNode.getElement()).getName().equals(((ExtRule) node.getElement()).getName())) {
+						coreRule = cNode;
+						break;
+					}
+			}
+			
+			if(coreRule == null){
+				warning(EbnfJavaValidator.packageConsistencyCheckCorrespondingRuleMissingDescription, node.getElement(), 1);
+				return false;
+			}
+			
+			if (compareRules(coreRule, updatedRule)) {
+				return true;
+			} else {
+				warning(EbnfJavaValidator.packageConsistencyCheckRuleDifferentDescription, node.getElement(), 1);
+				return false;
+			}
+			
+		}
+	}
+
+	// returns true, if the rules are equal
+	private boolean compareRules(AbstractNode cNode, AbstractNode uNode) {
+		EList<LeafNode> cLeaves = removeWS(cNode.getLeafNodes());
+		EList<LeafNode> uLeaves = removeWS(uNode.getLeafNodes());
+		if (cLeaves.size() != uLeaves.size())
+			return false;
+		
+		for(int i=0; i < cLeaves.size(); i++) {
+			if(!(cLeaves.get(i).serialize().equals(uLeaves.get(i).serialize())))
+				return false;
+			
+		}
+		return true;
+	}
+
+	private EList<LeafNode> removeWS(EList<LeafNode> leaves) {
+		for(int i=0; i < leaves.size(); i++) {
+			if(!(leaves.get(i).getGrammarElement() instanceof org.eclipse.xtext.impl.TerminalRuleImpl))
+				leaves.remove(i);
+		}
+		return leaves;
+	}
+	
+	// ----------------------------------------------------------------------------------------------------
+
+	@Check(CheckType.EXPENSIVE)
+	public void checkReferencedOnlyOnce(Rule rule) {
+		if (!checkReferencedOnlyOnce)
+			return;
+
+		if (EbnfAnalysisUtils.isTokenRule(rule))
+			return;
+
+		List<Rule> references = EbnfAnalysisUtils.findReferences(rule,
+				resourceDescriptions);
+
+		if (references.size() == 1) {
+			warning(EbnfJavaValidator.ruleReferencedOneDescription, 1,
+					EbnfJavaValidator.ruleReferencedOneDescription);
+		}
+	}
+
+	// ----------------------------------------------------------------------------------------------------
+
+	@Check(CheckType.EXPENSIVE)
+	public void checkPassthroughRule(Rule rule) {
+		if (!checkPassthroughRule)
+			return;
+
+		List<Rule> references = EbnfAnalysisUtils.findReferences(rule,
+				resourceDescriptions);
+
+		if (EbnfAnalysisUtils.isPassthroughRule(rule)) {
+			if (references.size() == 0) {
+				warning(
+						EbnfJavaValidator.unreferencedPassthroughRuleDescription,
+						1,
+						EbnfJavaValidator.unreferencedPassthroughRuleDescription);
+			} else {
+				warning(EbnfJavaValidator.passthroughRuleDescription, 1,
+						EbnfJavaValidator.passthroughRuleDescription);
+			}
+		}
+	}
+
+	// ----------------------------------------------------------------------------------------------------
+
+	@Check(CheckType.EXPENSIVE)
+	public void checkUnusedRule(Rule rule) {
+		if (!checkUnusedRule)
+			return;
+
+		List<Rule> references = EbnfAnalysisUtils.findReferences(rule,
+				resourceDescriptions);
+
+		if ((references.size() == 0) && (rule.getRulenumber() != 1))
+			warning(EbnfJavaValidator.unusedRuleDescription, 1,
+					EbnfJavaValidator.unusedRuleDescription);
+	}
+
+	// ----------------------------------------------------------------------------------------------------
+
+	private List<DefinitionList> collectDefinitionLists(CompositeNode o) {
+		List<DefinitionList> list = new ArrayList<DefinitionList>();
+
+		for (int i = 0; i < o.getChildren().size(); i++) {
+			AbstractNode child = o.getChildren().get(i);
+			if (child.getElement() instanceof DefinitionList) {
+				list.add((DefinitionList) child.getElement());
+			}
+
+			if (child instanceof CompositeNode) {
+				list.addAll(collectDefinitionLists((CompositeNode) child));
+			}
+		}
+
+		return list;
+	}
+
+	// ----------------------------------------------------------------------------------------------------
+
+	@Check(CheckType.EXPENSIVE)
+	public void checkEqualAlternative(Rule rule) {
+		if (!checkEqualAlternative)
+			return;
+
+		// TODO: is not per rule, but global!
+
+		// quadratic!
+		CompositeNode startNode = NodeUtil.getNodeAdapter(rule).getParserNode();
+
+		List<DefinitionList> definitionLists = collectDefinitionLists(startNode);
+
+		for (int k = 0; k < definitionLists.size(); k++) {
+
+			EList<SingleDefinition> singleDefinitions = definitionLists.get(k)
+					.getSingleDefinition();
+			for (int i = 0; i < singleDefinitions.size(); i++) {
+				for (int j = 0; j < singleDefinitions.size(); j++) {
+					if (i == j)
+						continue;
+
+					SingleDefinition upper = singleDefinitions.get(i);
+					SingleDefinition lower = singleDefinitions.get(j);
+					CompositeNode upperNode = NodeUtil.getNodeAdapter(upper)
+							.getParserNode();
+					CompositeNode lowerNode = NodeUtil.getNodeAdapter(lower)
+							.getParserNode();
+
+					String upperString = upperNode.serialize().trim()
+							.replaceAll("[ \t\n\r]", "");
+					String lowerString = lowerNode.serialize().trim()
+							.replaceAll("[ \t\n\r]", "");
+
+					if (lowerString.equals(upperString))
+						warning(EbnfJavaValidator.equalAlternativeDescription,
+								1,
+								EbnfJavaValidator.equalAlternativeDescription);
+				}
+			}
+		}
+
+	}
+
+	// ----------------------------------------------------------------------------------------------------
+
+	@Check(CheckType.EXPENSIVE)
+	public void checkDuplicateRules(Rule rule) {
+		if (!checkDuplicateRules)
+			return;
+
+		CompositeNode node = NodeUtil.getNodeAdapter(rule).getParserNode();
+		CompositeNode root = node.getParent();
+		
+		AbstractNode last = node.getChildren().get(
+				node.getChildren().size() - 1);
+
+		if (!(last instanceof CompositeNode))
+			return;
+
+		CompositeNode rightHandSideNode = (CompositeNode) last;
+		String rightHandSideText = rightHandSideNode.serialize().trim()
+				.replaceAll("[ \t\n\r]", "");
+
+		for (int i = 0; i < root.getChildren().size(); i++) {
+			if (root.getChildren().get(i) == node)
+				continue;
+			if (root.getChildren().get(i) == null)
+				continue;
+			if (!(root.getChildren().get(i) instanceof CompositeNode))
+				continue;
+			
+			CompositeNode child = (CompositeNode) root.getChildren().get(i);
+			
+			AbstractNode childLastChild = child.getChildren().get(
+					child.getChildren().size() - 1);
+			if (childLastChild instanceof CompositeNode) {
+				CompositeNode childLastChildCompositeNode = (CompositeNode) childLastChild;
+				String text = childLastChildCompositeNode.serialize().trim()
+						.replaceAll("[ \t\n\r]", "");
+				if (text.equals(rightHandSideText)) {
+					Rule matchingRule = (Rule) child.getElement();
+					String description = EbnfJavaValidator.duplicateRulesDescription
+							+ " with rule "
+							+ matchingRule.getRulenumber()
+							+ " (Line "
+							+ child.getLine() + ")";
+					warning(description, 1, description);
+				}
+			}
+		}
+	}
+	
+	// ----------------------------------------------------------------------------------------------------
+	
+	@Check(CheckType.EXPENSIVE)
+	public void checkSubruleDuplicates(Rule rule) {
+		if (!checkSubruleDuplicates)
+			return;
+
+		//TODO: currently compares complete rules and not subrules
+		
+		CompositeNode node = NodeUtil.getNodeAdapter(rule).getParserNode();
+		CompositeNode root = node.getParent();
+		
+		AbstractNode last = node.getChildren().get(
+				node.getChildren().size() - 1);
+
+		if (!(last instanceof CompositeNode))
+			return;
+
+		CompositeNode rightHandSideNode = (CompositeNode) last;
+		String rightHandSideText = rightHandSideNode.serialize().trim()
+				.replaceAll("[ \t\n\r]", "");
+
+		for (int i = 0; i < root.getChildren().size(); i++) {
+			if (root.getChildren().get(i) == node)
+				continue;
+			if (root.getChildren().get(i) == null)
+				continue;
+			if (!(root.getChildren().get(i) instanceof CompositeNode))
+				continue;
+			
+			CompositeNode child = (CompositeNode) root.getChildren().get(i);
+			
+			AbstractNode childLastChild = child.getChildren().get(
+					child.getChildren().size() - 1);
+			if (childLastChild instanceof CompositeNode) {
+				CompositeNode childLastChildCompositeNode = (CompositeNode) childLastChild;
+				String text = childLastChildCompositeNode.serialize().trim()
+						.replaceAll("[ \t\n\r]", "");
+				if (text.equals(rightHandSideText)) {
+					Rule matchingRule = (Rule) child.getElement();
+					String description = EbnfJavaValidator.duplicateSubRulesDescription
+							+ " with rule "
+							+ matchingRule.getRulenumber()
+							+ " (Line "
+							+ child.getLine() + ")";
+					warning(description, 1, description);
+				}
+			}
+		}
+	}
+	
+}
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/validation/EbnfNamesAreUniqueValidationHelper.java
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/validation/EbnfNamesAreUniqueValidationHelper.java	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/validation/EbnfNamesAreUniqueValidationHelper.java	(revision 5)
@@ -0,0 +1,54 @@
+package de.ugoe.cs.swe.bnftools.validation;
+
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.resource.IEObjectDescription;
+import org.eclipse.xtext.validation.NamesAreUniqueValidationHelper;
+import org.eclipse.xtext.validation.ValidationMessageAcceptor;
+
+import com.google.common.collect.Maps;
+
+import de.ugoe.cs.swe.bnftools.ebnf.ExtRule;
+import de.ugoe.cs.swe.bnftools.ebnf.MergeRule;
+
+public class EbnfNamesAreUniqueValidationHelper extends
+		NamesAreUniqueValidationHelper {
+	
+	protected void checkDescriptionForDuplicatedName(
+			IEObjectDescription description,
+			Map<EClass, Map<String, IEObjectDescription>> clusterTypeToName,
+			ValidationMessageAcceptor acceptor) {
+		
+		EObject object = description.getEObjectOrProxy();
+		EClass eClass = object.eClass();
+		String qualifiedName = description.getName();
+		EClass clusterType = getAssociatedClusterType(eClass);
+		
+		if (object instanceof ExtRule)
+			return;
+		if(object instanceof MergeRule)
+			return;
+		Map<String, IEObjectDescription> nameToDescription = clusterTypeToName.get(clusterType);
+		
+		if (nameToDescription == null) {
+			nameToDescription = Maps.newHashMap();
+			nameToDescription.put(qualifiedName, description);
+		
+			clusterTypeToName.put(clusterType, nameToDescription);
+		} else {
+			if (nameToDescription.containsKey(qualifiedName)) {
+				IEObjectDescription prevDescription = nameToDescription.get(qualifiedName);
+				if (prevDescription != null) {
+					createDuplicateNameError(prevDescription, clusterType, acceptor);
+					nameToDescription.put(qualifiedName, null);
+				}
+				createDuplicateNameError(description, clusterType, acceptor);
+			} else {
+				nameToDescription.put(qualifiedName, description);
+			}
+		}
+	}
+
+}
Index: trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/valueconverter/EbnfTerminalConverters.java
===================================================================
--- trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/valueconverter/EbnfTerminalConverters.java	(revision 5)
+++ trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/valueconverter/EbnfTerminalConverters.java	(revision 5)
@@ -0,0 +1,33 @@
+package de.ugoe.cs.swe.bnftools.valueconverter;
+
+import org.eclipse.xtext.common.services.DefaultTerminalConverters;
+import org.eclipse.xtext.conversion.IValueConverter;
+import org.eclipse.xtext.conversion.ValueConverter;
+import org.eclipse.xtext.conversion.ValueConverterException;
+import org.eclipse.xtext.conversion.impl.AbstractNullSafeConverter;
+import org.eclipse.xtext.parsetree.AbstractNode;
+import org.eclipse.xtext.util.Strings;
+
+public class EbnfTerminalConverters extends DefaultTerminalConverters {
+
+	@ValueConverter(rule = "STRING")
+	public IValueConverter<String> STRING() {
+		return new AbstractNullSafeConverter<String>() {
+			@Override
+			protected String internalToValue(String string, AbstractNode node) {
+				try {
+					return string.substring(1,
+							string.length() - 1);
+				} catch (IllegalArgumentException e) {
+					throw new ValueConverterException(e.getMessage(), node, e);
+				}
+			}
+
+			@Override
+			protected String internalToString(String value) {
+				return '"' + Strings.convertToJavaString(value, false) + '"';
+			}
+		};
+	}
+
+}
