mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Merge remote-tracking branch 'origin/GP-1172_ElseIfSyntax' (Closes
#1609)
This commit is contained in:
commit
81ea93cb29
7 changed files with 197 additions and 25 deletions
|
@ -71,6 +71,7 @@ void EmitXml::endBlock(int4 id) {
|
|||
|
||||
/// Tell the emitter that a new line is desired at the current indent level
|
||||
void EmitXml::tagLine(void) {
|
||||
emitPending();
|
||||
*s << "<break " << highlight[(int4)no_color] << " indent=\"0x" << hex <<
|
||||
indentlevel << "\"/>";
|
||||
}
|
||||
|
@ -79,6 +80,7 @@ void EmitXml::tagLine(void) {
|
|||
/// is overridden only for the line, then it returns to its previous value.
|
||||
/// \param indent is the desired indent level for the new line
|
||||
void EmitXml::tagLine(int4 indent) {
|
||||
emitPending();
|
||||
*s << "<break " << highlight[(int4)no_color] << " indent=\"0x" << hex <<
|
||||
indent << "\"/>";
|
||||
}
|
||||
|
@ -923,6 +925,7 @@ void EmitPrettyPrint::endBlock(int4 id)
|
|||
void EmitPrettyPrint::tagLine(void)
|
||||
|
||||
{
|
||||
emitPending();
|
||||
checkbreak();
|
||||
TokenSplit &tok( tokqueue.push() );
|
||||
tok.tagLine();
|
||||
|
@ -932,6 +935,7 @@ void EmitPrettyPrint::tagLine(void)
|
|||
void EmitPrettyPrint::tagLine(int4 indent)
|
||||
|
||||
{
|
||||
emitPending();
|
||||
checkbreak();
|
||||
TokenSplit &tok( tokqueue.push() );
|
||||
tok.tagLine(indent);
|
||||
|
|
|
@ -26,6 +26,7 @@ class PcodeOp;
|
|||
class FlowBlock;
|
||||
class Funcdata;
|
||||
class Symbol;
|
||||
class PendPrint;
|
||||
|
||||
/// \brief Base class (and interface) for pretty printing and XML markup of tokens
|
||||
///
|
||||
|
@ -80,9 +81,11 @@ protected:
|
|||
int4 indentlevel; ///< Current indent level (in fixed width characters)
|
||||
int4 parenlevel; ///< Current depth of parentheses
|
||||
int4 indentincrement; ///< Change in indentlevel per level of nesting
|
||||
PendPrint *pendPrint; ///< Pending print callback
|
||||
void resetDefaultsInternal(void) { indentincrement = 2; } ///< Set options to default values for EmitXml
|
||||
void emitPending(void); ///< Emit any pending print commands
|
||||
public:
|
||||
EmitXml(void) { s = (ostream *)0; indentlevel=0; parenlevel=0; resetDefaultsInternal(); } ///< Constructor
|
||||
EmitXml(void) { s = (ostream *)0; indentlevel=0; parenlevel=0; pendPrint=(PendPrint *)0; resetDefaultsInternal(); } ///< Constructor
|
||||
|
||||
/// \brief Possible types of syntax highlighting
|
||||
enum syntax_highlight {
|
||||
|
@ -136,7 +139,7 @@ public:
|
|||
/// Inform the emitter that a printing group is ending.
|
||||
/// \param id is the id associated with the group (as returned by openGroup)
|
||||
virtual void closeGroup(int4 id) {}
|
||||
virtual void clear(void) { parenlevel = 0; indentlevel=0; } ///< Reset the emitter to its initial state
|
||||
virtual void clear(void) { parenlevel = 0; indentlevel=0; pendPrint=(PendPrint *)0; } ///< Reset the emitter to its initial state
|
||||
virtual void setOutputStream(ostream *t) { s = t; } ///< Set the output stream for the emitter
|
||||
virtual ostream *getOutputStream(void) const { return s; } ///< Get the current output stream
|
||||
virtual void spaces(int4 num,int4 bump=0);
|
||||
|
@ -214,6 +217,24 @@ public:
|
|||
///
|
||||
/// \param val is the desired number of characters to indent
|
||||
void setIndentIncrement(int4 val) { indentincrement = val; }
|
||||
|
||||
/// \brief Set a pending print callback
|
||||
///
|
||||
/// The callback will be issued prior to the the next call to tagLine() unless
|
||||
/// a the method cancelPendingPrint() is called first.
|
||||
/// \param pend is the callback to be issued
|
||||
void setPendingPrint(PendPrint *pend) { pendPrint = pend; }
|
||||
|
||||
/// \brief Cancel any pending print callback
|
||||
///
|
||||
/// If there is any print callback pending, cancel it
|
||||
void cancelPendingPrint(void) { pendPrint = (PendPrint *)0; }
|
||||
|
||||
/// \brief Check if the given print callback is still pending
|
||||
///
|
||||
/// \param pend is the given print callback to check
|
||||
/// \return \b true if the specific print callback is pending
|
||||
bool hasPendingPrint(PendPrint *pend) const { return (pendPrint == pend); }
|
||||
};
|
||||
|
||||
/// \brief A trivial emitter that outputs syntax straight to the stream
|
||||
|
@ -779,4 +800,25 @@ public:
|
|||
void setXML(bool val); ///< Toggle whether the low-level emitter emits XML markup or not
|
||||
};
|
||||
|
||||
/// \brief Helper class for sending cancelable print commands to an ExitXml
|
||||
///
|
||||
/// The PendPrint is issued as a placeholder for commands to the emitter using its
|
||||
/// setPendingPrint() method. The callback() method is overridden to tailor the exact
|
||||
/// sequence of print commands. The print commands will be executed prior to the next
|
||||
/// tagLine() call to the emitter, unless the PendPrint is cancelled.
|
||||
class PendPrint {
|
||||
public:
|
||||
virtual ~PendPrint(void) {} ///< Destructor
|
||||
virtual void callback(EmitXml *emit)=0; ///< Callback that executes the actual print commands
|
||||
};
|
||||
|
||||
inline void EmitXml::emitPending(void)
|
||||
|
||||
{
|
||||
if (pendPrint != (PendPrint *)0) {
|
||||
pendPrint->callback(this);
|
||||
pendPrint = (PendPrint *)0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2596,17 +2596,28 @@ void PrintC::emitBlockCondition(const BlockCondition *bl)
|
|||
}
|
||||
}
|
||||
|
||||
void PendingBrace::callback(EmitXml *emit)
|
||||
|
||||
{
|
||||
emit->print("{");
|
||||
indentId = emit->startIndent();
|
||||
}
|
||||
|
||||
void PrintC::emitBlockIf(const BlockIf *bl)
|
||||
|
||||
{
|
||||
const PcodeOp *op;
|
||||
PendingBrace pendingBrace;
|
||||
|
||||
if (isSet(pending_brace))
|
||||
emit->setPendingPrint(&pendingBrace);
|
||||
|
||||
// if block never prints final branch
|
||||
// so no_branch and only_branch don't matter
|
||||
// and shouldn't be passed automatically to
|
||||
// the subblocks
|
||||
pushMod();
|
||||
unsetMod(no_branch|only_branch);
|
||||
unsetMod(no_branch|only_branch|pending_brace);
|
||||
|
||||
pushMod();
|
||||
setMod(no_branch);
|
||||
|
@ -2614,7 +2625,11 @@ void PrintC::emitBlockIf(const BlockIf *bl)
|
|||
condBlock->emit(this);
|
||||
popMod();
|
||||
emitCommentBlockTree(condBlock);
|
||||
emit->tagLine();
|
||||
if (emit->hasPendingPrint(&pendingBrace)) // If we issued a brace but it did not emit
|
||||
emit->cancelPendingPrint(); // Cancel the brace in order to have "else if" syntax
|
||||
else
|
||||
emit->tagLine(); // Otherwise start the "if" on a new line
|
||||
|
||||
op = condBlock->lastOp();
|
||||
emit->tagOp("if",EmitXml::keyword_color,op);
|
||||
emit->spaces(1);
|
||||
|
@ -2625,34 +2640,48 @@ void PrintC::emitBlockIf(const BlockIf *bl)
|
|||
if (bl->getGotoTarget() != (FlowBlock *)0) {
|
||||
emit->spaces(1);
|
||||
emitGotoStatement(condBlock,bl->getGotoTarget(),bl->getGotoType());
|
||||
popMod();
|
||||
return;
|
||||
}
|
||||
|
||||
setMod(no_branch);
|
||||
emit->spaces(1);
|
||||
int4 id = emit->startIndent();
|
||||
emit->print("{");
|
||||
int4 id1 = emit->beginBlock(bl->getBlock(1));
|
||||
bl->getBlock(1)->emit(this);
|
||||
emit->endBlock(id1);
|
||||
emit->stopIndent(id);
|
||||
emit->tagLine();
|
||||
emit->print("}");
|
||||
if (bl->getSize()==3) {
|
||||
emit->tagLine();
|
||||
emit->print("else",EmitXml::keyword_color);
|
||||
else {
|
||||
setMod(no_branch);
|
||||
emit->spaces(1);
|
||||
int4 id = emit->startIndent();
|
||||
emit->print("{");
|
||||
int4 id2 = emit->beginBlock(bl->getBlock(2));
|
||||
bl->getBlock(2)->emit(this);
|
||||
emit->endBlock(id2);
|
||||
int4 id1 = emit->beginBlock(bl->getBlock(1));
|
||||
bl->getBlock(1)->emit(this);
|
||||
emit->endBlock(id1);
|
||||
emit->stopIndent(id);
|
||||
emit->tagLine();
|
||||
emit->print("}");
|
||||
if (bl->getSize() == 3) {
|
||||
emit->tagLine();
|
||||
emit->print("else",EmitXml::keyword_color);
|
||||
emit->spaces(1);
|
||||
FlowBlock *elseBlock = bl->getBlock(2);
|
||||
if (elseBlock->getType() == FlowBlock::t_if) {
|
||||
// Attempt to merge the "else" and "if" syntax
|
||||
setMod(pending_brace);
|
||||
int4 id2 = emit->beginBlock(elseBlock);
|
||||
elseBlock->emit(this);
|
||||
emit->endBlock(id2);
|
||||
}
|
||||
else {
|
||||
int4 id = emit->startIndent();
|
||||
emit->print("{");
|
||||
int4 id2 = emit->beginBlock(elseBlock);
|
||||
elseBlock->emit(this);
|
||||
emit->endBlock(id2);
|
||||
emit->stopIndent(id);
|
||||
emit->tagLine();
|
||||
emit->print("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
popMod();
|
||||
if (pendingBrace.getIndentId() >= 0) {
|
||||
emit->stopIndent(pendingBrace.getIndentId());
|
||||
emit->tagLine();
|
||||
emit->print("}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Print the loop using the keyword \e for, followed by a semicolon separated
|
||||
|
|
|
@ -301,4 +301,16 @@ public:
|
|||
virtual void opPopcountOp(const PcodeOp *op) { opFunc(op); }
|
||||
};
|
||||
|
||||
/// \brief Set of print commands for displaying an open brace '{' and setting a new indent level
|
||||
///
|
||||
/// These are the print commands sent to the emitter prior to printing and \e else block.
|
||||
/// The open brace can be canceled if the block decides it wants to use "else if" syntax.
|
||||
class PendingBrace : public PendPrint {
|
||||
int4 indentId; ///< Id associated with the new indent level
|
||||
public:
|
||||
PendingBrace(void) { indentId = -1; } ///< Constructor
|
||||
int4 getIndentId(void) const { return indentId; } ///< If commands have been issued, returns the new indent level id.
|
||||
virtual void callback(EmitXml *emit);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -149,7 +149,8 @@ public:
|
|||
falsebranch = 0x800, ///< Print the false branch (for flat)
|
||||
nofallthru = 0x1000, ///< Fall-thru no longer exists
|
||||
negatetoken = 0x2000, ///< Print the token representing the negation of current token
|
||||
hide_thisparam = 0x4000 ///< Do not print the 'this' parameter in argument lists
|
||||
hide_thisparam = 0x4000, ///< Do not print the 'this' parameter in argument lists
|
||||
pending_brace = 0x8000 ///< The current block may need to surround itself with additional braces
|
||||
};
|
||||
/// \brief Possible types of Atom
|
||||
enum tagtype {
|
||||
|
@ -282,7 +283,6 @@ protected:
|
|||
int4 getPending(void) const { return pending; } ///< Get the number of pending nodes yet to be put on the RPN stack
|
||||
void resetDefaultsInternal(void); ///< Reset options to default for PrintLanguage
|
||||
|
||||
|
||||
/// \brief Print a single unicode character as a \e character \e constant for the high-level language
|
||||
///
|
||||
/// For most languages, this prints the character surrounded by single quotes.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue