The preprocessor doesn’t immediately allow recursion. It actually works hard to disable it. This is to avoid issues such as foo and bar, here, that if you tried to expand them would give you an infinite expansion.

We won’t need stringification in the hacking below, so we won’t need this rule for what follows, except that it can be a helpful trick to work out what macro calls expand to.

we expand bar(qux, 42) => s([f=qux]([x=42])) => s(qux(42)) and s() makes the argument into a verbatim string without expanding it.

The trick to this is that first(is_true __VA_ARGS__) will be first(is_true) = is_true if __VA_ARGS__ is empty, but if __VA_ARGS__ = x, y, z then first(is_true __VA_ARGS__) = first(is_true x, y, z) is_true x (notice no comma between is_true and x). So

and assuming we do not have a fooqux macro, that is the end result. Concatenation binds tighter than evaluation, just like stringification binds tighter than substitution and concatenation.

If b is 1, we get the arguments in the if-part and then an else part that throws the second set of parameters away. If we call with b equal to 0, we throw away the first part and provide an else part that will include the parameters there. Both if and else parts use variadic arguments, … and __VA_ARGS__ to handle any set of arguments.

In the expansion of bar, we see foo, which is no longer disabled, so we can expand that, and the whole bar processing progresses as earlier.

The key specifications of the UV scan lens are listed below. Compared to similar products in the market, we offer a larger scanning area and flexible design of achromatic performance. For high-powered laser and ultrafast laser sources, we offer a special Q-series to minimize thermal lensing and focal shift.

If we take bar(qux, 42) up to this step, we have substituted to get s(qux(42)). The same with bar(qax(), 42) because qax() will have been evaluated, expanding to qux. So s(qux(42)) is the expression the preprocessor has before the last step, and the last step is just going through this expression and substituting all the macros it finds. It goes left-to-right, so if . is the current position, it will go

The second() macro gives you the second value in its input, and if second(p, 0) expands to something where p doesn’t contain any commas, that will be zero. If, however, we call test(is_true()), then p expands to -, 1, so second(p, 0) becomes second(-, 1, 0) which evaluates to 1. In other words, test(is_true()) is 1, and test(xxx) for any xxx that doesn’t expand to something with a comma in it, will be 0.

After handling foo, we have another bar to handle. While we expanded foo, we were in a bar context where expansions of bar were disabled, but we are no longer in that context, and we can expand bar again, which we do.

If you evaluate delay(foo) you expand to foo empty(), since there are no parentheses after foo it isn’t expanded, but empty() is expanded, and to the empty string, so the result is an unevaluated foo. If you write delay(foo)(), then it evaluates to foo(), a macro call waiting to happen. As long as foo isn’t forbidden itself, it can expand to something that is at a later point, and in that way circumvent the recursion protection.

Expanding bar is similar: you are in a context where you are expanding bar, you can easily handle B, but you need to expand foo. Inside foo, you can handle F, but when you see bar, you must tag it, and it cannot be expanded any further.

because evaluating if_else(xxx) will substitute to cat(if_,truthiness([b=xxx])) => cat(if_,truthiness([xxx])) and the xxx is the end of the parameter evaluation. That means that on the scan of the expression after substitution we see cat(if_,truthiness(xxx)) which we call cat() with, and it will translate it into if_truthiness(xxx) which isn’t what we want. We need to make sure that the truthiness(b) expression is evaluated before we invoke cat, and we can do that by one level of indirection:

You have two kinds of macros, the simple ones like foo above, called object-like, and then so-called function-like macros. The latter, you define with parentheses after the name and with zero or more arguments between the parentheses.

It is simple, and it works, but it is also pretty useless. You have to provide verbatim 0 or 1 to the if_else macro, or it doesn’t pick if_0 or if_1, it will simply expand to some if_foo token that likely isn’t even defined. Unless we can evaluate b as some sort of test expression, we might as well just choose if_0 or if_1 direction.

and assign bar to x if foo is true and baz otherwise. Maybe that is not something you want to do, and that’s okay, but it is something that you can do, with a bit of hacking.

Our F-Theta scan lenses are optimized for laser-material processes, specifically for engraving, cutting, welding, and bonding. The scan lenses are available in working wavelength telecentric (TSL-Q and TSL series) and non-telecentric (SL-Q and SL series) configurations. For a vision system that requires an additional wavelength, we provide achromatic scan lenses in telecentric (TSLA series) and non-telecentric (SLA series) configurations.

google lens网页版

