This section addresses the language specification of OpenC++. OpenC++ is identical to C++ except two extensions. To connect a base-level program and a meta-level program, OpenC++ introduces a new kind of declaration into C++. Also, new extended syntax is available in OpenC++ if the syntax is defined by the meta-level program.
OpenC++ provides a new syntax for metaclass declaration. This
declaration form is the only connection between the base level
and the meta level. Although the default metaclass is Class
,
programmers can change it by using this declaration form:
metaclass
metaclass-name
[ class-name [ (
meta-arguments )
] ] ;
This declares the metaclass for a class. It must appear
before the class is defined. If the class name is not specified, this
declaration means nothing except that the metaclass is loaded
into the compiler. meta-arguments is a sequence of
identifiers, type names,
literals, and C++ expressions surrounded by ()
. The
elements must be separated by commas. The identifiers appearing in meta-arguments do not have to be declared in advance. What
should be placed at meta-arguments is specified by the metaclass.
The code shown below is an example of metaclass declaration:
metaclass PersistentClass Point;
class Point {
public:
int x, y;
};
The metaclass for Point
is PersistentClass
.
This syntax was chosen so that it looks like a variable declaration such
as:
class Point p0;
The former declaration defines a class metaobject Point
as
an instance of metaclass PersistentClass
, and the latter defines
an object p0
as an instance of class Point
.
The extended syntax described here is effective if programmers define it by the MOP. By default, it causes a syntax error. To make it available, the programmers must register a new keyword, which is used in one of the following forms:
(
function-arguments )
]
A keyword can be registered to lead a modifier. It may
appear in front of class declarations, the new
operator, or
function arguments. For example, these statements are valid:
distribute class Dictionary { ... };
Point* p = remote(athos) new Point;
void append(ref int i, int j);
Here, distribute
, remote
, and ref
are registered keywords.
Also, a modifier can be placed in front of a member declaration. For example,
class Point {
public:
sync int x, y;
};
The keyword sync
is a modifier.
(
function-arguments )
] :
Programmers may define a keyword as a member-access specifier. It
appears at the same place that the built-in access specifier such as public
can appears. For example, if after
is a
user-defined keyword, then programmers may write:
class Window {
public:
void Move();
after:
void Move() { ... } // after method
}
->
keyword (
expression ){
statements }
.
keyword (
expression ){
statements }
::
keyword (
expression ){
statements }
A user-defined keyword may lead something like the while
statement. In the grammar, that is not a statement but an expression.
It can appear at any place where C++ expressions appear. expression is any C++ expression. It may be empty or separated by
commas like function-call arguments.
Here is an example of the while-style statement:
Matrix m2;
m2.forall(e){
e = 0;
}
A user-defined keyword can also lead other styles of statements.
->
keyword (
expr ;
expr ;
expr ){
statements }
.
keyword (
expr ;
expr ;
expr ){
statements }
::
keyword (
expr ;
expr ;
expr ){
statements }
The for-style statement takes three expressions like the for
statement. Except that, it is the same as the while-style statement.
->
keyword (
arg-declaration-list ){
statements }
.
keyword (
arg-declaration-list ){
statements }
::
keyword (
arg-declaration-list ){
statements }
The closure statement takes an argument declaration list instead of an expression. That is the only difference from the while-style statement. For example, programmers may write something like this:
ButtonWidget b;
b.press(int x, int y){
printf("pressed at (%d, %d)\n", x, y);
}
This might be translated into this:
void callback(int x, int y){
printf("pressed at (%d, %d)\n", x, y);
}
:
ButtonWidget b;
b.press(callback); // register a callback function
Besides extended syntax, OpenC++'s grammar is somewhat loosened as compared with C++'s grammar. For example, the next code is semantically wrong in C++:
Point p = { 1, 3, 5 };
The C++ compiler will report that p
cannot be initialized by
{ 1, 3, 5 }
. Such an aggregate can be used only to
initialize an array.
The OpenC++ compiler simply accepts such a semantically-wrong code.
It ignores semantical correctness expecting that the code will be
translated into valid C++ code.