Skip to content
Justin Schwartz edited this page Jun 27, 2020 · 1 revision

ACE Rules

Because ACE uses simple regular expressions to parse files (as opposed to a full grammar parser), it also imposes some restrictions on the C code it expects to receive. The style of code that the asss core uses already follows the formatting rules, which are fairly common expectations anyway. Therefore, module makers should have no trouble following the formatting rules.

The rules were set in place based on what generally doesn't happen in existing modules anyway. These rules may change to be more forgiving and flexible in future releases of ACE, depending on feedback and support.

Functions

Prototypes

ACE automatically prototypes functions that are defined in ACE code, other function prototypes encountered in the source will result in an error.

Types

All functions are static (or local as asss uses.) Using the local keyword in function declarations is optional and has no effect, the resulting output code will always contain local in the definition.

Formatting

Functions are expected to always contain their return type, name, and parameters on one line. Additionally, the parenthesis surrounding the parameter list must be touching the function name. Other formatting may still make it through to the output code, but will not be recognized specially, resulting in undefined behavior.

The closing brace } to a function must always be unindented, and a } must never be encountered as the first character of a line before the end of the function, or the result will be undefined.

Well-formed code

/* OK */
local int func1(int a)
{
	return 0;
}

int func2(int b) {
	return 1;
}

Code resulting in undefined behavior

/* NOT COOL */
local int badfunc3
	(int c)
{
	return 2;
}

int badfunc4(int d)
{

if (1 == 0)
{
	die("woops!");
}
return 3;
}

int badfunc5(int e)
	{
		return 4;
	}
	
int badfunc6 (int f)
{
	return 5;
}

Structures, Unions, and Enums

Structs

Structures declared will be moved to the top of code. Nested structures are permitted, but when using multiple lines to declare it will invoke a special behavior of assigning the struct a name in the global namespace. The item in the parent struct will then become nestedstructactualname varname in the actual code.

Assigned names to nested structs take the form struct__parentstructname__nestedstructname where nestedstructname is the name of the field in the parent struct and parentstructname may be blank if the name was not yet assigned.

Due to the simplicity of the parser, some non-C struct definition methods may be possible (such as using "typedef" in a nested struct), but are unsupported and may disappear later.

When using typedef struct NAME { ... } ALIAS; syntax, ACE enforces the restriction that the NAME must match the ALIAS to avoid confusion.

Struct examples

/* legal struct definition */
typedef struct A
{
	struct
	{
		//this becomes globally defined struct struct_A_B
		int C;	
	} B;
	
	struct { int D; } E; //this does not get specially treated, it is simply an anonymous struct
} A;

/* illegal definition #1 */
typedef struct F
{
	int G;
	int H;
} I;

/* illegal definition #2 */
typedef struct J
{
	short
	int
	K;
} J;

Unions and Enums

These are not explicitly parsed by ACE yet. Take care when declaring these in your .aces files, you may find it more convenient to declare them in a header file. If you are nesting these in a struct, following the rule of keeping the definition on one line should work.

At this time, if you want to use a union or enum in a struct you must declare it nested in the struct and on one line, or simply declare it in a header file and not the .aces file at all. You may use globally defined enums/unions in function bodies as normal, but take care if you are using them in function headers, referring to the enum "ENUMTYPE" as "enum ENUMTYPE" and using explicit typedefs ("typedef ENUMTYPE { } ENUMTYPE;" when declaring is the only supported way to go.

Additional support will be added at a future time depending on demand.

Miscellaneous Code

Any non-whitespace lines outside of directive blocks and functions will be moved to the output code, but will not necessarily be placed in the expected location. All "middle" code will be placed after function prototypes but before function bodies.

  • Declaring global variables will work all right.
  • Comments placed outside of a function but meant to talk about a function will generally end up detached completely from the function they were meant for.
  • #includes and #defines are moved to the top of the module, other preprocessor commands are not supported and will result in unexpected output code.
Clone this wiki locally