So, now in this chapter we are going to transform the output from the infix notation to the postfix one. Further we will replace the sign characters '+' and '-' with the strings "pos" and "neg" (to avoid confusion with the arithmetic operators).
In the postfix notation parenthesis are not needed, so we have to disable them globally by applying the following changes in "Printer.H":
Wow! That was a quick start; but what still needs to be done is to render functions also in the postfix order (and without parenthesis). To do that, please make in PrintAbsyn::visitFunc(..) the following changes:
Now since we have also positively and negatively signed functions, we have to apply similar changes to PrintAbsyn::visitPFunc(..) and PrintAbsyn::visitNFunc(..):
Well, now again compile and test with our example input:
Cool! Now, we have even transformed the functions from the infix to the postfix notation; but there is still a slight problem: Where do we know from, how many parameters the function e.g. "sin" is going to take? Since we do not render the parenthesis anymore we cannot tell from the postfix notation the number of parameters for an arbitrary function!
So we have to cheat; we just assume that we know it, period. Well in the case of the sine it is easy, since it is a standard mathematical function which we know from high school of having just one parameter. But in other cases like for the function "f(..)" we have to assume away the problem.
I could offer you a simple solution by attaching immediately after the function`s name the number of parameters it takes, e.g. "f(a,b)" would translate to "a b f#2". Since this solution is really simple, you are free to implement this yourself ;).
Because our input example is insufficient, we have missed another detail; change it to "(a+b) * sin(-c,+d)" (in formula.inp) and run a test:
Mmh, but we have still work to do, since what we really want is "a b + c neg d pos sin *". So again we need to replace the '-'/'+' signs with "neg"/"pos" strings; here are the changes for PrintAbsyn::visitPVar(..) and PrintAbsyn::visitNVar(..):
Now that looks fine! Well remember, we had positively and negatively signed version of the natural and real numbers, variables, functions and POEs. Together, we have applied the changes for the variables and functions, but you have still to change the implementation for the numbers and POEs.
Since we have already gone twice through such similar changes, I`m not showing you all necessary details anymore, but I will tell you where you have to apply them; you need to adapt the following functions:
In the postfix notation parenthesis are not needed, so we have to disable them globally by applying the following changes in "Printer.H":
Those two lines will get rid of most of the undesired parenthesis. Now, replace the PrintAbsyn::visitTerm(..) and PrintAbsyn::visitFact(..) functions in "Printer.C" with the following code:#define _L_PAREN "" // instead of '('
#define _R_PAREN "" // instead of ')'
void PrintAbsyn::visitTerm(Term* p) {As you can see, we have just changed the order from the infix notation (operand-operator-operand) to the postfix notation (operand-operand-operator). Compile the changes and make a test, to see how they are going to affect to output:
int oldi = _i_;
if (oldi > 0) render(_L_PAREN);
_i_ = 0; p->exp_1->accept(this); //
_i_ = 1; p->exp_2->accept(this); // order changed from in2po
_i_ = 0; p->termop_->accept(this); //
if (oldi > 0) render(_R_PAREN);
_i_ = oldi;
}
void PrintAbsyn::visitFact(Fact* p) {
int oldi = _i_;
if (oldi > 1) render(_L_PAREN);
_i_ = 1; p->exp_1->accept(this); //
_i_ = 2; p->exp_2->accept(this); // order changed from in2po
_i_ = 0; p->factop_->accept(this); //
if (oldi > 1) render(_R_PAREN);
_i_ = oldi;
}
$ make && ./testformula formula.inp
» Parse Succesful!
»
» [Abstract Syntax]
» (Program [(Formula [(Fact (Term (Var "a") [AddOp] (Var "b")) [MulOp] (Func "sin" [(NVar "c")] ))])])
»
» [Linearized Tree]
» a b + sin (- c) *
» Parse Succesful!
»
» [Abstract Syntax]
» (Program [(Formula [(Fact (Term (Var "a") [AddOp] (Var "b")) [MulOp] (Func "sin" [(NVar "c")] ))])])
»
» [Linearized Tree]
» a b + sin (- c) *
Wow! That was a quick start; but what still needs to be done is to render functions also in the postfix order (and without parenthesis). To do that, please make in PrintAbsyn::visitFunc(..) the following changes:
void PrintAbsyn::visitFunc(Func* p) {
int oldi = _i_;
if (oldi > 2) render(_L_PAREN);
//render('('); // do not render parameter list parenthesis
if(p->listexp_) {_i_ = 0; p->listexp_->accept(this);}
//render(')'); // do not render parameter list parenthesis
visitIdent(p->ident_); // order changed from in2po
if (oldi > 2) render(_R_PAREN);
_i_ = oldi;
}
As you have noticed, we replaced also the sign characters '-' and '+' with the strings "neg" and "pos". You could argue, that it is not strictly necessary to put the "pos" string, since this is mathematically superfluous. Yes, you are right! But I have kept it, for the sake of symmetry; if you prefer you can out-comment the rendering of the positive signs.void PrintAbsyn::visitPFunc(PFunc* p) {
int oldi = _i_;
if (oldi > 2) render(_L_PAREN);
//render('('); // do not render parameter list parenthesis
if(p->listexp_) {_i_ = 0; p->listexp_->accept(this);}
//render(')'); // do not render parameter list parenthesis
visitIdent(p->ident_); // order changed from in2po
render("pos"); // in2po & '+' replaced with "pos"
if (oldi > 2) render(_R_PAREN);
_i_ = oldi;
}
void PrintAbsyn::visitNFunc(NFunc* p) {
int oldi = _i_;
//if (oldi > 2) render(_L_PAREN);
//render('('); // do not render parameter list parenthesis
if(p->listexp_) {_i_ = 0; p->listexp_->accept(this);}
//render(')'); // do not render parameter parenthesis
visitIdent(p->ident_); // order changed from in2po
render("neg"); // in2po & '-' replaced with "neg"
//if (oldi > 2) render(_R_PAREN);
_i_ = oldi;
}
Well, now again compile and test with our example input:
$ make && ./testformula formula.inp
» Parse Succesful!
»
» [Abstract Syntax]
» (Program [(Formula [(Fact (Term (Var "a") [AddOp] (Var "b")) [MulOp] (Func "sin" [(NVar "c")] ))])])
»
» [Linearized Tree]
» a b + - c sin *
» Parse Succesful!
»
» [Abstract Syntax]
» (Program [(Formula [(Fact (Term (Var "a") [AddOp] (Var "b")) [MulOp] (Func "sin" [(NVar "c")] ))])])
»
» [Linearized Tree]
» a b + - c sin *
Cool! Now, we have even transformed the functions from the infix to the postfix notation; but there is still a slight problem: Where do we know from, how many parameters the function e.g. "sin" is going to take? Since we do not render the parenthesis anymore we cannot tell from the postfix notation the number of parameters for an arbitrary function!
So we have to cheat; we just assume that we know it, period. Well in the case of the sine it is easy, since it is a standard mathematical function which we know from high school of having just one parameter. But in other cases like for the function "f(..)" we have to assume away the problem.
I could offer you a simple solution by attaching immediately after the function`s name the number of parameters it takes, e.g. "f(a,b)" would translate to "a b f#2". Since this solution is really simple, you are free to implement this yourself ;).
Because our input example is insufficient, we have missed another detail; change it to "(a+b) * sin(-c,+d)" (in formula.inp) and run a test:
$ ./testformula formula.inp
» Parse Succesful!
»
» [Abstract Syntax]
» (Program [(Formula [(Fact (Term (Var "a") [AddOp] (Var "b")) [MulOp] (Func "sin" [(NVar "c"), (PVar "d")] ))])])
»
» [Linearized Tree]
» a b + - c, + d sin *
Well ... the comma after the 'c' should not really be there! To suppress it apply the following changes to PrintAbsyn::visitListExp(..) (it renders the parameter list of functions):» Parse Succesful!
»
» [Abstract Syntax]
» (Program [(Formula [(Fact (Term (Var "a") [AddOp] (Var "b")) [MulOp] (Func "sin" [(NVar "c"), (PVar "d")] ))])])
»
» [Linearized Tree]
» a b + - c, + d sin *
Compile and make the test and you will discover that the comma is gone! Here is the output:void PrintAbsyn::visitListExp(ListExp *listexp) {
while(listexp!= 0) {
if (listexp->listexp_ == 0) {
listexp->exp_->accept(this);
listexp = 0;
} else {
listexp->exp_->accept(this);
//render(','); // do not render the comma
listexp = listexp->listexp_;
}
}
}
$ ./testformula formula.inp
» Parse Succesful!
»
» [Abstract Syntax]
» (Program [(Formula [(Fact (Term (Var "a") [AddOp] (Var "b")) [MulOp] (Func
» "sin" [(NVar "c"), (PVar "d")] ))])])
»
» [Linearized Tree]
» a b + - c + d sin *
» Parse Succesful!
»
» [Abstract Syntax]
» (Program [(Formula [(Fact (Term (Var "a") [AddOp] (Var "b")) [MulOp] (Func
» "sin" [(NVar "c"), (PVar "d")] ))])])
»
» [Linearized Tree]
» a b + - c + d sin *
Mmh, but we have still work to do, since what we really want is "a b + c neg d pos sin *". So again we need to replace the '-'/'+' signs with "neg"/"pos" strings; here are the changes for PrintAbsyn::visitPVar(..) and PrintAbsyn::visitNVar(..):
It is always the same game: Disable any eventual parenthesis rendering (if not already disable globally) and replace the signs by strings! That`s it! So compile and make the test:void PrintAbsyn::visitPVar(PVar* p) {
int oldi = _i_;
if (oldi > 2) render(_L_PAREN);
visitIdent(p->ident_);
render("pos");
if (oldi > 2) render(_R_PAREN);
_i_ = oldi;
}
void PrintAbsyn::visitNVar(NVar* p) {
int oldi = _i_;
if (oldi > 2) render(_L_PAREN);
visitIdent(p->ident_);
render("neg");
if (oldi > 2) render(_R_PAREN);
_i_ = oldi;
}
$ make && ./testformula formula.inp
» Parse Succesful!
»
» [Abstract Syntax]
» (Program [(Formula [(Fact (Term (Var "a") [AddOp] (Var "b")) [MulOp] (Func "sin" [(NVar "c"), (PVar "d")] ))])])
»
» [Linearized Tree]
» a b + c neg d pos sin *
» Parse Succesful!
»
» [Abstract Syntax]
» (Program [(Formula [(Fact (Term (Var "a") [AddOp] (Var "b")) [MulOp] (Func "sin" [(NVar "c"), (PVar "d")] ))])])
»
» [Linearized Tree]
» a b + c neg d pos sin *
Now that looks fine! Well remember, we had positively and negatively signed version of the natural and real numbers, variables, functions and POEs. Together, we have applied the changes for the variables and functions, but you have still to change the implementation for the numbers and POEs.
Since we have already gone twice through such similar changes, I`m not showing you all necessary details anymore, but I will tell you where you have to apply them; you need to adapt the following functions:
- PrintAbsyn::visitPNat(..)
- PrintAbsyn::visitNNat(..)
- PrintAbsyn::visitPReal(..)
- PrintAbsyn::visitNReal(..)
- PrintAbsyn::visitPOE(..)
- PrintAbsyn::visitPos(..)
- PrintAbsyn::visitNeg(..)
This should do it! Test with a few input examples your adaptions to find out if you have made everything correct! ;D In the next chapter we will talk about how the preprocessor has been implemented (to get rid of multiple signs).void PrintAbsyn::visitInteger(Integer i) {
char tmp[16];
sprintf(tmp, "%d ", i); // space after %d appended
bufAppend(tmp);
}
void PrintAbsyn::visitDouble(Double d) {
char tmp[16];
sprintf(tmp, "%g ", d); // space after %g appended
bufAppend(tmp);
}