I am attempting to port a macro from MASM6 to TASM5 (in IDEAL mode) and I am encountering errors. The macro itself assembles fine, but when I attempt to call it, I receive the following error during assembly:
Error xxx.asm(##) Can't use macro name in expression: M_SWAP16
The macro takes the numeric value from a text macro and performs a byte swap. The macro is generally called with ops that take immediate values or during variable initialization.
MACRO M_swap16 operand
LOCAL result
result = (((operand and 0FFh) shl 8) or ((operand and 0FF00h) shr 8))
exitm %result
ENDM
IPPROTO_TCP EQU 6
.
.
.
mov [protocol], M_swap16(IPPROTO_TCP) ; fails
.
.
.
protocol DW ?
protocol_default DW M_swap16(IPPROTO_TCP) ; fails
It works fine in MASM 6.11. Switching TASM from IDEAL to MASM mode doesn't help. Neither does moving the macro into the EQU statement. Ideas?
Unfortunately TASM5 doesn't appear to support macros returning results to expressions at least according to the last official docs. This is also what the error you are seeing is saying. More specifically, the EXITM directive doesn't take an argument like MASM can regardless of the mode you are in. However TASM's macros can still emit a line of code, so if you aren't worried about passing the expression in to the macro, I propose the following workaround (IDEAL mode):
MACRO M_swap16_EXPRESSION expr,operand
LOCAL result
result = (((operand and 0FFh) shl 8) or ((operand and 0FF00h) shr 8))
expr result
ENDM
The macro above takes an additional argument "expr" as the 1st argument which is the assembly expression you were trying to plug the original expression in. It will perform the assembly-time arithmetic on the operand and emit the final assembly line. It can be used like this:
M_swap16_EXPRESSION <mov [protocol],>,IPPROTO_TCP
...
M_swap16_EXPRESSION <protocol_default DW>,IPPROTO_TCP
I admit its ugly, but it might be the next best thing if you must use TASM.
Related
I'm trying to get a better understanding of Elixir macros, but I'm having trouble figuring out how to set up a scenario where I can pattern match the argument that I pass to a macro when the value I'm trying to pass is a variable. Here's a simple example to illustrate:
macro_test.ex
defmodule MacroTest do
use MacroTest.UseMe
def run() do
atom = :hello_world
macro_a(atom)
end
end
use_me.ex
defmodule MacroTest.UseMe do
defmacro __using__(_) do
quote do
defmacro macro_a(:hello_world) do
quote do
"Success!"
end
end
defmacro macro_a(:some_other_atom) do
quote do
"Did something else..."
end
end
end
end
end
When I try to compile this code, I get the error
== Compilation error in file lib/macro_test.ex ==
** (FunctionClauseError) no function clause matching in MacroTest.macro_a/1
If I change the initial run() function so that the atom is passed directly to the macro, such as macro_a(:hello_world), then it compiles/runs just fine.
How can I alter this scenario so that the macro can pattern match on a value that has been provided as a variable, rather than the literal value itself?
It depends on what you want to do. Macros run at compile time, and operate on portions of source code (as opposed to the run time value returned by said piece of source code). So in this case, the macro knows that it has been called with a variable called atom, but it has no way of knowing that this variable has been assigned to earlier in the calling function.
You could check the value of the given variable at run time:
defmacro macro_a(a) do
quote do
case unquote(a) do
:hello_world ->
"Success!"
:some_other_atom ->
"Did something else..."
end
end
end
That is, every invocation of macro_a gets replaced by the case expression above, using whatever variable or other expression was passed as argument.
I'll start with my code:
macro example(args...)
local s = __source__
println(s) # This part works, showing macro is called on line 9
quote
println(s) # Julia tells me this variable "s" is not defined
println(__source__) # Likewise, "__source__" is not defined here either
end
end
#example 42 # Line 9 of my file
In my macro above I want to record the line number that is calling the macro and use it within my quote block. Both capturing it in a variable outside the quote block and using it within, or using it directly in the quote block don't work. My understanding is the code outside the quote block runs at parse-time, and the expression returned from the quote block is evaluated at run-time.
I feel like there must be a way to capture that variable and inject it right into the expression that will be evaluated later, but I haven't figured out how to do that. Any help here is appreciated. If there is a better way to do this let me know.
I ended up finding out an answer on my own. In the second line if I changed __source__ to __source__.line or __source__.file it worked fine as long as I then used $ to interpolate the result into the expression the macro returned. I'm still not sure why __source__ on its own didn't work, but using either .line or .file methods is working for me now.
I'm experiencing a similar problem trying to use __source__.
I think I can offer insight into why source.line, etc worked though.
The value of source.line is an integer. The value of source.fike is a string. Numbers and strings evaluate to themselves.
A symbol, on the other hand, evaluates to whatever value it has in the environment.
I'm trying to read and understand a file written in C (here) and not knowing much C (or if it's C++ to begin with), I'm wondering how the following:
#define BEGIN yy_start = 1 + 2 *
when called like this:
BEGIN(new_state)
is working. I know BEGIN is a macro/placeholder setting yy_start. However I can't find anything on how the argument passed in is handled and operands don't get me anywhere.
Question: How are arguments handled in a C/C++ macro if they are not handled explicitly?
How are arguments handled in a C/C++ macro if they are not handled explicitly?
If a macro is not declared with arguments then it does not take arguments at all. Indeed, C explicitly distinguishes between macros that accept arguments and those that don't. In your particular case, given a definition of BEGIN as an object-like macro:
#define BEGIN yy_start = 1 + 2 *
This invocation ...
BEGIN(new_state)
... expands to:
yy_start = 1 + 2 *(new_state)
. In particular, note that only the macro name is replaced. The parenthesized tokens following it are not part of the macro invocation, and are not affected by the macro expansion.
The macro BEGIN has no arguments so the resulting code will be
yy_start = 1 + 2 *(new_state)
It is done in preprocessing.
I'm looking to create a macro in P6 which converts its argument to a string.
Here's my macro:
macro tfilter($expr) {
quasi {
my $str = Q ({{{$expr}}});
filter-sub $str;
};
}
And here is how I call it:
my #some = tfilter(age < 50);
However, when I run the program, I obtain the error:
Unable to parse expression in quote words; couldn't find final '>'
How do I fix this?
Your use case, converting some code to a string via a macro, is very reasonable. There isn't an established API for this yet (even in my head), although I have come across and thought about the same use case. It would be nice in cases such as:
assert a ** 2 + b ** 2 == c ** 2;
This assert statement macro could evaluate its expression, and if it fails, it could print it out. Printing it out requires stringifying it. (In fact, in this case, having file-and-line information would be a nice touch also.)
(Edit: 007 is a language laboratory to flesh out macros in Perl 6.)
Right now in 007 if you stringify a Q object (an AST), you get a condensed object representation of the AST itself, not the code it represents:
$ bin/007 -e='say(~quasi { 2 + 2 })'
Q::Infix::Addition {
identifier: Q::Identifier "infix:+",
lhs: Q::Literal::Int 2,
rhs: Q::Literal::Int 2
}
This is potentially more meaningful and immediate than outputting source code. Consider also the fact that it's possible to build ASTs that were never source code in the first place. (And people are expected to do this. And to mix such "synthetic Qtrees" with natural ones from programs.)
So maybe what we're looking at is a property on Q nodes called .source or something. Then we'd be able to do this:
$ bin/007 -e='say((quasi { 2 + 2 }).source)'
2 + 2
(Note: doesn't work yet.)
It's an interesting question what .source ought to output for synthetic Qtrees. Should it throw an exception? Or just output <black box source>? Or do a best-effort attempt to turn itself into stringified source?
Coming back to your original code, this line fascinates me:
my $str = Q ({{{$expr}}});
It's actually a really cogent attempt to express what you want to do (turn an AST into its string representation). But I doubt it'll ever work as-is. In the end, it's still kind of based on a source-code-as-strings kind of thinking à la C. The fundamental issue with it is that the place where you put your {{{$expr}}} (inside of a string quote environment) is not a place where an expression AST is able to go. From an AST node type perspective, it doesn't typecheck because expressions are not a subtype of quote environments.
Hope that helps!
(PS: Taking a step back, I think you're doing yourself a disservice by making filter-sub accept a string argument. What will you do with the string inside of this function? Parse it for information? In that case you'd be better off analyzing the AST, not the string.)
(PPS: Moritz++ on #perl6 points out that there's an unrelated syntax error in age < 50 that needs to be addressed. Perl 6 is picky about things being defined before they are used; macros do not change this equation much. Therefore, the Perl 6 parser is going to assume that age is a function you haven't declared yet. Then it's going to consider the < an opening quote character. Eventually it'll be disappointed that there's no >. Again, macros don't rescue you from needing to declare your variables up-front. (Though see #159 for further discussion.))
In SAS/IML is it possible to change a variable if only a macro with its name is available? Using symget on left side produces mistake:
proc iml;
variable = 0;
call symput ('macVar', 'variable');
/* &macVar = 1;*/
symget('macVar') = 1;
print variable;
quit;
ERROR 180-322: Statement is not valid or it is used out of proper order.
The &-sign works, but the code is in a do-loop and symget must be used.
The problem stems from task to write a function that accepts variable number of arguments and processes them in several do-loops. It is connected with the following questions:
SAS IML use of Mattrib with Macro (symget) in a loop
SAS IML pass reference to variable defined in macro
Loop over names in SAS-IML?
In other languages (R, C++, Java, Matlab, etc..) the task is solved with help of abstraction.
Ideas?
SOLVED
Thanks a lot.
Useful article.
Use the VALSET subroutine:
call valset(symget('macVar'), 1);
You find the article "Read hundreds of data sets into matrices." helpful, since so many of your questions are about similar.