📄 cppcodegenerator.java
字号:
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: CppCodeGenerator.java,v 1.1 2002/11/08 17:38:09 agno Exp $
*/
// C++ code generator by Pete Wells: pete@yamuna.demon.co.uk
// #line generation contributed by: Ric Klaren <klaren@cs.utwente.nl>
import java.util.Enumeration;
import java.util.Hashtable;
import antlr_oaa.collections.impl.BitSet;
import antlr_oaa.collections.impl.Vector;
import java.io.PrintWriter; //SAS: changed for proper text file io
import java.io.IOException;
import java.io.FileWriter;
/**Generate MyParser.cpp, MyParser.hpp, MyLexer.cpp, MyLexer.hpp and MyParserTokenTypes.hpp */
public class CppCodeGenerator extends CodeGenerator {
// non-zero if inside syntactic predicate generation
protected int syntacticPredLevel = 0;
// Are we generating ASTs (for parsers and tree parsers) right now?
protected boolean genAST = false;
// Are we saving the text consumed (for lexers) right now?
protected boolean saveText = false;
// Generate #line's
protected boolean genHashLines = true;
// Used to keep track of lineno in output
protected int outputLine;
protected String outputFile;
// Grammar parameters set up to handle different grammar classes.
// These are used to get instanceof tests out of code generation
boolean usingCustomAST = false;
String labeledElementType;
String labeledElementASTType; // mostly the same as labeledElementType except in parsers
String labeledElementASTInit;
String labeledElementInit;
String commonExtraArgs;
String commonExtraParams;
String commonLocalVars;
String lt1Value;
String exceptionThrown;
String throwNoViable;
// Tracks the rule being generated. Used for mapTreeId
RuleBlock currentRule;
// Tracks the rule or labeled subrule being generated. Used for AST generation.
String currentASTResult;
// Mapping between the ids used in the current alt, and the
// names of variables used to represent their AST values.
Hashtable treeVariableMap = new Hashtable();
// Count of unnamed generated variables
int astVarNumber = 1;
// Special value used to mark duplicate in treeVariableMap
protected static final String NONUNIQUE = new String();
public static final int caseSizeThreshold = 127; // ascii is max
private Vector semPreds;
private static String namespaceStd = "ANTLR_USE_NAMESPACE(std)";
private static String namespaceAntlr = "ANTLR_USE_NAMESPACE(antlr)";
private static NameSpace nameSpace = null;
private static final String preIncludeCpp = "pre_include_cpp";
private static final String preIncludeHpp = "pre_include_hpp";
private static final String postIncludeCpp = "post_include_cpp";
private static final String postIncludeHpp = "post_include_hpp";
/** Create a C++ code-generator using the given Grammar.
* The caller must still call setTool, setBehavior, and setAnalyzer
* before generating code.
*/
public CppCodeGenerator() {
super();
charFormatter = new CppCharFormatter();
}
/** Adds a semantic predicate string to the sem pred vector
These strings will be used to build an array of sem pred names
when building a debugging parser. This method should only be
called when the debug option is specified
*/
protected int addSemPred(String predicate) {
semPreds.appendElement(predicate);
return semPreds.size()-1;
}
public void exitIfError() {
if (tool.hasError) {
System.out.println("Exiting due to errors.");
System.exit(1);
}
}
protected int countLines( String s )
{
int lines = 0;
for( int i = 0; i < s.length(); i++ )
{
if( s.charAt(i) == '\n' )
lines++;
}
return lines;
}
/** Output a String to the currentOutput stream.
* Ignored if string is null.
* @param s The string to output
*/
protected void _print(String s) {
if (s != null) {
outputLine += countLines(s);
currentOutput.print(s);
}
}
/** Print an action without leading tabs, attempting to
* preserve the current indentation level for multi-line actions
* Ignored if string is null.
* @param s The action string to output
*/
protected void _printAction(String s) {
if (s != null) {
outputLine += countLines(s)+1;
super._printAction(s);
}
}
/** Print an action stored in a token surrounded by #line stuff */
public void printAction(Token t) {
if (t != null) {
genLineNo(t.getLine());
printTabs();
_printAction(t.getText());
genLineNo2();
}
}
/** Print a header action by #line stuff
* @param name The name of the header part
*/
public void printHeaderAction(String name) {
Token a = (antlr_oaa.Token)behavior.headerActions.get(name);
if (a != null) {
genLineNo(a.getLine());
println(a.getText());
genLineNo2();
}
}
/** Output a String followed by newline, to the currentOutput stream.
* Ignored if string is null.
* @param s The string to output
*/
protected void _println(String s) {
if (s != null) {
outputLine += countLines(s)+1;
currentOutput.println(s);
}
}
/** Output tab indent followed by a String followed by newline,
* to the currentOutput stream. Ignored if string is null.
* @param s The string to output
*/
protected void println(String s) {
if (s != null) {
printTabs();
outputLine += countLines(s)+1;
currentOutput.println(s);
}
}
/** Generate a #line or // line depending on options */
public void genLineNo(int line) {
if ( line == 0 ) {
line++;
}
if( genHashLines )
_println("#line "+line+" \""+Tool.fileMinusPath(tool.grammarFile)+"\"");
else
println("// line "+line+" \""+Tool.fileMinusPath(tool.grammarFile)+"\"");
}
/** Generate a #line or // line depending on options */
public void genLineNo(GrammarElement el)
{
if( el != null )
genLineNo(el.getLine());
}
/** Generate a #line or // line depending on options */
public void genLineNo(Token t)
{
if (t != null)
genLineNo(t.getLine());
}
/** Generate a #line or // line depending on options */
public void genLineNo2()
{
if( genHashLines )
{
_println("#line "+(outputLine+1)+" \""+outputFile+"\"");
}
}
/**Generate the parser, lexer, treeparser, and token types in C++ */
public void gen() {
// Do the code generation
try {
// Loop over all grammars
Enumeration grammarIter = behavior.grammars.elements();
while (grammarIter.hasMoreElements()) {
Grammar g = (Grammar)grammarIter.nextElement();
// Connect all the components to each other
g.setGrammarAnalyzer(analyzer);
g.setCodeGenerator(this);
analyzer.setGrammar(g);
// To get right overloading behavior across hetrogeneous grammars
setupGrammarParameters(g);
g.generate();
exitIfError();
}
// Loop over all token managers (some of which are lexers)
Enumeration tmIter = behavior.tokenManagers.elements();
while (tmIter.hasMoreElements()) {
TokenManager tm = (TokenManager)tmIter.nextElement();
if (!tm.isReadOnly()) {
// Write the token manager tokens as C++
// this must appear before genTokenInterchange so that
// labels are set on string literals
genTokenTypes(tm);
// Write the token manager tokens as plain text
genTokenInterchange(tm);
}
exitIfError();
}
}
catch (IOException e) {
System.out.println(e.getMessage());
}
}
/** Generate code for the given grammar element.
* @param blk The {...} action to generate
*/
public void gen(ActionElement action) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genAction("+action+")");
if ( action.isSemPred ) {
genSemPred(action.actionText, action.line);
}
else {
if ( grammar.hasSyntacticPredicate ) {
println("if ( inputState->guessing==0 ) {");
tabs++;
}
ActionTransInfo tInfo = new ActionTransInfo();
String actionStr = processActionForTreeSpecifiers(action.actionText, action.getLine(), currentRule, tInfo);
if ( tInfo.refRuleRoot!=null ) {
// Somebody referenced "#rule", make sure translated var is valid
// assignment to #rule is left as a ref also, meaning that assignments
// with no other refs like "#rule = foo();" still forces this code to be
// generated (unnecessarily).
println(tInfo.refRuleRoot + " = "+labeledElementASTType+"(currentAST.root);");
}
// dump the translated action
genLineNo(action);
printAction(actionStr);
genLineNo2();
if ( tInfo.assignToRoot ) {
// Somebody did a "#rule=", reset internal currentAST.root
println("currentAST.root = "+tInfo.refRuleRoot+";");
// reset the child pointer too to be last sibling in sibling list
// now use if else in stead of x ? y : z to shut CC 4.2 up.
println("if ( "+tInfo.refRuleRoot+"!="+labeledElementASTInit+" &&");
tabs++;
println(tInfo.refRuleRoot+"->getFirstChild() != "+labeledElementASTInit+" )");
println(" currentAST.child = "+tInfo.refRuleRoot+"->getFirstChild();");
tabs--;
println("else");
tabs++;
println("currentAST.child = "+tInfo.refRuleRoot+";");
tabs--;
println("currentAST.advanceChildToEnd();");
}
if ( grammar.hasSyntacticPredicate ) {
tabs--;
println("}");
}
}
}
/** Generate code for the given grammar element.
* @param blk The "x|y|z|..." block to generate
*/
public void gen(AlternativeBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen("+blk+")");
println("{");
genBlockPreamble(blk);
// Tell AST generation to build subrule result
String saveCurrentASTResult = currentASTResult;
if (blk.getLabel() != null) {
currentASTResult = blk.getLabel();
}
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
CppBlockFinishingInfo howToFinish = genCommonBlock(blk, true);
genBlockFinish(howToFinish, throwNoViable);
println("}");
// Restore previous AST generation
currentASTResult = saveCurrentASTResult;
}
/** Generate code for the given grammar element.
* @param blk The block-end element to generate. Block-end
* elements are synthesized by the grammar parser to represent
* the end of a block.
*/
public void gen(BlockEndElement end) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genRuleEnd("+end+")");
}
/** Generate code for the given grammar element.
* @param blk The character literal reference to generate
*/
public void gen(CharLiteralElement atom) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genChar("+atom+")");
if ( atom.getLabel()!=null ) {
println(atom.getLabel() + " = " + lt1Value + ";");
}
boolean oldsaveText = saveText;
saveText = saveText && atom.getAutoGenType()==GrammarElement.AUTO_GEN_NONE;
genMatch(atom);
saveText = oldsaveText;
}
/** Generate code for the given grammar element.
* @param blk The character-range reference to generate
*/
public void gen(CharRangeElement r) {
if ( r.getLabel()!=null && syntacticPredLevel == 0) {
println(r.getLabel() + " = " + lt1Value + ";");
}
println("matchRange("+textOrChar(r.beginText)+","+textOrChar(r.endText)+");");
}
/** Generate the lexer C++ files */
public void gen(LexerGrammar g) throws IOException {
// If debugging, create a new sempred vector for this grammar
if (g.debuggingOutput)
semPreds = new Vector();
setGrammar(g);
if (!(grammar instanceof LexerGrammar)) {
tool.panic("Internal error generating lexer");
}
genBody(g);
genInclude(g);
}
/** Generate code for the given grammar element.
* @param blk The (...)+ block to generate
*/
public void gen(OneOrMoreBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen+("+blk+")");
String label;
String cnt;
println("{");
genBlockPreamble(blk);
if ( blk.getLabel() != null ) {
cnt = "_cnt_"+blk.getLabel();
}
else {
cnt = "_cnt" + blk.ID;
}
println("int "+cnt+"=0;");
if ( blk.getLabel() != null ) {
label = blk.getLabel();
}
else {
label = "_loop" + blk.ID;
}
println("for (;;) {");
tabs++;
// Tell AST generation to build subrule result
String saveCurrentASTResult = currentASTResult;
if (blk.getLabel() != null) {
currentASTResult = blk.getLabel();
}
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
// generate exit test if greedy set to false
// and an alt is ambiguous with exit branch
// or when lookahead derived purely from end-of-file
// Lookahead analysis stops when end-of-file is hit,
// returning set {epsilon}. Since {epsilon} is not
// ambig with any real tokens, no error is reported
// by deterministic() routines and we have to check
// for the case where the lookahead depth didn't get
// set to NONDETERMINISTIC (this only happens when the
// FOLLOW contains real atoms + epsilon).
boolean generateNonGreedyExitPath = false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -