I would like to write an interpreter in haskell for a simple imperative language.
To do that, I first wrote gramar of that language for the tool BNFC (http://bnfc.digitalgrammars.com/).
Part of that grammar is dedicated to arithmetic expressions, such as:
EAdd. Expr ::= Expr "+" Expr ;
EMinus. Expr ::= Expr "-" Expr ;
EMul. Expr ::= Expr "*" Expr ;
ENum. Expr ::= Integer ;
Having just that, I can run the BNFC tool and test it by provided script. It parses arithmetic operations succesfully.
However, if I add another section (let's say with types):
Tint. Type ::= "int" ;
And then put the expr secion, arithmetic operations no longer parse (when testing on 1 + 2 it says "Parse failed... [some tokens here] syntax error at line 1 before 1 + 2")
Why does it happen? How to fix it?
To rephrase:
Why such gramar:
TInt. Type ::= "int" ;
EAdd. Expr ::= Expr "+" Expr ;
ENum. Expr ::= Integer ;
does not parse correctly 1 + 1 using bnfc?
In the absence of an entrypoint declaration, bnfc will use the first category defined in the grammar as entry point in the test script.
I.e. if you add Tint. Type ::= "int" ; at the top of your file, the script generated by bnfc will try to parse a Type, not an Expr.
Related
Why does the following not match the :
expect {
timeout {puts timedout\n}
\[1\]: {puts matched\n}
}
> expect test.tcl
[1]:
timedout
If I change it and remove the colon the match works:
expect {
timeout {puts timedout\n}
\[1\] {puts matched\n}
}
$ expect test.tcl
[1]
matched
Or if I get rid of the 1st bracket
expect {
timeout {puts timedout\n}
1\]: {puts matched\n}
}
then it matches:
$ expect test.tcl
1]:
matched
It is not the problem with :, but with [.
The [ is special to both Tcl and the Expect pattern matcher so it is particularly messy. To match a literal [, you have to backslash once from Tcl and then again so that it is not treated as a range during pattern matching. The first backslash, of course, has to be backslashed to prevent it from turning the next backslash into a literal backslash!
expect "\\\[" ; #matches literal '['
So, your code should be,
expect {
timeout {puts timedout\n}
\\\[1]: {puts matched\n}
}
You can prefix the ] with a backslash if it makes you feel good, but it is not
necessary. Since there is no matching left-hand bracket to be matched within the
double-quoted string, nothing special happens with the right-hand bracket. It stands for itself and is passed on to the Expect command, where it is then interpreted as the end of the range.
The next set of examples shows the behavior of [ as a pattern preceded by differing numbers of backslashes. If the [ is not prefixed by a backslash, Tcl interprets whatever follows as a command. For these examples, imagine that there is a procedure named XY that returns the string n*w.
expect" [XY]" ; # matches n followed by anything
expect "\[XY]" ; # matches X or Y
expect "\\[XY]" ; # matches n followed by anything followed by w
expect "\\\[XY]" ; # matches [XYl
expect "\\\\[XY]" ; # matches \ followed by n followed ...
expect "\\\\\[XY]" ; # matches sequence of \ and X or Y
The \\[XY] case deserves close scrutiny. Tcl interprets the first backslash to mean that the second is a literal character. Tcl then produces n*w as the result of the XY command. The pattern matcher ultimately sees the four character string n*w. The pattern matcher interprets this in the usual way. The backslash indicates that the n is to be matched literally (which it would even without the backslash since the n is not special to the pattern matcher).
Source : Exploring Expect
The patterns that worked for me:
-exact {[1]:}
-exact "\[1]:"
{\[1]:}
"\\\[1]:"
I have TCL 8.6 and the following code works fine:
set a abc
set b abcd
if {$a eq $b} {puts hi}
But the following gets me error:
set a abc
set b abcd
expr $a eq $b
invalid bareword "abc"
in expression "abc eq abcd";
should be "$abc" or "{abc}" or "abc(...)" or ...
I wonder what is going on? Isn't that the condition expression in if command same as the expression in expr command?
No, it's not the same. There is a difference between what you see, and what expr sees, i.e. the string that it will try to evaluate. This is because every word of the command invocation (just like with every command invocation in Tcl) is subjected to substitution before the command is executed.
First case: the braces prevent the contents of the expression from being prematurely substituted. You see {$a eq $b}, expr sees $a eq $b. This is two operands ($a and $b) and an operator (eq): expr can work with this.
Second case: the three arguments are substituted before they are passed to expr. You see $a eq $b, expr sees abc eq abcd. That's two nonsense values and an operator, and expr can't deal with that.
If there is a string that isn't a boolean value or the name of an operator in an expr expression, it should be part of a variable substitution ($abc), or the name of a function (abc(...)), or part of a command substitution ([... abc ...]), or else be explicitly quoted ("abc" or {abc}).
Always brace the arguments to expr. Doing so prevents many problems, this one being one of the milder.
Documentation: expr
Question
What does the following line do?
eval "set abc \$${SID}(abc)"
My try
I know that $someArray(index) is how arrays are accessed in TCL.
So
set abc $SID(abc)
would expect abc to be a key of the array SID (as far as I know abc could be anything as all arrays in TCL are associative. Is this correct?). Then it assigns the value to abc.
So in Pseudocode that line does
Ensure: SID is array, abc exists
abc <- SID[abc]
But why are there braces around SID? Why the eval?
Braces are used to prevent substitution of variables of more characters than necessary.
$variableonetwo
Refers to a variable named variableonetwo and returns its value:
% set variableonetwo 1
% puts $variableonetwo
1
But...
${variableone}two
Refers to the variable named variableone and the string two:
% set variableone 1
% puts ${variableone}two
1two
% puts $variableonetwo
can't read "variableonetwo": no such variable
eval is used to... well evaluate/execute a command.
eval "set abc \$${SID}(abc)"
Will try to evaluate the following if $SID has the value foo which is an array.
set abc $foo(abc)
An advantage of using eval here is that you are able to have not one but two substitutions in the same line, the first being substituting $SID to an array name and the second being from the array value (from the provided key).
1)
% expr "1==1"
1
2)
% expr "i==i"
invalid bareword "i"
in expression "i==i";
should be "$i" or "{i}" or "i(...)" or ...
Why am getting this error in step - 2
1) % if {"i" == "i"} {
puts "hai"
}
hai
2) % if {i == "i"} {
puts "hai"
}
invalid bareword "i"
in expression "i == "i"";
should be "$i" or "{i}" or "i(...)" or ...
if {"i" == "i"} This is wotking with if condition .
Here I found like expr command evaluating only integers , not comparing strings , But the In "if" condition everything (integer as well as string) are evaluating .
How Things are working here ?
The answer is in the expr man page.
Operands may be specified in any of the following ways:
...
[4] As a string enclosed in double-quotes. The expression parser
will perform backslash, variable, and command substitutions on
the information between the quotes, and use the resulting value
as the operand
[5] As a string enclosed in braces. The characters between the open
brace and matching close brace will be used as the operand with‐
out any substitutions.
...
So, expr can compare strings, but you must enclose them in double quotes or curly braces, depending on whether you want substituions performed or not.
Therefore, in your example 2, you must use
% expr {"i" == "i"}
or
% expr {{i} == {i}}
Better to user the string comparison operands:
% expr {"i" eq "i"}
% expr {{i} eq {i}}
to be sure that the content of the string is not converted to numerical values.
In Tcl 8.4
you can use
%expr {"i" == "i"}
or
%expr ( "i" == "i" )
Both syntaxes will work.
There are standard functions such as atof and atoi in C's stdlib.h for converting strings to floats / integers (and to do the reverse too). Is there an equivalent of this in Tcl or do I need to write my own process for carrying out these tasks?
Everything is a string in Tcl, but functions that expect a number (like expr) will use that 'string' as an integer:
% set str " 123 "
123
% set num [expr $str*2]
246
If you want to format a number in a specific way (like producing a floating a point number of a specific precision) then you can use format:
% set str " 1.234 "
1.234
% set fnum [format "%.2f" $str]
1.23
As noted, everything is a string in Tcl, so you can just use a given string as an integer or whatever else you need it as. The only caveat being that it needs to be something that can be interpreted as what you want to use it as (ie, you can use "a" as an integer)
You can test to see if something can be interpreted as the type you want using the string is subcommand:
string is integer "5" ;# true
string is integer "a" ;# false
string is list "a b cc" ;# true
string is list "{a b}c" ;# false
I should note as well that equivatents to atof and atoi can be viewed as conversion of internal Tcl data structures to external binary representations. This is done by the [binary format] command.
One can test string is double $x before using $x in expressions.
E.g., [string is double 1.2.3] returns 0
In my case, this code worked:
set a [string trimleft $a 0]