We use cat(not_,b) to expand b into 0/something and then call test with the result of the expansion. If cat(not_,b) is not_0 that will expand to not_0 => is_true() so the call to test(p) gives us 1. If b is not 0, then cat(not_,b) becomes some single token, not_xxx, which becomes the first token in second(p, 0) and we get 0.

We can delay an evaluation by putting something between the name of a function-like macro and the parentheses that causes its expansion.

lens官网

Once the stringification, substitution, concatenation and parameter-expansion is done, the preprocessor goes through the result once more, expanding the macros it finds.

So we have the power to create if-statements, but can we also iterate over arguments? We could use variadic parameters as a kind of list

Nothing in the source code really changes, just the type information. But that is bad enough. C doesn’t do generic types, and there are a couple of places where you need to provide type information. Composite expressions, for example. So, I figured macros would get me most of the way, with _Generic() expressions for static type dispatch. And it did; I have a solution I am reasonably satisfied with. Except that there is some redundancy in what code I must generate from macros to make it work.

F-theta scan lens are subject to spot size variations on the planar surface, and the spot size diagram plot provides more information about the typical variation as a result of the angle movements of both mirrors on the XY axis of a galvanometer. The spot size variations can also be calculated using the following equation.

I find it a bit scary that you can program this way with C’s preprocessor. It is pretty cool, but I am happy that I ended up not using too crazy things for my slices. It was bad enough where that code landed.

Here, bar(42) will expand to <42> bar_, not seing any recursive expansion and so it will not tag anything. That means that we can evaluate

The problem is, once again, that we reveal our intentions to do recursion a bit too early. The delay() macro prevents expansion for one attempt, but we have two here. One for the map() macro and another for the else_0 function that handles the recursive case. If we want to implement recursion this way, we need to prevent two attempts at expansion.

Now if_else(xxx) gets expanded to if_else_(truthiness([b=xxx])) = if_else_(truthiness(xxx)) and inside if_else_ we get cat(if_,[b=truthiness(xxx)]) where truthiness(xxx) is evaluated before we call cat.

Still, the idea is sound. If we can avoid expanding to a forbidden token while we evaluate a macro, we should be able to get an expression back that we can evaluate to get the next step of a recursion.

The way it works is, the preprocessor knows which macros it is in the process of expanding, and if it sees any of those during the expansion, the expansion there is tagged (painted blue, in the parlance), and that expansion is forever left as is.

Wrapping f(x) in s(f(x)) will turn the substituted value for f(x) into a string (it will be "bar(42)") and you can inspect it.

The mechanical scanning angle is related to the scanning mirror. It is usually the rotation angle of the two mirrors, which controls the scanning range from two directions. In the Galvo Scanner system, the specifications of the scanner refer to the mechanical scanning angle of the mirror.

