I am learning promela syntax for Spin Modal Checker. I encountered this simple piece of code.
int count;
active proctype count(){
if
:: count++
:: count--
fi
}
As I know semicolon is used to define end of statement. Can I use ; in the end of both count++ and count-- and after fi; Will it change the way program is behaving? I would be grateful for clearing this semicolon thing for me.
Semicolons in Promela are so-called separators.
From the reference:
The semicolon and the arrow are equivalent statement separators in Promela; they are not statement terminators, although the parser has been taught to be forgiving for occasional lapses. The last statement in a sequence need not be followed by a statement separator, unlike, for instance, in the C programming language.
So the answer to your question is: you don't need to put semicolons after count++, count--, or fi because they are the last statements. The parser will ignore if you put them there anyway.
Related
I know that we use ; for commenting in Clojure, which is equivalent of // in Java. But I cannot understand why we need #_
Can someone please explain this? Is it used to ignore text? How is it different from ; if that is the case?
; is a line comment; it ignores the text from ; to the end of the line in your source. This also means, that sometimes a comment on the last line leads to lines with just closing parens, which usually is avoided. The main usecase for ; is to write comments for humans to read.
#_ is called
discard; it
ignores the next form, which means it is agnostic of line breaks in your
source file. This is primarily used to quickly "toggle" code. You can also stack #_. E.g. {#_#_ :a 42}.
Note, that there is also the (comment ...) macro, which throws away the body and returns nil; so the body must be "valid" and you are well advised not use it, where the result could cause havoc. This is primarily used to provide some "prove of concept" inside the source or code you can quickly run in the REPL, but should not run as part of the ns, or when you are to lazy to write a proper test.
In the code below, should we use semicolon at the end of assignment to num or not? Why?
# Python code to check whether a number
# is even or odd using bool()
def check(num):
return(bool(num%2==0))
# Driver Code
num = 8;
if(check(num)):
print("Even")
else:
print("Odd")
Many programming languages like C, C++, Java and others use semicolons to separate statements. In Python the semicolons are optional for single statements in a line. They are only mandatory, if you want write multiple statements in the same line. Some Python programmers write semicolons at the end of the line, because they are so used to it from other languages.
Thus, there is no need for the semicolon after num = 8, and you should avoid it, because it's unusual.
Semicolon is not required in your variable(s), but if you put them in one line, it will be more readable. Consider this x=2 y=3 and x=2; y=3
In Rust, I have noticed that everything is an expression except 2 kinds of statements. Every expression that adds ; will become a statement. Rust's grammar wants statements to follow other statements.
So why don't we add ; at the end of an if / else "expression"? This is also an expression, so why don't we do this:
if true {
println!("true");
} else {
println!("false");
};
The most common answer in the discussion is that it looks more like what users coming from other languages expect, and there is no harm in allowing that syntax (since the result type is () thanks to semicolons in the branches).
I guess because it is a block expression in other languages like Java or Nginx-Conf a semicolon is only set after statements and not after blocks.
Why in the most programming languages required to put a semicolon after statements but not after things like if elseif and else?
Do the compilers all look out for newlines? If that's true then why wouldn't they do that for all statements?
Am I missing something? It really doesn't make sense to me...
Usually the semicolon is required because the compilers ignore most whitespace. It's not needed after statements like if, elseif, else because it's not the end of the statement. Those are only complete statements when followed by a statement or block of statements.
Because compilers for those languages don't consider whitespace for statement termination. A statement has to be terminated some how and it's done with a semicolon. You can write all code (although it would be a horrible, horrible idea) on one line as long as you terminate statements correctly.
Some compilers ignore whitespace and use the semicolon to determine statements, like variable assignments vs. if {} code blocks.
Other languages, like python, use whitespace to find statements and if blocks.
It relates to the difference between statements and expressions. Languages like C require a block to contain a series of statements. Control flow structures like if and while are statements all on their own:
void foo() {
if (bar) {
/* ... */
}
while (baz) {
/* ... */
}
}
There are no semicolons needed here because everything inside foo() is a statement. The question is, what if you want an expression like bar() in a place where a statement is expected? The C grammar says you can do that by adding a semicolon after the expression (in other words, an expression followed by ; is a statement).
So, this isn't valid:
void foo() {
1 + 2
}
Because 1 + 2 is an expression. You need to turn it into a statement:
void foo() {
1 + 2;
}
To fully understand what's going on, it's important to note that a block (something in curlies like { foo(); } is also a statement, and that the grammar for if is something like:
if ( <condition> ) <statement> (else <statement>)?
This is why if statements can have blocks for bodies or single statements: a block is a single statement.
Why use ';' rather than '\n' to terminate a statement.
Very few languages uses white space as something that affects the semantics of a language (new line being white space). This is because it is very error prone for the developer (as the white space is for all intense invisible).
Look at languages that do use white space to affect the semantics and you will see the effect on the programmers (special tools are usually built to help align things etc). Lots of bald developers (male and female) who have torn out their hair if frustration because they inserted a space instead of a tab and this caused the loop to be exited early. :-)
Also by not using white space to alter semantic meaning of the language you can now use white space solely for the human readers of the language to try and format the code into a form that makes it easy to read (for the human) (or you can abuse the white space to hide meaning).
Why are not all statements white space
Its just that you need a way to check the end of statement.
Some things it is obvious where the end of the statement is and you do not need a an extra delimiter to allow the parser to detect the end of a statement.
A source code is a set of statements. We have to delimitate the statements, using delimitators. If we use the newline as the delimitator, we can't structure our codes. Very long lines will only be readable by scrolling. (to avoid scrolling, long lines usually are split.) For example:
ParserUtils.RefreshProperty(m_cfg.PORTAL_ID, ParserUtils.CreateHashFromUrl(strDetailLinkUrl), Convert.ToInt32(m_cfg.Type), strPrice, strAddress, strStreet, strPostCode, strFeatures, strDescription, strImgFile, strBedrooms, strReception, strBath, strStatus, strLink, strPropType, strOutside, strTenure, strKeywords, strFullText, strContactInfo, m_ieBrowser.URL);
is very ugly and instead of this, we split this line to several lines to make this more readable:
ParserUtils.RefreshProperty(m_cfg.PORTAL_ID,
ParserUtils.CreateHashFromUrl(strDetailLinkUrl),
Convert.ToInt32(m_cfg.Type), strPrice,
strAddress, strStreet, strPostCode, strFeatures, strDescription, strImgFile,
strBedrooms, strReception, strBath, strStatus, strLink, strPropType,
strOutside, strTenure, strKeywords, strFullText, strContactInfo,
m_ieBrowser.URL);
This would be impossible if newline was the delimitator. Ifs, whiles and fors would be a total mess if newline was the operator. Consider this code:
for (int i = 0; i < n; i++)
{
if (i % 2 == 0)
{
System.out.println("It can be divided by two");
}
{
System.out.println("It can't be divided by two");
}
}
If newline was the operator instead of the semicolon, this source code would be very ugly:
for (int i = 0
i < 0
i++) { if (i % 2 == 0) { System.out.println("It can be divided by two")
} { System.out.println("It can't be divided by two")
} }
This code is difficult to read, and it's logically valid as the delimitator. For example, my wife writes my tasks on a paper (an algorithm) like this:
Buy food(Bread, Meat, Butter),
Go and pay the taxes,
Call your mother, because she wants to talk to you
These tasks are separated by commas, but notice that parameters are separated by commas too. We have to make a difference between a comma as a parameter separator and a comma as a delimitator of tasks, because the computer is not as intelligent as human beings. As a conclusion, the separator of tasks is a bigger comma than the separator of parameters. That's why the delimitator of statements is a semicolon and the delimitator of parameters is a comma.
I have tried something like this in my Bison file...
ReturnS: RETURN expression {printf(";")}
...but the semicolon gets printed AFTER the next token, past this rule, instead of right after the expression. This rule was made as we're required to convert the input file to a c-like form and the original language doesn't require a semicolon after the expression in the return statement, but C does, so I thought I'd add it manually to the output with printf. That doesn't seem to work, as the semicolon gets added but for some reason, it gets added after the next token is parsed (outside the ReturnS rule) instead of right when the expression rule returns to ReturnS.
This rule also causes the same result:
loop_for: FOR var_name COLONEQUALS expression TO {printf("%s<=", $<chartype>2);} expression STEP {printf("%s+=", $<chartype>2);} expression {printf(")\n");} Code ENDFOR
Besides the first two printf's not working right (I'll post another question regarding that), the last printf is actually called AFTER the first token/literal of the "Code" rule has been parsed, resulting in something like this:
for (i=0; i<=5; i+=1
a)
=a+1;
instead of
for (i=0; i<=5; i+=1)
a=a+1;
Any ideas what I'm doing wrong?
Probably because the grammar has to look-ahead one token to decide to reduce by the rule you show.
The action is executed when the rule is reduced, and it is very typical that the grammar has to read one more token before it knows that it can/should reduce the previous rule.
For example, if an expression can consist of an indefinite sequence of added terms, it has to read beyond the last term to know there isn't another '+' to continue the expression.
After seeing the Yacc/Bison grammar and Lex/Flex analyzer, some of the problems became obvious, and others took a little more sorting out.
Having the lexical analyzer do much of the printing meant that the grammar was not properly in control of what appeared when. The analyzer was doing too much.
The analyzer was also not doing enough work - making the grammar process strings and numbers one character at a time is possible, but unnecessarily hard work.
Handling comments is tricky if they need to be preserved. In a regular C compiler, the lexical analyzer throws the comments away; in this case, the comments had to be preserved. The rule handling this was moved from the grammar (where it was causing shift/reduce and reduce/reduce conflicts because of empty strings matching comments) to the lexical analyzer. This may not always be optimal, but it seemed to work OK in this context.
The lexical analyzer needed to ensure that it returned a suitable value for yylval when a value was needed.
The grammar needed to propagate suitable values in $$ to ensure that rules had the necessary information. Keywords for the most part did not need a value; things like variable names and numbers do.
The grammar had to do the printing in the appropriate places.
The prototype solution returned had a major memory leak because it used strdup() liberally and didn't use free() at all. Making sure that the leaks are fixed - possibly by using a char array rather than a char pointer for YYSTYPE - is left to the OP.
Comments aren't a good place to provide code samples, so I'm going to provide an example of code that works, after Jonathan (replied above) did some work on my code. All due credit goes to him, this isn't mine.
Instead of having FLEX print any recognized parts and letting BISON do the formatting afterwards, Jonathan suggested that FLEX prints nothing and only returns to BISON, which should then handle all printing it self.
So, instead of something like this...
FLEX
"FOR" {printf("for ("); return FOR;}
"TO" {printf("; "); return TO;}
"STEP" {printf("; "); return STEP;}
"ENDFOR" {printf("\n"); printf("}\n"); return ENDFOR;}
[a-zA-Z]+ {printf("%s",yytext); yylval.strV = yytext; return CHARACTERS;}
":=" {printf("="); lisnew=0; return COLONEQUALS;}
BISON
loop_for: FOR var_name {strcpy(myvar, $<strV>2);} COLONEQUALS expression TO {printf("%s<=", myvar);} expression STEP {printf("%s+=", myvar);} expression {printf(")\n");} Code ENDFOR
...he suggested this:
FLEX
[a-zA-Z][a-zA-Z0-9]* { yylval = strdup(yytext); return VARNAME;}
[1-9][0-9]*|0 { yylval = strdup(yytext); return NUMBER; }
BISON
loop_for: FOR var_name COLONEQUALS NUMBER TO NUMBER STEP NUMBER
{ printf("for (%s = %s; %s <= %s; %s += %s)\n", $2, $4, $2, $6, $2, $8); }
var_name: VARNAME