0

My macro can receive either a variable, say 'x' or a complex expression, say f() or x + y. I want it to do x = 1 in case it is a single variable and do nothing if it was f(), how to acieve this behaviour?

My own programming language compiler compiles to C if anyone wonders why I need this.

Another way to look at this is that I may need to get a pointer of a provided argument if that's possible and do nothing otherwise. Or basically I need IS_LVALUE(x) macro. Similarly to IS_CONST_EXPR(x) found in Linux source code.

#define __index_set_macro(object, ix, item) \
    ({ val _T = object; \
    if (__is_int(_T) && __is_int(ix) && __is_int(item)) \
        _T ^= (-(!!item) ^ _T) & (1UL << ix); \
        object = _T; \
    else __index_set(_T, ix, item); })

void __index_set(val object, val index, val item) {
    if (__is_heap(object)) {
        leaf *l = __leaf(object);
        switch (l->type) {
            case leaf_arr:
                if (!__is_num(index)) __throw_n(__str(E004_0), 2);
                *__array_at(object, __get(index)) = item;
                return;
            case leaf_obj:
                __property_set(object, index, item);
                return;
            default:
            __throw_n(__tem(E008_1, __type_of(object)), 3);
        }
    }
    else {
        __throw_n(__tem(E008_1, __type_of(object)), 3);
    }
}

val is a boxed value which is treated as int32_t if the most significant bit is zero or as a pointer to a struct on heap otherwise. I need a function __set_index(object, index, item) that works with both, i.e. in my language you can write:

a := 0
a[0] = 1 // i.e. you set bit
b := [0 1 2 3] // create an array
b[0] = 123 // you change the value of the first item

which is compiled to:

val a = __let(0);
__set_index(a, 0, 1);
val b = __array(4, (val[]){0, 1, 2, 3});
__set_index(b, 0, 123);

as you can see I need __set_index to distinguish at runtime either it does a = some bit operations(a) or ((heap_object*)b)->table)[index] = item;

exebook
  • 32,014
  • 33
  • 141
  • 226
  • 2
    provide some example as your description is far from being clear – 0___________ May 19 '21 at 09:19
  • At the beginning you say you want to distinguish between a variable and an expression at preprocessing time. But in your example you say you want to distinguish between different variable types at runtime. Which is it? – interjay May 19 '21 at 10:01
  • 1
    Since you say your "own programming language compiler compiles to C", your compiler should be intelligent enough IMO to know what it is dealing with and generate different code accordingly. Rather than a single macro used willy-nilly, you should use different macros depending on the type of the arguments, and your compiler should know the difference.] – Jonathan Leffler May 19 '21 at 10:39
  • 2
    You can't really do this I think, since a variable name may be an expression, or part of an expression, and an expression might give a lvalue even though there is no variable. Otherwise I invented a little trick [here](https://stackoverflow.com/a/56184944/584518) to separate _types_ from expressions. – Lundin May 19 '21 at 10:48
  • 1
    Lvalues include: Identifiers for objects, string literals, unary `*` expressions, subscript expressions, structure and union member selections (`.` and `->` operators), compound literals, parenthesized lvalues, and `_Generic` expressions that select an lvalue operand. It is unlikely you will be able to distinguish these in a macro. – Eric Postpischil May 19 '21 at 11:28
  • 2
    You say your “own programming language compiler compiles to C”, but it looks like it does some simple transformations rather than compiling. To implement semantics like this in your own programming language, you ought to do proper parsing and semantic analysis and generate new code (whether in C or LLVM IR or whatever). Trying to squeeze your semantics into C tricks and kludges is not a good approach. – Eric Postpischil May 19 '21 at 11:34
  • 1
    Closest thing to such a macro I can come up with is `#define IS_LVALUE(x) ( ((uintptr_t) & (x)) != 0 )`. Assuming address 0 isn't allowed, then in case `x` is an lvalue this returns 1, otherwise you get a compiler error "lvalue required". (Still there's some corner cases not supported like functions.) – Lundin May 19 '21 at 11:40
  • 1
    Anyways, I'm going to close this as a dupe to "no it isn't possible" for now, this has been asked before. – Lundin May 19 '21 at 11:44

0 Answers0