Writing a simple MSBuild condition parser - c++

I'm trying to write an MSBuild condition parser. The conditions are described here.
So I've come up with a grammar that appears to work fine:
S -> !S
S -> S == S
S -> S != S
S -> S && S
S -> S || S
S -> Fn( str )
S -> str == str
S -> str != str
S -> n < n
S -> n <= n
S -> n > n
S -> n >= n
This seems to fit my needs and I've come up with a set of C++ classes that define this simple language. ie I can create the classes such that they fit above and then I can call "run" on the base statement and I get a boolean value out of the other end.
Using this language the following:
(!Exists( "C:\\config.sys" ) && 14 < 17) || (AString == AString2 && HasTrailingSlash( "C:" ))
becomes defined as (And forgive the huge line of code! ;)):
Statement baseStatement( new StatementOrStatement( new StatementAndStatement( new NotStatement( new ExistsFunctionStatement( "C:\\Config.sys" ) ), new NumberLessThanNumberStatement( 14.0, 17.0 ) ), new StatementAndStatement( new StringEqualStringStatement( "AString", "AString2" ), new HasTrailingSlashFunctionStatement( "C:\\" ) ) ) );
I can simply run the above statement as follows:
const bool result = baseStatement.Run();
So thus far all is fine. It seems I can represent the whole "language" using my grammar and i can build the grammar into a valid full statement.
However now I have the next problem. I need to actually parse the string. I have no idea of where to start on this. Can anyone help me on how I write the actual string parser to parse the original statement into the set of C++ classes above? I'm rather lost on this front.
I'm doing this purely for my own learning reasons so as far as possible I don't want to use someone else's parser library.
Thanks in advance!

There are quite a few relevant questions already
What's the best way to write a parser by hand?
Resources for writing a recursive descent parser by hand
How to write a recursive descent parser from scratch?
https://stackoverflow.com/questions/2405623/looking-for-a-tutorial-on-recursive-descent-parsing

Related

Scala functional programming concepts instead of multiple for loops