Here, when you evaluate foo(baz(), 42) you can see that the argument for f is baz() (because we stringify first, but it will be substituted into f and evaluated in s(f) (substituted s(f) to s(baz()) and then evaluated to s(bar)).

Usually, the F-Theta lens has two scanning angles, one scanning angle is an optical scanning angle, and another is a mechanical scanning angle. The optical scanning angle is the field of view of the lens, which determines the diagonal length of the maximum scanning field.

Field-flattening lenses resolve the challenges of spherical-field-orientated optics by creating a flat focal field, but at the cost of inducing a nonlinear behavior. The displacement term between the effective focal length (𝑓) and the deflection angle (𝜃) prevents a uniform movement (i.e. constant scan rate) of the scanning mirror due to this nonlinearity (𝑓 ∗ tan 𝜃). It also results in an angular field-of-view and causes inaccuracies between varying magnification and observed measurements by the vision system. To resolve this nonlinearity, F-theta lenses are designed and engineered for the beam displacement to be independent of the tangent of the deflection angle.

Image

We substitute to go from cat2(foo, qux(42)) to cat([x=foo],[y=qux(42)]) and notice that this time, when we evaluate the parameters, we have an expression to evaluate: qux(42) => bar! That means that after the substitution we get cat(foo, bar) and when we do the second scan we will evaluate cat(foo, bar) => foobar.

So, we can test for 0 now, and from that we can test for non-zero using the familiar !!x operation to translate any x into its truthiness boolean.

Our F-theta scan lenses are designed for a wide range of applications. It is available over a broad wavelength, ranging from UV, VIS, NIR, and CO2 Laser. We also provide custom solutions for any wavelength-specific applications.

Image

Back reflection ghosting is the surface reflection from the scanning lens. The reflected focus points appear at different positions. When using a picosecond or femtosecond pulsed laser, the reflected focus point can easily damage the coating or lens material on the lens surface.

Telecentricity describes the angle of incidence of the laser beam delivered to the surface of the material during laser processing. In general, the angle of incidence for every point on the focal plane is the same, while non-telecentric lenses have varying angles of incidence on different points of the same plane. The end result of telecentricity produces repeatable and homogeneous spot size distribution on the object space field while reducing the effects of parallax error.

If only one mirror is used, the aperture stop is located on the mirror. If two mirrors are used, the aperture stop is located in the middle of the two mirrors, and the beam will be skewed. Usually, they will use two galvanometers and focus the beam on a 2D plane.

It is a bit messy, but I will explain it some other time. The point is that I can, for example, write a generic macro that creates a slice from a buffer and a length, where I need the underlying base-type to dispatch on:

F-Theta is usually used in laser scanning systems. The working wavelength is a single wavelength and the working piece is a plane. The F-Theta lens belongs to a large field of view and a small relative system design. Then the aperture stop diameter is equal to the laser beam diameter. In the 2D Galvo Scanner system, there is actually no optical aperture pupil.

Here, foo3(qux, 42) is transformed into cat2(foo, [f=qux]([x=42])) and which gives us cat2(foo, qux(42)), and that is what we need to evaluate. It’s a macro call, so same procedure as always.

If we expand foobar, we first have to expand foo, so now we will be in a context where we are expanding foobar and foo. Inside foo, things progress as above, we leave F alone, we expand bar, then get a B and then a tagged foo because we cannot expand recursively.

If you place two

Here, the substitution gives us bar(qax(), 42) => s([f=qax()]([x=42])) and [f=qax()] is evaluated, qax() => qux, so the result is s(qux(42)) => "qux(42)".

We won’t get [42] [32] foo, though; eval() leaves foo(32) alone in the expansion. Because we saw that foo inside the expansion of foo, it is tagged. It doesn’t matter that we didn’t see it as a function-like macro; that just prevented us from expanding it; we saw it, and it is now impossible to expand.

I wasted a lot of time not quite getting there—the final realisation that I wouldn’t make it was that I needed to generate macros, and you cannot do that in other macros. I gave up (but I will tell you about the solution I ended up with some other time; it isn’t bad, just not quite what I wanted). Before I gave up, however, I went deep down the rabbit hole of macro meta-programming, and it is now my intent to drag you down with me.

google lens下载

that step translates f(x) into bar(42), substituting f for the argument bar and x for the argument 42. It just puts in the raw arguments again, just as for stringification. At this point, we don’t expand the arguments.

Macros in arguments are expanded in this step; it is not that this step isn’t doing anything. It is just that in these two examples, the expansion is to the verbatim input, qux to qux (and not qux() and 42 to 42).

Not that you can tell, because unless you do step 3, concatenation, they will be expanded in step 4 before you see any results.

Ronar-Smith® F-Theta scan lenses are designed to meet the broad industrial requirements of our customers. When laser-material processes require a constant field of view with no dependency between the lens magnification and the depth, an object-space telecentric lens is recommended. For processes that have less stringent requirements on the quality of finish at the focal plane, a non-telecentric lens is capable of delivering the job to the customers’ satisfaction.

We don’t evaluate qux(42) because s() doesn’t evaluate its input, it stringify it, and once we are past expanding s, we don’t attempt to evaluate the result.

There is nothing complicated in implementing such slices. You need a pointer to an underlying buffer and a length (and maybe a capacity), and that’s that. The only thing that makes it difficult is that I need slices of different types. They all behave exactly the same, even with the same code, except for the type of the underlying buffer. That varies, and thus so does the return type of indexing, some initialisation code (where the user provides the buffer that must be of the correct type) and a few other things.

google lens中文

Here, we define if_else(b), where b must be 0 or 1, such that it either picks if_0 (where b is 0) that will ignore its parameters but evaluate to else_0, or it evaluates to if_1 that will expand its parameters and follow them with else_1. The idea is that you would call if_else() followed by an if-part in parentheses, thus invoking either if_0 or if_1, and then they provide an else part that you invoke with a second set of arguments. It could look like this:

Image

to get a function-like macro that doesn’t take any arguments but expands to 42. For function-like macros, you have to provide the parentheses to expand the macro. The macro name alone, foo, isn’t expanded.

google lens怎么用

This is a challenge for the designer. In the optimization, the designer must not only consider the performance of the design but also avoid the reflection focus point on the lens.

Is there then no way to evaluate before concatenating? Of course, there is; we just need to cheat the preprocessor into doing it. If one level of indirection doesn’t work, try two:

For most applications in laser-material processes, a planar imaging field is necessary for quality output. Traditional optics such as paraxial lenses focuses only on their spherical plane, resulting in distortions such as spherical aberration while imaging on a planar surface.

qux(42) where qux(42) evaluates to bar, so the result should be foobar. But the rule is that we first substitute

UV lasers at 355nm are advantageous as micromachining tools. Light at this wavelength interacts with materials primarily through photoablation, through which high-energy photons break molecular bonds, resulting in a clean cut with minimal disruptive effects on the surrounding material. For applications ranging from microelectronics to medical equipment production, solid-state UV lasers offer high versatility at low operational costs for the micromachining industry. Demand for large area scanning range, and simplified optical system design for both laser processing and vision inspection beams, present new challenges for a critical component in a laser system, namely, the scanning lens.

(Without the s(-) wrapper, you get bar(42), which will be expanded to 2 * 42. If you were hoping that the preprocessor would give you 84, you forgot that it only does text substitution; it will not evaluate expressions).

It looks promising, but we are not out of the woods. The last expansion, which gave us the third bar_, happened inside an expansion of bar_, so it is tagged, and we won’t expand further.

Scanninglensmagnification

The two main design categories of scan lenses include telecentric and non-telecentric F-Theta scan lenses. Telecentric F-Theta scan lens is a special type of lens system whereby the deflected off-axial laser beam can be perpendicularly focused onto the workpiece like the on-axial focusing beam. The advantage of the telecentric scan lens is that it can flatten the field curvature to be least distorted while offering superb spot quality throughout the scan field. The overall design concept is shown in Figure 11.

For each slice type, there is a CSTR_SLICE_BASE_ macro, and the CSTR_SLICE_BASE(TYPE) picks the right one by concatenating CSTR_SLICE_BASE_ with TYPE.

We can use truthiness() in our if_else to handle more general input. Zero will still mean false, but everything else will be true.

After we have stringified, substituted and concatenated, we expand parameter tokens. That just means that we expand the parameters we got if they are macros.

GoogleLens

F-theta lens provides the linear dependence between 𝑓 and 𝜃, creating a linear displacement that is ideal for use with scanners (XY galvanometer with mirrors) rotating at a constant angular velocity. The fixed velocity of the scanners corresponds to a constant velocity of the focal point on the flat focal field, with little to no electronic noise correction required. The complex scanner algorithm for the nonlinear compensation is eliminated, hence providing an accurate, safe, and inexpensive solution to customers.

you have some intuition about what you expect to happen, but that intuition is probably from programming in C (or similar languages). You want a to get the value of evaluating foo() and then be used with that value in the body of FOO. Likewise for b <- bar(x, y) and c <- baz. And mostly, that is what happens. But this isn’t C, and macros do not behave the same way. The rules for expanding a function-like macro, and the order in which they are applied, are:

When we call foo(qux, 42), we might expect this to become foo

It doesn’t have to be this way. We can trick the preprocessor to expand to someing that that doesn’t contain a forbidden name, and then we can evaluate at a later time.

Anyone who says that C’s preprocessor macros are easy to use probably hasn’t used them that much… the rules are simple, perhaps, but they are tricky.

In practical applications, there is no mechanical boundary to create any kind of aperture in it. When designing, they will place the aperture in the middle of the two mirrors, as shown in the figure below.

That is something you will know after spending an afternoon learning C, but there is a bit more to macros and the rules for how they expand, and while pure text substitution isn’t much of a programming language, you can do some meta-programming. Especially if you get to use variadic macros in ways that they were never intended to be used.^[We didn’t have variadic macros when I learned C, but they’ve been in the standard since C99, so you should have them now.]

We use two mechanical scanning mirrors as Mirror X angle and Mirror Y angle respectively, then the relationship between them and the optical scanning angle is: (Mirror X angle)2 + (Mirror Y angle)2 = (optical scan angle/2)2

The preprocessor is rather dumb. It does text substitution, nothing more. It is annoying at times, but this can also allow you to manipulate parts of expressions if you so desire, so there is some sense to it.

This is, fortunately, quite easy to fix. If we write empty empty() (), then the first expansion will remove the middle empty() leaving empty() for the next expansion.

So, anyway, we can write macros that either expand to is_true() or not, and if they expand to is_true() we can use that to get a truth-value out of them.

Say you want to expand foo above. Then you enter a state that knows that it is expanding foo, it handles the token F without any issues (it is not a macro, so it is left as it is)

Expansion works as you would expect, with the same rules we have discussed earlier if we are working with function-like macros, except that recursion isn’t allowed.

The large scanning area is advantageous for high throughput precision laser processing. This is essential when display electronics require high-speed manufacturing; e.g. the laser lift-off in flexible and large-area OLED processes. These scanning lenses can work in conjunction with our customized design of beam expanders (refer to WOE application note of Versatile Beam Expansion – from tunable to automation) and new design of beam shapers (refer to WOE application note of Beam Shapers – shaping the beam from DUV to MIR).

But we are getting ahead of ourselves. We need to dig a little further into how function-like macros are expanded before we move on.

see that there is a function-like macro, s(), evaluate it (following the same rules as we are following now, and replace the call with the result

between two tokens, you concatenate them. The tokens are just text, as always, so this means that A

In my slice code, I use _Generic() to dispatch on types, but sometimes I must dispatch on a slice type and sometimes on an underlying type. So I defined macros that map from a slice type to the underlying type like this:

We cannot guard against someone shoving some macro into test() that expands the way that is_true() does, but this is C, and nothing is ever safe. It is good enough.

It is not much fun, of course, if we have to explicitly evaluate for each expansion of the recursion, but we we can build exponentially larger number of expansions like this:

It is roughly what you can do with _Generic() for types, but that feature is somewhat limited. You can only expand values to values and not, for example, types.

Ronar-Smith® F-Theta Scan Lenses are meticulously designed and crafted for a broad range of laser applications. With over a decade of expertise in optical grade and coating production, Ronar-Smith® scan lenses yield some of the world’s finest optical performance in the market. We also provide customization services for customers based on their requirements.

We can define foobar as first a foo and then a bar, and see that it is the recursive expansions that disable some expansions, not consecutive ones.

We expand foo2(qux, 42) by substituting the arguments to get cat(foo, [f=qux]([x=42])) where I have put the substitution in square brackets. In this step, we need to expand the macros in those substituted expressions, but qux evaluates to qux. It is a function-like macro, so qux() evaluates to something (it evaluates to bar), but qux without parentheses doesn’t. And 42, of course, evaluates to 42. The result is cat(foo, qux(42)) so the arguments to cat, which it will concatenate without evaluation, are foo and qux(42). We do not evaluate qux(42) because that expression wasn’t part of a parameter; we created it from two separate arguments.

And there is more to them. Otherwise, we couldn’t do half the meta-programming we can. But I think it is time for a little break to see how we can do something useful with what we’ve got so far.

I’ve been working on a small C library for Python- or Go-like slices the last couple of weeks. Essentially arrays, but where I can index from the end using negative numbers (like in Python) and where I can extract a sub-slice, x[i:j], in constant time (like in Go; I implement them the same way as Go does).

B becomes AB (unless we have substituted something in for A or B).

Ronar-Smith® F-Theta achromatic scan lens is designed to limit spherical and chromatic aberration, and bring in two different wavelengths (working and visible) onto the same plane. This enables the transmission of wavelength-specific laser beams during laser-material processes while ensuring that the visible (feedback) and laser beam wavelengths are temporally and spatially matched. Our achromatic scan lens enables machine vision in industrial processes for automation control and feedback while ensuring the product quality is not compromised.

google lens电脑版

When a vision system is being integrated into a laser machining system, our achromatic telecentric scan lenses are color-corrected between working and vision wavelengths. The achromatic telecentric scan lens offers the same benefits as the normal telecentric lens while providing accurate vision positioning. The design layout is shown in Figure 12.

but when it needs to expand bar it expands the tokens there and remembers that it is now expanding both foo and bar. Then it scans alone, past B that doesn’t require any special handling, and it runs into foo. Since it is in the process of expanding a foo, this foo cannot be expanded. It is tagged, and in any future processing, it will be left alone.

There’s a trick that I have used a lot, and most recently with the slices I mentioned at the beginning of this post. If you have to choose between different expansions based on a type or a value, you can define macros for each choice and write another macro that picks the appropriate one.

you are trying to give expr() a composite expression. It sees two arguments because there is a comma in the arguments you give expr, so you are calling expr() with (struct foo){ .bar = a and .baz = b}, and not a single token.

There is no substitution and no further expansion, you get the argument as a string, and that’s that. This is the first thing that happens, so such stringified arguments are not processed further.

If you put a single # in front of a macro parameter, that parameter is turned into a string. The string contains the verbatim argument you provided.