I've been playing around with macros. I saw an interesting post where I can structure my macro in a function like structure here. I've tried to implement one and here is what I currently have.
#define Max(X,Y) \
do { \
auto var1 = x; \
auto var2 = y; \
var1 > var2 ? var1 : var2; \
} while (0)
and in my main function
void main()
{
int result = Max(10, 5)
}
but I'm getting all these errors,
error C2059: syntax error : 'do'
error C2143: syntax error : missing ';' before '{'
Not sure what I did wrong. I just copied the code from the hyperlink above and just modified the code. Any help would be greatly appreciated!
Consider what the macro expands into:
int result = do {
auto var1 = x;
auto var2 = y;
var1 > var2 ? var1 : var2;
} while (0);
That's not valid C++ because loops don't have return values in C++.
Oh, and I actually did notice a small problem with the macro. The parameter names are capitalized (X, Y) but used as lower-case (x, y). That will not work as expected. You have to use the same name in the macro body as you used for the macro parameters.
Related
I want to do something like this macro in Nim
#define BINARY_OP(op) \
do { \
double left = getLast(); \
double right = getLast(); \
push(right op left); \
} while (false)
I tried to do this:
macro binaryOp(op: untyped) =
let right = getLast()
let left = getLast()
vm.push(left op right)
But the compiler throws an error:
Error: attempting to call routine: 'op'
How can I fix this?
Update
I want to use the macro like this:
binaryop(+)
Nim macros are not like C macros, they're code generators that take in source code. What you want is a template, which is akin to C macros, but still more sophisticated.
template binaryOp(op: untyped) =
let right = 10
let left = 20
echo op(left, right)
binaryOp(`+`)
In this case you need to use backticks to lexically strop +, explained here.
All these following lines of code are Julia expressions:
x = 10
1 + 1
println("hi")
if you want to pass an expression to a macro, it works like this. Macro foo just returns the given expression, which will be executed:
macro foo(ex)
return ex
end
#foo println("yes") # prints yes
x = #foo 1+1
println(x) # prints 2
If you want to convert a string into an expression, you can use Meta.parse():
string = "1+1"
expr = Meta.parse(string)
x = #foo expr
println(x) # prints 1 + 1
But, obviously, the macro treats expr as a symbol. What am i getting wrong here?
Thanks in advance!
Macro hygiene is important "macros must ensure that the variables they introduce in their returned expressions do not accidentally clash with existing variables in the surrounding code they expand into." There is a section in the docs. It is easiest just to show a simple case:
macro foo(x)
return :($x)
end
When you enter an ordinary expression in the REPL, it is evaluated immediately. To suppress that evaluation, surround the expression with :( ).
julia> 1 + 1
2
julia> :(1 + 1)
:(1 + 1)
# note this is the same result as you get using Meta.parse
julia> Meta.parse("1 + 1")
:(1 + 1)
So, Meta.parse will convert an appropriate string to an expression. And if you eval the result, the expression will be evaluated. Note that printing a simple expression removes the outer :( )
julia> expr = Meta.parse("1 + 1")
:(1 + 1)
julia> print(expr)
1 + 1
julia> result = eval(expr)
2
Usually, macros are used to manipulate things before the usual evaluation of expressions; they are syntax transformations, mostly. Macros are performed before other source code is compiled/evaluated/executed.
Rather than seeking a macro that evaluates a string as if it were typed directly into the REPL (without quotes), use this function instead.
evalstr(x::AbstractString) = eval(Meta.parse(x))
While I do not recommend this next macro, it is good to know the technique.
A macro named <name>_str is used like this <name>"<string contents>" :
julia> macro eval_str(x)
:(eval(Meta.parse($x)))
end
julia> eval"1 + 1"
2
(p.s. do not reuse Base function names as variable names, use str not string)
Please let me know if there is something I have not addressed.
I have this macro:
macro_rules! set_vars {
( $($x:ident),* ) => {
let outer = 42;
$( let $x = outer; )*
}
}
Which expands this invocation:
set_vars!(x, y, z);
into what I expect (from --pretty=expanded):
let outer = 42;
let x = outer;
let y = outer;
let z = outer;
In the subsequent code I can print x, y, and z just fine, but outer seems to be undefined:
error[E0425]: cannot find value `outer` in this scope
--> src/main.rs:11:5
|
11 | outer;
| ^^^^^ not found in this scope
I can access the outer variable if I pass it as an explicit macro parameter.
Is this intentional, something to do with "macro hygiene"? If so, then it would probably make sense to mark such "internal" variables in --pretty=expanded in some special way?
Yes, this is macro hygiene. Identifiers declared within the macro are not available outside of the macro (and vice versa). Rust macros are not C macros (that is, Rust macros are more than glorified text replacement).
See also:
The Little Book of Rust Macros
A Practical Intro to Macros
So, what are hygienic macros anyway?
In an IML proc I have several martices and several vectors with the names of columns:
proc IML;
mydata1 = {1 2 3, 2 3 4};
mydata2 = {1 2, 2 3};
names1 = {'red' 'green' 'blue'};
names2 = {'black' 'white'};
To assign column names to columns in matrices one can copypaste the mattrib statement enough times:
/* mattrib mydata1 colname=names1;*/
/* mattrib mydata2 colname=names2;*/
However, in my case the number of matrices is defined at execution, thus a do loop is needed. The following code
varNumb=2;
do idx=1 to varNumb;
call symputx ('mydataX', cat('mydata',idx));
call symputx ('namesX', cat('names',idx));
mattrib (symget('mydataX')) colname=(symget('namesX'));
end;
print (mydata1[,'red']) (mydata2[,'white']);
quit;
however produces the "Expecting a name" error on the first symget.
Similar question Loop over names in SAS-IML? offers the macro workaround with symget, what produces an error here.
What is the correct way of using mattrib with symget? Is there other way of making a variable from a string than macro?
Any help would be appreciated.
Thanks,
Alex
EDIT1
The problem is in the symget function. The &-sign resolves the name of the matrix contained in the macro variable, the symget only returns the name of the macro.
proc IML;
mydata1 = {1 2 3};
call symputx ('mydataX', 'mydata1');
mydataNew = (symget('mydataX'));
print (&mydataX);
print (symget("mydataX"));
print mydataNew;
quit;
results in
mydata1 :
1 2 3
mydata1
mydataNew :
mydata1
Any ideas?
EDIT2
Function value solves the symget problem in EDIT1
mydataNew = value(symget('mydataX'));
print (&mydataX);
print (value(symget("mydataX")));
print mydataNew;
The mattrib issue but persists.
SOLVED
Thanks Rick, you have opened my eyes to CALL EXECUTE() statement.
When you use CALL SYMPUTX, you should not use quotes for the second argument. Your statement
call symputx ('mydataX', 'mydata1');
assigns the string 'mydata1' to the macro variable.
In general, trying to use macro variables in SAS/IML loops often results in complicated code. See the article Macros and loops in the SAS/IML language for an indication of the issues caused by trying to combine a macro preprocessor with an interactive language. Because the MATTRIB statement expects a literal value for the matrix name, I recomend that you use CALL EXECUTE rather than macro substitution to execute the MATTRIB statement.
You are also having problems because a macro variable is always a scalar string, whereas the column name is a vector of strings. Use the ROWCAT function to concatenate the vector of names into a single string.
The following statements accomplish your objective without using macro variables:
/* Use CALL EXECUTE to set matrix attributes dynamically.
Requires that matrixName and varNames be defined at main scope */
start SetMattrib;
cmd = "mattrib " + matrixName + " colname={" + varNames + "};";
*print cmd; /* for debugging */
call execute(cmd);
finish;
varNumb=2;
do idx=1 to varNumb;
matrixName = cat('mydata',idx);
varNames = rowcat( value(cat('names',idx)) + " " );
run SetMattrib;
end;
I have the following macro:
#define testMethod(a, b) \
if (a.length > b.length) \
return a; \
return b;
When I try to call it with:
NSString *s = testMethod(#"fir", #"sec");
I get an error:
"Excepted ";" at end of declaration"
Why?
if is a statement, not an expression. It can't return a value like that.
You probably mean:
#define testMethod(a, b) ((a).length > (b).length ? (a) : (b))
The extra parenthesis around the arguments on the right side are common, and are there to protect you against unexpected precendence-related incidents.
Also note that because the above is pre-processed by doing textual replacement, it will probably construct more objects than the equivalent function would.
If you want to use the macro within expressions, it should be defined as an expression itself, not as a group of statements. You end up with a syntax error because the macro is literally substituted, and statements are not allowed within another statement.
GCC has an extension called "statement expressions" that can help you achieve this, but it is non-standard:
#define testMethod(a, b) ({ \
typeof(a) result = (a).length > (b).length ? (a) : (b); \
result; \
})
Actually, in your case none of this is needed because the statements can be easily converted to an expression:
#define testMethod(a, b) ((a).length > (b).length ? (a) : (b))
You need not to use the return statement... try to use the following code
#define testMethod(a,b) ((a) < (b) ? (a) : (b))
may this will help you..