I am trying to learn functional programming in Scala. Right now I'm using the OOP way of having for loops to do a job. I have two lists userCurrentRole and entitlements over which I'm doing a double for loop:
for {
curr <- userCurrentRole {
ent <- entitlements
} {
if (ent.userEmail.split("#")(0) == curr.head) {
if (ent.roleName != curr(1)) {
grantOrRevoke += 1
grantList += SomeCaseClass(curr.head, ent.roleName)
}
}
}
}
Is it possible to convert this double for loop into a logic that uses map or filter or both or any functional programming features of scala, but without a for loop?
EDIT 1: Added a list addition inside the double if..
The good news is: you are already using functional style! Since the for is not a loop per se, but a "for comprehension", which desugars into flatMap and map calls. It's only easier to read / write.
However, the thing you should avoid is mutable variables, like the grantOrRevoke thing you have there.
val revocations = for {
curr <- userCurrentRole {
ent <- entitlements
if ent.userEmail.split("#")(0) == curr.head
if ent.roleName != curr(1)
} yield {
1
}
revocations.size // same as revocations.sum
Note that the ifs inside the for block (usually) desugar to withFilter calls, which is often preferable to filter calls, since the latter builds up a new collection whereas the former avoids that.
You can write it like this:
val grantOrRevoke = userCurrentRole
.map(curr => entitlements
.filter(ent => ent.userEmail.split("#")(0) == curr.head && ent.roleName != curr(1))
.size)
.sum
Well, you are already using some higher order functions, only that you don't notice it, because you believe those are for loops, but they aren't loops. They are just sugar syntax for calls to map & flatMap. But in your case, also to foreach and that plus mutability, is want doesn't make it functional.
I would recommend you to take a look to the scaladoc, you will find that collections have a lot of useful methods.
For example, in this case, we may use count & sum.
val grantOrRevoke = userCurrentRole.iterator.map {
// Maybe it would be better to have a list of tuples instead of a list of lists.
case List(username, userRole) =>
entitlements.count { ent =>
(ent.userEmail.split("#", 2)(0) == username) && (ent.roleName == userRole)
}
}.sum

Stuck adding formula to dynamically added columns

I have a query that returns a dynamic number of columns. I need to dynamically add the same amount of custom columns. I have successfully gotten this far. I'm stuck creating the formulas for the custom columns. This is what I have so far. (This is not the actual query, this is simplified)
Here is the Code:
Test = List.Accumulate(MyList, Source,
(state, current) => Table.AddColumn(
state, "A Temp" & Number.ToText(current), each [A1])
)
For now, I just added [A1] as a place holder for the formula. I need the formula to accumulate as follows:
A Temp1 = [A1] / [TOTAL]
A Temp2 = [A2] / [TOTAL]
A Temp3 = [A3] / [TOTAL]
Above is not actual code. Just what I need the formulas to do for each custom column.
Is this possible? I have tried everything I could think of. I'm using power query in excel BTW.
This isn't exactly what you asked for, but I think it will help.
Test = List.Accumulate(
List.Select(Table.ColumnNames(Source), each _ <> "TOTAL"),
Source,
(state, current) => Table.AddColumn(state,
"Temp " & current,
each Record.Field(_, current) / [TOTAL]))
It's not exactly what you asked for as it gives column names like Temp A1 instead of A Temp1.

Merging two FORTRAN codes

I have two FORTRAN codes that are almost identical except for one line of code, and the FILE names in my OPEN statements. This one different line of code produces the two distinct final results I am looking for hence why I have two different codes.
I would like to merge these two codes into one if possible.
What is the best way to do this? To be specific, I want to have only one FORTRAN file which will run either FORTRAN 'code'. That way, when I need to edit either code I am only doing so in one file. Now having two different files it is a bit of an inconvenience.
A simplified example code for the two different files are below, Sample.f90 and Sample2.f90. What IF statements can I use that will allow me to choose which initial condition to use, either R = COS(x+y) or R = SIN(x+y)? I am not familiar at all with how to use IF statements for this.
PROGRAM SAMPLE !Sample.f90
USE TestModule
IMPLICIT NONE
REAL, DIMENSION(-10,10) :: R
INTEGER :: i,j
REAL :: x,y
OPEN(UNIT = 100, FILE = 'Sample1.dat')
DO j = -10,10
DO i = -10,10
x = i*0.1
y = j*0.1
R(i,j) = COS(x+y)
END DO
END DO
WRITE(100,*) R(0,1)
END PROGRAM
!The next program is of the form:
PROGRAM SAMPLE2 !Sample2.f90
USE TestModule2
IMPLICIT NONE
REAL, DIMENSION(-10,10) :: R
INTEGER :: i,j
REAL :: x,y
OPEN(UNIT = 101, FILE = 'Sample2.dat')
DO j = -10,10
DO i = -10,10
x = i*0.1
y = j*0.1
R(i,j) = SIN(x+y)
END DO
END DO
WRITE(101,*) R(0,1)
END PROGRAM
There is the run-time approach. You have an interactive query of which version you want to run, then an IF statement that selects one of the two alternative statements based on that. Another version of this is to read the choice from the command line using the intrinsic GET_COMMAND_ARGUMENT.
A compile-time approach would be to use the preprocessor to select one statement or the other by defining a symbol (e.g., SYM) or not with your compile command (-DSYM), that using #ifdef SYM, #else, #endif to select which Fortran statement to compile.
Some code fragments. Declare choice as an integer and filename as a string.
read (*, '( "Input choice: " )', advance="no" ) choice
or
call GET_COMMAND_ARGUMENT ( 1, string )
read (string, *) choice
then:
if (choice /=1 .AND. choice /=2 ) then
write (*, *) "bad choice"
stop
end if
if (choice == 1) then
filename = "FileOne.txt"
else
filename = "FileTwo.txt"
end if
open (file=filename, ....
and similar IF statement to setup the initial condition.
Or instead you can include or not -DCHOICEONE in your compilation command and use preprocessor lines:
#ifdef CHOICEONE
filename = "FileOne.txt"
#else
filename = "FileTwo.txt"
#endif
etc.

expression evaluator in scala (with maybe placeholders?)

I am reading something like this from my configuration file :
metric1.critical = "<2000 || >20000"
metric1.okay = "=1"
metric1.warning = "<=3000"
metric2.okay = ">0.9 && < 1.1 "
metric3.warning ="( >0.9 && <1.5) || (<500 &&>200)"
and I have a
metric1.value = //have some value
My aim is to basically evaluate
if(metric1.value<2000 || metric1.value > 20000)
metric1.setAlert("critical");
else if(metric1.value=1)
metric.setAlert("okay");
//and so on
I am not really good with regex so I am going to try not to use it. I am coding in Scala and wanted to know if any existing library can help with this. Maybe i need to put placeholders to fill in the blanks and then evaluate the expression? But how do I evaluate the expression most efficiently and with less overhead?
EDIT:
In java how we have expression evaluator Libraries i was hoping i could find something similar for my code . Maybe I can add placeholders in the config file like "?" these to substitute my metric1.value (read variables) and then use an evaluator?
OR
Can someone suggest a good regex for this?
Thanks in advance!
This sounds like you want to define your own syntax using a parser combinator library.
There is a parser combinator built into the scala class library. Since the scala library has been modularized, it is now a separate project that lives at https://github.com/scala/scala-parser-combinators.
Update: everybody looking for a parser combinator library that is conceptually similar to scala-parser-combinators should take a look at fastparse. It is very fast, and does not use macros. So it can serve as a drop-in replacement for scala-parser-combinators.
There are some examples on how to use it in Programming in Scala, Chapter 33, "Combinator Parsing".
Here is a little grammar, ast and evaluator to get you started. This is missing a lot of things such as whitespace handling, operator priority etc. You should also not use strings for encoding the different comparison operators. But I think with this and the chapter from Programming in Scala you should be able to come up with something that suits your needs.
import scala.util.parsing.combinator.{JavaTokenParsers, PackratParsers}
sealed abstract class AST
sealed abstract class BooleanExpression extends AST
case class BooleanOperation(op: String, lhs: BooleanExpression, rhs:BooleanExpression) extends BooleanExpression
case class Comparison(op:String, rhs:Constant) extends BooleanExpression
case class Constant(value: Double) extends AST
object ConditionParser extends JavaTokenParsers with PackratParsers {
val booleanOperator : PackratParser[String] = literal("||") | literal("&&")
val comparisonOperator : PackratParser[String] = literal("<=") | literal(">=") | literal("==") | literal("!=") | literal("<") | literal(">")
val constant : PackratParser[Constant] = floatingPointNumber.^^ { x => Constant(x.toDouble) }
val comparison : PackratParser[Comparison] = (comparisonOperator ~ constant) ^^ { case op ~ rhs => Comparison(op, rhs) }
lazy val p1 : PackratParser[BooleanExpression] = booleanOperation | comparison
val booleanOperation = (p1 ~ booleanOperator ~ p1) ^^ { case lhs ~ op ~ rhs => BooleanOperation(op, lhs, rhs) }
}
object Evaluator {
def evaluate(expression:BooleanExpression, value:Double) : Boolean = expression match {
case Comparison("<=", Constant(c)) => value <= c
case Comparison(">=", Constant(c)) => value >= c
case Comparison("==", Constant(c)) => value == c
case Comparison("!=", Constant(c)) => value != c
case Comparison("<", Constant(c)) => value < c
case Comparison(">", Constant(c)) => value > c
case BooleanOperation("||", a, b) => evaluate(a, value) || evaluate(b, value)
case BooleanOperation("&&", a, b) => evaluate(a, value) && evaluate(b, value)
}
}
object Test extends App {
def parse(text:String) : BooleanExpression = ConditionParser.parseAll(ConditionParser.p1, text).get
val texts = Seq(
"<2000",
"<2000||>20000",
"==1",
"<=3000",
">0.9&&<1.1")
val xs = Seq(0.0, 1.0, 100000.0)
for {
text <- texts
expression = parse(text)
x <- xs
result = Evaluator.evaluate(expression, x)
} {
println(s"$text $expression $x $result")
}
}
Scala has built in Interpreter library which you can use. The library provides functionalities similar to eval() in many other languages. You can pass Scala code snippet as String to the .interpret method and it will evaluate it.
import scala.tools.nsc.{ Interpreter, Settings }
val settings = new Settings
settings.usejavacp.value = true
val in = new Interpreter(settings)
val lowerCritical = "<2000" // set the value from config
val value = 200
in.interpret(s"$value $lowerCritical") //> res0: Boolean = true
val value1 = 20000 //> value1 : Int = 20000
in.interpret(s"$value1 $lowerCritical") //> res1: Boolean = false
You want to use an actual parser for this.
Most answers are suggesting Scala's parser combinators, and that's a perfectly valid choice, if a bit out-of-date.
I'd suggest Parboiled2, an other parser combinator implementation that has the distinct advantage of being written as Scala macros - without getting too technical, it means your parser is generated at compile time rather than runtime, which can yield significant performance improvements. Some benchmarks have Parboiled2 up to 200 times as fast as Scala's parser combinator.
And since parser combinators are now in a separate dependency (as of 2.11, I believe), there really is no good reason to prefer them to Parboiled2.
I recently faced the same problem and I ended up writing my own expression evaluation library scalexpr. It is a simple library but it can validate / evaluate expressions that are similar to the ones in the question. You can do things like:
val ctx = Map("id" -> 10L, "name" -> "sensor1")
val parser = ExpressionParser()
val expr = parser.parseBooleanExpression(""" id == 10L || name == "sensor1" """).get
println(expr3.resolve(ctx3)) // prints true
If you don't want to use the library, I recommend the fastparse parser... It is much faster than parser combinators, a little bit slower than parboiled, but much easier to use than both.

How can use let - in for multiple lines in OCaml?

I want to do the following:
let dist = Stack.pop stck and dir = Stack.pop stck in (
print_endline(dist);
print_endline(dir);
......
......
)
The above gives me the following error:
Error: This expression has type unit
This is not a function; it cannot be applied.
How can I use the variables dist and dir over multiple lines?
The error is not in the piece of code you show here. I guess you forgot a ; somewhere.
But there is a subtle error in your code.
In this line of code
let dist = Stack.pop stck and dir = Stack.pop stck in
You expect to obtain the first element of the stack in dist and the second one in dir but it may not be the case as the order of evaluation is unspecified.
The basic syntax of your code is OK. Here's a simple example showing that it works fine:
$ ocaml
OCaml version 4.01.0
# let x = 5 and y = 4 in (
print_int x;
print_int y;
);;
54- : unit = ()
#
The reported errors have to do with other problems. We would need more context to see what's wrong. Possibly the errors are in the lines you elided. Or they could be caused by what comes next.