Merge remote-tracking branch 'origin/GP-1172_ElseIfSyntax' (Closes

#1609)
This commit is contained in:
Ryan Kurtz 2021-08-05 09:45:01 -04:00
commit 81ea93cb29
7 changed files with 197 additions and 25 deletions

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.