I want to make a macro which will inject some code, like:
if (foo) {
[Bar fooBar];
}
and then, where ever I need that, I put FOOBAR in the code. Not sure, but at compile time then the compiler replaces this with the actual code like in the example above. Maybe there's something different than a macro I could use for this?
Use \ to escape each line-break you want to be part of the macro.
However, be aware that using macros like this can hide structure if you aren't careful. Taking your example:
if (bar)
FOOBAR();
else
do_something_else();
Guess what this expands to. Probably not what you think. Here's what the compiler sees (indentation adjusted):
if (bar)
if (foo)
{
[Bar fooBar];
}
;
else
do_something_else();
Oops! That semicolon is a separate, empty statement. Each if takes only one statement; the first if's statement is the second if, and the second if's statement is the compound statement ({…}), so they have both met their quota, leaving the semicolon out.
So the semicolon is not bound to an if—it's unconditional. That causes a syntax error when you then try to apply the else to an unconditional statement.
The fix, ugly as it is, is to wrap the contents of FOOBAR in a do…while statement:
#define FOOBAR() \
do { \
if (foo) \
[Bar fooBar]; \
} while(0) /*semicolon omitted*/
Because we leave out the semicolon in the macro definition, the do…while is an unterminated statement, so that the semicolon outside the macro usage will bind to it. Then our expanded code looks like this:
//First, the unexpanded code again
if (bar)
FOOBAR();
else
do_something_else();
//Expanded
if (bar)
do
{
if (foo)
[Bar fooBar];
}
while(0);
else
do_something_else();
The else now binds to if (bar), as you intended.
You can define a macro on multiple lines by adding a \ to the end of each line except the last. Unfortunately the macro will expand to a single line when you actually use it.
Related
I have the following macro:
`define check(CONDITION) \
begin \
if (!(CONDITION)) \
$display("'%s' failed.", `"CONDITION`"); \
end
And the following expansions:
module test;
initial begin
`check(0)
`check(1 == 0)
end
endmodule
They print the following:
'0' failed.
'1 == 0' failed.
If I have a condition over strings, though, then the macro expansion won't work properly. Concretely, adding the following line leads to a compile error:
`check("foo" == "bar")
What I would like, though, is to have the following printed:
'"foo" == "bar"' failed.
Is there a way to write the macro body that would allow this? I would like to avoid solutions where I have two macros, one where strings aren't allowed inside the condition and one explicitly for strings.
You can't do this with just one macro in SystemVerilog. It would take something like the qq() operator in PERL for this to work.
Given the following:
for fn_name <- [:foo, :bar, :baz] do
defmacro unquote(fn_name)(do: inner) do
fn_name = unquote(fn_name) # <--- Why?
quote do
IO.puts "#{unquote(fn_name)} called"
unquote(inner)
end
end
end
What's the reason for fn_name = unquote(fn_name)? If I omit this line, it's a compile error. What's the reason for this "double" unquoting?
Let's simplify the example a little bit:
for fn_name <- [:foo, :bar, :baz] do
defmacro unquote(fn_name)(do: inner) do
fn_name = unquote(fn_name) # <--- Why?
quote do
{unquote(fn_name), unquote(inner)}
end
end
end
In the example above, because quote is returning a tuple with two unquoted elements, it is equivalent to:
for fn_name <- [:foo, :bar, :baz] do
defmacro unquote(fn_name)(do: inner) do
fn_name = unquote(fn_name) # <--- Why?
{fn_name, inner}
end
end
Now it is easier to understand what happens if you don't unquote(fn_name) before: the variable fn_name simply wouldn't exist inside the macro definition. Remember that all defs (def, defp, defmacro, etc) start a new variable scope, so if you want to use fn_name inside, you need to define it somehow.
The other property we are seeing in this code is that Elixir will stop unquoting when it sees a quote. So in the quote above, unquote won't be unquoted when the macro is defined but rather when the macro is executed, which also explains why the variable is required to be defined inside the macro.
It's because of Hygiene.
Elixir has the concept of macro hygiene. Hygiene means that variables, imports, and aliases that you define in a macro do not leak into the caller’s own definitions.
for fn_name <- [:foo, :bar, :baz] do
defmacro unquote(fn_name)(do: inner) do
fn_name = unquote(fn_name) # <-- This is macro's context
quote do
IO.puts "#{unquote(fn_name)} called" # <-- This is caller's context
unquote(inner)
end
end
end
You should read Hygiene Protects the Caller’s Context from Chris McCord's Metaprogramming Elixir book
I'm a progress noob, actually having problem with basic blocks.
Below the issue is in my if else statement. It works fine when its just if, then, else then, but when I want to put in more than one statement into the if portion, I have to put it in a block, so I'm using if, then do: else, then do: but these aren't working for me. Any obvious errors you can see? My error message is **Colon followed by white space terminates a statement. (199)
INPUT FROM "r:\_content\stephen\4gl apps\dpl\output.csv".
REPEAT:
ASSIGN i_cntr = (i_cntr + 1).
myRow = "".
IMPORT DELIMITER ',' myRow.
IF myRow[5] <> "" THEN DO:
/*change this to assign 2 rows - 2 creates - 2 sets of four*/
c_fname = myRow[1].
MESSAGE
c_fname SKIP
myRow[2] SKIP
myRow[3] skip
myRow[4] skip
myRow[5] SKIP
i_cntr
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END./*end of if, then do:*/
ELSE IF myRow[5] = "" THEN DO:
MESSAGE
myRow[1] SKIP
myRow[2] skip
myRow[3] skip
myRow[4] skip
i_cntr
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END./*end of else if, then do:*/
END./*end of repeat*/
A very simple syntax error: you need at least one space after the END-statement.
END. /*end of if, then do:*/
/* ^ Make sure there's space above here! */
And if you don't want to follow the excellent advice in Tims answer (use CASE). This is the "complete" syntax of the IF statement.
IF expression1 THEN DO:
/* Code goes here */
END.
ELSE IF expression2 THEN DO:
/* Code goes here */
END.
ELSE DO:
/* Code goes here */
END.
expressions:
A constant, field name, variable name, or expression whose value is logical (TRUE or FALSE). The expression can include comparisons, logical operators, and parentheses.
You can also leave out the DO: END. When the IF code to be executed only consists of a single statement:
IF TRUE THEN DISPLAY "TRUE".
ELSE DISPLAY "NOT TRUE".
You could also use other block-statements (such as FOR or REPEAT) but that will most likely only create code that is hard to read.
Rather than using nested IF/ELSE, you'd be better off using a CASE statement like so:
CASE varname:
WHEN "" THEN DO: /*something */ END.
WHEN "value" THEN DO: /*something */ END.
OTHERWISE DO: /*something */ END.
END CASE.
Check the docs on this statement for more details.
I figured out the issue. This wasn't caused by a coding error. Apparently Progress doesn't like comments too close to the code, which caused it to throw an error.
END. /*end of if, then do:*/ => This is ok.
END./*end of if, then do:*/ => This caused the issue comments too close to statement.
Thanks To Tim Kuehn for his response.
I am trying to grab all functions from a C file in a perl script.
Pattern example :
function return type
function name (function parameters)
{
So far I have: m/^(.*)\((.*)\)/
But this grabs functions inside as well, such as if statements, so I was hoping to match for the { as well since that would eliminate all internal functions but m/^(.*)\((.*)\)/\n\{/
doesn't work.
How do I match for the \n{ i.e the { in the next line, so that I can catch
add(int a, int b)
{
... but avoid, say
if(a = b)
Have a look at C::Scan over at CPAN
There are no asterisks you want to match in the C source. Therefore, remove the backslashes before asterisks in the pattern.
The following might be closer to what you want:
m/^(.*?\(.*?\))\s*\n{/m
On compiling the following code with Scala 2.7.3,
package spoj
object Prime1 {
def main(args: Array[String]) {
def isPrime(n: Int) = (n != 1) && (2 to n/2 forall (n % _ != 0))
val read = new java.util.Scanner(System.in)
var nTests = read nextInt // [*]
while(nTests > 0) {
val (start, end) = (read nextInt, read nextInt)
start to end filter(isPrime(_)) foreach println
println
nTests -= 1
}
}
}
I get the following compile time error :
PRIME1.scala:8: error: illegal start of simple expression
while(nTests > 0) {
^
PRIME1.scala:14: error: block must end in result expression, not in definition
}
^
two errors found
When I add a semicolon at the end of the line commented as [*], the program compiles fine. Can anyone please explain why does Scala's semicolon inference fail to work on that particular line?
Is it because scala is assuming that you are using the syntax a foo b (equivalent to a.foo(b)) in your call to readInt. That is, it assumes that the while loop is the argument to readInt (recall that every expression has a type) and hence the last statement is a declaration:
var ntests = read nextInt x
wherex is your while block.
I must say that, as a point of preference, I've now returned to using the usual a.foo(b) syntax over a foo b unless specifically working with a DSL which was designed with that use in mind (like actors' a ! b). It makes things much clearer in general and you don't get bitten by weird stuff like this!
Additional comment to the answer by oxbow_lakes...
var ntests = read nextInt()
Should fix things for you as an alternative to the semicolon
To add a little more about the semicolon inference, Scala actually does this in two stages. First it infers a special token called nl by the language spec. The parser allows nl to be used as a statement separator, as well as semicolons. However, nl is also permitted in a few other places by the grammar. In particular, a single nl is allowed after infix operators when the first token on the next line can start an expression -- and while can start an expression, which is why it interprets it that way. Unfortunately, although while can start a expression, a while statement cannot be used in an infix expression, hence the error. Personally, it seems a rather quirky way for the parser to work, but there's quite plausibly a sane rationale behind it for all I know!
As yet another option to the others suggested, putting a blank newline between your [*] line and the while line will also fix the problem, because only a single nl is permitted after infix operators, so multiple nls forces a different interpretation by the parser.