48 Commits

Author SHA1 Message Date
Daniel_Cortez
b411e5a7bc Switch from symbol subtypes to symbol subtype flags
The new system should be more flexible as it allows to combine symbol subtypes.
2018-12-31 21:44:10 +07:00
spacemud
19dabbbeb0 Show symbol name with indeterminate array size warning (#370)
* Show symbol name with indeterminate array size warning

* Update older test to account for bug fix

* Add tests
2018-10-15 16:34:33 +01:00
Daniel_Cortez
bc04b2ef04 Show suggestions for mistyped identifiers (#353) 2018-09-29 07:03:44 +06:00
Barnaby Keene
27bdc075b2
Revert "Check if function is naked before adding +1 for PROC opcide (#357)" (#361)
This reverts commit 6dec728efe5b8c394b4059e6845d394392c68605.
2018-09-02 18:49:49 +01:00
Adrian Graber
6dec728efe Check if function is naked before adding +1 for PROC opcide (#357) 2018-09-02 18:40:35 +01:00
Zeex
16995c5ee1 Whitespace cleanup 2018-08-11 23:12:45 +06:00
Barnaby Keene
d5f01e80e1
Merge branch 'dev' into fix-i308 2018-07-27 08:03:35 +01:00
Yashas
8948f207ea disable 239 for native functions 2018-07-08 12:04:38 +05:30
Yashas
1578ab15a3 fix result propogation in constexpr operator chains
## compile-time chained operator evaluation mechanism

Constants are stored in `value` object. The object has two members: `constval` and `boolresult`. The `constval` member stores the actual value which the object represents: `15`  and `10` for example in `15 < 20`.  All operators are in a chain of operators. On most occasions, there is just one operator in the chain but it is still a valid singleton chain. The `boolresult` member stores the result of the previous operations which the constant was involved in if any. For example, in `15 < 20 < 30`, the `boolresult` member of object representing `20` stores the result of `15 < 20`. In more complex expressions such as, `15 < 20 < 30 < 40 < 50`, the `boolresult` member of object representing `40` stores the result of the `15 < 20 < 30 < 40`.

The `boolresult` of the first constant in a chain is set to `TRUE` by default.

**Details:**

The processing of chains begins at `plnge_rel` which maintains two `value` objects: `lval` and `lval2`. The `lval` is taken by `plnge_rel` as an argument of the first constant (stored in `constval` field) value in the operator chain. The result of the full chain is also passed through it by storing the result in the `constval` field (like `15 < 20` evaluates to the constant `1`; the result of `15 < 20` is `1` which is also a constant).

The `boolresult` of `lval` is set to `TRUE` as this is the first constant in the chain. The `plnge_rel` progresses through the chain one by one with `lval` and `lval2` always being the left operand and the right operand respectively. For each operator it calls `plnge2` which dumps instructions for loading constant and the right operand into the staging buffer. If the right operand turns out to be a constant, the staging buffer is flushed and `static cell calc(cell left,void (*oper)(),cell right,char *boolresult);` is called to evaluate the compile-time expression with the constant value of the left and right operand passed as `left` and `right` arguments along with the operator and `boolresult` of the left operand. `calc` evluates the expression and returns the right operand and sets the `boolresult` to the result of the operator chain. After the call returns, `constval` of `lval` (left operand) is set to the `constval` of `lval2` (right operand). As of now, the `lval` now stores the right operand and the result of the operator chain uptil now.

`plnge2` returns and control is transfered back to `plnge_rel`. `plnge_rel` copies the value stored in `lval2` into `lval`. This implies that the `boolresult` and `constval` fields of `lval2` are copied into `lval` as the previous right operand is now the left operand for the next operator in the chain. **Oops! BUG!** The `boolresult` which was stored in `lval` is lost and is replaced by `FALSE` which was stored in `lval2` which is the default for `value` objets (set by `clear_value`). The compiler should've ensured that the `boolresult` of `lval` was retained. `plnge2` is again called to process the right operand and evaluate the expression.

This keeps repeating until the entire chain has been evaluated. After the entire chain has been evaluated, `lval` has `constval` as the most recent right operand and `boolresult` has the result of the entire chain. The compiler sets `constval` of `lval` to `boolresult` of `lval` and its tag to `bool`. Note that this is done in the last step. The `lval` now is a constant representing the result of the entire chain of operators, i.e. `1` if the chain evaluated to `TRUE` or `0` otherwise.

**Relavant bugged code:**
```
static int plnge_rel(int *opstr,int opoff,int (*hier)(value *lval),value *lval)
{
  .
  .
  .
  lval->boolresult=TRUE;
  do {
    /* same check as in plnge(), but "chkbitwise" is always TRUE */
    if (count>0 && bitwise_opercount!=0)
      error(212);
    if (count>0) {
      relop_prefix();
      *lval=lval2;      /* copy right hand expression of the previous iteration */
    } /* if */
    opidx+=opoff;
    plnge2(op1[opidx],hier,lval,&lval2);
    if (count++>0)
      relop_suffix();
  } while (nextop(&opidx,opstr)); /* enddo */
  lval->constval=lval->boolresult;
  lval->tag=pc_addtag("bool");    /* force tag to be "bool" */
  return FALSE;         /* result of expression is not an lvalue */
}
```

```
static void plnge2(void (*oper)(void),
                   int (*hier)(value *lval),
                   value *lval1,value *lval2)
{
    .
    .
    .
    if (check_userop(oper,lval1->tag,lval2->tag,2,NULL,&lval1->tag)) {
      lval1->ident=iEXPRESSION;
      lval1->constval=0;
    } else if (lval1->ident==iCONSTEXPR && lval2->ident==iCONSTEXPR) {
      /* only constant expression if both constant */
      stgdel(index,cidx);       /* scratch generated code and calculate */
      check_tagmismatch(lval1->tag,lval2->tag,FALSE,-1);
      lval1->constval=calc(lval1->constval,oper,lval2->constval,&lval1->boolresult);
    } else {
    .
    .
    .
}
```

```
static cell calc(cell left,void (*oper)(),cell right,char *boolresult)
{
  .
  .
  .
  else if (oper==os_le)
    return *boolresult &= (char)(left <= right), right;
  else if (oper==os_ge)
    return *boolresult &= (char)(left >= right), right;
  else if (oper==os_lt)
    return *boolresult &= (char)(left < right), right;
  else if (oper==os_gt)
    return *boolresult &= (char)(left > right), right;
  .
  .
  .
}
```

As you can see, the `boolresult` is ANDed with the result of the current operation. If one of the operators in the chain earlier had evaluated to false, the `&` will force `boolresult` to remain `FALSE` irrespective of whether the current expression evaluates to true or not.

### What's the bug?

The compiler loses the `boolresult` of `lval` in `plnge_rel` and replaces it with the `boolresult` of `lval2` which is always initalized to `FALSE` by `clear_val`.

The fix is to ensure that `lval` retains the value.

This commits does this by copying the `boolresult` of `lval2` into `lval` before `*lval=lval2`. This ensures that the `boolresult` is retained in `lval`.
2018-06-09 10:58:20 +05:30
Zeex
537c91ab91
Merge pull request #302 from YashasSamaga/fix-i276
suggest `const` qualifier for arguments and inform user when an array/string literal is passed as a non-const argument
2018-06-03 03:36:05 +06:00
Yashas
293c9a3b31 mark symbols passed as non-const args modified
This commit makes the compiler mark array symbols which are passed as non-const argument modified.
2018-05-10 23:01:52 +05:30
Yashas
c363c5b1de add warning for literal passed to non-const parameter
Adds a new warning to warn users when they pass an array/string literal to a non-const qualified parameter.

```
f1(arr[]) {
 	new a = arr[0];
 	#pragma unused a
}

f2(arr[5]) {
    new a = arr[0];
    #pragma unused a
}
f3(const arr[]) {
    new a = arr[0];
    #pragma unused a
}
f4(const arr[5]) {
    new a = arr[0];
    #pragma unused a
}

main () {
	f1("test");
	f2("test");
	f3("test");
	f4("test");

	new arr[5];
	f1(arr);
	f2(arr);
	f3(arr);
	f4(arr);

	f1(arr[0]);
	//f2(arr[0]); - array size must match
	f3(arr[0]);
	//f4(arr[0]); - array size must match
}
```

```
test.pwn(1) : warning 214: possibly a "const" array argument was intended: "arr"
test.pwn(6) : warning 214: possibly a "const" array argument was intended: "arr"
test.pwn(20) : warning 239: literal array/string passed to a non-const parameter
test.pwn(21) : warning 239: literal array/string passed to a non-const parameter
```
2018-05-10 10:44:36 +05:30
Yashas
fd4369e67b debug info for index tagmm warnings
This commit makes the compiler display debug information for "index" tag mismatch warnings.
2018-05-08 09:43:34 +05:30
Zeex
a840b4a4c3
Merge pull request #245 from YashasSamaga/fix-i160
fixes inconsistencies with the tagof operator
2018-04-22 19:46:39 +06:00
Zeex
892744313d
Merge pull request #255 from Daniel-Cortez/constvalue-opt
Memoize the last node in constvalue lists
2018-04-22 19:19:43 +06:00
Zeex
06382a9782
Merge pull request #274 from YashasSamaga/fix-i268
fixes tagof behaviour on default values
2018-04-22 19:16:44 +06:00
Zeex
7a53a93574 Fix crash when number of arguments exceeds sMAXARGS
During first pass the call to error() is ignored and therefore
doesn't break ouf of the loop. This causes stack courrption because
of OBB write to arglist.

Fixes #298.
2018-04-22 18:48:55 +06:00
Daniel_Cortez
9ca1b4a61e Redo constvalue list optimisation 2018-02-22 03:51:42 +07:00
Yashas
42c18c2a10 fixes tagof behaviour on default values
Previously, if the tagof operator was used on an argument with default value, the tag identifier recorded would be 0 in case the default value was used.

```
f({Tag1, Tag2}:a = Tag2:123, b = tagof(a)) { }
main () { f(); }
```

In the above code, the argument `a` would have the value `123` but `b` would have `0`.

This commit patches the bug. The value of `b` will be the tag identifier of the default argument.

This commit patches for two cases: default argument is a reference and default argument is a variable.

The case of reference arrays is not handled correctly as the tag of the default reference array is not well defined.

**Implementation details:**
The compiler first processes arguments which are not taking default values (including `tagof` and `sizeof` parameters). The compiler does a second pass on the list of all formal parameters and processes the default values. The compiler then does a final pass on the list of formal parameters and processes `sizeof` and `tagof` parameters.

The compiler maintains a list of tags of all the arguments in a `constvalue` list called `taglst` as it processes the arguments.

The name field of the members of the tag list is the argument name and the tag field stores the tag identifier of that argument (tag identifier of the actual parameter).

In the first pass where the expclit arguments are being processed, the compiler checks the argument's tag and adds the tag along with the formal parameter name (can be thought of as <formal-paramter-name : tag pair>) to the tag list if the tag identifier is NOT zero.

In the second pass where the default values are being handled, the compiler does not modify the tag list (**source of the bug**).

After all the arguments other than `sizeof` and `tagof` have been handled othe, the compiler iterates through the list of arguments and takes care of `sizeof` and `tagof` arguments.

Here it checks to which formal parameter (say F) the `tagof` parameter (say T) points to. It then checks the tag list for that symbol F, if an entry is found, it uses the tag identifier associated with that argument. If not found, it defaults to 0.

Since the tags of default arguments along with it's formal name is not added to the tag list, the third pass won't be aware of any tag associated with the default values and assumes 0.

This commit adds code to add the tags of the default values to the tag list so that the compiler is aware of the tag of the default values in the final pass.
2018-01-28 12:46:03 +05:30
Yashas
345b415d55 debug info for tagmismatch warnings
This commit adds useful information to the "tag mismatch" warning.
2018-01-18 21:41:26 +05:30
Yashas
5a0fd0fda1 fixes inconsistencies with the tagof operator
The standalone tagof operator tries to export tall tags which it works with.

The tagof operator when used as a default argument checks if the tag is zero before exporting.

As the zero tag identifier cannot be exported (even if its `PUBLICTAG` bit is set), it makes sense to use `0` as tag identifier instead of `0 | PUBLICTAG`.

This commit changes the standalone tagof operator behaviour so that the zero tag identifier does not get its `PUBLICTAG` bit set.
2018-01-07 20:19:05 +05:30
Zeex
11199da210 Fix compile warnings in pawnc 2017-12-30 16:12:33 +06:00
Daniel_Cortez
939c06011d emit/__emit: Another syntax change 2017-12-10 03:51:19 +07:00
Daniel_Cortez
d5691209d6 emit/__emit: Move the "anti-optimisation" workaround to 'emit_parse_line()'
Conflicts:
	source/compiler/sc1.c
2017-12-06 21:52:51 +07:00
Daniel_Cortez
e922e48aa6 emit/__emit: Fix incorrect code generation 2017-12-04 18:24:32 +07:00
Daniel_Cortez
907c4b610e emit/__emit: Syntax change 2017-11-29 21:52:05 +07:00
Daniel_Cortez
06feab9224 emit/__emit: Code cleanup 2017-11-11 20:50:07 +07:00
Zeex
17ebeb8ebe Revert "triggers an error for issue #129"
This reverts commit 9e4a2b283fd01549d05058c8946ecee974e30dbe.

Reverting because of #198.
2017-10-23 08:04:02 +06:00
Zeex
2a85a9fa33 Merge pull request #190 from YashasSamaga/i154-fix
trigger error if an array of unknown size is being returned
2017-10-08 02:48:48 +06:00
Zeex
9daeae3d1a Merge pull request #151 from YashasSamaga/i129-fix
triggers an error for issue #129
2017-10-08 02:47:20 +06:00
Daniel_Cortez
6119df8f2b Rename asm to emit, add __emit as an alternate keyword. 2017-10-06 15:51:24 +07:00
Yashas
00a1cd7e88 trigger an error if an array of unknown size is returned 2017-09-29 16:21:33 +05:30
VVWVV
f7edb7dd90 Fix asm operator in expressions
Signed-off-by: VVWVV <d0u61ev@gmail.com>
2017-08-01 22:35:40 +03:00
VVWVV
e19354a52c Add new asm operator instead of #emit
Signed-off-by: VVWVV <d0u61ev@gmail.com>
2017-07-29 22:02:26 +03:00
Zeex
43cd36b891 Fix false 'assignment to itself' warning
Change lvalue type (ident) to iEXPRESSION if a unary operator is
applied to it ('!', '~', '-'). This allows the self-assignment
check to pass.

Fixes #78.
2017-05-01 12:09:08 +06:00
Yashas
9e4a2b283f triggers an error for issue #129
cond ? array1 : array2

Triggers an array if the size of array1 and array2 do not match.
2017-02-12 22:25:12 +05:30
Zeex
3a4878f54b Fix clang warnings 2017-02-11 19:32:10 +06:00
Zeex
f9e9c181dd Mark symbols as read when they are passed as function arguments
This is an improved version of the earlier fix for bug #131.

Also should fix https://github.com/Misiur/YSI-Includes/issues/154.
2017-01-28 12:59:49 +06:00
Zeex
25b21eb0aa Improve reparse check
Only reparse if the function has a tagged result (old behavior) or a
global variable is passed as one of its arguments at some point before
declaration/definition.

Also warn if need to reparse so that developers are aware of potential
performance hit.

Fixes #131.
2017-01-22 17:26:14 +06:00
Zeex
69f1ec61f9 Fix typo in constant name (DEPRICATED -> DEPRECATED) 2017-01-21 14:33:46 +06:00
Sergei Marochkin
485361acb4 Revert and fix it (thanks to @oscar-broman) 2016-09-07 09:44:08 +03:00
Sergei Marochkin
b5959fcf15 Remove Linux crash lines 2016-09-05 11:16:56 +03:00
Marcin Misiurski
8e11f682d6 Fix enum field size (credit to @Arkshine) 2015-03-25 14:19:10 +01:00
Zeex
4d2c600507 Fix crash on error 33 in ternary operator
If one of the two values is a string literal and the other is a
non-array, the symbol associated with the first one will be NULL.
But the code checked if sym->name!=NULL rather than sym!=NULL,
hence the crash.

--------- test code --------

main() {
    new a, b;
    return (a != 0 ? b : "string");
}

----- end of test code -----
2014-04-21 10:52:44 +07:00
Zeex
53ef10ffc7 Fix crash when using tagof(tagname:)
This fixes #18.
2014-02-19 22:31:50 +07:00
Zeex
53221dd2cc Introduce #pragma naked
When applied to a function #pragma naked merely disables the "should return
a value" warning for the function. It's intended to be used with functions
that return a value via #emit instead of the normal return statement.

This pragma works only on function definitions, not declarations. It's also
pretty stupid - the function may be defined way after this directive and it
won't stop on things coming in between.

For example, here all declarations between #pragma naked and f() are
effectively ignored:

#pragma naked

new x;       // ignored
forward g(); // ignored
native n();  // ignored

f() {
    // f() becomes naked
}

Note that #pragma naked does not affect generated code in any way, unlike
e.g. __declspec(naked) or __attribute__((naked)) in C/C++ where the compiler
omits the code for the prolog and epilog.
2014-01-05 01:26:10 +07:00
Zeex
c20d9cb33b Fix compile crash when calling a function at global scope
This fixes a crash that occurs if a global variable is initialized
with the result of a function call.

See 3) here: http://forum.sa-mp.com/showthread.php?t=355877

--------- test code --------

native use(...);

f() {
	return 0;
}

new x = f();

main() {
	use(x);
}

----- end of test code -----
2014-01-01 16:49:55 +07:00
Zeex
766b96bcf3 Lower case directory names 2013-09-19 13:06:46 +07:00