Open IS4Code opened 3 years ago
I think the code that handles symbol resolution for default values should take all parameters into account
Well, that's the problem: there's no way to take an expression operand into account if it's not defined yet.
The point is that the functionalities for sizeof
and tagof
are actually duplicated: arg2=tagof(arg1)
is handled by the code in function doarg()
(file sc1.c
), where the compiler memoizes the name of the operand of tagof
, to process it after the function is fully declared and all arguments are known, while arg2=(tagof(arg1))
is processed in hier2()
(sc3.c
), as a part of a "normal" constant expression, which is why this kind of sizeof
/tagof
doesn't work on following function arguments, as they're not defined at the moment when the expression is parsed.
I believe that duplicating the functionalities of sizeof
and tagof
was a deliberate choice of the original author of Pawn to allow them to be used on function arguments that are defined after being referenced by the said operators. There's a downside to it though, as the compiler expects a )
or ,
right after the sizeof
or tagof
, so we can't do something like
Func(str[], length = sizeof(str) - 1) // error 001: expected token: ")", but found "-"
{ /* ... */ }
while this would work:
Func(str[], length = (sizeof(str) - 1)) // OK
{ /* ... */ }
In order to "fix" this (I'm not sure if this can really be considered a bug, hence the quotes), we could do the following:
Remove the duplicate functionality from function doarg()
, so sizeof
and tagof
would be handled as parts of "normal" constant expressions.
But then the normal sizeof
and tagof
(the ones in sc3.c
) wouldn't work on following function arguments, thus possibly breaking compatibility with some of the existing Pawn code.
Make (sizeof(arg))
and (tagof(arg))
work on following function arguments.
Currently there's no easy way to do this, as we can't just read the default value expressions and then compute them later after all function arguments are defined; there's no "delayed execution" mechanism for expressions.
One thing we could do here is "record" the default expressions while normally parsing them token by token (I already implemented a token recording mechanism for operators __static_assert
and __static_check
last year), temporarily silencing the error reporting mechanism beforehand, so undefined arguments won't be reported as errors; and then re-parse the recorded expressions later, but that wouldn't be simple either.
@Daniel-Cortez Yeah, I imagine it would not be easy... In any case, suppressing the error and then either reparsing or updating what was parsed seems like the best option. Then the normal constant expression parsing could be used in all cases to support the sized(x)-1
case.
Another thing worth mentioning is that the default values are constant expressions, which means it's possible to use named constants there, but the user might forget to use a named constant instead of a hardcoded value in one of the declarations and/or the definition of the function, e.g.:
const DEFAULT_VAL = 1;
Func(arg = DEFAULT_VAL);
/*...*/
Func(arg = 1) // should be "arg = DEFAULT_VAL"
{
// ...
}
In this example the resulting default value for arg
would still be 1
, so the compiler won't detect this kind of mistake, it would only become apparent when the value of DEFAULT_VAL
is changed. This is where recording the default expressions and comparing them at each function re-declaration/definition might come in handy, although a simple strcmp(oldstr,newstr)
won't do - we'll also need to remove excess whitespaces, so, for example, DEFAULT_VAL + 1
won't be treated as different from DEFAULT_VAL+1
. There are also operators sizeof
, tagof
, __nameof
and __addressof
that actually require a whitespace after them if the argument isn't enclosed into parentheses, as otherwise they would break after the whitespace removal (e.g. sizeof a1
would become sizeofa1
), so we'll have to work around them somehow.
Also, the following code
Func(const a[], size = (sizeof(a)))
return a[0] - a[0] + arg;
would make the compiler print warning 224: indeterminate array size in "sizeof" expression (symbol "a")
and assume 0
in place of sizeof
, although after removing the excess pair of parentheses around sizeof(a)
Func(const a[], size = sizeof(a))
return a[0] - a[0] + arg;
the code would compile with no errors or warnings. For now I'm not sure how to resolve this; perhaps we should make the compiler compute recorded default expressions at each function call if they cause warning 224 when first parsing them at the function declaration/definition.
This issue has been automatically marked as stale because it has not had recent activity.
A simple
sizeof
/tagof
expression works when referencing a parameter at the same or greater position, i.e.:This is an interesting behaviour in the first place, but it is useful enough. However, the following does not work:
That is, using a complex expression (parentheses, operators etc.) with a
sizeof
/tagof
operator that references the following parameters (or the current parameter) does not compile ('undefined symbol "val"').I think the code that handles symbol resolution for default values should take all parameters into account, for the sake of consistency (and in case some macro modifies the expression).
Workspace Information:
-;+ -d3 -(+ -Z