blob: edbd9d4a17d786b04c92aa36d449c894cb9263bc [file] [log] [blame]
%name CFCParseHeader
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
%token_type {char*}
%token_prefix CFC_TOKENTYPE_
%extra_argument { CFCParser *state }
%include {
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include "CFC.h"
#include "CFCLexHeader.h"
#ifndef true
#define true 1
#define false 0
#endif
static CFCClass*
S_start_class(CFCParser *state, CFCDocuComment *docucomment, char *exposure,
char *modifiers, char *class_name, char *class_nickname,
char *inheritance) {
CFCFileSpec *file_spec = CFCParser_get_file_spec(state);
int is_final = false;
int is_inert = false;
int is_abstract = false;
if (modifiers) {
if (strstr(modifiers, "inline")) {
CFCUtil_die("Illegal class modifiers: '%s'", modifiers);
}
is_final = !!strstr(modifiers, "final");
is_inert = !!strstr(modifiers, "inert");
is_abstract = !!strstr(modifiers, "abstract");
}
CFCParser_set_class_name(state, class_name);
CFCParser_set_class_final(state, is_final);
CFCClass *klass = CFCClass_create(CFCParser_get_parcel(state), exposure,
class_name, class_nickname, docucomment,
file_spec, inheritance, is_final,
is_inert, is_abstract);
CFCBase_decref((CFCBase*)docucomment);
return klass;
}
static CFCVariable*
S_new_var(char *exposure, char *modifiers, CFCType *type, char *name) {
int inert = false;
if (modifiers) {
if (strcmp(modifiers, "inert") != 0) {
CFCUtil_die("Illegal variable modifiers: '%s'", modifiers);
}
inert = true;
}
CFCVariable *var = CFCVariable_new(exposure, name, type, inert);
/* Consume tokens. */
CFCBase_decref((CFCBase*)type);
return var;
}
static CFCBase*
S_new_sub(CFCParser *state, CFCDocuComment *docucomment,
char *exposure, char *modifiers, CFCType *type, char *name,
CFCParamList *param_list) {
/* Find modifiers by scanning the list. */
int is_abstract = false;
int is_final = false;
int is_inline = false;
int is_inert = false;
if (modifiers) {
is_abstract = !!strstr(modifiers, "abstract");
is_final = !!strstr(modifiers, "final");
is_inline = !!strstr(modifiers, "inline");
is_inert = !!strstr(modifiers, "inert");
}
if (CFCParser_get_class_final(state) && !is_inert) {
is_final = true;
}
/* If "inert", it's a function, otherwise it's a method. */
CFCBase *sub;
if (is_inert) {
if (is_abstract) {
CFCUtil_die("Inert functions must not be abstract");
}
if (is_final) {
CFCUtil_die("Inert functions must not be final");
}
sub = (CFCBase*)CFCFunction_new(exposure, name, type, param_list,
docucomment, is_inline);
}
else {
if (is_inline) {
CFCUtil_die("Methods must not be inline");
}
const char *class_name = CFCParser_get_class_name(state);
sub = (CFCBase*)CFCMethod_new(exposure, name, type, param_list,
docucomment, class_name, is_final,
is_abstract);
}
/* Consume tokens. */
CFCBase_decref((CFCBase*)docucomment);
CFCBase_decref((CFCBase*)type);
CFCBase_decref((CFCBase*)param_list);
return sub;
}
static CFCType*
S_new_type(CFCParser *state, int flags, char *type_name,
char *asterisk_postfix, char *array_postfix) {
(void)state; /* unused */
CFCType *type = NULL;
size_t type_name_len = strlen(type_name);
int indirection = asterisk_postfix ? (int)strlen(asterisk_postfix) : 0;
/* Apply "nullable" to outermost pointer, but "const", etc to innermost
* type. This is an ugly kludge and the Clownfish header language needs to
* be fixed, either to support C's terrible pointer type syntax, or to do
* something better. */
int composite_flags = 0;
if (indirection) {
composite_flags = flags & CFCTYPE_NULLABLE;
flags &= ~CFCTYPE_NULLABLE;
}
if (!strcmp(type_name, "int8_t")
|| !strcmp(type_name, "int16_t")
|| !strcmp(type_name, "int32_t")
|| !strcmp(type_name, "int64_t")
|| !strcmp(type_name, "uint8_t")
|| !strcmp(type_name, "uint16_t")
|| !strcmp(type_name, "uint32_t")
|| !strcmp(type_name, "uint64_t")
|| !strcmp(type_name, "char")
|| !strcmp(type_name, "short")
|| !strcmp(type_name, "int")
|| !strcmp(type_name, "long")
|| !strcmp(type_name, "size_t")
|| !strcmp(type_name, "bool")
) {
type = CFCType_new_integer(flags, type_name);
}
else if (!strcmp(type_name, "float")
|| !strcmp(type_name, "double")
) {
type = CFCType_new_float(flags, type_name);
}
else if (!strcmp(type_name, "void")) {
type = CFCType_new_void(!!(flags & CFCTYPE_CONST));
}
else if (!strcmp(type_name, "va_list")) {
type = CFCType_new_va_list();
}
else if (type_name_len > 2
&& !strcmp(type_name + type_name_len - 2, "_t")
) {
type = CFCType_new_arbitrary(CFCParser_get_parcel(state), type_name);
}
else if (indirection > 0) {
/* The only remaining possibility is an object type, and we can let
* the constructor perform the complex validation of the type name. */
indirection--;
if (indirection == 0) {
flags |= composite_flags;
composite_flags = 0;
}
type = CFCType_new_object(flags, CFCParser_get_parcel(state), type_name, 1);
}
else {
CFCUtil_die("Invalid type specification at/near '%s'", type_name);
}
if (indirection) {
CFCType *composite = CFCType_new_composite(composite_flags, type,
indirection, NULL);
CFCBase_decref((CFCBase*)type);
type = composite;
}
else if (array_postfix) {
CFCType *composite = CFCType_new_composite(composite_flags, type,
0, array_postfix);
CFCBase_decref((CFCBase*)type);
type = composite;
}
return type;
}
} /* End include block. */
%syntax_error {
(void)yymajor;
(void)yyminor;
CFCParser_set_errors(state, true);
CFCParser_set_lineno(state, yyget_lineno());
}
%type result {CFCBase*}
%type file {CFCFile*}
%type major_block {CFCBase*}
%type parcel_definition {CFCParcel*}
%type class_declaration {CFCClass*}
%type class_head {CFCClass*}
%type class_defs {CFCClass*}
%type var_declaration_statement {CFCVariable*}
%type subroutine_declaration_statement {CFCBase*}
%type type {CFCType*}
%type param_variable {CFCVariable*}
%type param_list {CFCParamList*}
%type param_list_elems {CFCParamList*}
%type docucomment {CFCDocuComment*}
%type cblock {CFCCBlock*}
%type type_qualifier {int}
%type type_qualifier_list {int}
%destructor result {
(void)state; /* Suppress unused variable warning. */
CFCBase_decref((CFCBase*)$$);
}
%destructor file { CFCBase_decref((CFCBase*)$$); }
%destructor major_block { CFCBase_decref((CFCBase*)$$); }
%destructor parcel_definition { CFCBase_decref((CFCBase*)$$); }
%destructor class_declaration { CFCBase_decref((CFCBase*)$$); }
%destructor class_head { CFCBase_decref((CFCBase*)$$); }
%destructor class_defs { CFCBase_decref((CFCBase*)$$); }
%destructor var_declaration_statement { CFCBase_decref((CFCBase*)$$); }
%destructor subroutine_declaration_statement { CFCBase_decref((CFCBase*)$$); }
%destructor type { CFCBase_decref((CFCBase*)$$); }
%destructor param_variable { CFCBase_decref((CFCBase*)$$); }
%destructor param_list { CFCBase_decref((CFCBase*)$$); }
%destructor param_list_elems { CFCBase_decref((CFCBase*)$$); }
%destructor docucomment { CFCBase_decref((CFCBase*)$$); }
%destructor cblock { CFCBase_decref((CFCBase*)$$); }
result ::= type(A).
{
CFCParser_set_result(state, (CFCBase*)A);
CFCBase_decref((CFCBase*)A);
}
result ::= param_list(A).
{
CFCParser_set_result(state, (CFCBase*)A);
CFCBase_decref((CFCBase*)A);
}
result ::= param_variable(A).
{
CFCParser_set_result(state, (CFCBase*)A);
CFCBase_decref((CFCBase*)A);
}
result ::= docucomment(A).
{
CFCParser_set_result(state, (CFCBase*)A);
CFCBase_decref((CFCBase*)A);
}
result ::= parcel_definition(A).
{
CFCParser_set_result(state, (CFCBase*)A);
CFCBase_decref((CFCBase*)A);
}
result ::= cblock(A).
{
CFCParser_set_result(state, (CFCBase*)A);
CFCBase_decref((CFCBase*)A);
}
result ::= var_declaration_statement(A).
{
CFCParser_set_result(state, (CFCBase*)A);
CFCBase_decref((CFCBase*)A);
}
result ::= subroutine_declaration_statement(A).
{
CFCParser_set_result(state, (CFCBase*)A);
CFCBase_decref((CFCBase*)A);
}
result ::= class_declaration(A).
{
CFCParser_set_result(state, (CFCBase*)A);
CFCBase_decref((CFCBase*)A);
}
result ::= file(A).
{
CFCParser_set_result(state, (CFCBase*)A);
CFCBase_decref((CFCBase*)A);
}
/* FILE_START is a pseudo token, not passed by lexer. */
file(A) ::= FILE_START parcel_definition(B).
{
A = CFCFile_new(B, CFCParser_get_file_spec(state));
CFCBase_decref((CFCBase*)B);
}
file(A) ::= file(B) major_block(C).
{
A = B;
CFCFile_add_block(A, C);
CFCBase_decref((CFCBase*)C);
}
major_block(A) ::= class_declaration(B). { A = (CFCBase*)B; }
major_block(A) ::= cblock(B). { A = (CFCBase*)B; }
parcel_definition(A) ::= PARCEL qualified_id(B) SEMICOLON.
{
A = CFCParcel_fetch(B);
if (!A) {
/* Allow unregistered parcels to simplify tests. */
A = CFCParcel_new(B, NULL, NULL, NULL, NULL);
CFCParcel_register(A);
}
else {
CFCBase_incref((CFCBase*)A);
}
CFCParser_set_parcel(state, A);
}
class_declaration(A) ::= class_defs(B) RIGHT_CURLY_BRACE.
{
A = B;
CFCParser_set_class_name(state, NULL);
}
class_head(A) ::= docucomment(B) exposure_specifier(C) declaration_modifier_list(D) CLASS qualified_id(E) nickname(F) class_inheritance(G). { A = S_start_class(state, B, C, D, E, F, G ); }
class_head(A) ::= exposure_specifier(C) declaration_modifier_list(D) CLASS qualified_id(E) nickname(F) class_inheritance(G). { A = S_start_class(state, NULL, C, D, E, F, G ); }
class_head(A) ::= docucomment(B) declaration_modifier_list(D) CLASS qualified_id(E) nickname(F) class_inheritance(G). { A = S_start_class(state, B, NULL, D, E, F, G ); }
class_head(A) ::= declaration_modifier_list(D) CLASS qualified_id(E) nickname(F) class_inheritance(G). { A = S_start_class(state, NULL, NULL, D, E, F, G ); }
class_head(A) ::= docucomment(B) exposure_specifier(C) CLASS qualified_id(E) nickname(F) class_inheritance(G). { A = S_start_class(state, B, C, NULL, E, F, G ); }
class_head(A) ::= exposure_specifier(C) CLASS qualified_id(E) nickname(F) class_inheritance(G). { A = S_start_class(state, NULL, C, NULL, E, F, G ); }
class_head(A) ::= docucomment(B) CLASS qualified_id(E) nickname(F) class_inheritance(G). { A = S_start_class(state, B, NULL, NULL, E, F, G ); }
class_head(A) ::= CLASS qualified_id(E) nickname(F) class_inheritance(G). { A = S_start_class(state, NULL, NULL, NULL, E, F, G ); }
class_head(A) ::= docucomment(B) exposure_specifier(C) declaration_modifier_list(D) CLASS qualified_id(E) class_inheritance(G). { A = S_start_class(state, B, C, D, E, NULL, G ); }
class_head(A) ::= exposure_specifier(C) declaration_modifier_list(D) CLASS qualified_id(E) class_inheritance(G). { A = S_start_class(state, NULL, C, D, E, NULL, G ); }
class_head(A) ::= docucomment(B) declaration_modifier_list(D) CLASS qualified_id(E) class_inheritance(G). { A = S_start_class(state, B, NULL, D, E, NULL, G ); }
class_head(A) ::= declaration_modifier_list(D) CLASS qualified_id(E) class_inheritance(G). { A = S_start_class(state, NULL, NULL, D, E, NULL, G ); }
class_head(A) ::= docucomment(B) exposure_specifier(C) CLASS qualified_id(E) class_inheritance(G). { A = S_start_class(state, B, C, NULL, E, NULL, G ); }
class_head(A) ::= exposure_specifier(C) CLASS qualified_id(E) class_inheritance(G). { A = S_start_class(state, NULL, C, NULL, E, NULL, G ); }
class_head(A) ::= docucomment(B) CLASS qualified_id(E) class_inheritance(G). { A = S_start_class(state, B, NULL, NULL, E, NULL, G ); }
class_head(A) ::= CLASS qualified_id(E) class_inheritance(G). { A = S_start_class(state, NULL, NULL, NULL, E, NULL, G ); }
class_head(A) ::= docucomment(B) exposure_specifier(C) declaration_modifier_list(D) CLASS qualified_id(E) nickname(F) . { A = S_start_class(state, B, C, D, E, F, NULL ); }
class_head(A) ::= exposure_specifier(C) declaration_modifier_list(D) CLASS qualified_id(E) nickname(F) . { A = S_start_class(state, NULL, C, D, E, F, NULL ); }
class_head(A) ::= docucomment(B) declaration_modifier_list(D) CLASS qualified_id(E) nickname(F) . { A = S_start_class(state, B, NULL, D, E, F, NULL ); }
class_head(A) ::= declaration_modifier_list(D) CLASS qualified_id(E) nickname(F) . { A = S_start_class(state, NULL, NULL, D, E, F, NULL ); }
class_head(A) ::= docucomment(B) exposure_specifier(C) CLASS qualified_id(E) nickname(F) . { A = S_start_class(state, B, C, NULL, E, F, NULL ); }
class_head(A) ::= exposure_specifier(C) CLASS qualified_id(E) nickname(F) . { A = S_start_class(state, NULL, C, NULL, E, F, NULL ); }
class_head(A) ::= docucomment(B) CLASS qualified_id(E) nickname(F) . { A = S_start_class(state, B, NULL, NULL, E, F, NULL ); }
class_head(A) ::= CLASS qualified_id(E) nickname(F) . { A = S_start_class(state, NULL, NULL, NULL, E, F, NULL ); }
class_head(A) ::= docucomment(B) exposure_specifier(C) declaration_modifier_list(D) CLASS qualified_id(E) . { A = S_start_class(state, B, C, D, E, NULL, NULL ); }
class_head(A) ::= exposure_specifier(C) declaration_modifier_list(D) CLASS qualified_id(E) . { A = S_start_class(state, NULL, C, D, E, NULL, NULL ); }
class_head(A) ::= docucomment(B) declaration_modifier_list(D) CLASS qualified_id(E) . { A = S_start_class(state, B, NULL, D, E, NULL, NULL ); }
class_head(A) ::= declaration_modifier_list(D) CLASS qualified_id(E) . { A = S_start_class(state, NULL, NULL, D, E, NULL, NULL ); }
class_head(A) ::= docucomment(B) exposure_specifier(C) CLASS qualified_id(E) . { A = S_start_class(state, B, C, NULL, E, NULL, NULL ); }
class_head(A) ::= exposure_specifier(C) CLASS qualified_id(E) . { A = S_start_class(state, NULL, C, NULL, E, NULL, NULL ); }
class_head(A) ::= docucomment(B) CLASS qualified_id(E) . { A = S_start_class(state, B, NULL, NULL, E, NULL, NULL ); }
class_head(A) ::= CLASS qualified_id(E) . { A = S_start_class(state, NULL, NULL, NULL, E, NULL, NULL ); }
class_defs(A) ::= class_head(B) LEFT_CURLY_BRACE.
{
A = B;
}
class_defs(A) ::= class_defs(B) var_declaration_statement(C).
{
A = B;
if (CFCVariable_inert(C)) {
CFCClass_add_inert_var(A, C);
}
else {
CFCClass_add_member_var(A, C);
}
CFCBase_decref((CFCBase*)C);
}
class_defs(A) ::= class_defs(B) subroutine_declaration_statement(C).
{
A = B;
if (strcmp(CFCBase_get_cfc_class(C), "Clownfish::CFC::Model::Function") == 0) {
CFCClass_add_function(A, (CFCFunction*)C);
}
else {
CFCClass_add_method(A, (CFCMethod*)C);
}
CFCBase_decref((CFCBase*)C);
}
var_declaration_statement(A) ::=
type(D) declarator(E) SEMICOLON.
{
A = S_new_var(CFCParser_dupe(state, "private"), NULL, D, E);
}
var_declaration_statement(A) ::=
declaration_modifier_list(C)
type(D) declarator(E) SEMICOLON.
{
A = S_new_var(CFCParser_dupe(state, "parcel"), C, D, E);
}
var_declaration_statement(A) ::=
exposure_specifier(B)
declaration_modifier_list(C)
type(D) declarator(E) SEMICOLON.
{
A = S_new_var(B, C, D, E);
}
subroutine_declaration_statement(A) ::=
type(E) declarator(F) param_list(G) SEMICOLON.
{
A = S_new_sub(state, NULL, NULL, NULL, E, F, G);
}
subroutine_declaration_statement(A) ::=
declaration_modifier_list(D)
type(E) declarator(F) param_list(G) SEMICOLON.
{
A = S_new_sub(state, NULL, NULL, D, E, F, G);
}
subroutine_declaration_statement(A) ::=
exposure_specifier(C)
declaration_modifier_list(D)
type(E) declarator(F) param_list(G) SEMICOLON.
{
A = S_new_sub(state, NULL, C, D, E, F, G);
}
subroutine_declaration_statement(A) ::=
exposure_specifier(C)
type(E) declarator(F) param_list(G) SEMICOLON.
{
A = S_new_sub(state, NULL, C, NULL, E, F, G);
}
subroutine_declaration_statement(A) ::=
docucomment(B)
type(E) declarator(F) param_list(G) SEMICOLON.
{
A = S_new_sub(state, B, NULL, NULL, E, F, G);
}
subroutine_declaration_statement(A) ::=
docucomment(B)
declaration_modifier_list(D)
type(E) declarator(F) param_list(G) SEMICOLON.
{
A = S_new_sub(state, B, NULL, D, E, F, G);
}
subroutine_declaration_statement(A) ::=
docucomment(B)
exposure_specifier(C)
declaration_modifier_list(D)
type(E) declarator(F) param_list(G) SEMICOLON.
{
A = S_new_sub(state, B, C, D, E, F, G);
}
subroutine_declaration_statement(A) ::=
docucomment(B)
exposure_specifier(C)
type(E) declarator(F) param_list(G) SEMICOLON.
{
A = S_new_sub(state, B, C, NULL, E, F, G);
}
type(A) ::= type_name(C).
{
A = S_new_type(state, 0, C, NULL, NULL);
}
type(A) ::= type_name(C) asterisk_postfix(D).
{
A = S_new_type(state, 0, C, D, NULL);
}
type(A) ::= type_name(C) array_postfix(E).
{
A = S_new_type(state, 0, C, NULL, E);
}
type(A) ::= type_qualifier_list(B) type_name(C).
{
A = S_new_type(state, B, C, NULL, NULL);
}
type(A) ::= type_qualifier_list(B) type_name(C) asterisk_postfix(D).
{
A = S_new_type(state, B, C, D, NULL);
}
type(A) ::= type_qualifier_list(B) type_name(C) array_postfix(E).
{
A = S_new_type(state, B, C, NULL, E);
}
type_name(A) ::= VOID(B). { A = B; }
type_name(A) ::= VA_LIST(B). { A = B; }
type_name(A) ::= INTEGER_TYPE_NAME(B). { A = B; }
type_name(A) ::= FLOAT_TYPE_NAME(B). { A = B; }
type_name(A) ::= IDENTIFIER(B). { A = B; }
exposure_specifier(A) ::= PUBLIC(B). { A = B; }
type_qualifier(A) ::= CONST. { A = CFCTYPE_CONST; }
type_qualifier(A) ::= NULLABLE. { A = CFCTYPE_NULLABLE; }
type_qualifier(A) ::= INCREMENTED. { A = CFCTYPE_INCREMENTED; }
type_qualifier(A) ::= DECREMENTED. { A = CFCTYPE_DECREMENTED; }
type_qualifier_list(A) ::= type_qualifier(B).
{
A = B;
}
type_qualifier_list(A) ::= type_qualifier_list(B) type_qualifier(C).
{
A = B;
A |= C;
}
declaration_modifier(A) ::= INERT(B). { A = B; }
declaration_modifier(A) ::= INLINE(B). { A = B; }
declaration_modifier(A) ::= ABSTRACT(B). { A = B; }
declaration_modifier(A) ::= FINAL(B). { A = B; }
declaration_modifier_list(A) ::= declaration_modifier(B). { A = B; }
declaration_modifier_list(A) ::= declaration_modifier_list(B) declaration_modifier(C).
{
size_t size = strlen(B) + strlen(C) + 2;
A = (char*)CFCParser_allocate(state, size);
sprintf(A, "%s %s", B, C);
}
asterisk_postfix(A) ::= ASTERISK(B). { A = B; }
asterisk_postfix(A) ::= asterisk_postfix(B) ASTERISK.
{
size_t size = strlen(B) + 2;
A = (char*)CFCParser_allocate(state, size);
sprintf(A, "%s*", B);
}
array_postfix_elem(A) ::= LEFT_SQUARE_BRACKET RIGHT_SQUARE_BRACKET.
{
A = CFCParser_dupe(state, "[]");
}
array_postfix_elem(A) ::= LEFT_SQUARE_BRACKET INTEGER_LITERAL(B) RIGHT_SQUARE_BRACKET.
{
size_t size = strlen(B) + 3;
A = (char*)CFCParser_allocate(state, size);
sprintf(A, "[%s]", B);
}
array_postfix(A) ::= array_postfix_elem(B). { A = B; }
array_postfix(A) ::= array_postfix(B) array_postfix_elem(C).
{
size_t size = strlen(B) + strlen(C) + 1;
A = (char*)CFCParser_allocate(state, size);
sprintf(A, "%s%s", B, C);
}
scalar_constant(A) ::= HEX_LITERAL(B). { A = B; }
scalar_constant(A) ::= FLOAT_LITERAL(B). { A = B; }
scalar_constant(A) ::= INTEGER_LITERAL(B). { A = B; }
scalar_constant(A) ::= STRING_LITERAL(B). { A = B; }
scalar_constant(A) ::= TRUE(B). { A = B; }
scalar_constant(A) ::= FALSE(B). { A = B; }
scalar_constant(A) ::= NULL(B). { A = B; }
declarator(A) ::= IDENTIFIER(B).
{
A = B;
}
param_variable(A) ::= type(B) declarator(C).
{
A = S_new_var(NULL, NULL, B, C);
}
param_list(A) ::= LEFT_PAREN RIGHT_PAREN.
{
A = CFCParamList_new(false);
}
param_list(A) ::= LEFT_PAREN param_list_elems(B) RIGHT_PAREN.
{
A = B;
}
param_list(A) ::= LEFT_PAREN param_list_elems(B) COMMA ELLIPSIS RIGHT_PAREN.
{
A = B;
CFCParamList_set_variadic(A, true);
}
param_list_elems(A) ::= param_list_elems(B) COMMA param_variable(C).
{
A = B;
CFCParamList_add_param(A, C, NULL);
CFCBase_decref((CFCBase*)C);
}
param_list_elems(A) ::= param_list_elems(B) COMMA param_variable(C) EQUALS scalar_constant(D).
{
A = B;
CFCParamList_add_param(A, C, D);
CFCBase_decref((CFCBase*)C);
}
param_list_elems(A) ::= param_variable(B).
{
A = CFCParamList_new(false);
CFCParamList_add_param(A, B, NULL);
CFCBase_decref((CFCBase*)B);
}
param_list_elems(A) ::= param_variable(B) EQUALS scalar_constant(C).
{
A = CFCParamList_new(false);
CFCParamList_add_param(A, B, C);
CFCBase_decref((CFCBase*)B);
}
qualified_id(A) ::= IDENTIFIER(B). { A = B; }
qualified_id(A) ::= qualified_id(B) SCOPE_OP IDENTIFIER(C).
{
size_t size = strlen(B) + strlen(C) + 3;
A = (char*)CFCParser_allocate(state, size);
sprintf(A, "%s::%s", B, C);
}
docucomment(A) ::= DOCUCOMMENT(B). { A = CFCDocuComment_parse(B); }
class_inheritance(A) ::= INHERITS qualified_id(B). { A = B; }
nickname(A) ::= NICKNAME IDENTIFIER(B). { A = B; }
cblock(A) ::= CBLOCK_START blob(B) CBLOCK_CLOSE. { A = CFCCBlock_new(B); }
cblock(A) ::= CBLOCK_START CBLOCK_CLOSE. { A = CFCCBlock_new(""); }
blob(A) ::= BLOB(B). { A = B; }
blob(A) ::= blob(B) BLOB(C).
{
size_t size = strlen(B) + strlen(C) + 1;
A = (char*)CFCParser_allocate(state, size);
sprintf(A, "%s%s", B, C);
}