Merge branch 'master' of github.com:pawn-lang/compiler into HEAD

This commit is contained in:
Alex "Y_Less" Cole 2018-10-30 22:43:31 +01:00
commit 5400511d86
80 changed files with 1994 additions and 690 deletions

2
.gitattributes vendored
View File

@ -1 +1,3 @@
* text=auto
*.pwn linguist-language=Pawn
*.inc linguist-language=Pawn

View File

@ -1,36 +1,37 @@
<!-- pawn-lang compiler issue template -->
<!--
This area is for:
- Bug reports
- Feature suggestions
- Questions directly regarding the compiler's implementation, command arguments
or usage. This is NOT a place to ask questions about compiler errors or
warnings you are getting UNLESS those errors or warnings are unexpected and
the result of a possible bug.
For any other questions, post on the SA:MP forum or the unofficial SA:MP
Discord server in the #programming channel.
The issues section of this repository is managed by @Southclaws who will assign
labels etc.
Please ensure that your issue is directly related to the pawn-lang/compiler. Issues
seeking help with scripting or doubts about SA-MP are not relevant to this project.
-->
**Is this a BUG REPORT, FEATURE REQUEST or QUESTION?**:
### Issue description:
<!--
Information that could be useful:
- how to reproduce the problem
- observed behavior
- expected behavior
- other relevant information
-->
* [ ] Bug Report
* [ ] Feature Request
* [ ] Question
### Minimal complete verifiable example (MCVE):
<!--
Please provide a minimal complete verifiable code which compiles
and reproduces the problem. If the compiler is showing undefined (random) behavior,
provide the code which invokes such behavior.
**What happened**:
Learn more about writing MCVE from [StackOverflow](https://stackoverflow.com/help/mcve).
**What you expected to happen**:
If this section is not relevant, feel free to remove this section from your issue.
-->
**How to reproduce it (as minimally and precisely as possible)**:
```
```
**Anything else we need to know?**:
<!-- comments on the code, if any -->
**Environment**:
### Workspace Information:
* Operating System
* Compiler version
* How are you invoking the compiler? Pawno, Sublime, vscode, sampctl or command-line?
* If using sampctl, the version number
* Compiler version:
* Command line arguments provided (or sampctl version):
* Operating System:

14
.github/stale.yml vendored Normal file
View File

@ -0,0 +1,14 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 90
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 9000
# Issues with these labels will never be considered stale
exemptLabels:
- "state: discuss"
# Label to use when marking an issue as stale
staleLabel: "state: stale"
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had recent activity.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
build
.vs
.vscode
source/compiler/tests/*.amx

View File

@ -14,9 +14,11 @@ addons:
- cmake
before_script:
- cmake source/compiler -DCMAKE_BUILD_TYPE=RelWithDebInfo
-DCMAKE_C_FLAGS="-m32 -Werror -Wno-address-of-packed-member"
-DCPACK_GENERATOR="TGZ;ZIP"
- mkdir build && cd build
- cmake ../source/compiler
-DCMAKE_BUILD_TYPE=RelWithDebInfo
-DCMAKE_C_FLAGS="-m32 -Werror -Wno-address-of-packed-member"
-DCPACK_GENERATOR="TGZ;ZIP"
script:
- make
@ -32,10 +34,10 @@ deploy:
secure: gDAuRNlF2uVhVHyZtJrX6MwNxnkfkQzohrC/6UcKAgqt+NKs4vZyq5FzTUceiDAkB0se70ZVx08e9ibAiXP/b7D1MPkAEiRxt9J6Vu3x6Bi1kPPuK5RfjFeT3gc1SbrULAP8Nz0NdU0chUhei6/V5NGhTegwp925DJOISq7+Ibw=
file_glob: true
file:
- 'pawnc-*-linux.tar.gz'
- 'pawnc-*-macos.zip'
- 'build/pawnc-*-linux.tar.gz'
- 'build/pawnc-*-macos.zip'
draft: true
skip_cleanup: true
on:
tags: true
repo: Zeex/pawn
repo: pawn-lang/compiler

1
CODEOWNERS Normal file
View File

@ -0,0 +1 @@
* @pawn-lang/compiler

View File

@ -5,7 +5,8 @@ configuration:
- RelWithDebInfo
before_build:
- cmake -G "Visual Studio 15 2017" source/compiler -DCPACK_GENERATOR=ZIP -DCMAKE_GENERATOR_TOOLSET=v100
- mkdir build && cd build
- cmake ../source/compiler -G "Visual Studio 14 2015" -DCPACK_GENERATOR=ZIP -DCMAKE_GENERATOR_TOOLSET=v100
build_script:
- cmake --build . --config %CONFIGURATION%
@ -15,17 +16,17 @@ test_script:
- ctest --build-config %CONFIGURATION%
on_failure:
- type Testing\Temporary\LastTest.log<Paste>
- type Testing\Temporary\LastTest.log
artifacts:
- path: pawnc-*-windows.zip
- path: build/pawnc-*-windows.zip
name: Binary package
deploy:
description: '<Put release description here>'
provider: GitHub
auth_token:
secure: ++mk9GhXTpN/hdVjIIi/nHpu0gYpDybMJNDPB3lld8r1UyfoPbz08SVGeSS84HjR
secure: dEyljMC1z2hb032HYJQY+CIZIdQ382cuHU/3LJA96nbqOl5xfGYPVP/TGbJANbtz
artifact: /pawnc-.*-windows\.zip/
draft: true
prerelease: true

184
readme.md
View File

@ -1,135 +1,119 @@
# Pawn
# Pawn Community Compiler
[![Build Status][build_status]][build] [![Build Status - Windows][build_status_win]][build_win]
[![Build Status][build_status_linux]][build_linux]
[![Build Status - Windows][build_status_win]][build_win]
[Original readme](readme_compuphase.txt)
## What
## What is this?
This is a modified version of the Pawn 3.2.3664 compiler with many bug fixes and
enhancements.
This is a modified copy of the Pawn compiler version 3.2.3664 by Compuphase that fixes some bugs and adds a few features.
This project was originally started by Zeex but on 2017-12-31, the project was
taken over by some members of the SA:MP community. Zeex still contributes to the
project, along with the [Compiler Team][team].
This project was originally maintained and managed by Zeex who left the project due to lack of time on 2017-12-31. Thank you for all your hard work on keeping this project alive Zeex!
The original readme is available [here][original_readme]
The project is now maintained by the [Compiler Team](https://github.com/orgs/pawn-lang/teams/compiler) here at the pawn-lang GitHub org.
## Why
## List of changes
This project exists to:
See [Known compiler bugs](../../wiki/Known-compiler-bugs) for the list of fixed bugs and [What's new](../../wiki/What's-new) for the list of features and other notable changes.
- Fix known bugs with the original compiler
- Provide a better development experience for the SA:MP community
[Release notes](https://github.com/pawn-lang/compiler/releases) descibe changes in each version of the compiler.
If you find problem, you can [open an issue][issues] and contributors can work
on a fix. This isn't true with the original compiler that comes with the SA:MP
server distribution.
## Download
There are also new features that enhance the development experience, such as
telling you which tags are involved in a "tag mismatch" or showing you where
that pesky "symbol is never used" is actually declared.
Binary packages can be downloads from [Releases](https://github.com/pawn-lang/compiler/releases).
There are plenty of features and fixes that are documented, see below for links:
You can also get the latest development binaries for Windows on [AppVeyor](https://ci.appveyor.com/project/pawn-lang/compiler/branch/master/artifacts). This archive is built automatically on every Git commit and can be pretty unstable, so use at your own risk.
- [Known compiler bugs][bugs] contains a list of bugs that the team are aware of
with their status.
## Installation on Windows
- [What's new][new] contains features and other notable changes.
Download the ZIP archive and extract `pawnc.dll`, `pawncc.exe`, `pawndisasmsm.exe` to your pawno directory or another directory of your choice if you're using a different editor.
- [Release notes][releases] list of all official releases of the compiler
binaries.
## Installation on openSUSE/SLES
## How to Use
There is an installation package available for openSUSE/SLES users so that you can easily install the compiler on your distribution. Please follow these steps:
Binary packages can be downloaded from [Releases][releases], see the below
sections for platform-specific installation instructions.
1. Go to https://build.opensuse.org/package/show/home:mschnitzer/pawncc
2. On the right side, select your distribution (only if it's not disabled!)
3. Click "Go to download repository"
4. Copy the link and enter in sudo mode in your shell: `zypper ar $COPIED_LINK home:mschnitzer`
5. Again as root, type: `zypper ref`
6. Install the package with `zypper in pawncc`
7. Run `pawncc` in your shell to test if it's working
**Note:** You will _probably_ get warnings/errors/fatals when you first build
with this compiler — you need to add the `-Z` flag to your build configuration
or add `#pragma compat`. See [this page][compat] for more information.
## Building from source code
You can also get the latest development binaries for Windows on
[AppVeyor][artifacts]. This archive is built automatically on every Git commit
and can be pretty unstable, so use at your own risk.
In general you will need [CMake](https://cmake.org/) and a C compiller to build Pawn from source code.
### Windows
### Building on Windows
If you just use an editor configured to run `pawncc` such as Pawno, Sublime Text
or VS Code you can simply delete your existing `pawncc.exe` and replace it with
the new one.
* Clone this repo: `git clone https://github.com/Zeex/pawn.git C:\pawn` (you can use another directory instead of `C:\Pawn`, but make sure the path doesn't have spaces).
* Install [Visual Studio Community](https://www.visualstudio.com/vs/community/), it's free.
* Install [CMake](https://cmake.org/).
Download the ZIP archive and extract `pawnc.dll`, `pawncc.exe`,
`pawndisasmsm.exe` to your original `pawncc` directory. If you use Pawno, this
will be in the `pawno/` folder that's inside your server directory.
When installing make sure to check "Add CMake to system PATH" to make your life easier.
### openSUSE/SLES
* Generate a Visual Studio project.
There is an installation package available for openSUSE/SLES users so that you
can easily install the compiler on your distribution. Please follow these steps:
In Command promprt or Powershell execute the following:
1. Go to <https://build.opensuse.org/package/show/home:mschnitzer/pawncc>
2. On the right side, select your distribution (only if it's not disabled!)
3. Click "Go to download repository"
4. Copy the link and enter in sudo mode in your shell:
`zypper ar $COPIED_LINK home:mschnitzer`
5. Again as root, type: `zypper ref`
6. Install the package with `zypper in pawncc`
7. Run `pawncc` in your shell to test if it's working
```cmd
cd C:\Pawn
mkdir build && cd build
cmake ..\source\compiler -G "Visual Studio 15 2017"
```
### With sampctl
* From the same directory as in the previous step run:
If you are a [sampctl][sampctl] user, you are already using this compiler!
```
cmake --build . --config Release
```
### Build From Source
or open the pawnc.sln in Visual Studio and build from there (but make sure to choose the "Release" configuration).
This will create `pawnc.dll` and `pawncc.exe` in the `Release` folder. You can now copy these files to your `pawno` folder for convenience or put them in a separate folder and configure your code editor accordingly.
### Building on Linux
Use your distribution's package manager to install the required dependencies. For example, in Ubuntu you would do:
```sh
sudo apt install gcc gcc-multilib make cmake
```
`gcc-multilib` is needed for compiling a 32-bit binary (64-bit is not supported).
Now you can clone this repo and build the compiler:
```sh
git clone https://github.com/Zeex/pawn.git ~/pawn
cd ~/pawn
mkdir build && cd build
cmake ../source/compiler -DCMAKE_C_FLAGS=-m32 -DCMAKE_BUILD_TYPE=Release
make
```
Replace "Release" with "Debug" if you want to build a debug executable for development or submitting bugs.
### Building on macOS
* Install Xcode: https://developer.apple.com/xcode/
* Install Command Line Tools for Xcode:
```sh
xcode-select --install
```
* Install CMake:
```sh
brew install cmake
```
* Now you can clone this repo and build the compiler:
```sh
git clone https://github.com/Zeex/pawn.git ~/pawn
cd ~/pawn
mkdir build && cd build
cmake ../source/compiler -DCMAKE_C_FLAGS=-m32 -DCMAKE_BUILD_TYPE=Release
make
```
If you are interested in contributing or just using a specific version, check
out [this page][build_source] for instructions for compiling for your platform.
## Background
The project was originally started as a set of patches aimed to create a compiler that would be compatible with the compiler used in [SA-MP (San Andreas Multiplayer)](http://sa-mp.com/).
The project was originally started as a set of patches aimed to create a
compiler that would be compatible with the compiler used in
[SA-MP (San Andreas Multiplayer)](http://sa-mp.com/).
SA-MP uses a modified version of Pawn 3.2.3664 [1] with Windows-only executables, and the developers said that they lost the source code for it which means it can't be ported to other platforms (e.g. Linux) and newly discovered bugs can't be fixed. So the main goal of the project is to re-create changes that were previously made by the devs as well as fix all known compiler bugs.
SA-MP uses a modified version of Pawn 3.2.3664 [1] with Windows-only
executables, and the developers said that they lost the source code for it which
means it can't be ported to other platforms (e.g. Linux) and newly discovered
bugs can't be fixed. So the main goal of the project is to re-create changes
that were previously made by the devs as well as fix all known compiler bugs.
[1] It's worth noting that the version of the AMX embedded into the SA-MP server seems to be based on an older release of Pawn.
[1] It's worth noting that the version of the AMX embedded into the SA-MP server
seems to be based on an older release of Pawn.
[build]: https://travis-ci.org/pawn-lang/compiler
[build_status]: https://travis-ci.org/pawn-lang/compiler.svg?branch=master
[build_linux]: https://travis-ci.org/pawn-lang/compiler
[build_status_linux]: https://travis-ci.org/pawn-lang/compiler.svg?branch=master
[build_win]: https://ci.appveyor.com/project/Southclaws/compiler/branch/master
[build_status_win]: https://ci.appveyor.com/api/projects/status/k112tbr1afrkif0n?svg=true
[build_status_win]:
https://ci.appveyor.com/api/projects/status/k112tbr1afrkif0n?svg=true
[team]: https://github.com/pawn-lang/compiler/graphs/contributors
[original_readme]:
https://github.com/pawn-lang/compiler/tree/master/readme_compuphase.txt
[issues]: https://github.com/pawn-lang/compiler/issues
[bugs]: https://github.com/pawn-lang/compiler/wiki/Known-compiler-bugs
[new]: https://github.com/pawn-lang/compiler/wiki/What's-new
[releases]: https://github.com/pawn-lang/compiler/releases
[artifacts]:
https://ci.appveyor.com/project/Southclaws/compiler/branch/master/artifacts
[compat]: https://github.com/pawn-lang/compiler/wiki/Compatibility-mode
[sampctl]: http://bit.ly/sampctl
[build_source]: https://github.com/pawn-lang/compiler/wiki/Building-From-Source

View File

@ -68,6 +68,7 @@ if(WIN32)
set_target_properties(amxDGram PROPERTIES LINK_FLAGS
"/export:amx_DGramInit /export:amx_DGramCleanup")
endif()
target_link_libraries(amxDGram ws2_32)
endif()
# amxFile

View File

@ -1860,7 +1860,7 @@ int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char
* supports this too.
*/
#define NEXT(cip) goto **cip++
#define NEXT(cip) goto **(void **)cip++
int AMXAPI amx_Exec(AMX *amx, cell *retval, int index)
{
@ -2047,14 +2047,14 @@ static const void * const amx_opcodelist[] = {
NEXT(cip);
op_load_i:
/* verify address */
if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp)
if ((pri>=hea && pri<stk) || (ucell)pri>=(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
pri=_R(data,pri);
NEXT(cip);
op_lodb_i:
GETPARAM(offs);
/* verify address */
if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp)
if ((pri>=hea && pri<stk) || (ucell)pri>=(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
switch (offs) {
case 1:
@ -2120,14 +2120,14 @@ static const void * const amx_opcodelist[] = {
NEXT(cip);
op_stor_i:
/* verify address */
if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp)
if ((alt>=hea && alt<stk) || (ucell)alt>=(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
_W(data,alt,pri);
NEXT(cip);
op_strb_i:
GETPARAM(offs);
/* verify address */
if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp)
if ((alt>=hea && alt<stk) || (ucell)alt>=(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
switch (offs) {
case 1:
@ -2144,7 +2144,7 @@ static const void * const amx_opcodelist[] = {
op_lidx:
offs=pri*sizeof(cell)+alt; /* implicit shift value for a cell */
/* verify address */
if (offs>=hea && offs<stk || (ucell)offs>=(ucell)amx->stp)
if ((offs>=hea && offs<stk) || (ucell)offs>=(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
pri=_R(data,offs);
NEXT(cip);
@ -2152,7 +2152,7 @@ static const void * const amx_opcodelist[] = {
GETPARAM(offs);
offs=(pri << (int)offs)+alt;
/* verify address */
if (offs>=hea && offs<stk || (ucell)offs>=(ucell)amx->stp)
if ((offs>=hea && offs<stk) || (ucell)offs>=(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
pri=_R(data,offs);
NEXT(cip);
@ -2641,13 +2641,13 @@ static const void * const amx_opcodelist[] = {
/* verify top & bottom memory addresses, for both source and destination
* addresses
*/
if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp)
if ((pri>=hea && pri<stk) || (ucell)pri>=(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
if ((pri+offs)>hea && (pri+offs)<stk || (ucell)(pri+offs)>(ucell)amx->stp)
if (((pri+offs)>hea && (pri+offs)<stk) || (ucell)(pri+offs)>(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp)
if ((alt>=hea && alt<stk) || (ucell)alt>=(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
if ((alt+offs)>hea && (alt+offs)<stk || (ucell)(alt+offs)>(ucell)amx->stp)
if (((alt+offs)>hea && (alt+offs)<stk) || (ucell)(alt+offs)>(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
#if defined _R_DEFAULT
memcpy(data+(int)alt, data+(int)pri, (int)offs);
@ -2667,13 +2667,13 @@ static const void * const amx_opcodelist[] = {
/* verify top & bottom memory addresses, for both source and destination
* addresses
*/
if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp)
if ((pri>=hea && pri<stk) || (ucell)pri>=(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
if ((pri+offs)>hea && (pri+offs)<stk || (ucell)(pri+offs)>(ucell)amx->stp)
if (((pri+offs)>hea && (pri+offs)<stk) || (ucell)(pri+offs)>(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp)
if ((alt>=hea && alt<stk) || (ucell)alt>=(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
if ((alt+offs)>hea && (alt+offs)<stk || (ucell)(alt+offs)>(ucell)amx->stp)
if (((alt+offs)>hea && (alt+offs)<stk) || (ucell)(alt+offs)>(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
#if defined _R_DEFAULT
pri=memcmp(data+(int)alt, data+(int)pri, (int)offs);
@ -2688,9 +2688,9 @@ static const void * const amx_opcodelist[] = {
op_fill:
GETPARAM(offs);
/* verify top & bottom memory addresses */
if (alt>=hea && alt<stk || (ucell)alt>=(ucell)amx->stp)
if ((alt>=hea && alt<stk) || (ucell)alt>=(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
if ((alt+offs)>hea && (alt+offs)<stk || (ucell)(alt+offs)>(ucell)amx->stp)
if (((alt+offs)>hea && (alt+offs)<stk) || (ucell)(alt+offs)>(ucell)amx->stp)
ABORT(amx,AMX_ERR_MEMACCESS);
for (i=(int)alt; offs>=(int)sizeof(cell); i+=sizeof(cell), offs-=sizeof(cell))
_W32(data,i,pri);
@ -4242,7 +4242,7 @@ int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr)
data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat;
assert(phys_addr!=NULL);
if (amx_addr>=amx->hea && amx_addr<amx->stk || amx_addr<0 || amx_addr>=amx->stp) {
if ((amx_addr>=amx->hea && amx_addr<amx->stk) || amx_addr<0 || amx_addr>=amx->stp) {
*phys_addr=NULL;
return AMX_ERR_MEMACCESS;
} /* if */
@ -4491,19 +4491,19 @@ static const long utf8_lowmark[5] = { 0x80, 0x800, 0x10000L, 0x200000L, 0x400000
switch (followup) {
case 4:
if (((c=*string++) & 0xc0) != 0x80) goto error;
result = (result << 6) | c & 0x3f;
result = (result << 6) | (c & 0x3f);
case 3:
if (((c=*string++) & 0xc0) != 0x80) goto error;
result = (result << 6) | c & 0x3f;
result = (result << 6) | (c & 0x3f);
case 2:
if (((c=*string++) & 0xc0) != 0x80) goto error;
result = (result << 6) | c & 0x3f;
result = (result << 6) | (c & 0x3f);
case 1:
if (((c=*string++) & 0xc0) != 0x80) goto error;
result = (result << 6) | c & 0x3f;
result = (result << 6) | (c & 0x3f);
case 0:
if (((c=*string++) & 0xc0) != 0x80) goto error;
result = (result << 6) | c & 0x3f;
result = (result << 6) | (c & 0x3f);
} /* switch */
/* Do additional checks: shortest encoding & reserved positions. The
* lowmark limits also depends on the code length; it can be read from
@ -4511,7 +4511,7 @@ static const long utf8_lowmark[5] = { 0x80, 0x800, 0x10000L, 0x200000L, 0x400000
*/
if (result<utf8_lowmark[followup])
goto error;
if (result>=0xd800 && result<=0xdfff || result==0xfffe || result==0xffff)
if ((result>=0xd800 && result<=0xdfff) || result==0xfffe || result==0xffff)
goto error;
} /* if */
@ -4546,40 +4546,40 @@ int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value)
} else if (value<0x800) {
/* 110xxxxx 10xxxxxx */
if (maxchars < 2) goto error;
*string++ = (char)((value>>6) & 0x1f | 0xc0);
*string++ = (char)(value & 0x3f | 0x80);
*string++ = (char)(((value>>6) & 0x1f) | 0xc0);
*string++ = (char)((value & 0x3f) | 0x80);
} else if (value<0x10000) {
/* 1110xxxx 10xxxxxx 10xxxxxx (16 bits, BMP plane) */
if (maxchars < 3) goto error;
if (value>=0xd800 && value<=0xdfff || value==0xfffe || value==0xffff)
if ((value>=0xd800 && value<=0xdfff) || value==0xfffe || value==0xffff)
goto error; /* surrogate pairs and invalid characters */
*string++ = (char)((value>>12) & 0x0f | 0xe0);
*string++ = (char)((value>>6) & 0x3f | 0x80);
*string++ = (char)(value & 0x3f | 0x80);
*string++ = (char)(((value>>12) & 0x0f) | 0xe0);
*string++ = (char)(((value>>6) & 0x3f) | 0x80);
*string++ = (char)((value & 0x3f) | 0x80);
} else if (value<0x200000) {
/* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
if (maxchars < 4) goto error;
*string++ = (char)((value>>18) & 0x07 | 0xf0);
*string++ = (char)((value>>12) & 0x3f | 0x80);
*string++ = (char)((value>>6) & 0x3f | 0x80);
*string++ = (char)(value & 0x3f | 0x80);
*string++ = (char)(((value>>18) & 0x07) | 0xf0);
*string++ = (char)(((value>>12) & 0x3f) | 0x80);
*string++ = (char)(((value>>6) & 0x3f) | 0x80);
*string++ = (char)((value & 0x3f) | 0x80);
} else if (value<0x4000000) {
/* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
if (maxchars < 5) goto error;
*string++ = (char)((value>>24) & 0x03 | 0xf8);
*string++ = (char)((value>>18) & 0x3f | 0x80);
*string++ = (char)((value>>12) & 0x3f | 0x80);
*string++ = (char)((value>>6) & 0x3f | 0x80);
*string++ = (char)(value & 0x3f | 0x80);
*string++ = (char)(((value>>24) & 0x03) | 0xf8);
*string++ = (char)(((value>>18) & 0x3f) | 0x80);
*string++ = (char)(((value>>12) & 0x3f) | 0x80);
*string++ = (char)(((value>>6) & 0x3f) | 0x80);
*string++ = (char)((value & 0x3f) | 0x80);
} else {
/* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (31 bits) */
if (maxchars < 6) goto error;
*string++ = (char)((value>>30) & 0x01 | 0xfc);
*string++ = (char)((value>>24) & 0x3f | 0x80);
*string++ = (char)((value>>18) & 0x3f | 0x80);
*string++ = (char)((value>>12) & 0x3f | 0x80);
*string++ = (char)((value>>6) & 0x3f | 0x80);
*string++ = (char)(value & 0x3f | 0x80);
*string++ = (char)(((value>>30) & 0x01) | 0xfc);
*string++ = (char)(((value>>24) & 0x3f) | 0x80);
*string++ = (char)(((value>>18) & 0x3f) | 0x80);
*string++ = (char)(((value>>12) & 0x3f) | 0x80);
*string++ = (char)(((value>>6) & 0x3f) | 0x80);
*string++ = (char)((value & 0x3f) | 0x80);
} /* if */
if (endptr!=NULL)

View File

@ -16,6 +16,7 @@
*
* Version: $Id: amxargs.c 5588 2016-10-25 11:13:28Z $
*/
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
# if !defined UNICODE /* for Windows */
# define UNICODE

View File

@ -20,6 +20,7 @@
*
* Version: $Id: amxaux.c 3612 2006-07-22 09:59:46Z thiadmer $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -29,12 +30,15 @@
size_t AMXAPI aux_ProgramSize(char *filename)
{
FILE *fp;
size_t size;
AMX_HEADER hdr;
if ((fp=fopen(filename,"rb")) == NULL)
return 0;
fread(&hdr, sizeof hdr, 1, fp);
size = fread(&hdr, sizeof hdr, 1, fp);
fclose(fp);
if (size < 1)
return 0;
amx_Align16(&hdr.magic);
amx_Align32((uint32_t *)&hdr.stp);
@ -44,13 +48,18 @@ size_t AMXAPI aux_ProgramSize(char *filename)
int AMXAPI aux_LoadProgram(AMX *amx, char *filename, void *memblock)
{
FILE *fp;
size_t size;
AMX_HEADER hdr;
int result, didalloc;
/* open the file, read and check the header */
if ((fp = fopen(filename, "rb")) == NULL)
return AMX_ERR_NOTFOUND;
fread(&hdr, sizeof hdr, 1, fp);
size = fread(&hdr, sizeof hdr, 1, fp);
if (size < 1) {
fclose(fp);
return AMX_ERR_FORMAT;
} /* if */
amx_Align16(&hdr.magic);
amx_Align32((uint32_t *)&hdr.size);
amx_Align32((uint32_t *)&hdr.stp);
@ -72,8 +81,10 @@ int AMXAPI aux_LoadProgram(AMX *amx, char *filename, void *memblock)
/* read in the file */
rewind(fp);
fread(memblock, 1, (size_t)hdr.size, fp);
size = fread(memblock, 1, (size_t)hdr.size, fp);
fclose(fp);
if (size < (size_t)hdr.size)
return AMX_ERR_FORMAT;
/* initialize the abstract machine */
memset(amx, 0, sizeof *amx);

View File

@ -20,6 +20,7 @@
*
* Version: $Id: amxaux.h 3612 2006-07-22 09:59:46Z thiadmer $
*/
#ifndef AMXAUX_H_INCLUDED
#define AMXAUX_H_INCLUDED

View File

@ -1283,7 +1283,7 @@ static cell AMX_NATIVE_CALL n_getvalue(AMX *amx,const cell *params)
if (c==EOL_CHAR && inlist(amx,'\r',params+2,(int)params[0]/sizeof(cell)-1)!=0)
c='\r';
#endif
if ((chars>1 || chars>0 && sign>0)
if ((chars>1 || (chars>0 && sign>0))
&& (n=inlist(amx,c,params+2,(int)params[0]/sizeof(cell)-1))!=0)
{
if (n>0)

View File

@ -16,6 +16,7 @@
*
* Version: $Id: amxcore.c 5504 2016-05-15 13:42:30Z $
*/
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
# if !defined UNICODE /* for Windows */
# define UNICODE
@ -181,7 +182,7 @@ static cell AMX_NATIVE_CALL setarg(AMX *amx,const cell *params)
/* adjust the address in "value" in case of an array access */
value+=params[2]*sizeof(cell);
/* verify the address */
if (value<0 || value>=amx->hea && value<amx->stk)
if (value<0 || (value>=amx->hea && value<amx->stk))
return 0;
/* set the value indirectly */
* (cell *)(data+(int)value) = params[3];

View File

@ -22,6 +22,7 @@
*
* Version: $Id: amxdbg.c 3612 2006-07-22 09:59:46Z thiadmer $
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

View File

@ -22,6 +22,7 @@
*
* Version: $Id: amxdgram.c 3664 2006-11-08 12:09:25Z thiadmer $
*/
#include <assert.h>
#include <stdio.h>
#if defined LINUX

View File

@ -16,6 +16,7 @@
*
* Version: $Id: amxfile.c 5588 2016-10-25 11:13:28Z $
*/
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
# if !defined UNICODE /* for Windows */
# define UNICODE

View File

@ -17,6 +17,7 @@
* 2004-01-09: Adaptions for 64-bit cells (using "double precision"), by
* Thiadmer Riemersma
*/
#include <stdlib.h> /* for atof() */
#include <stdio.h> /* for NULL */
#include <assert.h>

View File

@ -20,6 +20,7 @@
*
* Version: $Id: amxgc.c 3660 2006-11-05 13:05:09Z thiadmer $
*/
#include <assert.h>
#include <limits.h>
#include <stdlib.h> /* for malloc()/free() */

View File

@ -20,6 +20,7 @@
*
* Version: $Id: amxprocess.c 3664 2006-11-08 12:09:25Z thiadmer $
*/
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
# if !defined UNICODE /* for Windows */
# define UNICODE

View File

@ -16,6 +16,7 @@
*
* Version: $Id: amxstring.c 5514 2016-05-20 14:26:51Z $
*/
#include <limits.h>
#include <string.h>
#include <assert.h>

View File

@ -16,6 +16,7 @@
*
* Version: $Id: amxtime.c 5588 2016-10-25 11:13:28Z $
*/
#include <time.h>
#include <assert.h>
#include "amx.h"

View File

@ -24,6 +24,7 @@
*
* Version: $Id: fixed.c 3662 2006-11-07 08:44:33Z thiadmer $
*/
#include <assert.h>
#include <stdio.h> /* for NULL */
#include "amx.h"

View File

@ -50,6 +50,7 @@
* needs only to transfer a file:
* pawndbg myprog.amx -rs232=1 -transfer -quit
*/
#include <assert.h>
#include <ctype.h>
#include <setjmp.h>

View File

@ -20,6 +20,7 @@
*
* Version: $Id: pawnrun.c 3615 2006-07-27 07:49:08Z thiadmer $
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

View File

@ -4,6 +4,7 @@
*
* This file may be freely used. No warranties of any kind.
*/
#include <stdio.h>
#include <stdlib.h> /* for exit() */
#include <signal.h>

View File

@ -4,6 +4,7 @@
*
* This file may be freely used. No warranties of any kind.
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

View File

@ -4,6 +4,7 @@
*
* This file may be freely used. No warranties of any kind.
*/
#include <stdio.h>
#include <stdlib.h> /* for exit() */
#include <signal.h>

View File

@ -4,6 +4,7 @@
*
* This file may be freely used. No warranties of any kind.
*/
#include <stdio.h>
#include <stdlib.h> /* for exit() */
#include <string.h> /* for memset() (on some compilers) */

View File

@ -5,6 +5,7 @@
*
* This file may be freely used. No warranties of any kind.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

View File

@ -19,6 +19,7 @@
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

View File

@ -5,7 +5,7 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../cmake)
set(VERSION_MAJOR 3)
set(VERSION_MINOR 10)
set(VERSION_BUILD 6)
set(VERSION_BUILD 9)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_BUILD})
set(VERSION_STR ${VERSION})
math(EXPR VERSION_INT "${VERSION_MAJOR} << 8 | ${VERSION_MINOR}")
@ -139,6 +139,9 @@ target_link_libraries(pawncc pawnc)
# The Pawn disassembler
set(PAWNDISASM_SRCS
pawndisasm.c
sc.h
../amx/amx.h
../amx/amxdbg.h
../amx/amxdbg.c
)
add_executable(pawndisasm ${PAWNDISASM_SRCS})
@ -160,10 +163,30 @@ if(MSVC)
DESTINATION bin)
endif()
# Generate tests (only if enabled, i.e. BUILD_TESTING=ON)
# Generate targets for running compiler tests
include(CTest)
if(BUILD_TESTING)
enable_testing()
set(PAWNRUNS_SRCS
pawnruns.c
../amx/amx.c
../amx/amx.h
../amx/amxaux.c
../amx/amxaux.h
../amx/amxcons.c
../amx/amxcore.c
)
if(UNIX)
set(PAWNRUNS_SRCS
${PAWNRUNS_SRCS}
../linux/getch.c
../linux/getch.h
../linux/binreloc.c
)
endif()
add_executable(pawnruns ${PAWNRUNS_SRCS})
if(UNIX)
target_link_libraries(pawnruns dl)
endif()
add_subdirectory(tests)
endif()

View File

@ -22,6 +22,7 @@
*
* Version: $Id: libpawnc.c 3612 2006-07-22 09:59:46Z thiadmer $
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

View File

@ -7,10 +7,10 @@
#define HAVE_SAFESTR
#endif
#if defined strlcpy
#if defined strlcpy && !defined HAVE_STRLCPY
#define HAVE_STRLCPY
#endif
#if defined strlcat
#if defined strlcat && !defined HAVE_STRLCAT
#define HAVE_STRLCAT
#endif

View File

@ -22,6 +22,7 @@
*
* Version: $Id: pawncc.c 3612 2006-07-22 09:59:46Z thiadmer $
*/
#include "sc.h"
int main(int argc, char *argv[])

View File

@ -20,6 +20,7 @@
*
* Version: $Id$
*/
#include <assert.h>
#include <errno.h>
#include <stdio.h>
@ -221,7 +222,8 @@ static OPCODE opcodelist[] = {
void print_opcode(FILE *ftxt,cell opcode,cell cip)
{
fprintf(ftxt,"%08"PRIxC" %s ",cip,opcodelist[(int)(opcode &0x0000ffff)].name);
fprintf(ftxt,"%08"PRIxC" %s",
cip,opcodelist[(int)(opcode &0x0000ffff)].name);
}
void print_funcname(FILE *ftxt,cell address)
@ -263,21 +265,21 @@ cell parm0(FILE *ftxt,const cell *params,cell opcode,cell cip)
cell parm1(FILE *ftxt,const cell *params,cell opcode,cell cip)
{
print_opcode(ftxt,opcode,cip);
fprintf(ftxt,"%08"PRIxC"\n",*params);
fprintf(ftxt," %08"PRIxC"\n",*params);
return 2;
}
cell parm2(FILE *ftxt,const cell *params,cell opcode,cell cip)
{
print_opcode(ftxt,opcode,cip);
fprintf(ftxt,"%08"PRIxC" %08"PRIxC"\n",params[0],params[1]);
fprintf(ftxt," %08"PRIxC" %08"PRIxC"\n",params[0],params[1]);
return 3;
}
cell parm3(FILE *ftxt,const cell *params,cell opcode,cell cip)
{
print_opcode(ftxt,opcode,cip);
fprintf(ftxt,"%08"PRIxC" %08"PRIxC" %08"PRIxC"\n",
fprintf(ftxt," %08"PRIxC" %08"PRIxC" %08"PRIxC"\n",
params[0],params[1],params[2]);
return 4;
}
@ -285,7 +287,7 @@ cell parm3(FILE *ftxt,const cell *params,cell opcode,cell cip)
cell parm4(FILE *ftxt,const cell *params,cell opcode,cell cip)
{
print_opcode(ftxt,opcode,cip);
fprintf(ftxt,"%08"PRIxC" %08"PRIxC" %08"PRIxC" %08"PRIxC"\n",
fprintf(ftxt," %08"PRIxC" %08"PRIxC" %08"PRIxC" %08"PRIxC"\n",
params[0],params[1],params[2],params[3]);
return 5;
}
@ -293,7 +295,7 @@ cell parm4(FILE *ftxt,const cell *params,cell opcode,cell cip)
cell parm5(FILE *ftxt,const cell *params,cell opcode,cell cip)
{
print_opcode(ftxt,opcode,cip);
fprintf(ftxt,"%08"PRIxC" %08"PRIxC" %08"PRIxC" %08"PRIxC" %08"PRIxC"\n",
fprintf(ftxt," %08"PRIxC" %08"PRIxC" %08"PRIxC" %08"PRIxC" %08"PRIxC"\n",
params[0],params[1],params[2],params[3],params[4]);
return 6;
}
@ -309,7 +311,7 @@ cell do_proc(FILE *ftxt,const cell *params,cell opcode,cell cip)
cell do_call(FILE *ftxt,const cell *params,cell opcode,cell cip)
{
print_opcode(ftxt,opcode,cip);
fprintf(ftxt,"%08"PRIxC,*params);
fprintf(ftxt," %08"PRIxC,*params);
print_funcname(ftxt,*params);
fputs("\n",ftxt);
return 2;
@ -318,7 +320,7 @@ cell do_call(FILE *ftxt,const cell *params,cell opcode,cell cip)
cell do_jump(FILE *ftxt,const cell *params,cell opcode,cell cip)
{
print_opcode(ftxt,opcode,cip);
fprintf(ftxt,"%08"PRIxC"\n",*params);
fprintf(ftxt," %08"PRIxC"\n",*params);
return 2;
}
@ -345,7 +347,7 @@ cell do_sysreq(FILE *ftxt,const cell *params,cell opcode,cell cip)
} /* if */
print_opcode(ftxt,opcode,cip);
fprintf(ftxt,"%08"PRIxC,*params);
fprintf(ftxt," %08"PRIxC,*params);
if (namelen>0)
fprintf(ftxt,"\t; %s",name);
fprintf(ftxt,"\n");
@ -355,7 +357,7 @@ cell do_sysreq(FILE *ftxt,const cell *params,cell opcode,cell cip)
cell do_switch(FILE *ftxt,const cell *params,cell opcode,cell cip)
{
print_opcode(ftxt,opcode,cip);
fprintf(ftxt,"%08"PRIxC"\n",*params);
fprintf(ftxt," %08"PRIxC"\n",*params);
return 2;
}
@ -366,7 +368,7 @@ cell casetbl(FILE *ftxt,const cell *params,cell opcode,cell cip)
print_opcode(ftxt,opcode,cip);
num=params[0]+1;
fprintf(ftxt,"%08"PRIxC" %08"PRIxC"\n",params[0],params[1]);
fprintf(ftxt," %08"PRIxC" %08"PRIxC"\n",params[0],params[1]);
for (idx=1; idx<num; idx++)
fprintf(ftxt," %08"PRIxC" %08"PRIxC"\n",
params[2*idx],params[2*idx+1]);

View File

@ -0,0 +1,55 @@
/* A simpler runner based on source/amx/pawnrun/prun1.c.
*
* Copyright (c) ITB CompuPhase, 2001-2005
*
* This file may be freely used. No warranties of any kind.
*/
#include <stdio.h>
#include <stdlib.h> /* for exit() */
#include <signal.h>
#include <string.h> /* for memset() (on some compilers) */
#include "../amx/amx.h"
#include "../amx/amxaux.h"
static void ErrorExit(AMX *amx, int errorcode)
{
printf("Run time error %d: \"%s\"\n", errorcode, aux_StrError(errorcode));
exit(1);
}
static void PrintUsage(char *program)
{
printf("Usage: %s <filename>\n<filename> is a compiled script.\n", program);
exit(1);
}
int main(int argc,char *argv[])
{
extern AMX_NATIVE_INFO console_Natives[];
extern AMX_NATIVE_INFO core_Natives[];
AMX amx;
cell ret = 0;
int err;
if (argc != 2)
PrintUsage(argv[0]);
err = aux_LoadProgram(&amx, argv[1], NULL);
if (err != AMX_ERR_NONE)
ErrorExit(&amx, err);
amx_Register(&amx, console_Natives, -1);
err = amx_Register(&amx, core_Natives, -1);
if (err != AMX_ERR_NONE)
ErrorExit(&amx, err);
err = amx_Exec(&amx, &ret, AMX_EXEC_MAIN);
if (err != AMX_ERR_NONE)
ErrorExit(&amx, err);
printf("%s returns %ld\n", argv[1], (long)ret);
aux_FreeProgram(&amx);
return 0;
}

View File

@ -27,6 +27,7 @@
*
* Version: $Id: sc.h 3660 2006-11-05 13:05:09Z thiadmer $
*/
#ifndef SC_H_INCLUDED
#define SC_H_INCLUDED
#include <limits.h>
@ -113,6 +114,10 @@ typedef struct s_constvalue {
* tag for enumeration lists */
} constvalue;
typedef struct s_constvalue_root {
constvalue *first,*last;
} constvalue_root;
/* Symbol table format
*
* The symbol name read from the input file is stored in "name", the
@ -148,13 +153,13 @@ typedef struct s_symbol {
} x; /* 'x' for 'extra' */
union {
arginfo *arglist; /* types of all parameters for functions */
constvalue *enumlist;/* list of names for the "root" of an enumeration */
constvalue_root *enumlist;/* list of names for the "root" of an enumeration */
struct {
cell length; /* arrays: length (size) */
short level; /* number of dimensions below this level */
} array;
} dim; /* for 'dimension', both functions and arrays */
constvalue *states; /* list of state function/state variable ids + addresses */
constvalue_root *states;/* list of state function/state variable ids + addresses */
int fnumber; /* static global variables: file number in which the declaration is visible */
int lnumber; /* line number (in the current source file) for the declaration */
struct s_symbol **refer; /* referrer list, functions that "use" this symbol */
@ -303,6 +308,11 @@ typedef struct s_valuepair {
#define opcodes(n) ((n)*sizeof(cell)) /* opcode size */
#define opargs(n) ((n)*sizeof(cell)) /* size of typical argument */
/* general purpose macros */
#if !defined makelong
#define makelong(low,high) ((long)(low) | ((long)(high) << (sizeof(long)*4)))
#endif
/* Tokens recognized by lex()
* Some of these constants are assigned as well to the variable "lastst" (see SC1.C)
*/
@ -398,14 +408,16 @@ typedef struct s_valuepair {
#define tLABEL 337
#define tSTRING 338
/* argument types for emit/__emit */
#define teNUMERIC 339 /* integer/rational number */
#define teDATA 340 /* data (variable name or address) */
#define teLOCAL 341 /* local variable (name or offset) */
#define teFUNCTN 342 /* Pawn function */
#define teNATIVE 343 /* native function */
#define teANY 339 /* any value */
#define teNUMERIC 340 /* integer/rational number */
#define teDATA 341 /* data (variable name or address) */
#define teLOCAL 342 /* local variable (name or offset) */
#define teFUNCTN 343 /* Pawn function */
#define teNATIVE 344 /* native function */
#define teNONNEG 345 /* nonnegative integer */
/* for assigment to "lastst" only (see SC1.C) */
#define tEXPR 344
#define tENDLESS 345 /* endless loop */
#define tEXPR 346
#define tENDLESS 347 /* endless loop */
/* (reversed) evaluation of staging buffer */
#define sSTARTREORDER 0x01
@ -475,6 +487,35 @@ typedef enum s_optmark {
#define MAX_INSTR_LEN 30
#define eotNUMBER 0
#define eotFUNCTION 1
#define eotLABEL 2
typedef struct s_emit_outval {
int type;
union {
ucell ucell;
const char *string;
} value;
} emit_outval;
/* constants for error_suggest() */
#define MAX_EDIT_DIST 2 /* allow two mis-typed characters; when there are more,
* the names are too different, and no match is returned */
enum { /* identifier types */
estSYMBOL = 0,
estNONSYMBOL,
estAUTOMATON,
estSTATE
};
enum { /* symbol types */
essNONLABEL, /* find symbols of any type but labels */
essVARCONST, /* array, single variable or named constant */
essARRAY,
essCONST,
essFUNCTN,
essLABEL
};
/* interface functions */
#if defined __cplusplus
extern "C" {
@ -549,13 +590,14 @@ long pc_lengthbin(void *handle); /* return the length of the file */
SC_FUNC void set_extension(char *filename,char *extension,int force);
SC_FUNC symbol *fetchfunc(char *name,int tag);
SC_FUNC char *operator_symname(char *symname,char *opername,int tag1,int tag2,int numtags,int resulttag);
SC_FUNC void check_index_tagmismatch(char *symname,int expectedtag,int actualtag,int allowcoerce,int errline);
SC_FUNC void check_tagmismatch(int formaltag,int actualtag,int allowcoerce,int errline);
SC_FUNC void check_tagmismatch_multiple(int formaltags[],int numtags,int actualtag,int errline);
SC_FUNC char *funcdisplayname(char *dest,char *funcname);
SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr);
SC_FUNC constvalue *append_constval(constvalue *table,const char *name,cell val,int index);
SC_FUNC constvalue *find_constval(constvalue *table,char *name,int index);
SC_FUNC void delete_consttable(constvalue *table);
SC_FUNC constvalue *append_constval(constvalue_root *table,const char *name,cell val,int index);
SC_FUNC constvalue *find_constval(constvalue_root *table,char *name,int index);
SC_FUNC void delete_consttable(constvalue_root *table);
SC_FUNC symbol *add_constant(char *name,cell val,int vclass,int tag);
SC_FUNC symbol *add_builtin_constant(char *name,cell val,int vclass,int tag);
SC_FUNC symbol *add_builtin_string_constant(char *name,const char *val,int vclass);
@ -622,7 +664,7 @@ SC_FUNC void setlinedirect(int line);
SC_FUNC void setlineconst(int line);
SC_FUNC void setlabel(int index);
SC_FUNC void markexpr(optmark type,const char *name,cell offset);
SC_FUNC void startfunc(char *fname);
SC_FUNC void startfunc(char *fname,int generateproc);
SC_FUNC void endfunc(void);
SC_FUNC void alignframe(int numbytes);
SC_FUNC void rvalue(value *lval);
@ -699,11 +741,12 @@ SC_FUNC void dec(value *lval);
SC_FUNC void jmp_ne0(int number);
SC_FUNC void jmp_eq0(int number);
SC_FUNC void outval(cell val,int newline);
SC_FUNC void outinstr(const char *name,ucell args[],int numargs);
SC_FUNC void outinstr(const char *name,emit_outval params[],int numparams);
/* function prototypes in SC5.C */
SC_FUNC int error(int number,...);
SC_FUNC int error(long number,...);
SC_FUNC void errorset(int code,int line);
SC_FUNC int error_suggest(int error,const char *name,const char *name2,int type,int subtype);
/* function prototypes in SC6.C */
SC_FUNC int assemble(FILE *fout,FILE *fin);
@ -801,8 +844,8 @@ SC_VDECL symbol *line_sym;
SC_VDECL cell *litq; /* the literal queue */
SC_VDECL unsigned char pline[]; /* the line read from the input file */
SC_VDECL const unsigned char *lptr;/* points to the current position in "pline" */
SC_VDECL constvalue tagname_tab;/* tagname table */
SC_VDECL constvalue libname_tab;/* library table (#pragma library "..." syntax) */
SC_VDECL constvalue_root tagname_tab;/* tagname table */
SC_VDECL constvalue_root libname_tab;/* library table (#pragma library "..." syntax) */
SC_VDECL constvalue *curlibrary;/* current library */
SC_VDECL int pc_addlibtable; /* is the library table added to the AMX file? */
SC_VDECL symbol *curfunc; /* pointer to current function */
@ -859,8 +902,8 @@ SC_VDECL int pc_naked; /* if true mark following function as naked */
SC_VDECL int pc_compat; /* running in compatibility mode? */
SC_VDECL int pc_recursion; /* enable detailed recursion report? */
SC_VDECL constvalue sc_automaton_tab; /* automaton table */
SC_VDECL constvalue sc_state_tab; /* state table */
SC_VDECL constvalue_root sc_automaton_tab; /* automaton table */
SC_VDECL constvalue_root sc_state_tab; /* state table */
SC_VDECL FILE *inpf; /* file read from (source or include) */
SC_VDECL FILE *inpf_org; /* main source file */

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
*
* Version: $Id: sc2.c 3655 2006-10-23 20:17:52Z thiadmer $
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
@ -396,8 +397,11 @@ static void readline(unsigned char *line)
*line='\0'; /* delete line */
cont=FALSE;
} else {
/* check whether to erase leading whitespace after '\\' on next line */
/* check whether to erase leading spaces */
if (cont) {
unsigned char *ptr=line;
while (*ptr<=' ' && *ptr!='\0')
ptr++;
if (ptr!=line)
memmove(line,ptr,strlen((char*)ptr)+1);
} /* if */
@ -414,6 +418,10 @@ static void readline(unsigned char *line)
ptr--; /* skip trailing whitespace */
if (*ptr=='\\') {
cont=TRUE;
/* set '\a' at the position of '\\' to make it possible to check
* for a line continuation in a single line comment (error 49)
*/
*ptr++='\a';
*ptr='\0'; /* erase '\n' (and any trailing whitespace) */
} /* if */
} /* if */
@ -441,6 +449,7 @@ static void readline(unsigned char *line)
static void stripcomment(unsigned char *line)
{
char c;
char* continuation;
#if !defined SC_LIGHT
#define COMMENT_LIMIT 100
#define COMMENT_MARGIN 40 /* length of the longest word */
@ -512,6 +521,24 @@ static void stripcomment(unsigned char *line)
if (icomment==2)
*line++=' ';
} else if (*line=='/' && *(line+1)=='/'){ /* comment to end of line */
continuation=(char*)line;
while ((continuation=strchr(continuation,'\a'))!=NULL){
/* don't give the error if the next line is also commented out.
it is quite annoying to get an error for commenting out a define using:
//
// #define LONG_MACRO\
// did span \
// multiple lines
//
*/
while (*continuation<=' ' && *continuation!='\0')
continuation++; /* skip whitespace */
if (*continuation!='/' || *(continuation+1)!='/') {
error(49); /* invalid line continuation */
break;
}
}
#if !defined SC_LIGHT
if (*(line+2)=='/' && *(line+3)<=' ') {
/* documentation comment */
@ -903,6 +930,23 @@ static const unsigned char *getstring(unsigned char *dest,int max,const unsigned
return line;
}
/* strdupwithouta
*
* Duplicate a string, stripping out `\a`s.
*/
static char* strdupwithouta(const char* sourcestring)
{
char* result=strdup(sourcestring);
char* a=result;
if (result==NULL) {
return NULL;
}
while ((a=strchr(a,'\a'))!=NULL) {
*a=' ';
}
return result;
}
enum {
CMD_NONE,
CMD_TERM,
@ -1115,7 +1159,7 @@ static int command(void)
/* remove leading whitespace */
while (*lptr<=' ' && *lptr!='\0')
lptr++;
pc_deprecate=strdup((const char *)lptr);
pc_deprecate=strdupwithouta((const char *)lptr);
if (pc_deprecate!=NULL) {
char *ptr=pc_deprecate+strlen(pc_deprecate)-1;
/* remove trailing whitespace */
@ -1499,7 +1543,7 @@ static int command(void)
while (*lptr<=' ' && *lptr!='\0')
lptr++;
if (!SKIPPING) {
char *usermsg=strdup((const char *)lptr);
char *usermsg=strdupwithouta((const char *)lptr);
if (usermsg!=NULL) {
char *ptr=usermsg+strlen(usermsg)-1;
/* remove trailing whitespace and newlines */
@ -1893,6 +1937,10 @@ static const unsigned char *unpackedstring(const unsigned char *lptr,int *flags)
while (*lptr==' ' || *lptr=='\t') /* this is as defines with parameters may add them */
lptr++; /* when you use a space after , in a match pattern */
while (*lptr!='\0') {
if (*lptr=='\a') {
lptr++;
continue;
} /* if */
if (!instring) {
if (*lptr=='\"') {
instring=1;
@ -1963,6 +2011,10 @@ static const unsigned char *packedstring(const unsigned char *lptr,int *flags)
i=sizeof(ucell)-(sCHARBITS/8); /* start at most significant byte */
val=0;
while (*lptr!='\0') {
if (*lptr=='\a') { /* ignore '\a' (which was inserted at a line concatenation) */
lptr++;
continue;
} /* if */
if (!instring) {
if (*lptr=='\"') {
instring=1;
@ -2028,7 +2080,7 @@ static const unsigned char *packedstring(const unsigned char *lptr,int *flags)
if (*lptr==',' || *lptr==')' || *lptr=='}' || *lptr==';' ||
*lptr==':' || *lptr=='\n' || *lptr=='\r')
lptr=stringize; /* backtrack to end of last string for closing " */
lptr=stringize; /* backtrack to end of last string for closing " */
return lptr;
}
@ -2097,8 +2149,8 @@ char *sc_tokens[] = {
"#tryinclude", "#undef", "#warning",
";", ";", "-integer value-", "-rational value-", "-identifier-",
"-label-", "-string-",
"-numeric value-", "-data offset-", "-local variable-", "-function-",
"-native function-"
"-any value-", "-numeric value-", "-data offset-", "-local variable-",
"-function-", "-native function-", "-nonnegative integer-"
};
SC_FUNC int lex(cell *lexvalue,char **lexsym)
@ -2949,7 +3001,7 @@ SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_
sym->usage &= ~uDEFINE; /* clear "defined" flag */
/* set all states as "undefined" too */
if (sym->states!=NULL)
for (stateptr=sym->states->next; stateptr!=NULL; stateptr=stateptr->next)
for (stateptr=sym->states->first; stateptr!=NULL; stateptr=stateptr->next)
stateptr->value=0;
/* for user defined operators, also remove the "prototyped" flag, as
* user-defined operators *must* be declared before use
@ -2989,10 +3041,10 @@ static symbol *find_symbol(const symbol *root,const char *name,int fnumber,int a
&& (sym->parent==NULL || sym->ident==iCONSTEXPR) /* sub-types (hierarchical types) are skipped, except for enum fields */
&& (sym->fnumber<0 || sym->fnumber==fnumber)) /* check file number for scope */
{
assert(sym->states==NULL || sym->states->next!=NULL); /* first element of the state list is the "root" */
assert(sym->states==NULL || sym->states->first!=NULL); /* first element of the state list is the "root" */
if (sym->ident==iFUNCTN
|| (automaton<0 && sym->states==NULL)
|| (automaton>=0 && sym->states!=NULL && state_getfsa(sym->states->next->index)==automaton))
|| (automaton>=0 && sym->states!=NULL && state_getfsa(sym->states->first->index)==automaton))
{
if (cmptag==NULL && sym->fnumber==fnumber)
return sym; /* return first match */
@ -3110,8 +3162,8 @@ SC_FUNC symbol *findglb(const char *name,int filter)
* also verify whether there is an intersection between the symbol's
* state list and the current state list
*/
assert(sym->states!=NULL && sym->states->next!=NULL);
if (!state_conflict_id(sc_curstates,sym->states->next->index))
assert(sym->states!=NULL && sym->states->first!=NULL);
if (!state_conflict_id(sc_curstates,sym->states->first->index))
sym=NULL;
} /* if */
} /* if */

View File

@ -20,6 +20,7 @@
*
* Version: $Id: sc3.c 3660 2006-11-05 13:05:09Z thiadmer $
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h> /* for _MAX_PATH */
@ -512,6 +513,7 @@ static int plnge_rel(int *opstr,int opoff,int (*hier)(value *lval),value *lval)
error(212);
if (count>0) {
relop_prefix();
lval2.boolresult=lval->boolresult;
*lval=lval2; /* copy right hand expression of the previous iteration */
} /* if */
opidx+=opoff;
@ -747,7 +749,7 @@ SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state)
return 0;
tokeninfo(&val,&str); /* do not copy the name yet, must check automaton first */
if (*automaton==NULL) {
error(86,name); /* unknown automaton */
error_suggest(86,name,NULL,estAUTOMATON,0); /* unknown automaton */
return 0;
} /* if */
assert((*automaton)->index>0);
@ -767,7 +769,7 @@ SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state)
char *fsaname=(*automaton)->name;
if (*fsaname=='\0')
fsaname="<main>";
error(87,name,fsaname); /* unknown state for automaton */
error_suggest(87,name,fsaname,estSTATE,fsa); /* unknown state for automaton */
return 0;
} /* if */
@ -1014,8 +1016,8 @@ static int hier14(value *lval1)
return error(48); /* array dimensions must match */
else if (ltlength<val || (exactmatch && ltlength>val) || val==0)
return error(47); /* array sizes must match */
else if (lval3.ident!=iARRAYCELL && !matchtag(lval3.sym->x.tags.index,idxtag,TRUE))
error(229,(lval2.sym!=NULL) ? lval2.sym->name : lval3.sym->name); /* index tag mismatch */
else if (lval3.ident!=iARRAYCELL)
check_index_tagmismatch((lval2.sym!=NULL) ? lval2.sym->name : lval3.sym->name,lval3.sym->x.tags.index,idxtag,TRUE,0);
if (level>0) {
/* check the sizes of all sublevels too */
symbol *sym1 = lval3.sym;
@ -1036,8 +1038,8 @@ static int hier14(value *lval1)
*/
if (sym1->dim.array.length!=sym2->dim.array.length)
error(47); /* array sizes must match */
else if (!matchtag(sym1->x.tags.index,sym2->x.tags.index,TRUE))
error(229,sym2->name); /* index tag mismatch */
else
check_index_tagmismatch(sym2->name,sym1->x.tags.index,sym2->x.tags.index,TRUE,0);
} /* for */
/* get the total size in cells of the multi-dimensional array */
val=array_totalsize(lval3.sym);
@ -1319,7 +1321,7 @@ static int hier2(value *lval)
paranthese++;
tok=lex(&val,&st);
if (tok!=tSYMBOL)
return error(20,st); /* illegal symbol name */
return error_suggest(20,st,NULL,estNONSYMBOL,tok); /* illegal symbol name */
sym=findloc(st);
if (sym==NULL)
sym=findglb(st,sSTATEVAR);
@ -1342,18 +1344,18 @@ static int hier2(value *lval)
paranthese++;
tok=lex(&val,&st);
if (tok!=tSYMBOL)
return error(20,st); /* illegal symbol name */
return error_suggest(20,st,NULL,estNONSYMBOL,tok); /* illegal symbol name */
sym=findloc(st);
if (sym==NULL)
sym=findglb(st,sSTATEVAR);
if (sym==NULL)
return error(17,st); /* undefined symbol */
return error_suggest(17,st,NULL,estSYMBOL,essVARCONST); /* undefined symbol */
if (sym->ident==iCONSTEXPR)
error(39); /* constant symbol has no size */
else if (sym->ident==iFUNCTN || sym->ident==iREFFUNC)
error(72); /* "function" symbol has no size */
else if ((sym->usage & uDEFINE)==0)
return error(17,st); /* undefined symbol (symbol is in the table, but it is "used" only) */
return error_suggest(17,st,NULL,estSYMBOL,essVARCONST); /* undefined symbol (symbol is in the table, but it is "used" only) */
clear_value(lval);
lval->ident=iCONSTEXPR;
lval->constval=1; /* preset */
@ -1368,7 +1370,7 @@ static int hier2(value *lval)
int cmptag=subsym->x.tags.index;
tokeninfo(&val,&idxname);
if ((idxsym=findconst(idxname,&cmptag))==NULL)
error(80,idxname); /* unknown symbol, or non-constant */
error_suggest(80,idxname,NULL,estSYMBOL,essCONST); /* unknown symbol, or non-constant */
else if (cmptag>1)
error(91,idxname); /* ambiguous constant */
} /* if */
@ -1395,7 +1397,7 @@ static int hier2(value *lval)
paranthese++;
tok=lex(&val,&st);
if (tok!=tSYMBOL && tok!=tLABEL)
return error(20,st); /* illegal symbol name */
return error_suggest(20,st,NULL,estNONSYMBOL,tok); /* illegal symbol name */
if (tok==tLABEL) {
constvalue *tagsym=find_constval(&tagname_tab,st,0);
tag=(int)((tagsym!=NULL) ? tagsym->value : 0);
@ -1404,9 +1406,9 @@ static int hier2(value *lval)
if (sym==NULL)
sym=findglb(st,sSTATEVAR);
if (sym==NULL)
return error(17,st); /* undefined symbol */
return error_suggest(17,st,NULL,estSYMBOL,essNONLABEL); /* undefined symbol */
if ((sym->usage & uDEFINE)==0)
return error(17,st); /* undefined symbol (symbol is in the table, but it is "used" only) */
return error_suggest(17,st,NULL,estSYMBOL,essNONLABEL); /* undefined symbol (symbol is in the table, but it is "used" only) */
tag=sym->tag;
} /* if */
if (sym!=NULL && (sym->ident==iARRAY || sym->ident==iREFARRAY)) {
@ -1420,7 +1422,7 @@ static int hier2(value *lval)
int cmptag=subsym->x.tags.index;
tokeninfo(&val,&idxname);
if ((idxsym=findconst(idxname,&cmptag))==NULL)
error(80,idxname); /* unknown symbol, or non-constant */
error_suggest(80,idxname,NULL,estSYMBOL,essCONST); /* unknown symbol, or non-constant */
else if (cmptag>1)
error(91,idxname); /* ambiguous constant */
} /* if */
@ -1433,10 +1435,13 @@ static int hier2(value *lval)
else if (level==sym->dim.array.level+1 && idxsym!=NULL)
tag=idxsym->x.tags.index;
} /* if */
exporttag(tag);
if (tag!=0) {
exporttag(tag);
tag |= PUBLICTAG;
} /* if */
clear_value(lval);
lval->ident=iCONSTEXPR;
lval->constval=tag | PUBLICTAG;
lval->constval=tag;
ldconst(lval->constval,sPRI);
while (paranthese--)
needtoken(')');
@ -1596,7 +1601,7 @@ restart:
needtoken(close);
return FALSE;
} else if (sym->ident!=iARRAY && sym->ident!=iREFARRAY){
error(28,sym->name); /* cannot subscript, variable is not an array */
error_suggest(28,sym->name,NULL,estSYMBOL,essARRAY);/* cannot subscript, variable is not an array */
needtoken(close);
return FALSE;
} else if (sym->dim.array.level>0 && close!=']') {
@ -1849,10 +1854,10 @@ static int primary(value *lval)
* implemented, issue an error
*/
if ((sym->usage & uPROTOTYPED)==0)
error(17,st);
error_suggest(17,st,NULL,estSYMBOL,essFUNCTN); /* undefined symbol */
} else {
if ((sym->usage & uDEFINE)==0)
error(17,st);
error_suggest(17,st,NULL,estSYMBOL,essVARCONST); /* undefined symbol */
lval->sym=sym;
lval->ident=sym->ident;
lval->tag=sym->tag;
@ -1865,7 +1870,7 @@ static int primary(value *lval)
} /* if */
} else {
if (!sc_allowproccall)
return error(17,st); /* undefined symbol */
return error_suggest(17,st,NULL,estSYMBOL,essVARCONST); /* undefined symbol */
/* an unknown symbol, but used in a way compatible with the "procedure
* call" syntax. So assume that the symbol refers to a function.
*/
@ -1981,8 +1986,8 @@ static int nesting=0;
value lval = {0};
arginfo *arg;
char arglist[sMAXARGS];
constvalue arrayszlst = { NULL, "", 0, 0};/* array size list starts empty */
constvalue taglst = { NULL, "", 0, 0}; /* tag list starts empty */
constvalue_root arrayszlst = { NULL, NULL};/* array size list starts empty */
constvalue_root taglst = { NULL, NULL}; /* tag list starts empty */
symbol *symret;
cell lexval;
char *lexstr;
@ -2078,8 +2083,10 @@ static int nesting=0;
* of the function; check it again for functions with a variable
* argument list
*/
if (argpos>=sMAXARGS)
if (argpos>=sMAXARGS) {
error(45); /* too many function arguments */
break;
} /* if */
stgmark((char)(sEXPRSTART+argpos));/* mark beginning of new expression in stage */
if (arglist[argpos]!=ARG_UNHANDLED)
error(58); /* argument already set */
@ -2209,19 +2216,23 @@ static int nesting=0;
if (lval.sym==NULL || lval.ident==iARRAYCELL) {
if (arg[argidx].numdim!=1) {
error(48); /* array dimensions must match */
} else if (arg[argidx].dim[0]!=0) {
assert(arg[argidx].dim[0]>0);
if (lval.ident==iARRAYCELL) {
error(47); /* array sizes must match */
} else {
assert(lval.constval!=0); /* literal array must have a size */
/* A literal array must have exactly the same size as the
* function argument; a literal string may be smaller than
* the function argument.
*/
if ((lval.constval>0 && arg[argidx].dim[0]!=lval.constval)
|| (lval.constval<0 && arg[argidx].dim[0] < -lval.constval))
error(47); /* array sizes must match */
} else {
if (lval.sym==NULL && (arg[argidx].usage & uCONST)==0 && (sym->usage & uNATIVE)==0)
error(239);
if (arg[argidx].dim[0]!=0) {
assert(arg[argidx].dim[0]>0);
if (lval.ident==iARRAYCELL) {
error(7); /* array sizes must match */
} else {
assert(lval.constval!=0); /* literal array must have a size */
/* A literal array must have exactly the same size as the
* function argument; a literal string may be smaller than
* the function argument.
*/
if ((lval.constval>0 && arg[argidx].dim[0]!=lval.constval)
|| (lval.constval<0 && arg[argidx].dim[0]<-lval.constval))
error(47); /* array sizes must match */
} /* if */
} /* if */
} /* if */
if (lval.ident!=iARRAYCELL || lval.constval > 0) {
@ -2245,8 +2256,8 @@ static int nesting=0;
assert(level<sDIMEN_MAX);
if (arg[argidx].dim[level]!=0 && sym->dim.array.length!=arg[argidx].dim[level])
error(47); /* array sizes must match */
else if (!matchtag(arg[argidx].idxtag[level],sym->x.tags.index,TRUE))
error(229,sym->name); /* index tag mismatch */
else
check_index_tagmismatch(sym->name,arg[argidx].idxtag[level],sym->x.tags.index,TRUE,0);
append_constval(&arrayszlst,arg[argidx].name,sym->dim.array.length,level);
sym=finddepend(sym);
assert(sym!=NULL);
@ -2257,15 +2268,16 @@ static int nesting=0;
assert(sym!=NULL);
if (arg[argidx].dim[level]!=0 && sym->dim.array.length!=arg[argidx].dim[level])
error(47); /* array sizes must match */
else if (!matchtag(arg[argidx].idxtag[level],sym->x.tags.index,TRUE))
error(229,sym->name); /* index tag mismatch */
else
check_index_tagmismatch(sym->name,arg[argidx].idxtag[level],sym->x.tags.index,TRUE,0);
append_constval(&arrayszlst,arg[argidx].name,sym->dim.array.length,level);
} /* if */
/* address already in PRI */
check_tagmismatch_multiple(arg[argidx].tags,arg[argidx].numtags,lval.tag,-1);
if (lval.tag!=0)
append_constval(&taglst,arg[argidx].name,lval.tag,0);
// ??? set uWRITTEN?
if (lval.sym!=NULL && (arg[argidx].usage & uCONST)==0)
markusage(lval.sym,uWRITTEN);
argidx++; /* argument done */
break;
} /* switch */
@ -2335,6 +2347,8 @@ static int nesting=0;
check_userop(NULL,arg[argidx].defvalue_tag,arg[argidx].tags[0],2,NULL,&dummytag);
assert(dummytag==arg[argidx].tags[0]);
} /* if */
if (arg[argidx].defvalue_tag!=0)
append_constval(&taglst,arg[argidx].name,arg[argidx].defvalue_tag,0);
pushreg(sPRI); /* store the function argument on the stack */
markexpr(sPARM,NULL,0); /* mark the end of a sub-expression */
nest_stkusage++;

View File

@ -20,6 +20,7 @@
*
* Version: $Id: sc4.c 3633 2006-08-11 16:20:18Z thiadmer $
*/
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
@ -75,7 +76,7 @@ SC_FUNC void writeleader(symbol *root)
*/
assert(glb_declared==0);
begdseg();
for (fsa=sc_automaton_tab.next; fsa!=NULL; fsa=fsa->next) {
for (fsa=sc_automaton_tab.first; fsa!=NULL; fsa=fsa->next) {
defstorage();
stgwrite("0\t; automaton ");
if (strlen(fsa->name)==0)
@ -91,7 +92,7 @@ SC_FUNC void writeleader(symbol *root)
begcseg();
for (sym=root->next; sym!=NULL; sym=sym->next) {
if (sym->ident==iFUNCTN && (sym->usage & (uPUBLIC | uREAD))!=0 && sym->states!=NULL) {
stlist=sym->states->next;
stlist=sym->states->first;
assert(stlist!=NULL); /* there should be at least one state item */
listid=stlist->index;
assert(listid==-1 || listid>0);
@ -109,7 +110,7 @@ SC_FUNC void writeleader(symbol *root)
continue;
} /* if */
/* generate label numbers for all statelist ids */
for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) {
for (stlist=sym->states->first; stlist!=NULL; stlist=stlist->next) {
assert(strlen(stlist->name)==0);
strcpy(stlist->name,itoh(getlabel()));
} /* for */
@ -126,7 +127,7 @@ SC_FUNC void writeleader(symbol *root)
*/
statecount=0;
strcpy(lbl_default,itoh(lbl_nostate));
for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) {
for (stlist=sym->states->first; stlist!=NULL; stlist=stlist->next) {
if (stlist->index==-1) {
assert(strlen(stlist->name)<sizeof lbl_default);
strcpy(lbl_default,stlist->name);
@ -146,10 +147,10 @@ SC_FUNC void writeleader(symbol *root)
/* generate the jump table */
setlabel(lbl_table);
ffcase(statecount,lbl_default,TRUE);
for (state=sc_state_tab.next; state!=NULL; state=state->next) {
for (state=sc_state_tab.first; state!=NULL; state=state->next) {
if (state->index==fsa_id) {
/* find the label for this list id */
for (stlist=sym->states->next; stlist!=NULL; stlist=stlist->next) {
for (stlist=sym->states->first; stlist!=NULL; stlist=stlist->next) {
if (stlist->index!=-1 && state_inlist(stlist->index,(int)state->value)) {
ffcase(state->value,stlist->name,FALSE);
break;
@ -343,9 +344,12 @@ SC_FUNC void markexpr(optmark type,const char *name,cell offset)
*
* Global references: funcstatus (referred to only)
*/
SC_FUNC void startfunc(char *fname)
SC_FUNC void startfunc(char *fname,int generateproc)
{
stgwrite("\tproc");
if (generateproc) {
stgwrite("\tproc");
code_idx+=opcodes(1);
} /* if */
if (sc_asmfile) {
char symname[2*sNAMEMAX+16];
funcdisplayname(symname,fname);
@ -353,7 +357,6 @@ SC_FUNC void startfunc(char *fname)
stgwrite(symname);
} /* if */
stgwrite("\n");
code_idx+=opcodes(1);
}
/* endfunc
@ -1379,19 +1382,31 @@ SC_FUNC void outval(cell val,int newline)
}
/* write an instruction with arguments */
SC_FUNC void outinstr(const char *name,ucell args[],int numargs)
SC_FUNC void outinstr(const char *name,emit_outval params[],int numparams)
{
int i;
stgwrite("\t");
stgwrite(name);
for (i=0; i<numargs; i++) {
for (i=0; i<numparams; i++) {
stgwrite(" ");
stgwrite(itoh(args[i]));
switch (params[i].type)
{
case eotLABEL:
stgwrite("l.");
/* fallthrough */
case eotNUMBER:
stgwrite(itoh(params[i].value.ucell));
break;
case eotFUNCTION:
stgwrite(".");
stgwrite(params[i].value.string);
break;
}
} /* for */
stgwrite("\n");
code_idx+=opargs(numargs)+opcodes(1);
code_idx+=opcodes(1)+opargs(numparams);
}

View File

@ -21,6 +21,7 @@
*
* Version: $Id: sc5.c 3579 2006-06-06 13:35:29Z thiadmer $
*/
#include <assert.h>
#if defined __WIN32__ || defined _WIN32 || defined __MSDOS__
#include <io.h>
@ -28,6 +29,7 @@
#if defined LINUX || defined __GNUC__
#include <unistd.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h> /* ANSI standardized variable argument list functions */
@ -183,7 +185,7 @@ static char *warnmsg[] = {
/*226*/ "a variable is assigned to itself (symbol \"%s\")\n",
/*227*/ "more initiallers than enum fields\n",
/*228*/ "length of initialler exceeds size of the enum field\n",
/*229*/ "index tag mismatch (symbol \"%s\")\n",
/*229*/ "index tag mismatch (symbol \"%s\"): expected tag %s but found %s\n",
/*230*/ "no implementation for state \"%s\" in function \"%s\", no fall-back\n",
/*231*/ "state specification on forward declaration is ignored\n",
/*232*/ "output file is written, but with compact encoding disabled\n",
@ -191,7 +193,13 @@ static char *warnmsg[] = {
/*234*/ "function is deprecated (symbol \"%s\") %s\n",
/*235*/ "public function lacks forward declaration (symbol \"%s\")\n",
/*236*/ "unknown parameter in substitution (incorrect #define pattern)\n",
/*237*/ "user warning: %s\n"
/*237*/ "user warning: %s\n",
/*238*/ "meaningless combination of class specifiers (%s)\n",
/*239*/ "literal array/string passed to a non-const parameter\n"
};
static char *noticemsg[] = {
/*001*/ "; did you mean \"%s\"?\n"
};
#define NUM_WARNINGS (sizeof warnmsg / sizeof warnmsg[0])
@ -217,13 +225,22 @@ static int errwarn;
* fcurrent (reffered to only)
* errflag (altered)
*/
SC_FUNC int error(int number,...)
SC_FUNC int error(long number,...)
{
static char *prefix[3]={ "error", "fatal error", "warning" };
static int lastline,errorcount;
static short lastfile;
char *msg,*pre;
va_list argptr;
char string[128];
int notice;
/* split the error field between the real error/warning number and an optional
* "notice" number
*/
notice=(unsigned long)number >> (sizeof(long)*4);
number&=(~(unsigned long)0) >> (sizeof(long)*4);
assert(number>0 && number<300);
/* errflag is reset on each semicolon.
* In a two-pass compiler, an error should not be reported twice. Therefore
@ -241,26 +258,37 @@ static short lastfile;
return 0;
} /* if */
if (number<100){
if (number<100) {
assert(number>0 && number<(1+arraysize(errmsg)));
msg=errmsg[number-1];
pre=prefix[0];
errflag=TRUE; /* set errflag (skip rest of erroneous expression) */
errnum++;
} else if (number<200){
} else if (number<200) {
assert(number>=100 && number<(100+arraysize(fatalmsg)));
msg=fatalmsg[number-100];
pre=prefix[1];
errnum++; /* a fatal error also counts as an error */
} else if (errwarn) {
assert(number>=200 && number<(200+arraysize(warnmsg)));
msg=warnmsg[number-200];
pre=prefix[0];
errflag=TRUE;
errnum++;
} else {
assert(number>=200 && number<(200+arraysize(warnmsg)));
msg=warnmsg[number-200];
pre=prefix[2];
warnnum++;
} /* if */
if (notice!=0) {
assert(notice>0 && notice<(1+arraysize(noticemsg)) && noticemsg[notice-1][0]!='\0');
strcpy(string,msg);
strcpy(&string[strlen(string)-1],noticemsg[notice-1]);
msg=string;
} /* if */
assert(errstart<=fline);
if (errline>0)
errstart=errline;
@ -268,9 +296,9 @@ static short lastfile;
errline=fline;
assert(errstart<=errline);
va_start(argptr,number);
if (strlen(errfname)==0) {
if (errfname[0]=='\0') {
int start=(errstart==errline) ? -1 : errstart;
if (pc_error(number,msg,inpfname,start,errline,argptr)) {
if (pc_error((int)number,msg,inpfname,start,errline,argptr)) {
if (outf!=NULL) {
pc_closeasm(outf,TRUE);
outf=NULL;
@ -281,9 +309,9 @@ static short lastfile;
FILE *fp=fopen(errfname,"a");
if (fp!=NULL) {
if (errstart>=0 && errstart!=errline)
fprintf(fp,"%s(%d -- %d) : %s %03d: ",inpfname,errstart,errline,pre,number);
fprintf(fp,"%s(%d -- %d) : %s %03d: ",inpfname,errstart,errline,pre,(int)number);
else
fprintf(fp,"%s(%d) : %s %03d: ",inpfname,errline,pre,number);
fprintf(fp,"%s(%d) : %s %03d: ",inpfname,errline,pre,(int)number);
vfprintf(fp,msg,argptr);
fclose(fp);
} /* if */
@ -291,7 +319,7 @@ static short lastfile;
va_end(argptr);
if ((number>=100 && number<200) || errnum>25){
if (strlen(errfname)==0) {
if (errfname[0]=='\0') {
va_start(argptr,number);
pc_error(0,"\nCompilation aborted.\n\n",NULL,0,0,argptr);
va_end(argptr);
@ -420,3 +448,240 @@ int pc_geterrorwarnings()
return errwarn;
}
/* Implementation of Levenshtein distance, by Lorenzo Seidenari
*/
static int minimum(int a,int b,int c)
{
int min=a;
if(b<min)
min=b;
if(c<min)
min=c;
return min;
}
static int levenshtein_distance(const char *s,const char*t)
{
//Step 1
int k,i,j,cost,*d,distance;
int n=strlen(s);
int m=strlen(t);
assert(n>0 && m>0);
d=(int*)malloc((sizeof(int))*(m+1)*(n+1));
m++;
n++;
//Step 2
for (k=0;k<n;k++)
d[k]=k;
for (k=0;k<m;k++)
d[k*n]=k;
//Step 3 and 4
for (i=1;i<n;i++) {
for (j=1;j<m;j++) {
//Step 5
cost= (tolower(s[i-1])!=tolower(t[j-1]));
//Step 6
d[j*n+i]=minimum(d[(j-1)*n+i]+1,d[j*n+i-1]+1,d[(j-1)*n+i-1]+cost);
} /* for */
} /* for */
distance=d[n*m-1];
free(d);
return distance;
}
static int get_max_dist(const char *name)
{
int max_dist=strlen(name)/2; /* for short names, allow only a single edit */
if (max_dist>MAX_EDIT_DIST)
max_dist=MAX_EDIT_DIST;
return max_dist;
}
static int find_closest_symbol_table(const char *name,const symbol *root,int symboltype,symbol **closest_sym)
{
int dist,max_dist,closest_dist=INT_MAX;
char symname[2*sNAMEMAX+16];
symbol *sym;
int ident;
assert(closest_sym!=NULL);
*closest_sym =NULL;
assert(name!=NULL);
max_dist=get_max_dist(name);
for (sym=root->next; sym!=NULL; sym=sym->next) {
if (sym->fnumber!=-1 && sym->fnumber!=fcurrent)
continue;
ident=sym->ident;
if (symboltype==essNONLABEL) {
if (ident==iLABEL)
continue;
} else if (symboltype==essVARCONST) {
if (ident!=iCONSTEXPR && ident!=iVARIABLE && ident!=iREFERENCE && ident!=iARRAY && ident!=iREFARRAY)
continue;
} else if (symboltype==essARRAY) {
if (ident!=iARRAY && ident!=iREFARRAY)
continue;
} else if (symboltype==essCONST) {
if (ident!=iCONSTEXPR)
continue;
} else if (symboltype==essFUNCTN) {
if ((ident!=iFUNCTN && ident!=iREFFUNC) || (sym->usage & uDEFINE)==0)
continue;
} else if (symboltype==essLABEL) {
if (ident!=iLABEL || (sym->usage & uDEFINE)==0)
continue;
} /* if */
funcdisplayname(symname,sym->name);
dist=levenshtein_distance(name,symname);
if (dist>max_dist || dist>=closest_dist)
continue;
*closest_sym =sym;
closest_dist=dist;
if (closest_dist<=1)
break;
} /* for */
return closest_dist;
}
static symbol *find_closest_symbol(const char *name,int symboltype)
{
symbol *symloc,*symglb;
int distloc,distglb;
if (sc_status==statFIRST)
return NULL;
assert(name!=NULL);
if (name[0]=='\0')
return NULL;
distloc=find_closest_symbol_table(name,&loctab,symboltype,&symloc);
if (distloc<=1)
distglb=INT_MAX; /* don't bother searching in the global table */
else
distglb=find_closest_symbol_table(name,&glbtab,symboltype,&symglb);
return (distglb<distloc) ? symglb : symloc;
}
static constvalue *find_closest_automaton(const char *name)
{
constvalue *ptr=sc_automaton_tab.first;
constvalue *closest_match=NULL;
int dist,max_dist,closest_dist=INT_MAX;
assert(name!=NULL);
max_dist=get_max_dist(name);
while (ptr!=NULL) {
if (ptr->name[0]!='\0') {
dist=levenshtein_distance(name,ptr->name);
if (dist<closest_dist && dist<=max_dist) {
closest_match=ptr;
closest_dist=dist;
if (closest_dist<=1)
break;
} /* if */
} /* if */
ptr=ptr->next;
} /* while */
return closest_match;
}
static constvalue *find_closest_state(const char *name,int fsa)
{
constvalue *ptr=sc_state_tab.first;
constvalue *closest_match=NULL;
int dist,max_dist,closest_dist=INT_MAX;
assert(name!=NULL);
max_dist=get_max_dist(name);
while (ptr!=NULL) {
if (ptr->index==fsa && ptr->name[0]!='\0') {
dist=levenshtein_distance(name,ptr->name);
if (dist<closest_dist && dist<=max_dist) {
closest_match=ptr;
closest_dist=dist;
if (closest_dist<=1)
break;
} /* if */
} /* if */
ptr=ptr->next;
} /* while */
return closest_match;
}
static constvalue *find_closest_automaton_for_state(const char *statename,int fsa)
{
constvalue *ptr=sc_state_tab.first;
constvalue *closest_match=NULL;
constvalue *automaton;
const char *fsaname;
int dist,max_dist,closest_dist=INT_MAX;
assert(statename!=NULL);
max_dist=get_max_dist(statename);
automaton=automaton_findid(ptr->index);
assert(automaton!=NULL);
fsaname=automaton->name;
while (ptr!=NULL) {
if (fsa!=ptr->index && ptr->name[0]!='\0' && strcmp(statename,ptr->name)==0) {
automaton=automaton_findid(ptr->index);
assert(automaton!=NULL);
dist=levenshtein_distance(fsaname,automaton->name);
if (dist<closest_dist && dist<=max_dist) {
closest_match=automaton;
closest_dist=dist;
if (closest_dist<=1)
break;
} /* if */
} /* if */
ptr=ptr->next;
} /* while */
return closest_match;
}
SC_FUNC int error_suggest(int number,const char *name,const char *name2,int type,int subtype)
{
char string[sNAMEMAX*2+2]; /* for "<automaton>:<state>" */
const char *closest_name=NULL;
/* don't bother finding the closest names on errors
* that aren't going to be shown on the 1'st pass
*/
if ((errflag || sc_status!=statWRITE) && (number<100 || number>=200))
return 0;
if (type==estSYMBOL || (type==estNONSYMBOL && tMIDDLE<subtype && subtype<=tLAST)) {
symbol *closest_sym;
if (type!=estSYMBOL) {
extern char *sc_tokens[];
name=sc_tokens[subtype-tFIRST];
subtype=essVARCONST;
} /* if */
closest_sym =find_closest_symbol(name,subtype);
if (closest_sym !=NULL)
closest_name= closest_sym->name;
} else if (type==estAUTOMATON) {
constvalue *closest_automaton=find_closest_automaton(name);
if (closest_automaton!=NULL)
closest_name=closest_automaton->name;
} else if (type==estSTATE) {
constvalue *closest_state=find_closest_state(name,subtype);
if (closest_state !=NULL) {
closest_name=closest_state->name;
} else {
constvalue *closest_automaton=find_closest_automaton_for_state(name,subtype);
if (closest_automaton !=NULL) {
sprintf(string,"%s:%s", closest_automaton->name,name);
closest_name=string;
} /* if */
} /* if */
} else {
assert(0);
} /* if */
if (closest_name==NULL) {
error(number,name,name2);
} else if (name2!=NULL) {
error(makelong(number,1),name,name2,closest_name);
} else {
error(makelong(number,1),name,closest_name);
} /* if */
return 0;
}

View File

@ -20,6 +20,7 @@
*
* Version: $Id: sc6.c 3648 2006-10-12 11:24:50Z thiadmer $
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h> /* for macro max() */
@ -102,7 +103,7 @@ static ucell getparam(const char *s,char **n)
char name[sNAMEMAX+1];
symbol *sym;
if (*s=='.') {
if (s[0]=='.') {
/* this is a function, find it in the global symbol table */
for (i=0; !isspace(*(++s)); i++) {
assert(*s!='\0');
@ -115,6 +116,12 @@ static ucell getparam(const char *s,char **n)
assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC);
assert(sym->vclass==sGLOBAL);
result=sym->addr;
} else if (s[0]=='l' && s[1]=='.') {
/* this is a label */
i=(int)hex2long(s+2,NULL);
assert(i>=0 && i<sc_labnum);
assert(lbltab!=NULL);
result=lbltab[i];
} else {
for ( ;; ) {
result+=hex2long(s,(char**)&s);
@ -438,7 +445,7 @@ static cell SC_FASTCALL do_dumpn(FILE *fbin,char *params,cell opcode)
value=hex2long(params,&params);
num=(int)hex2long(params,NULL);
if (fbin!=NULL)
write_encoded_n(fbin,value,num);
write_encoded_n(fbin,value,num);
return num*sizeof(cell);
}
@ -813,7 +820,7 @@ SC_FUNC int assemble(FILE *fout,FILE *fin)
/* count number of libraries */
numlibraries=0;
if (pc_addlibtable) {
for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
for (constptr=libname_tab.first; constptr!=NULL; constptr=constptr->next) {
if (constptr->value>0) {
assert(strlen(constptr->name)>0);
numlibraries++;
@ -824,7 +831,7 @@ SC_FUNC int assemble(FILE *fout,FILE *fin)
/* count number of public tags */
numtags=0;
for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
for (constptr=tagname_tab.first; constptr!=NULL; constptr=constptr->next) {
if ((constptr->value & PUBLICTAG)!=0) {
assert(strlen(constptr->name)>0);
numtags++;
@ -950,7 +957,7 @@ SC_FUNC int assemble(FILE *fout,FILE *fin)
/* write the libraries table */
if (pc_addlibtable) {
count=0;
for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {
for (constptr=libname_tab.first; constptr!=NULL; constptr=constptr->next) {
if (constptr->value>0) {
assert(strlen(constptr->name)>0);
func.address=0;
@ -994,7 +1001,7 @@ SC_FUNC int assemble(FILE *fout,FILE *fin)
/* write the public tagnames table */
count=0;
for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
for (constptr=tagname_tab.first; constptr!=NULL; constptr=constptr->next) {
if ((constptr->value & PUBLICTAG)!=0) {
assert(strlen(constptr->name)>0);
func.address=constptr->value & TAGMASK;
@ -1214,21 +1221,21 @@ static void append_dbginfo(FILE *fout)
} /* for */
/* tag table */
for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
for (constptr=tagname_tab.first; constptr!=NULL; constptr=constptr->next) {
assert(strlen(constptr->name)>0);
dbghdr.tags++;
dbghdr.size+=sizeof(AMX_DBG_TAG)+strlen(constptr->name);
} /* for */
/* automaton table */
for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
for (constptr=sc_automaton_tab.first; constptr!=NULL; constptr=constptr->next) {
assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
dbghdr.automatons++;
dbghdr.size+=sizeof(AMX_DBG_MACHINE)+strlen(constptr->name);
} /* for */
/* state table */
for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
for (constptr=sc_state_tab.first; constptr!=NULL; constptr=constptr->next) {
assert(strlen(constptr->name)>0);
dbghdr.states++;
dbghdr.size+=sizeof(AMX_DBG_STATE)+strlen(constptr->name);
@ -1347,7 +1354,7 @@ static void append_dbginfo(FILE *fout)
} /* for */
/* tag table */
for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {
for (constptr=tagname_tab.first; constptr!=NULL; constptr=constptr->next) {
assert(strlen(constptr->name)>0);
id1=(int16_t)(constptr->value & TAGMASK);
#if BYTE_ORDER==BIG_ENDIAN
@ -1358,7 +1365,7 @@ static void append_dbginfo(FILE *fout)
} /* for */
/* automaton table */
for (constptr=sc_automaton_tab.next; constptr!=NULL; constptr=constptr->next) {
for (constptr=sc_automaton_tab.first; constptr!=NULL; constptr=constptr->next) {
assert(constptr->index==0 && strlen(constptr->name)==0 || strlen(constptr->name)>0);
id1=(int16_t)constptr->index;
address=(ucell)constptr->value;
@ -1372,7 +1379,7 @@ static void append_dbginfo(FILE *fout)
} /* for */
/* state table */
for (constptr=sc_state_tab.next; constptr!=NULL; constptr=constptr->next) {
for (constptr=sc_state_tab.first; constptr!=NULL; constptr=constptr->next) {
assert(strlen(constptr->name)>0);
id1=(int16_t)constptr->value;
id2=(int16_t)constptr->index;

View File

@ -47,6 +47,7 @@
*
* Version: $Id: sc7.c 3579 2006-06-06 13:35:29Z thiadmer $
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h> /* for atoi() */
@ -1332,14 +1333,12 @@ SC_FUNC void stgmark(char mark)
static int rebuffer(char *str)
{
if (sc_status==statWRITE) {
int st_len=strlen(str);
if (pipeidx>=2 && stgpipe[pipeidx-1]=='\0' && stgpipe[pipeidx-2]!='\n')
pipeidx-=1; /* overwrite last '\0' */
while (*str!='\0') { /* copy to staging buffer */
CHECK_STGPIPE(pipeidx);
stgpipe[pipeidx++]=*str++;
} /* while */
CHECK_STGPIPE(pipeidx);
stgpipe[pipeidx++]='\0';
pipeidx-=1; /* overwrite last '\0' */
CHECK_STGPIPE(pipeidx+st_len+1);
memcpy(stgpipe+pipeidx,str,st_len+1); /* copy to staging buffer */
pipeidx+=st_len+1;
} /* if */
return TRUE;
}
@ -1372,22 +1371,18 @@ static int filewrite(char *str)
SC_FUNC void stgwrite(const char *st)
{
int len;
int st_len;
int st_len=strlen(st);
if (staging) {
assert(stgidx==0 || stgbuf!=NULL); /* staging buffer must be valid if there is (apparently) something in it */
if (stgidx>=2 && stgbuf[stgidx-1]=='\0' && stgbuf[stgidx-2]!='\n')
stgidx-=1; /* overwrite last '\0' */
while (*st!='\0') { /* copy to staging buffer */
CHECK_STGBUFFER(stgidx);
stgbuf[stgidx++]=*st++;
stglen++;
} /* while */
CHECK_STGBUFFER(stgidx);
stgbuf[stgidx++]='\0';
stgidx-=1; /* overwrite last '\0' */
CHECK_STGBUFFER(stgidx+st_len+1);
memcpy(stgbuf+stgidx,st,st_len+1); /* copy to staging buffer */
stgidx+=st_len+1;
stglen+=st_len;
} else {
len=(stgbuf!=NULL) ? stglen : 0;
st_len=strlen(st);
CHECK_STGBUFFER(len+st_len+1);
memcpy(stgbuf+len,st,st_len+1);
len=len+st_len;

View File

@ -32,6 +32,7 @@
*
* Version: $Id: sci18n.c 3612 2006-07-22 09:59:46Z thiadmer $
*/
#include <assert.h>
#include <stdio.h>
#include <stddef.h>

View File

@ -26,6 +26,7 @@
*
* Version: $Id: sclist.c 3660 2006-11-05 13:05:09Z thiadmer $
*/
#include <assert.h>
#include <limits.h>
#include <stdlib.h>

View File

@ -45,6 +45,7 @@
*
* Version: $Id: scstate.c 3579 2006-06-06 13:35:29Z thiadmer $
*/
#include <assert.h>
#include <limits.h>
#include <stdio.h>
@ -76,7 +77,7 @@ static constvalue *find_automaton(const char *name,int *last)
assert(last!=NULL);
*last=0;
ptr=sc_automaton_tab.next;
ptr=sc_automaton_tab.first;
while (ptr!=NULL) {
if (strcmp(name,ptr->name)==0)
return ptr;
@ -110,7 +111,7 @@ SC_FUNC constvalue *automaton_find(const char *name)
SC_FUNC constvalue *automaton_findid(int id)
{
constvalue *ptr;
for (ptr=sc_automaton_tab.next; ptr!=NULL && ptr->index!=id; ptr=ptr->next)
for (ptr=sc_automaton_tab.first; ptr!=NULL && ptr->index!=id; ptr=ptr->next)
/* nothing */;
return ptr;
}
@ -122,7 +123,7 @@ static constvalue *find_state(const char *name,int fsa,int *last)
assert(last!=NULL);
*last=0;
ptr=sc_state_tab.next;
ptr=sc_state_tab.first;
while (ptr!=NULL) {
if (ptr->index==fsa) {
if (strcmp(name,ptr->name)==0)
@ -158,7 +159,7 @@ SC_FUNC constvalue *state_find(const char *name,int fsa_id)
SC_FUNC constvalue *state_findid(int id)
{
constvalue *ptr;
for (ptr=sc_state_tab.next; ptr!=NULL && ptr->value!=id; ptr=ptr->next)
for (ptr=sc_state_tab.first; ptr!=NULL && ptr->value!=id; ptr=ptr->next)
/* nothing */;
return ptr;
}
@ -341,7 +342,7 @@ SC_FUNC void state_conflict(symbol *root)
continue; /* hierarchical data type or no function */
if (sym->states==NULL)
continue; /* this function has no states */
for (srcptr=sym->states->next; srcptr!=NULL; srcptr=srcptr->next) {
for (srcptr=sym->states->first; srcptr!=NULL; srcptr=srcptr->next) {
if (srcptr->index==-1)
continue; /* state list id -1 is a special case */
psrc=state_getlist_ptr(srcptr->index);

View File

@ -22,6 +22,7 @@
*
* Version: $Id: scvars.c 3655 2006-10-23 20:17:52Z thiadmer $
*/
#include <stdio.h>
#include <stdlib.h> /* for _MAX_PATH */
#include "sc.h"
@ -37,8 +38,8 @@ SC_VDEFINE struct hashtable_t symbol_cache_ht;
SC_VDEFINE cell *litq; /* the literal queue */
SC_VDEFINE unsigned char pline[sLINEMAX+1]; /* the line read from the input file */
SC_VDEFINE const unsigned char *lptr; /* points to the current position in "pline" */
SC_VDEFINE constvalue tagname_tab={ NULL, "", 0, 0}; /* tagname table */
SC_VDEFINE constvalue libname_tab={ NULL, "", 0, 0}; /* library table (#pragma library "..." syntax) */
SC_VDEFINE constvalue_root tagname_tab={ NULL, NULL}; /* tagname table */
SC_VDEFINE constvalue_root libname_tab={ NULL, NULL}; /* library table (#pragma library "..." syntax) */
SC_VDEFINE constvalue *curlibrary=NULL; /* current library */
SC_VDEFINE int pc_addlibtable=TRUE; /* is the library table added to the AMX file? */
SC_VDEFINE symbol *curfunc; /* pointer to current function */
@ -96,8 +97,8 @@ SC_VDEFINE int pc_naked=FALSE; /* if true mark following function a
SC_VDEFINE int pc_compat=FALSE; /* running in compatibility mode? */
SC_VDEFINE int pc_recursion=FALSE; /* enable detailed recursion report? */
SC_VDEFINE constvalue sc_automaton_tab = { NULL, "", 0, 0}; /* automaton table */
SC_VDEFINE constvalue sc_state_tab = { NULL, "", 0, 0}; /* state table */
SC_VDEFINE constvalue_root sc_automaton_tab = { NULL, NULL}; /* automaton table */
SC_VDEFINE constvalue_root sc_state_tab = { NULL, NULL}; /* state table */
SC_VDEFINE FILE *inpf = NULL; /* file read from (source or include) */
SC_VDEFINE FILE *inpf_org= NULL; /* main source file */

3
source/compiler/tests/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.amx
*.asm
*.lst

View File

@ -1,55 +1,29 @@
set(DEFAULT_COMPILER_OPTIONS
-i${CMAKE_SOURCE_DIR}/include
"-\;+"
"-(+")
find_package(PythonInterp 2.7)
function(add_compiler_test test_name options)
if(PYTHONINTERP_FOUND)
add_custom_target(pawncc_tests
COMMAND ${PYTHON_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/run_tests.py
-c $<TARGET_FILE:pawncc>
-d $<TARGET_FILE:pawndisasm>
-r $<TARGET_FILE:pawnruns>
-i ../../../include
DEPENDS pawncc
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
file(GLOB_RECURSE meta_files "*.meta")
foreach(meta_file IN LISTS meta_files)
get_filename_component(test_name ${meta_file} NAME_WE)
add_test(NAME ${test_name}
COMMAND $<TARGET_FILE:pawncc> ${DEFAULT_COMPILER_OPTIONS} ${options})
set_tests_properties(${test_name} PROPERTIES
ENVIRONMENT PATH=$<TARGET_FILE_DIR:pawnc>)
endfunction()
# Compile tests
#
# These tests compare compile output against a regular expression and fail if the output
# doesn't match the expected pattern.
add_compiler_test(gh_217 ${CMAKE_CURRENT_SOURCE_DIR}/gh_217.pwn)
set_tests_properties(gh_217 PROPERTIES PASS_REGULAR_EXPRESSION "\
.*\\.pwn\\(11\\) : warning 237: user warning: this is warning 1\
.*\\.pwn\\(13\\) : warning 237: user warning: this iswarning 2\
.*\\.pwn\\(15\\) : warning 237: user warning: this is warning 3\
.*\\.pwn\\(17\\) : warning 237: user warning: this is warning 4\
.*\\.pwn\\(27\\) : warning 234: function is deprecated \\(symbol \"f\"\\) don't use this functionplease\
.*\\.pwn\\(32\\) : warning 234: function is deprecated \\(symbol \"f\"\\) don't use this functionplease\
")
add_compiler_test(reset_errline_gh_230 ${CMAKE_CURRENT_SOURCE_DIR}/reset_errline_gh_230.pwn)
set_tests_properties(reset_errline_gh_230 PROPERTIES PASS_REGULAR_EXPRESSION "\
.*\\.pwn\\(2\\) : error 017: undefined symbol \\\"undefined\\\"\
.*\\.pwn\\(2\\) : warning 215: expression has no effect\
.*\\.pwn\\(7\\) : warning 204: symbol is assigned a value that is never used: \\\"y\\\"\
.*\\.pwn\\(4\\) : warning 204: symbol is assigned a value that is never used: \\\"x\\\"\
")
add_compiler_test(unused_symbol_line_gh_252 ${CMAKE_CURRENT_SOURCE_DIR}/unused_symbol_line_gh_252.pwn)
set_tests_properties(unused_symbol_line_gh_252 PROPERTIES PASS_REGULAR_EXPRESSION "\
.*\\.pwn\\(4\\) : warning 203: symbol is never used: \\\"y\\\"
.*\\.pwn\\(8\\) : warning 203: symbol is never used: \\\"z\\\"
.*\\.pwn\\(1\\) : warning 203: symbol is never used: \\\"x\\\"
")
add_compiler_test(gh_283 ${CMAKE_CURRENT_SOURCE_DIR}/gh_283.pwn)
set_tests_properties(gh_283 PROPERTIES PASS_REGULAR_EXPRESSION "\
.*\\.pwn\\(5\\) : warning 234: function is deprecated \\(symbol \"print\"\\)\
")
# Crashers
#
# These tests simply check that the compiler doesn't crash.
#
# TODO: Probably need to support tests that exist with a non-zero code but don't crash?
# Right now this will cause a failure.
add_compiler_test(md_array_crash_gh_220 ${CMAKE_CURRENT_SOURCE_DIR}/md_array_crash_gh_220.pwn)
COMMAND ${PYTHON_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/run_tests.py
-c $<TARGET_FILE:pawncc>
-d $<TARGET_FILE:pawndisasm>
-r $<TARGET_FILE:pawnruns>
-i ../../../include
${test_name}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endforeach()
else()
message("Python was not found, you will not be able to run the tests")
endif()

View File

@ -0,0 +1,11 @@
{
'test_type': 'output_check',
'errors': """
const_array_args_and_literals_gh_276.pwn(13) : warning 214: possibly a "const" array argument was intended: "arr"
const_array_args_and_literals_gh_276.pwn(18) : warning 214: possibly a "const" array argument was intended: "arr"
const_array_args_and_literals_gh_276.pwn(30) : warning 214: possibly a "const" array argument was intended: "arr"
const_array_args_and_literals_gh_276.pwn(39) : warning 239: literal array/string passed to a non-const parameter
const_array_args_and_literals_gh_276.pwn(40) : warning 239: literal array/string passed to a non-const parameter
const_array_args_and_literals_gh_276.pwn(41) : warning 239: literal array/string passed to a non-const parameter
"""
}

View File

@ -0,0 +1,61 @@
forward OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]);
native SetTimer(funcname[], interval, repeating);
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
}
f0(arr[]) {
#pragma unused arr
}
f1(arr[]) { // line 13
new a = arr[0];
#pragma unused a
}
f2(arr[5]) {// line 18
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
}
f5(arr[][]) { // line 30
new a = arr[0][0];
#pragma unused a
}
f6(arr[][]) {
arr[0][0] = 0;
}
main () {
f0("test"); // line 39
f1("test"); // line 40
f2("test"); // line 41
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
new arr2[1][1];
f5(arr2);
f6(arr2);
SetTimer("test", 0, 0);
}

View File

@ -0,0 +1,9 @@
{
'test_type': 'output_check',
'errors': """
constexpr_result_prop_gh_308.pwn(2) : warning 237: user warning: "Test passed."
constexpr_result_prop_gh_308.pwn(6) : warning 237: user warning: "Test passed."
constexpr_result_prop_gh_308.pwn(10) : warning 237: user warning: "Test passed."
constexpr_result_prop_gh_308.pwn(14) : warning 237: user warning: "Test passed."
"""
}

View File

@ -0,0 +1,19 @@
#if (30 < 40 < 50)
#warning "Test passed."
#endif
#if !(30 < 40 < 35)
#warning "Test passed."
#endif
#if (30 < 40)
#warning "Test passed."
#endif
#if !(40 < 35)
#warning "Test passed."
#endif
main () {
}

View File

@ -0,0 +1,6 @@
{
'test_type': 'output_check',
'errors': """
destructor_not_impl_gh_310.pwn(4) : error 004: function "operator~(Error:)" is not implemented
"""
}

View File

@ -0,0 +1,4 @@
forward operator~(Error:right[], size);
main() {
new Error:e;
}

View File

@ -0,0 +1,11 @@
{
'test_type': 'output_check',
'errors': """
gh_217.pwn(11) : warning 237: user warning: this is warning 1
gh_217.pwn(13) : warning 237: user warning: this is warning 2
gh_217.pwn(15) : warning 237: user warning: this is warning 3
gh_217.pwn(17) : warning 237: user warning: this is warning 4
gh_217.pwn(28) : warning 234: function is deprecated (symbol "f") don't use this function please
gh_217.pwn(33) : warning 234: function is deprecated (symbol "f") don't use this function please
"""
}

View File

@ -1,6 +1,6 @@
// TODO: Check that string literals are concatenated correctly
native print(const s[]);
#include <console>
#define d1\
print("ok")
@ -17,7 +17,8 @@ warning 3
warning 4
// single-line comments can span \
multiple lines if you really want it
//multiple lines if you really want it
// no they can't, only with more //s.
#pragma deprecated don't\
use \

View File

@ -0,0 +1,6 @@
{
'test_type': 'output_check',
'errors': """
gh_283.pwn(5) : warning 234: function is deprecated (symbol "f")
"""
}

View File

@ -1,6 +1,6 @@
#pragma deprecated
native print(const string[]);
native f();
main() {
print("Hello World");
f();
}

View File

@ -0,0 +1,2 @@
static staticvar;
#pragma unused staticvar

View File

@ -0,0 +1,24 @@
{
'test_type': 'output_check',
'errors': """
gh_353_symbol_suggestions.pwn(12) : error 017: undefined symbol "abcxyz"
gh_353_symbol_suggestions.pwn(20) : error 017: undefined symbol "length"
gh_353_symbol_suggestions.pwn(30) : error 017: undefined symbol "float"
gh_353_symbol_suggestions.pwn(40) : error 017: undefined symbol "ab"
gh_353_symbol_suggestions.pwn(41) : error 017: undefined symbol "ab"
gh_353_symbol_suggestions.pwn(50) : error 017: undefined symbol "staticval"
gh_353_symbol_suggestions.pwn(58) : error 017: undefined symbol "val"; did you mean "var"?
gh_353_symbol_suggestions.pwn(62) : error 017: undefined symbol "celmax"; did you mean "cellmax"?
gh_353_symbol_suggestions.pwn(66) : error 017: undefined symbol "strcaf"; did you mean "strcat"?
gh_353_symbol_suggestions.pwn(69) : error 017: undefined symbol "test_e17"; did you mean "test_e017"?
gh_353_symbol_suggestions.pwn(78) : error 019: not a label: "lb"; did you mean "lbl"?
gh_353_symbol_suggestions.pwn(85) : error 020: invalid symbol name "assert"; did you mean "asset"?
gh_353_symbol_suggestions.pwn(96) : error 080: unknown symbol, or not a constant symbol (symbol "idx"); did you mean "id"?
gh_353_symbol_suggestions.pwn(107) : error 086: unknown automaton "automaton1"; did you mean "automaton_1"?
gh_353_symbol_suggestions.pwn(107) : error 036: empty statement
gh_353_symbol_suggestions.pwn(114) : error 087: unknown state "BEING1" for automaton "automaton_2"; did you mean "BEING_1"?
gh_353_symbol_suggestions.pwn(114) : error 036: empty statement
gh_353_symbol_suggestions.pwn(117) : error 087: unknown state "STATE_1" for automaton "automaton_2"; did you mean "automaton_1:STATE_1"?
gh_353_symbol_suggestions.pwn(117) : error 036: empty statement
"""
}

View File

@ -0,0 +1,118 @@
#include <console>
#include <file>
#include <string>
#include "gh_353_symbol_suggestions.inc"
forward test_nosuggest1();
public test_nosuggest1()
{
// The compiler shouldn't suggest any name for this error
// since "abcxyz" and "abcd" differ by more than 2 symbols.
const abcd = 1;
printf("%d\n", abcxyz);
#pragma unused abcd
}
forward test_nosuggest2();
public test_nosuggest2()
{
// There are no "()" after "length", so the compiler shouldn't suggest "flength".
printf("%d\n", length);
}
forward test_nosuggest3();
public test_nosuggest3()
{
// float.inc is not #included, so float() is not defined.
// After the 1'st pass the compiler thinks float() is an unimplemented function,
// so it shouldn't suggest variable "flt" in this case.
new Float:flt;
return float(0);
#pragma unused flt
}
forward test_nosuggest4();
public test_nosuggest4()
{
// "abc" is a label so the compiler shouldn't suggest its name
// where a variable or named constant is expected.
abc:
printf("%d\n", ab);
printf("%d\n", tagof ab);
#pragma unused abc
}
forward test_nosuggest5();
public test_nosuggest5()
{
// As the name suggests, variable "staticvar" is defined as static
// within another file, so the compiler shouldn't suggest its name here.
return staticval;
}
forward test_e017();
public test_e017()
{
// error 017: undefined symbol "val"; did you mean "var"?
new var = 1;
printf("%d\n", val);
#pragma unused var
// error 017: undefined symbol "celmax"; did you mean "cellmax"?
printf("%d\n", celmax);
// error 017: undefined symbol "strcaf"; did you mean "strcat"?
new str[4] = "a";
strcaf(str, "b");
// error 017: undefined symbol "test_e17"; did you mean "test_e017"?
printf("%d\n", tagof test_e17);
}
forward test_e019();
public test_e019()
{
// error 019: not a label: "lb"; did you mean "lbl"?
lbl:
goto lb;
}
forward test_e020();
public test_e020()
{
// error 020: invalid symbol name "assert"; did you mean "asset"?
new asset = 0;
printf("%d\n", defined assert);
#pragma unused asset
}
forward test_e080();
public test_e080()
{
// error 080: unknown symbol, or not a constant symbol (symbol "idx"); did you mean "id"?
new values[1];
new idx = 0;
const id = 0;
printf("%d\n", sizeof values[idx]);
#pragma unused values, idx, id
}
stock func1()<automaton_1:STATE_1>{}
stock func2()<automaton_2:BEING_1>{}
forward test_e086();
public test_e086()
{
// error 086: unknown automaton "automaton1"; did you mean "automaton_1"?
state automaton1:STATE_1;
}
forward test_e087();
public test_e087()
{
// error 087: unknown state BEING1" for automaton "automaton_2"; did you mean "BEING_1"?
state automaton_2:BEING1;
// error 087: unknown state "STATE_1" for automaton "automaton_2"; did you mean "automaton_1:STATE_1"?
state automaton_2:STATE_1;
}

View File

@ -0,0 +1,8 @@
{
'test_type': 'output_check',
'errors': """
md_array_crash_gh_220.pwn(6) : fatal error 111: user error: OK
Compilation aborted.
"""
}

View File

@ -3,4 +3,5 @@ new b[2000][500] = { { 0, -1, ... }, ... };
main() {
a[0][0] = b[0][0];
}
#error OK
}

View File

@ -0,0 +1,10 @@
{
'test_type': 'output_check',
'errors': """
md_array_size_chk_gh_314.pwn(1) : error 009: invalid array size (negative, zero or out of bounds)
md_array_size_chk_gh_314.pwn(2) : error 009: invalid array size (negative, zero or out of bounds)
md_array_size_chk_gh_314.pwn(3) : error 009: invalid array size (negative, zero or out of bounds)
md_array_size_chk_gh_314.pwn(5) : error 009: invalid array size (negative, zero or out of bounds)
md_array_size_chk_gh_314.pwn(30) : warning 224: indeterminate array size in "sizeof" expression (symbol "")
"""
}

View File

@ -0,0 +1,40 @@
new arr1[];
new arr2[5][];
new arr3[5][][5];
new arr4[5][5];
new arr5[][];
f1(arr[]) {
#pragma unused arr
}
f2(arr[5][]) {
#pragma unused arr
}
f3(arr[5][][5]) {
#pragma unused arr
}
f4(arr[5][5]) {
#pragma unused arr
}
f5(arr[][]) {
#pragma unused arr
}
main () {
arr1[0] = 0;
arr2[0][0] = 0;
arr3[0][0][0] = 0;
arr4[0][0] = 0;
arr5[0][0] = 0;
new a = sizeof(arr1);
a = sizeof(arr1[]);
a = sizeof(arr5[][]);
#pragma unused a
f1(arr1);
f2(arr2);
f3(arr3);
f4(arr4);
f5(arr5);
}

View File

@ -0,0 +1,7 @@
{
'test_type': 'output_check',
'errors': """
meaningless_class_specifiers_gh_172.pwn(1) : warning 238: meaningless combination of class specifiers (const reference)
meaningless_class_specifiers_gh_172.pwn(4) : warning 238: meaningless combination of class specifiers (const variable arguments)
"""
}

View File

@ -0,0 +1,24 @@
f1(const &v) {
#pragma unused v
}
f2(const ...) { }
f3(const v) {
#pragma unused v
}
f4(...) { }
f5(v) {
#pragma unused v
}
f6(&v) {
#pragma unused v
}
main() {
new a;
f1(a);
f2(a);
f3(a);
f4(a);
f5(a);
f6(a);
}

View File

@ -0,0 +1,12 @@
{
'test_type': 'pcode_check',
'code_pattern': r"""
[0-9a-f]+ proc
[0-9a-f]+ push.c 00000000
[0-9a-f]+ push.c 00000004
[0-9a-f]+ sysreq.c 00000000
[0-9a-f]+ stack 00000008
[0-9a-f]+ zero.pri
[0-9a-f]+ retn
"""
}

View File

@ -0,0 +1,5 @@
#include <console>
main() {
printf("Hello World!");
}

View File

@ -0,0 +1,9 @@
{
'test_type': 'output_check',
'errors': """
reset_errline_gh_230.pwn(2) : error 017: undefined symbol \"undefined\"
reset_errline_gh_230.pwn(2) : warning 215: expression has no effect
reset_errline_gh_230.pwn(7) : warning 204: symbol is assigned a value that is never used: "y"
reset_errline_gh_230.pwn(4) : warning 204: symbol is assigned a value that is never used: "x"
"""
}

View File

@ -0,0 +1,239 @@
#!/usr/bin/env python
import argparse
import glob
import os.path
import re
import subprocess
import sys
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--compiler',
required=True,
help='path to compiler executable (pawncc)')
parser.add_argument('-d', '--disassembler',
help='path to disassembler executable (pawndisasm)')
parser.add_argument('-i', '--include',
dest='include_dirs',
action='append',
help='add custom include directories for compile tests')
parser.add_argument('-r', '--runner',
help='path to runner executable (pawnruns)')
parser.add_argument('tests', metavar='test_name', nargs='*')
options = parser.parse_args(sys.argv[1:])
def run_command(args, executable=None, merge_stderr=False):
process = subprocess.Popen(args,
executable=executable,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
stdout, stderr = process.communicate()
stdout = stdout.decode('utf-8')
stderr = stderr.decode('utf-8')
if merge_stderr:
output = ''
if stdout:
output += stdout
if stderr:
output += stderr
return (process, output)
else:
return (process, stdout, stderr)
def run_compiler(args):
final_args = [';+', '-(+']
if options.include_dirs is not None:
for dir in options.include_dirs:
final_args.append('-i' + dir)
if args is not None:
final_args += args
return run_command(executable=options.compiler, args=final_args)
def normalize_newlines(s):
return s.replace('\r', '')
def remove_asm_comments(s):
return re.sub(r'\s*;.*\n', '\n', s)
def strip(s):
return s.strip(' \t\r\n')
class OutputCheckTest:
def __init__(self, name, errors=None, extra_args=None):
self.name = name
self.errors = errors
self.extra_args = extra_args
def run(self):
args = [self.name + '.pwn']
if self.extra_args is not None:
args += extra_args
process, stdout, stderr = run_compiler(args=args)
if self.errors is None:
if process.returncode != 0:
result = False
self.fail_reason = """
No errors specified and process exited with non-zero status
"""
return False
errors = strip(stderr)
expected_errors = strip(self.errors)
if errors != expected_errors:
self.fail_reason = (
'Error output didn\'t match\n\nExpected errors:\n\n{}\n\n'
'Actual errors:\n\n{}'
).format(expected_errors, errors)
return False
return True
class PCodeCheckTest:
def __init__(self,
name,
code_pattern=None,
extra_args=None):
self.name = name
self.code_pattern = code_pattern
self.extra_args = extra_args
def run(self):
args = ['-d0', self.name + '.pwn']
if self.extra_args is not None:
args += extra_args
process, stdout, stderr = run_compiler(args=args)
if process.returncode != 0:
self.fail_reason = \
'Compiler exited with status {}'.format(process.returncode)
errors = stderr
if errors:
self.fail_reason += '\n\nErrors:\n\n{}'.format(errors)
return False
if options.disassembler is None:
self.fail_reason = 'Disassembler path is not set, can\'t run this test'
return False
process, output = run_command([
options.disassembler,
self.name + '.amx'
], merge_stderr=True)
if process.returncode != 0:
self.fail_reason = \
'Disassembler exited with status {}'.format(process.returncode)
if output:
self.fail_reason += '\n\nOutput:\n\n{}'.format(output)
return False
with open(self.name + '.lst', 'r') as dump_file:
dump = dump_file.read()
if self.code_pattern:
dump = remove_asm_comments(dump)
code_pattern = strip(normalize_newlines(self.code_pattern))
if re.search(code_pattern, dump, re.MULTILINE) is None:
self.fail_reason = (
'Code didn\'t match\n\nExpected code:\n\n{}\n\n'
'Actual code:\n\n{}'
).format(code_pattern, dump)
return False
else:
self.fail_reason = 'Code pattern is required'
return False
return True
class RuntimeTest:
def __init__(self, name, output, should_fail):
self.name = name
self.output = output
self.should_fail = should_fail
def run(self):
process, stdout, stderr = run_compiler([self.name + '.pwn'])
if process.returncode != 0:
self.fail_reason = \
'Compiler exited with status {}'.format(process.returncode)
errors = stderr
if errors:
self.fail_reason += '\n\nErrors:\n\n{}'.format(errors)
return False
if options.runner is None:
self.fail_reason = 'Runner path is not set, can\'t run this test'
return False
process, output = run_command([
options.runner, self.name + '.amx'
], merge_stderr=True)
if not self.should_fail and process.returncode != 0:
self.fail_reason = (
'Runner exited with status {}\n\nOutput: {}'
).format(process.returncode, output)
return False
output = strip(output)
expected_output = strip(self.output)
if output != expected_output:
self.fail_reason = (
'Output didn\'t match\n\nExpected output:\n\n{}\n\n'
'Actual output:\n\n{}'
).format(expected_output, output)
return False
return True
tests = []
num_tests_disabled = 0
for meta_file in glob.glob('*.meta'):
name = os.path.splitext(meta_file)[0]
if options.tests and name not in options.tests:
continue
metadata = eval(open(meta_file).read(), None, None)
if metadata.get('disabled'):
num_tests_disabled += 1
continue
test_type = metadata['test_type']
if test_type == 'output_check':
tests.append(OutputCheckTest(
name=name,
errors=metadata.get('errors'),
extra_args=metadata.get('extra_args')))
elif test_type == 'pcode_check':
tests.append(PCodeCheckTest(
name=name,
code_pattern=metadata.get('code_pattern'),
extra_args=metadata.get('extra_args')))
elif test_type == 'runtime':
tests.append(RuntimeTest(
name=name,
output=metadata.get('output'),
should_fail=metadata.get('should_fail')))
else:
raise KeyError('Unknown test type: ' + test_type)
num_tests = len(tests)
sys.stdout.write(
'DISCOVERED {} TEST{}'.format(num_tests, '' if num_tests == 1 else 'S'))
if num_tests_disabled > 0:
sys.stdout.write(' ({} DISABLED)'.format(num_tests_disabled))
if num_tests > 0:
sys.stdout.write('\n\n')
num_tests_failed = 0
for test in tests:
sys.stdout.write('Running ' + test.name + '... ')
if not test.run():
sys.stdout.write('FAILED\n')
print('Test {} failed for the following reason: {}'.format(
test.name, test.fail_reason))
print('')
num_tests_failed += 1
else:
sys.stdout.write('PASSED\n')
num_tests_passed = len(tests) - num_tests_failed
if num_tests_failed > 0:
print('\n{} TEST{} PASSED, {} FAILED'.format(
num_tests_passed,
'' if num_tests_passed == 1 else 'S',
num_tests_failed))
sys.exit(1)
else:
print('\nALL TESTS PASSED')

View File

@ -0,0 +1,7 @@
{
'test_type': 'runtime',
'output': """
Run time error 4: "Array index out of bounds"
""",
'should_fail': True
}

View File

@ -0,0 +1,10 @@
#include <console>
main() {
new a[1] = {1};
new i = 1;
// When compiled with at least debug level 1 (default) the line below should produce:
// Run time error 4: "Array index out of bounds"
printf("%d", a[i]);
}

View File

@ -0,0 +1,12 @@
{
'test_type': 'output_check',
'errors': """
too_many_args_crash_gh_298.pwn(2) : error 045: too many function arguments
too_many_args_crash_gh_298.pwn(2) : warning 215: expression has no effect
too_many_args_crash_gh_298.pwn(2) : error 001: expected token: ";", but found ")"
too_many_args_crash_gh_298.pwn(2) : error 029: invalid expression, assumed zero
too_many_args_crash_gh_298.pwn(2) : fatal error 107: too many error messages on one line
Compilation aborted.
"""
}

View File

@ -0,0 +1,3 @@
main() {
printf("", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}

View File

@ -0,0 +1,8 @@
{
'test_type': 'output_check',
'errors': """
unused_symbol_line_gh_252.pwn(4) : warning 203: symbol is never used: "y"
unused_symbol_line_gh_252.pwn(8) : warning 203: symbol is never used: "z"
unused_symbol_line_gh_252.pwn(1) : warning 203: symbol is never used: "x"
"""
}