C// language specification

(That's C divided-by divided-by. C-- was already taken.)

C// is a simple language based on C (though valid C// programs aren't necessarily valid C programs). Due to it being based on C and compiling to C, many behaviors that are undefined or unspecified in C are also undefined or unspecified in C//.

C// accepts both types of C++ comments (// and /* */). Identifiers are sequences of characters that can contain letters, underscores, and digits, and cannot start with a digit. The following words are reserved and cannot be used as identifiers: struct, int, void, if, else, while, return

C// has two built-in types: void and int. void can only be used as a return type of a function, and indicates that the function doesn't return anything. int is a signed machine integer; if this overflows, behavior is undefined.



Structures can be defined the same way as in C:

struct name_of_struct {
	// variable declarations go here
	int x;
	int y;

Variable declarations cannot be combined (like int x, y;). The semicolon at the end of the struct definition is optional. Once a struct is defined, it can be used as a type, but it must always be preceded by the keyword struct (so, struct MyStruct var;, not MyStruct var;). There are no typedefs in C//.

Variables of structure types are always passed by value. If a struct-typed variable is passed to a function or copied to another variable, no changes made to either structure will be visible in the other structure. Implementations may decide, as an optimization, to pass structure values by reference instead of by value, as long as this does not change the behavior of the program (aside from memory usage and speed). For instance, the following code will print 1:

struct s {int x;};
void do_something(struct s var) {
	var.x = 2; // does not modify var1
int main() {
	struct s var1;
	struct s var2;
	var1.x = 1;
	var2 = var1;
	var2.x = 3; // does not modify var1
	return 0;

Structures must be defined before they're used in other structures or in function arguments and return values.


Functions are defined like they are in C:

type funciton_name(type1 arg1, type2 arg2) {

Functions may have any number of parameters. Functions cannot and do not need to have prototypes; functions defined anywhere in the file can call functions defined anywhere else in the file. If the return type is not void, the function must execute a 'return' statement before leaving the body; if it does not, the result is undefined.


The following statements exist, with the same semantics as C unless otherwise specified:

{ statements }
(same as C)
type name;
type name = expression;
Declares a variable. Multiple variables cannot be declared in the same statement.
lvalue = expression;
This is treated as a statement, not as an expression. The lvalue may only contain variable names and member access operators (e.g., foo().x is not a valid lvalue). Compound assignment operators are not supported.
if(condition) statement
if(condition) statement else statement
while(condition) statement
For all conditions, 0 is false and nonzero is true.
return expression;
This form of a return statement cannot be used in functions with the return type void
This form of a return statement can only be used in functions with the return type void
Evaluates an expression for its side effects. Only useful if the expression is a function call.


The following types of expression exist:

Precedence is the same as in C. Precedence can be overridden with parentheses.

Evaluation order for arguments to a function or operands to an operator (except && and ||) is unspecified.

IO and main

Each C// program must define a function with the signature int main() which will be called when the program executes. The return value of this function is passed to the system as the exit code of the program.

Each C// program has access to a function with the signature void print(int n) which displays a single integer followed by a newline. This function does not need to (and cannot) be declared.