I'm trying to define something in pascal (freepascal).
As in c++ you can pass variable define macro like this :
#define REP(i,k) for(int i=0; i<k; i++)
How can you do it in pascal?
I have added {$MACRO ON} command on the first line, and as a result it can run normal define without error like {$define lala:='hello world'}.
But when I try {define lala(i):=i} the program got an error.
How can I pass variable parameter in Pascal define?
Use an external preprocessor, and execute it in the build system before you use the Pascal compiler on the result.
The FPC macro system is not meant for meta programming but for calling convention macros in headers and compact enable/disable logic only (like home-brewn assert and other debug logging code) and doesn't support parametrisation.
Non hygienic macros are fundamentally incompatible with the Pascal unit system, and hygienic macros are covered by inline function/procedures.
You can use a combination of macros and includes to acheive something similar to token pasting...
ACME_Integer.inc
const ACME_1 = ACME_3;
const ACME_2 = pred(1 shl ACME_1);
type ACME_0 = 0..ACME_2;
//clear the passed in parameters so they can be reused in the next inclusion
{$undef ACME_0}{$undef ACME_1}{$undef ACME_2}{$undef ACME_3}
somefile.pas
{$macro on}
{$define ACME_0:=TAllocationPatchIndex}
{$define ACME_1:=TAllocationPatchIndex_bits}
{$define ACME_2:=TAllocationPatchIndex_high}
{$define ACME_3:=16}
{$Include ACME_Integer.inc}
{$define ACME_0:=TAllocationId}
{$define ACME_1:=TAllocationId_bits}
{$define ACME_2:=TAllocationId_high}
{$define ACME_3:=28}
{$Include ACME_Integer.inc}
expands out to
const TAllocationPatchIndex_bits = 16;
const TAllocationPatchIndex_high = pred(1 shl TAllocationPatchIndex_bits);
type TAllocationPatchIndex= 0..TAllocationPatchIndex_high;
const TAllocationId_bits = 28;
const TAllocationId_high = pred(1 shl TAllocationId_bits);
type TAllocationId= 0..TAllocationId_high;
whilst this example uses more code than it saves, you can obviously see that the include file could be quite complex, repetitive code that needs to be customized many times.
UPDATE - a more complex macro using named/optional arguments
ACME_Integer.inc
{$ifdef ACME_packed_array}
{$undef ACME_array}
{$define ACME_array:=ACME_packed_array}
{$undef ACME_array_decl}
{$define ACME_array_decl:=packed array}
{$else}
{$ifdef ACME_bitpacked_array}
{$undef ACME_array}
{$define ACME_array:=ACME_bitpacked_array}
{$undef ACME_array_decl}
{$define ACME_array_decl:=bitpacked array}
{$else}
{$undef ACME_array_decl}
{$define ACME_array_decl:=array}
{$endif}
{$endif}
{$ifndef ACME_array_type}
{$define ACME_array_type:=byte}
{$endif}
{$ifdef ACME_bitconst}
// we want to keep the X_bits constant
const ACME_bitconst = ACME_bits; //X_bits
{$ifdef ACME_high}
// we want to keep the X_high constant
const ACME_high = pred(1 shl ACME_bitconst); //X_high
type ACME_type = 0..ACME_high; //X
{$else}
// we don't care about keeping the X_high constant
type ACME_type = 0..pred(1 shl ACME_bitconst); //X
{$endif}
{$else}
{$ifdef ACME_high}
// we don't care about keeping the X_bits constant
const ACME_high = pred(1 shl ACME_bits); //X_high
type ACME_type = 0..ACME_high; //X
{$else}
// we don't care about keeping the X_high or X_bits constants
type ACME_type = 0..pred(1 shl ACME_bits); //X
{$endif}
{$endif}
{$ifdef ACME_array}
type ACME_array = ACME_array_decl [ACME_type] of ACME_array_type;
{$ifdef ACME_array_length}
const ACME_array_length = sizeof(ACME_array);
{$endif}
{$ifdef ACME_array_pointer}
type ACME_array_pointer=^ACME_array;
{$endif}
{$undef ACME_array}
{$endif}
{$undef ACME_type}
{$undef ACME_bitconst}
{$undef ACME_high}
{$undef ACME_bits}
{$undef ACME_packed_array}
{$undef ACME_bitpacked_array}
{$undef ACME_array}
{$undef ACME_array_pointer}
{$undef ACME_array_type}
{$undef ACME_array_decl}
{$undef ACME_array_length}
somefile.pas
{$macro on}
{$define ACME_type:=TSha256IndexSliceMagic}
{$define ACME_bitconst:=TSha256IndexSliceMagic_bits}
{$define ACME_high:=TSha256IndexSliceMagic_high}
{$define ACME_bits:=17}
{$Include ACME_Integer.inc}
{$define ACME_type:=TSha256DataBufferIndex}
{$define ACME_bitconst:=TSha256DataBufferIndex_bits}
{$define ACME_high:=TSha256DataBufferIndex_high}
{$define ACME_bits:=9}
{$define ACME_packed_array:=TSha256DataBuffer}
{$define ACME_array_pointer:=PSha256DataBuffer}
{$Include ACME_Integer.inc}
expands out to
const TSha256IndexSliceMagic_bits = 17;
const TSha256IndexSliceMagic_high = pred(1 shl TSha256IndexSliceMagic_bits);
type TSha256IndexSliceMagic= 0..TSha256IndexSliceMagic_high;
const TSha256DataBufferIndex_bits = 9;
const TSha256DataBufferIndex_high = pred(1 shl TSha256DataBufferIndex_bits);
type TSha256DataBufferIndex= 0..TSha256DataBufferIndex_high;
type TSha256DataBuffer = packed array [TSha256DataBufferIndex] of byte;
type PSha256DataBuffer = ^TSha256DataBuffer;
Related
I am developing an algorithm using PyOpenCL. To avoid code duplication I am trying to use templating along with C macros to replace function calls, since OpenCL 1.2 does not support function pointers.
I currently have the following macro section in my OpenCL kernel code:
#define LINEAR_FIT_SEARCH_METHOD ${linear_fit_search_method}
#if LINEAR_FIT_SEARCH_METHOD == MIN_MAX_INTENSITY_SEARCH
#define LINEAR_FIT_SEARCH_METHOD_CALL() determineFitUsingMinMaxIntensitySearch(lineIntensities,imgSizeY,linFitParameter,linFitSearchRangeXvalues)
#elif LINEAR_FIT_SEARCH_METHOD == MAX_INCLINE_SEARCH
#define LINEAR_FIT_SEARCH_METHOD_CALL() determineFitUsingInclineSearch(lineIntensities,imgSizeY,linFitParameter,linFitSearchRangeXvalues,inclineRefinementRange)
#endif
In the kernel code I also define the corresponding functions determineFitUsingMinMaxIntensitySearch and determineFitUsingInclineSearch. I am now attempting to use the macro to exchange the function call like this:
__private struct linearFitResultStruct fitResult = LINEAR_FIT_SEARCH_METHOD_CALL();
so that I select the desired call (note: I always only need either one or the other and configuration is done before the program runs (no need for dynamically switching the two)).
Using PyOpenCL templating I now do something like this:
def applyTemplating(self):
tpl = Template(self.kernelString)
if self.positioningMethod == "maximumIntensityIncline":
linear_fit_search_method="MAX_INCLINE_SEARCH"
if self.positioningMethod == "meanIntensityIntercept":
linear_fit_search_method="MIN_MAX_INTENSITY_SEARCH"
rendered_tpl = tpl.render(linear_fit_search_method=linear_fit_search_method)
self.kernelString=str(rendered_tpl)
Where self.kernelString contains the macro above along with the code.
Unfortunately I am getting this error, which I do not understand:
1:455:53: error: implicit declaration of function 'determineFitUsingInclineSearch' is invalid in OpenCL
1:9:41: note: expanded from macro 'LINEAR_FIT_SEARCH_METHOD_CALL'
1:455:41: error: initializing 'struct linearFitResultStruct' with an expression of incompatible type 'int'
1:536:30: error: conflicting types for 'determineFitUsingInclineSearch'
1:455:53: note: previous implicit declaration is here
1:9:41: note: expanded from macro 'LINEAR_FIT_SEARCH_METHOD_CALL'
1:616:41: error: initializing 'struct linearFitResultStruct' with an expression of incompatible type 'int'
I have very little experience with macros so:
Is what I am attempting even possible in this way or do I need to go a different route?
UPDATE 1:
This code runs fine when I set self.positioningMethod = "meanIntensityIntercept" in my unit test, but fails when setting self.positioningMethod = "maximumIntensityIncline" with the error message above. I cannot spot the error at the yet.
UPDATE 2:
I was also inspired by this post, if that helps:
how to compare string in C conditional preprocessor-directives
As you say you have very little experience with macros then I would go for something simple. determineFitUsingMinMaxIntensitySearch and determineFitUsingInclineSearch accept different number of arguments, so this could done this way:
kernel_code = """
#ifdef USE_FUNCTION_A
void function_a(
int x,
int y,
int extra_param,
__global const int* restrict in,
__global int* restrict out
)
{
//...
}
#else
void function_b(
int x,
int y,
__global const int* restrict in,
__global int* restrict out
)
{
//...
}
#endif
__kernel void my_kernel(
int x,
int y,
__global const int* restrict in,
__global int* restrict out
)
{
// ...
#ifdef USE_FUNCTION_A
function_a(x,y,5,in,out);
#else
function_b(x,y,in,out);
#endif
// ...
}
"""
if use_function_a:
prg = cl.Program(ctx, kernel_code).build("-DUSE_FUNCTION_A")
else:
prg = cl.Program(ctx, kernel_code).build("")
Short version
To prevent the compiler from raising a warning about unused variables I define the macro UNUSED as:
UNUSED(x)=x __attribute__((__unused__))
This macro is then employed in some functions' prototypes, for instance :
void ext(int foo, int UNUSED( bar ) )
However, doxygen is unhappy about that and returns some warnings:
/tmp/sandbox/main.cpp:13: warning: argument 'bar' of command #param is not found in the argument list of Dummy::ext(int foo, intUNUSEDbar)
/tmp/sandbox/main.cpp:13: warning: The following parameters of Dummy::ext(int foo, intUNUSEDbar) are not documented:
parameter 'UNUSED'
How should I tell doxygen to ignore the UNUSED macro ?
Long version
I have a code that looks like the following :
#include <iostream>
class Dummy
//! Dummy class
{
public :
//!Dummy function
/**
* \param foo First variable
* \param bar Second variable
*/
void ext(int foo, int UNUSED( bar ) )
{
std::cout << "foo = " << foo << std::endl;
}
};
//!Main function
int main(void)
{
Dummy MyDummy;
MyDummy.ext(1, 2);
return 0;
}
I compile it by invoking :
g++ -D 'UNUSED(x)=x __attribute__((__unused__))' main.cpp
To generate the default doxygen configuration file named Doxyfile I enter :
doxygen -g
Eventually, to generate the documentation I enter :
doxygen Doxyfile
The latter command outputs the following warning :
/tmp/sandbox/main.cpp:13: warning: argument 'bar' of command #param is not found in the argument list of Dummy::ext(int foo, intUNUSEDbar)
/tmp/sandbox/main.cpp:13: warning: The following parameters of Dummy::ext(int foo, intUNUSEDbar) are not documented:
parameter 'UNUSED'
Following instructions from the doxygen documentation, modify the Doxyfile so that it has the following parameters :
#Doxygen will run its own preprocessor before parsing the file
ENABLE_PREPROCESSING = YES
#The Doxygen preprocessor will not only define the macros (default
#behaviour) but also expand them
MACRO_EXPANSION = YES
#The Doxygen preprocessor will only expand the macros that are listed in
#the PREDEFINED setting. Any other macro will merely be defined, and not
#expanded.
EXPAND_ONLY_PREDEF = YES
#The Doxygen preprocessor will replace any occurrence of the UNUSED
#macro by its argument
PREDEFINED = UNUSED(x)=x
After those changes, invoking doxygen Doxyfile no longer raises warnings.
I came across this nice code from David Heffernan, but I cannot compile it in Lazarus.
Buffered files (for faster disk access)
I get 2 distinct error messages:
line 72 and 104: Duplicate identifier CacheSize
--> I just renamed it and: CacheSize:=aCacheSize
line 53 and 78: No matching implementation for interface method QueryInterface ...
I have no idea how to mend that. I tried to create to new interface function simply calling the original function, but it doesn't work.
Help, please!
The first can be fixed by enabling delphi mode ({$mode delphi} after the interface line, -Sd on the commandline, or the relevant tick in Lazarus properties.
The second needs modifications. The "const" in QueryInterface must be changed to constref
{$ifdef fpc}
function TBaseCachedFileStream.QueryInterface(constref IID: TGUID; out Obj): HResult;
{$else}
function TBaseCachedFileStream.QueryInterface(const IID: TGUID; out Obj): HResult;
{$endif}
both in implementation and interface. This change was made because on Intel const usually implies by reference, and on other CPUs it doesn't and forcing all CONST to constref internally leads to slower code on those processors.
Try this one
In interface part:
protected
function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
function _AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
function _Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
And in the implementation:
function TMyObject.QueryInterface(constref iid: tguid; out obj): longint;
begin
if GetInterface(iid, obj) then
Result := 0
else
Result := -1;
end;
function TMyObject._AddRef: longint;
begin
Result := InterLockedIncrement(FRefCount);
end;
function TMyObject._Release: longint;
begin
Result := InterLockedDecrement(FRefCount);
if FRefCount = 0 then
Free;
end;
I want to monitor several analysis ports, and "publish" the item through one analysis port.
It works for predefined item type, but fail to be parameterized.
The code:
class ovm_analysis_sink #(int NUM_PORTS = 1, type T = ovm_object ) extends ovm_component;
// .......................................
`ovm_component_param_utils(ovm_analysis_sink#(NUM_PORTS,T))
// .......................................
ovm_analysis_imp #(T,ovm_analysis_sink) mon_analysis_imp[NUM_PORTS-1:0];
ovm_analysis_port #(T) mon_analysis_port = new("mon_analysis_port", this);
virtual function void build() ;
string inst;
for(int i=0 ;i < NUM_PORTS ;i++ )
begin
$sformat(inst,"mon_analysis_imp_%0d",i);
mon_analysis_imp[i] = new(inst,this);
end
super.build() ;
endfunction : build
The usage of the analysis_sink:
ovm_analysis_sink #(3,a_type) a_item_sink;
And the error message:
Error-[ICTTFC] Incompatible complex type usage ovm_tb.sv, 42
Incompatible complex type usage in task or function call.
The following expression is incompatible with the formal parameter of the function.
The type of the actual is 'class $unit::ovm_analysis_sink#(3,class $unit::a_type)',
while the type of the formal is 'class $unit::ovm_analysis_sink#(1,class ovm_pkg::ovm_object)'.
Expression: this Source info: ovm_analysis_imp::new(inst, this)
The error says type incompatibility. That means the actual (run-time) and formal (compile-time) arguments/types of implementation port is not the same.
There is an error while declaration of analysis port. Declaring the port as shown above creates a handle of analysis imp port of type uvm_analysis_sink #(1,uvm_object) while, you want it to be of type uvm_analysis_sink #(3,a_type).
So, declare it as follows:
ovm_analysis_imp #(T,ovm_analysis_sink#(NUM_PORTS,T)) mon_analysis_imp[NUM_PORTS-1:0];
This shall remove the type conflict and make it type assignment compatible. Now any parameter overriding shall work.
I have created a sample UVM code on EDAPlayground for reference. Similar applies to your OVM testbench. For further information refer to this forum question.
Here is the code:
import processing.core._
import PConstants._
import PApplet._
class PApp extends PApplet{
args = Array("PApp")
var x: Float = 0.0f
var y: Float = 0.0f
var z: Float = 0.0f
override def setup(): Unit = {
size(200, 200, "P3D")
x = width/2
y = height/2
z = 0
}
override def draw(): Unit = {
translate(x, y, z)
rectMode(CENTER)
rect(0, 0, 10, 10)
z += 1
}
}
If I try to run this (ctrl-shift-R in intellij), I get this message:
Usage: PApplet [options] <class name> [sketch args]
See the Javadoc for PApplet for an explanation.
And no graphics appear. How can I solve this?
You should fill up the "Program arguments:" option inside the Run Configuration.
This is like this option is set up in my case:
As stated in the error message:
Usage: PApplet [options] <class name> [sketch args]
This means that when PApplet runs, it needs at least one argument - <class name> - the full class-path of your sketch. The options and Sketch Args are optional, as indicated by the square braces.
So, if you have a sketch like this:
package com.something.nice;
public class MySketch extends PApplet
{
...
}
Then, you'll need to pass com.something.nice.MySketch as an argument to your application.
In IntelliJ IDEA, you do this in your build configuration (via the menu: Run -> Edit Configurations...), in the "Program arguments" field.
This requirement was a result of the changes from Processing v2 to v3.
Applet is gone — Java's java.awt.Applet is no longer the base class
used by PApplet, so any sketches that make use of Applet-specific
methods (or assume that a PApplet is a Java AWT Component object) will
need to be rewritten.
You may also want to take note of this (same doc):
A new settings() method that is called behind the scenes. Most users
will never notice this, but if you're using Processing without its
preprocessor (i.e. from Eclipse or a similar development environment),
then put any calls to size(), fullScreen(), smooth(), noSmooth(), and
pixelDensity() into that method. More information can be found in the
reference. Only users who are in other development environments should
use settings(). It shouldn't be used for any other purpose.