wiki:Developer

Version 1 (modified by hkaulbersch, 10 years ago) (diff)

--

Developer Guide BNF Tools

BNF Tools is a BNF-Editor based on xText DSLs, which gives away alot of features.

The used Features are:

  • Grammardefinition
  • Validation
  • Quickfixing
  • Generation of content from the BNF
  • Formatting
  • Outlining
  • File import
  • Deployment as Plugin
  • Deployment as RCP (Rich Client Platform)

Grammardefinition:

The corefeature of xText.

This is defined in de.ugoe.cs.swe.bnftools.ebnf/de.ugoe.cs.swe.bnftools.ebnf/EBNF.xtext

IT contains the Entities after which the grammar must be defined, while the first rule is the Start e.g.:

EtsiBnf:

'grammar'name=ID

( type='/bnf'?';'

(importSection=ImportSection)?

(bnfEntry+=BnfEntry)+

)

|

( type='/delta;'

(importSection=ImportSection)?

(deltaEntry+=DeltaEntry)*

)

|

( type='/merge;'

(importSection=ImportSection)?

(mergeEntry+=MergeEntry)*

)

;

To turn this into a runable application the .mwe2 file in the same folder must be executed as MWE2 Workflow.

After this the whole project can be executed as an Eclipse Application for testing

Validation allows to check for conditions in the BNF-Document:

In the File de.ugoe.cs.swe.bnftools.ebnf/de.ugoe.cs.swe.ebnf.validation/EbnfValidator.xtend

validationrules can be defined e.g.:

@Check

defvoidcheckUnusedRule(Rule rule) {

varList<RuleReference> references = EbnfAnalysisUtils.findReferences(rule);

varList<Rule> references1 = EbnfAnalysisUtils.findReferences(rule,resourceDescriptions);

if((references.size+references1.size ==0) && (rule.getRulenumber() !=1))

warning(unusedRuleDescription, EbnfPackage$Literals::RULE__NAME,unusedRuleDescription, rule.name);

}

For this the@Checkannotation defines that the next function is a Validationcheck.

The parameter can be any Entity from the previously defined Grammar and every Entity of this Type will be checked this way.

And if the Check finds some inconsistency awarningwill be displayed to this Entity Instance in the Editor.

The other files in the Package contain supporting Methodes for the validation

like

EbnfAnalysisUtils.findReferences(rule);

or

EbnfAnalysisUtils.findReferences(rule,resourceDescriptions);

Which find the Rule references inside a BNF-File or outside a BNF-File.


Quickfixing can be applied to warnings given by Validations:

In the File de.ugoe.cs.swe.bnftools.ebnf.ui/de.ugoe.cs.swe.bnftools.ui.quickfix/EbnfQuickfixProvider.xtend

quickfixes for validation-warnings can be defined e.g.:

@Fix(EbnfValidator.unusedRuleDescription)

defvoidfixUnusedRule(Issue issue, IssueResolutionAcceptor acceptor) {

acceptor.accept(issue,"Remove unused rule","Delete the unused rule","upcase.png",[ element, context |

varRule rule = elementasRule;

varIXtextDocument xtextDocument = context.getXtextDocument();

varICompositeNode node = NodeModelUtils.findActualNodeFor(rule);

varintoffset = node.textRegion.offset;

varString nodeText = node.text;

varinttextLength = nodeText.length -2;

xtextDocument.replace(offset, textLength,"");

])

}

The @Fix(String token) annotation definies that the following method is a quickfix for a validationwarning, with that token as code parameter:

warning(unusedRuleDescription, EbnfPackage$Literals::RULE__NAME, unusedRuleDescription, rule.name);

@Fix(EbnfValidator.unusedRuleDescription)

The accaptor inside applies the changes, via two possible ways:

  1. Change the Document itself (like the example shows).
  1. Change the underlying ecoremodel.


Generation allows to generate other files from a BNF-Document:

In our case we create a .fo document, that can be transformed into a PDF-Document

using Apache FOP.

It can be customized in the File de.ugoe.cs.swe.bnftools.ebnf/de.ugoe.cs.swe.ebnf.generator/EbnfGenerator.xtend

Where the doGenerate methode defines how the files given by a Resource and a IfileSystemAccess should generate a new file. While for every relevant Entity from the

BNF a compile Methode handles the generation in the new file, while it calls the compile Methode for every related Entity e.g.:

