makegrammar.java
来自「SRI international 发布的OAA框架软件」· Java 代码 · 共 750 行 · 第 1/2 页
JAVA
750 行
package antlr_oaa;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: MakeGrammar.java,v 1.1 2002/11/08 17:37:53 agno Exp $
*/
import antlr_oaa.collections.Stack;
import antlr_oaa.collections.impl.LList;
import antlr_oaa.collections.impl.Vector;
public class MakeGrammar extends DefineGrammarSymbols {
protected Stack blocks = new LList(); // track subrules--Stack<BlockContext>
protected RuleRefElement lastRuleRef;
protected RuleEndElement ruleEnd; // used if not nested
protected RuleBlock ruleBlock; // points to block of current rule.
protected int nested = 0; // nesting inside a subrule
protected boolean grammarError = false;
ExceptionSpec currentExceptionSpec = null;
public MakeGrammar(Tool tool_, String[] args_, LLkAnalyzer analyzer_) {
super(tool_, args_, analyzer_);
}
/** Abort the processing of a grammar (due to syntax errors) */
public void abortGrammar() {
String s = "unknown grammar";
if ( grammar!=null ) {
s = grammar.getClassName();
}
tool.error("aborting grammar '" + s + "' due to errors");
super.abortGrammar();
}
protected void addElementToCurrentAlt(AlternativeElement e) {
e.enclosingRuleName = ruleBlock.ruleName;
context().addAlternativeElement(e);
}
public void beginAlt(boolean doAutoGen_) {
super.beginAlt(doAutoGen_);
Alternative alt = new Alternative();
alt.setAutoGen(doAutoGen_);
context().block.addAlternative(alt);
}
public void beginChildList() {
super.beginChildList();
context().block.addAlternative(new Alternative());
}
/** Add an exception group to a rule (currently a no-op) */
public void beginExceptionGroup() {
super.beginExceptionGroup();
if (!(context().block instanceof RuleBlock))
{
tool.panic("beginExceptionGroup called outside of rule block");
}
}
/** Add an exception spec to an exception group or rule block */
public void beginExceptionSpec(Token label) {
// Hack the label string a bit to remove leading/trailing space.
if (label != null) {
label.setText( Tool.stripFront( Tool.stripBack(label.getText(), " \n\r\t"), " \n\r\t") );
}
super.beginExceptionSpec(label);
// Don't check for currentExceptionSpec!=null because syntax errors
// may leave it set to something.
currentExceptionSpec = new ExceptionSpec(label);
}
public void beginSubRule(Token label, int line, boolean not) {
super.beginSubRule(label,line, not);
// we don't know what kind of subrule it is yet.
// push a dummy one that will allow us to collect the
// alternatives. Later, we'll switch to real object.
blocks.push(new BlockContext());
context().block = new AlternativeBlock(grammar, line, not);
context().altNum = 0; // reset alternative number
nested++;
// create a final node to which the last elememt of each
// alternative will point.
context().blockEnd = new BlockEndElement(grammar);
// make sure end node points to start of block
context().blockEnd.block = context().block;
labelElement(context().block, label);
}
public void beginTree(int line) throws SemanticException {
if (!(grammar instanceof TreeWalkerGrammar)) {
tool.error("Trees only allowed in TreeParser", grammar.getFilename(), line);
throw new SemanticException("Trees only allowed in TreeParser");
}
super.beginTree(line);
blocks.push(new TreeBlockContext());
context().block = new TreeElement(grammar, line);
context().altNum = 0; // reset alternative number
}
public BlockContext context() {
if ( blocks.height()==0 ) {
return null;
}
else {
return (BlockContext)blocks.top();
}
}
/**Used to build nextToken() for the lexer.
* This builds a rule which has every "public" rule in the given Vector of
* rules as it's alternate. Each rule ref generates a Token object.
* @param g The Grammar that is being processed
* @param lexRules A vector of lexer rules that will be used to create an alternate block.
* @param rname The name of the resulting rule.
*/
public static RuleBlock createNextTokenRule(Grammar g, Vector lexRules, String rname) {
// create actual rule data structure
RuleBlock rb = new RuleBlock(g, rname);
rb.setDefaultErrorHandler( g.getDefaultErrorHandler() );
RuleEndElement ruleEnd = new RuleEndElement(g);
rb.setEndElement(ruleEnd);
ruleEnd.block = rb;
// Add an alternative for each element of the rules vector.
for (int i=0; i<lexRules.size(); i++) {
RuleSymbol r = (RuleSymbol)lexRules.elementAt(i);
if (!r.isDefined()) {
g.tool.error("Lexer rule " + r.id.substring(1) + " is not defined");
}
else {
if ( r.access.equals("public") ) {
// create a rule ref to lexer rule
// the Token is a RULE_REF not a TOKEN_REF since the
// conversion to mRulename has already taken place
RuleRefElement rr =
new RuleRefElement(g,
new CommonToken(ANTLRTokenTypes.RULE_REF, r.getId()),
GrammarElement.AUTO_GEN_NONE);
//labelElement(rr, new Token("_rettoken"));
// rr.setIdAssign("_ttype");
rr.setLabel("theRetToken");
rr.enclosingRuleName = "nextToken";
rr.next = ruleEnd;
Alternative alt = new Alternative(rr);
alt.setAutoGen(true); // keep text of elements
rb.addAlternative(alt);
// Add a reference to the rule used for the alt
r.addReference(rr);
}
}
}
rb.setAutoGen(true); // keep text of elements
rb.prepareForAnalysis();
//System.out.println(rb);
return rb;
}
/** Return block as if they had typed: "( rule )?" */
private AlternativeBlock createOptionalRuleRef(String rule, int line) {
// Make the subrule
AlternativeBlock blk = new AlternativeBlock(grammar, line, false);
// Make sure rule is defined
String mrule = CodeGenerator.lexerRuleName(rule); // can only be a lexer rule!
if ( !grammar.isDefined(mrule) ) {
grammar.define(new RuleSymbol(mrule));
}
// Make the rule ref element
Token t = new CommonToken(ANTLRTokenTypes.TOKEN_REF, rule);
t.setLine(line);
RuleRefElement rref =
new RuleRefElement(grammar, t, GrammarElement.AUTO_GEN_NONE);
rref.enclosingRuleName = ruleBlock.ruleName;
// Make the end of block element
BlockEndElement end = new BlockEndElement(grammar);
end.block = blk; // end block points back to start of blk
// Make an alternative, putting the rule ref into it
Alternative alt = new Alternative(rref);
alt.addElement(end); // last element in alt points to end of block
// Add the alternative to this block
blk.addAlternative(alt);
// create an empty (optional) alt and add to blk
Alternative optAlt = new Alternative();
optAlt.addElement(end); // points immediately to end of block
blk.addAlternative(optAlt);
blk.prepareForAnalysis();
return blk;
}
public void defineRuleName(Token r,
String access,
boolean ruleAutoGen,
String docComment)
throws SemanticException
{
// if ( Character.isUpperCase(r.getText().charAt(0)) ) {
if ( r.type == ANTLRTokenTypes.TOKEN_REF ) {
if (!(grammar instanceof LexerGrammar)) {
tool.error("Lexical rule "+r.getText()+
" defined outside of lexer",
grammar.getFilename(), r.getLine());
r.setText(r.getText().toLowerCase());
}
}
else {
if (grammar instanceof LexerGrammar) {
tool.error("Non-lexical rule "+r.getText()+
" defined inside of lexer",
grammar.getFilename(), r.getLine());
r.setText(r.getText().toUpperCase());
}
}
super.defineRuleName(r, access, ruleAutoGen, docComment);
String id = r.getText();
// if ( Character.isUpperCase(id.charAt(0)) ) { // lexer rule?
if ( r.type == ANTLRTokenTypes.TOKEN_REF ) { // lexer rule?
id = CodeGenerator.lexerRuleName(id);
}
RuleSymbol rs = (RuleSymbol) grammar.getSymbol(id);
RuleBlock rb = new RuleBlock(grammar, r.getText(), r.getLine(), ruleAutoGen);
// Lexer rules do not generate default error handling
rb.setDefaultErrorHandler(grammar.getDefaultErrorHandler());
ruleBlock = rb;
blocks.push(new BlockContext()); // enter new context
context().block = rb;
rs.setBlock(rb);
ruleEnd = new RuleEndElement(grammar);
rb.setEndElement(ruleEnd);
nested = 0;
}
public void endAlt() {
super.endAlt();
if ( nested==0 ) { // all rule-level alts link to ruleEnd node
addElementToCurrentAlt(ruleEnd);
}
else {
addElementToCurrentAlt(context().blockEnd);
}
context().altNum++;
}
public void endChildList() {
super.endChildList();
// create a final node to which the last elememt of the single
// alternative will point. Done for compatibility with analyzer.
// Does NOT point to any block like alternative blocks because the
// TreeElement is not a block. This is used only as a placeholder.
BlockEndElement be = new BlockEndElement(grammar);
be.block = context().block;
addElementToCurrentAlt(be);
}
public void endExceptionGroup() {
super.endExceptionGroup();
}
public void endExceptionSpec() {
super.endExceptionSpec();
if (currentExceptionSpec == null)
{
tool.panic("exception processing internal error -- no active exception spec");
}
if (context().block instanceof RuleBlock)
{
// Named rule
((RuleBlock)context().block).addExceptionSpec(currentExceptionSpec);
} else {
// It must be a plain-old alternative block
if (context().currentAlt().exceptionSpec != null) {
tool.error("Alternative already has an exception specification", grammar.getFilename(), context().block.getLine());
}
else {
context().currentAlt().exceptionSpec = currentExceptionSpec;
}
}
currentExceptionSpec = null;
}
/** Called at the end of processing a grammar */
public void endGrammar() {
if (grammarError) {
abortGrammar();
}
else {
super.endGrammar();
}
}
public void endRule(String rule) {
super.endRule(rule);
BlockContext ctx = (BlockContext) blocks.pop(); // remove scope
// record the start of this block in the ending node
ruleEnd.block = ctx.block;
ruleEnd.block.prepareForAnalysis();
//System.out.println(ctx.block);
}
public void endSubRule() {
super.endSubRule();
nested--;
// remove subrule context from scope stack
BlockContext ctx = (BlockContext)blocks.pop();
AlternativeBlock block = ctx.block;
// If the subrule is marked with ~, check that it is
// a valid candidate for analysis
if (
block.not &&
!(block instanceof SynPredBlock) &&
!(block instanceof ZeroOrMoreBlock) &&
!(block instanceof OneOrMoreBlock)
)
{
if (!analyzer.subruleCanBeInverted(block, grammar instanceof LexerGrammar)) {
String newline = System.getProperty("line.separator");
tool.error(
"This subrule cannot be inverted. Only subrules of the form:"+newline +
" (T1|T2|T3...) or" + newline +
" ('c1'|'c2'|'c3'...)" + newline +
"may be inverted (ranges are also allowed).",
grammar.getFilename(),
block.getLine()
);
}
}
// add the subrule as element if not a syn pred
if ( block instanceof SynPredBlock ) {
// record a reference to the recently-recognized syn pred in the
// enclosing block.
SynPredBlock synpred = (SynPredBlock)block;
context().block.hasASynPred = true;
context().currentAlt().synPred = synpred;
grammar.hasSyntacticPredicate = true;
synpred.removeTrackingOfRuleRefs(grammar);
}
else {
addElementToCurrentAlt(block);
}
ctx.blockEnd.block.prepareForAnalysis();
}
public void endTree() {
super.endTree();
BlockContext ctx = (BlockContext) blocks.pop();
addElementToCurrentAlt(ctx.block); // add new TreeElement to enclosing alt.
}
/** Remember that a major error occured in the grammar */
public void hasError() {
grammarError = true;
}
private void labelElement(AlternativeElement el, Token label) {
if ( label != null ) {
// Does this label already exist?
for (int i = 0; i < ruleBlock.labeledElements.size(); i++) {
AlternativeElement altEl = (AlternativeElement)ruleBlock.labeledElements.elementAt(i);
String l = altEl.getLabel();
if (l != null && l.equals(label.getText())) {
tool.error("Label '" + label.getText() + "' has already been defined", grammar.getFilename(), label.getLine());
return;
}
}
// add this node to the list of labeled elements
el.setLabel(label.getText());
ruleBlock.labeledElements.appendElement(el);
}
}
public void noAutoGenSubRule() {
context().block.setAutoGen(false);
}
public void oneOrMoreSubRule() {
if (context().block.not) {
tool.error("'~' cannot be applied to (...)* subrule", grammar.getFilename(), context().block.getLine());
}
// create the right kind of object now that we know what that is
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?