override void doGenerate(Resource resource, IFileSystemAccess fsa) {

for(e : resource.allContents.toIterable.filter(EtsiBnf)) {

if(e.bnfEntry.size !=0) {

fsa.generateFile(e.name +".fo", e.compile)

}

}

defcompile(DefinitionList dList)'''«FORsDef : ist.singleDefinition»«sDef.compile»

«IF !sDef.equals(dList.singleDefinition.last)»|«ENDIF»«ENDFOR»'''

Generation of PDF using Apache FOP:

Based on the generated .fo file a PDF-document can be generated for this the class de.ugoe.cs.swe.bnftools.ebnf/de.ugoe.cs.swe.ebnf.generator/foToPDF can be used, either by giving the .fo file and the output URI without Ending or simply the giving the classpath of the file.

For this the dodoGenerateMethode needed an upgrade to access the filesystem via URIs:

overridevoiddoGenerate(Resource resource, IFileSystemAccess fsa) {

varString workspacePath = WorkspaceResolver.getWorkspace();

for(e : resource.allContents.toIterable.filter(EtsiBnf)) {

if(e.bnfEntry.size !=0) {

fsa.generateFile(e.name +".fo", e.compile)

generatepdf

varuri = (fsaasIFileSystemAccessExtension2).getURI(e.name +".fo");

varString fullUri = workspacePath + uri.path.substring(10, uri.path.length);

varFile file =newFile(fullUri);

if(file.exists) {

foToPdf.createPdfFromFo(fullUri.substring(0, fullUri.length -3));

}

}

}

}

To include apache fop you need to add all the jars in a folder e.g. Libs in your project, add this folder to your buildpath, cofigure buildpath and add the jars to it and add them in the plugin.xml on the page runtime at classpath.


Formatting or Prittey Printing is to format the BNF-Document:

In the File de.ugoe.cs.swe.bnftools.ebnf/de.ugoe.cs.swe.ebnf.formatting/EbnfFormatter.xtend

the Method configureFormatting(FormattingConfig c)allows to define formatting rules

before, after or between Enteties or Keywords.

e.g.:

@InjectextensionEbnfGrammarAccess

overrideprotectedvoidconfigureFormatting(FormattingConfig c) {

c.setLinewrap(0,1,2).before(SL_COMMENTRule)

c.setLinewrap(0,1,2).before(ML_COMMENTRule)

c.setLinewrap(0,1,1).after(ML_COMMENTRule)

varEbnfGrammarAccess f = getGrammarAccessasEbnfGrammarAccess;

c.setLinewrap.before(f.ruleRule);

c.setLinewrap.before(f.importRule);

c.setNoSpace.after(f.ruleAccess.rulenumberINTTerminalRuleCall_0_0_0)

}

The Entities are recieved via an Inector that gives access to The Grammar.


Outlining and Labeling are Features, that show the document Structure of the BNF-Document:

Outlinining can be customized in the File

de.ugoe.cs.swe.bnftools.ebnf.ui/de.ugoe.cs.swe.bnftools.ui.outline/EbnfOutlineTreeProvider.xtend.

Here you can define a_createChildren()with the rootNode and the BNF-Entity of the Grammar to change the outline sequence:

defvoid_createChildren(DocumentRootNode parentNode, EtsiBnf bnf) {

createNode(parentNode,bnf);

}

Labeling is made to customize what the outline text for an Entity should look like.

It can be customized in the file

de.ugoe.cs.swe.bnftools.ebnf.ui/de.ugoe.cs.swe.bnftools.ui.labeling/EbnfLabelProvider.xtend

Where for every Entity a text can be defined:

deftext(ImportSection sec){

'Imports'

}


File import allows to reference Rules from one BNF-Document in another:

There are 2 ways for imports, via URI and VIA Namespaces:

The BNF-Grammar uses the URI version. To Activate this the lines

fragment= scoping.ImportNamespacesScopingFragmentauto-inject{}

fragment= exporting.QualifiedNamesFragmentauto-inject{}

fragment= builder.BuilderIntegrationFragmentauto-inject{}

fragment= types.TypesGeneratorFragmentauto-inject{}

in the .mwe2 file have to be commented out and the lines:

fragment= scoping.ImportURIScopingFragmentauto-inject{}

fragment= exporting.SimpleNamesFragmentauto-inject{}

must be included.

After That imports can be defined like this and will automaticly be used:

'import'importURI=STRING

Also it is possible to add features to the UI via Xtext:

In the File de.ugoe.cs.swe.bnftools.ebnf.ui/plugin.xml new extensions to the UI can be created in the plugin.xml tab. e.g.:

<extension

point="org.eclipse.ui.handlers">

<handler

class="de.ugoe.cs.swe.bnftools.ui.EbnfExecutableExtensionFactory:de.ugoe.cs.swe.bnftools.ui.handler.GenerationHandler"

commandId="de.ugoe.cs.swe.bnftools.ui.handler.GenerationCommand">

</handler>

</extension>

<extension

point="org.eclipse.ui.commands">

<commandname="Generate Code"

id="de.ugoe.cs.swe.bnftools.ui.handler.GenerationCommand">

</command>

</extension>

<extensionpoint="org.eclipse.ui.menus">

<menuContributionlocationURI="popup:org.eclipse.jdt.ui.PackageExplorer">

<command

commandId="de.ugoe.cs.swe.bnftools.ui.handler.GenerationCommand"

style="push">

<visibleWhen

checkEnabled="false">

<iterate>

<adapttype="org.eclipse.core.resources.IResource">

<testproperty="org.eclipse.core.resources.name"

value="*.bnf"/>

</adapt>

</iterate>

</visibleWhen>

</command>

</menuContribution>

</extension>

This extension creates a new button in the popupmenu that opens when

rightclicking a .bnf file which triggers a handlerde.ugoe.cs.swe.bnftools.ui.handler.GenerationHandler

for this File that should call the Generator of the Grammar for this File.

@Override

publicObject execute(ExecutionEvent event)throwsExecutionException {

ISelection selection = HandlerUtil.getCurrentSelection(event);

if(selectioninstanceofIStructuredSelection) {

IStructuredSelection structuredSelection = (IStructuredSelection) selection;

Object firstElement = structuredSelection.getFirstElement();

if(firstElementinstanceofIFile) {

IFile file = (IFile) firstElement;

IProject project = file.getProject();

IFolder srcGenFolder = project.getFolder("src-gen");

if(!srcGenFolder.exists()) {

try{

srcGenFolder.create(true,true,newNullProgressMonitor());

}catch(CoreException e) {

returnnull;

}

}

final!EclipseResourceFileSystemAccess2 fsa =fileAccessProvider.get();

fsa.setOutputPath(srcGenFolder.getFullPath().toString());

URI uri = URI.createPlatformResourceURI(file.getFullPath().toString(),true);

ResourceSet rs =resourceSetProvider.get(project);

Resource r = rs.getResource(uri,true);

generator.doGenerate(r, fsa);

}

}

returnnull;

}

Here is a Problem since the!EclipseResourceFileSystemAccess2does not contain all the needed inforamtion. Maybe it can be looked up in the normal call of the generator.

Deployment as Plugin:

If you want to deploy your the BNF Tools you can use the deployment as plugin:

Rightclick your xTextProject, chooseexport, choosePlug-in development --> Deployable plug-ins and fragments, choose all parts of the project, *.ebnf *.ebnf.tests *.ebnf.ui and a directory. After you finish this will generate a jar for every one of the choosen projects. Add these to the pluigin-folder of a eclipse and it should be installed

Deployment as RCP:

If you want to create a Rich client platform for a standalone minimal worbench setup with only your plugin an requiered plugins in it RCP is a good choice (This is for an eclipse 3.x RCP).

First create yourxText Project, then create a newPlug-in Project.Give it a name,

e.g. de.ugoe.cs.swe.bnftools.ebnf.product. Click next, and unchooseGenerate an Activator, a Java Class that controls the plug-in-s life cycleandThis plug-in will make contributions to the UI.Also choosenoatRich client Platform. Press finish.

now open theManifest.MF, go to theOverview pageand chooseThis plug-in in a singleton. Then go to theDependencies pageand addorg.eclipse.core.runtime.

Now create a product configuration in your product project, on itsOverview Pageclick new, choose a fitting name and ID, your product project as defining Plugin and org.eclipse.ui.ide.workbench as application. Now go back to theManifest.MFand open theExtensions Page. There you should now see 1 Extensionorg.eclipse.core.runtime.productswith a product inside. This should haveorg.eclipse.ui.ide.workbenchas application and the given name of the product configuration as name. Rightclick the product and create a new property and if you want you can give it a customized name and value.

Now back to the product configurationand its dependencies page. There you add all your xtext projects and your product, then clickadd Requiered Plug-ins. After this you still need to add the Pluginsorg.eclipse.ui.ide.applicationandorg.eclipse.core.net

. now you can test your product by running it as a Runtime Eclipse, if there is a missing plugin you can find it using thevalidate plugins optionin the run configurations plug-ins page . Deploy it usingExport as an Eclipse Productin theproduct configuration.

@ To make the generator run properly you need to add org.eclipse.xtext.xbase to your product configuration dependencies