/** Copyright (c) 2003 Matthijs Hollemans** Permission is hereby granted, free of charge, to any person obtaining a* copy of this software and associated documentation files (the "Software"),* to deal in the Software without restriction, including without limitation* the rights to use, copy, modify, merge, publish, distribute, sublicense,* and/or sell copies of the Software, and to permit persons to whom the* Software is furnished to do so, subject to the following conditions:** The above copyright notice and this permission notice shall be included in* all copies or substantial portions of the Software.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER* DEALINGS IN THE SOFTWARE.*/%{#include <Message.h>#include <map>#include <string.h>#include <stdio.h>#include <stdlib.h>#include "rdef.h"#include "compile.h"#include "private.h"using namespace std;#define YYERROR_VERBOSEstatic void yyerror(const char*);struct ident_compare_t { // allows the maps to compare identifier namesbooloperator()(const char* s1, const char* s2) const{return strcmp(s1, s2) < 0;}};typedef std::map<const char*, int32, ident_compare_t> sym_tab_t;typedef sym_tab_t::iterator sym_iter_t;typedef std::map<const char*, type_t, ident_compare_t> type_tab_t;typedef type_tab_t::iterator type_iter_t;typedef std::map<const char*, define_t, ident_compare_t> define_tab_t;typedef define_tab_t::iterator define_iter_t;static sym_tab_t symbol_table; // symbol table for enumsstatic int32 enum_cnt; // counter for enum symbols without idstatic type_tab_t type_table; // symbol table for data typesstatic define_tab_t define_table; // symbol table for definesstatic void add_user_type(res_id_t, type_code, const char*, list_t);static void add_symbol(const char*, int32);static int32 get_symbol(const char*);static bool is_type(const char* name);static define_t get_define(const char* name);static data_t make_data(size_t, type_t);static data_t make_bool(bool);static data_t make_int(uint64);static data_t make_float(double);static data_t import_data(char*);static data_t resize_data(data_t, size_t);static BMessage* make_msg(list_t);static data_t flatten_msg(BMessage*);static data_t make_default(type_t);static data_t make_type(char* name, list_t);static list_t make_field_list(field_t);static list_t concat_field_list(list_t, field_t);static list_t make_data_list(data_t);static list_t concat_data_list(list_t, data_t);static data_t concat_data(data_t, data_t);static data_t cast(type_t, data_t);static data_t unary_expr(data_t, char);static data_t binary_expr(data_t, data_t, char);static void add_resource(res_id_t, type_code, data_t);//------------------------------------------------------------------------------%}%expect 15%union {bool b;uint64 i;double f;char* I;type_code t;res_id_t id;data_t d;list_t l;field_t F;type_t T;}%token ENUM RESOURCE ARCHIVE ARRAY MESSAGE RTYPE IMPORT%token <b> BOOL%token <i> INTEGER%token <f> FLOAT%token <d> STRING RAW%token <I> IDENT%token <t> TYPECODE%type <i> integer%type <f> float%type <id> id%type <d> archive array arrayfields data expr message msgfield%type <d> type typefield type_or_define%type <l> msgfields typefields typedeffields%type <F> typedeffield%type <T> datatype typecast%left '|'%left '^'%left '&'%left '+' '-'%left '*' '/' '%'%right FLIP%%script: /* empty */| script enum| script typedef| script resource;enum: enumstart '{' '}' ';'| enumstart '{' symbols '}' ';'| enumstart '{' symbols ',' '}' ';';enumstart: ENUM { enum_cnt = 0; };symbols: symbols ',' symboldef| symboldef;symboldef: IDENT{add_symbol($1, enum_cnt);++enum_cnt;}| IDENT '=' integer{int32 id = (int32) $3;add_symbol($1, id);enum_cnt = id + 1;};typedef: RTYPE id TYPECODE IDENT '{' typedeffields '}' ';'{add_user_type($2, $3, $4, $6);}| RTYPE id IDENT '{' typedeffields '}' ';'{add_user_type($2, B_RAW_TYPE, $3, $5);};typedeffields: typedeffields ',' typedeffield { $$ = concat_field_list($1, $3); }| typedeffield { $$ = make_field_list($1); };typedeffield: datatype IDENT{$$.type = $1;$$.name = $2;$$.resize = 0;$$.data = make_default($1);}| datatype IDENT '=' expr{$$.type = $1;$$.name = $2;$$.resize = 0;$$.data = cast($1, $4);}| datatype IDENT '[' INTEGER ']'{$$.type = $1;$$.name = $2;$$.resize = (size_t) $4;$$.data = resize_data(make_default($1), $$.resize);}| datatype IDENT '[' INTEGER ']' '=' expr{$$.type = $1;$$.name = $2;$$.resize = (size_t) $4;$$.data = resize_data(cast($1, $7), $$.resize);};resource: RESOURCE id expr ';'{add_resource($2, $3.type.code, $3);}| RESOURCE id TYPECODE expr ';'{add_resource($2, $3, $4);}| RESOURCE id '(' TYPECODE ')' expr ';'{add_resource($2, $4, $6);};id: /* empty */{$$.has_id = false; $$.has_name = false; $$.name = NULL;}| '(' ')'{$$.has_id = false; $$.has_name = false; $$.name = NULL;}| '(' integer ')'{$$.has_id = true; $$.id = (int32) $2;$$.has_name = false; $$.name = NULL;}| '(' integer ',' STRING ')'{$$.has_id = true; $$.id = (int32) $2;$$.has_name = true; $$.name = (char*) $4.ptr;}| '(' IDENT ')'{$$.has_id = true; $$.id = get_symbol($2);if (flags & RDEF_AUTO_NAMES){$$.has_name = true; $$.name = $2;}else{$$.has_name = false; $$.name = NULL;free_mem($2);}}| '(' IDENT ',' STRING ')'{$$.has_id = true; $$.id = get_symbol($2);$$.has_name = true; $$.name = (char*) $4.ptr;free_mem($2);}| '(' STRING ')'{$$.has_id = false;$$.has_name = true; $$.name = (char*) $2.ptr;};array: ARRAY '{' arrayfields '}' { $$ = $3; }| ARRAY '{' '}' { $$ = make_data(0, get_type("raw")); }| ARRAY { $$ = make_data(0, get_type("raw")); }| ARRAY IMPORT STRING { $$ = import_data((char*) $3.ptr); }| IMPORT STRING { $$ = import_data((char*) $2.ptr); };arrayfields: arrayfields ',' expr { $$ = concat_data($1, $3); }| expr { $$ = $1; $$.type = get_type("raw"); };message: MESSAGE '(' integer ')' '{' msgfields '}'{BMessage* msg = make_msg($6);msg->what = (int32) $3;$$ = flatten_msg(msg);}| MESSAGE '(' integer ')' '{' '}'{BMessage* msg = new BMessage;msg->what = (int32) $3;$$ = flatten_msg(msg);}| MESSAGE '(' integer ')'{BMessage* msg = new BMessage;msg->what = (int32) $3;$$ = flatten_msg(msg);}| MESSAGE '{' msgfields '}' { $$ = flatten_msg(make_msg($3)); }| MESSAGE '{' '}' { $$ = flatten_msg(new BMessage); }| MESSAGE { $$ = flatten_msg(new BMessage); };msgfields: msgfields ',' msgfield { $$ = concat_data_list($1, $3); }| msgfield { $$ = make_data_list($1); };msgfield: STRING '=' expr{$$ = $3;$$.name = (char*) $1.ptr;}| datatype STRING '=' expr{$$ = cast($1, $4);$$.name = (char*) $2.ptr;}| TYPECODE STRING '=' expr{$$ = $4;$$.type.code = $1;$$.name = (char*) $2.ptr;}| TYPECODE datatype STRING '=' expr{$$ = cast($2, $5);$$.type.code = $1;$$.name = (char*) $3.ptr;};archive: ARCHIVE IDENT '{' msgfields '}'{BMessage* msg = make_msg($4);msg->AddString("class", $2);free_mem($2);$$ = flatten_msg(msg);}| ARCHIVE '(' STRING ')' IDENT '{' msgfields '}'{BMessage* msg = make_msg($7);msg->AddString("class", $5);msg->AddString("add_on", (char*) $3.ptr);free_mem($5);free_mem($3.ptr);$$ = flatten_msg(msg);}| ARCHIVE '(' ',' integer ')' IDENT '{' msgfields '}'{BMessage* msg = make_msg($8);msg->what = (int32) $4;msg->AddString("class", $6);free_mem($6);$$ = flatten_msg(msg);}| ARCHIVE '(' STRING ',' integer ')' IDENT '{' msgfields '}'{BMessage* msg = make_msg($9);msg->what = (int32) $5;msg->AddString("class", $7);msg->AddString("add_on", (char*) $3.ptr);free_mem($7);free_mem($3.ptr);$$ = flatten_msg(msg);};type: IDENT '{' typefields '}' { $$ = make_type($1, $3); }| IDENT '{' '}'{list_t list; list.count = 0; list.items = NULL;$$ = make_type($1, list);}| IDENT expr{$$ = make_type($1, make_data_list($2));}| type_or_define { $$ = $1; };type_or_define: IDENT{if (is_type($1)){list_t list; list.count = 0; list.items = NULL;$$ = make_type($1, list);}else{define_t define = get_define($1);$$ = cast(get_type("int32"), make_int(define.value));free_mem($1);}};typefields: typefields ',' typefield { $$ = concat_data_list($1, $3); }| typefield { $$ = make_data_list($1); };typefield: IDENT '=' expr { $$ = $3; $$.name = $1; }| expr { $$ = $1; };expr: expr '+' expr { $$ = binary_expr($1, $3, '+'); }| expr '-' expr { $$ = binary_expr($1, $3, '-'); }| expr '*' expr { $$ = binary_expr($1, $3, '*'); }| expr '/' expr { $$ = binary_expr($1, $3, '/'); }| expr '%' expr { $$ = binary_expr($1, $3, '%'); }| expr '|' expr { $$ = binary_expr($1, $3, '|'); }| expr '^' expr { $$ = binary_expr($1, $3, '^'); }| expr '&' expr { $$ = binary_expr($1, $3, '&'); }| '~' expr %prec FLIP { $$ = unary_expr($2, '~'); }| data { $$ = $1; };data: BOOL { $$ = cast(get_type("bool"), make_bool($1)); }| integer { $$ = cast(get_type("int32"), make_int($1)); }| float { $$ = cast(get_type("float"), make_float($1)); }| STRING { $$ = cast($1.type, $1); }| RAW { $$ = cast($1.type, $1); }| array { $$ = cast($1.type, $1); }| message { $$ = cast($1.type, $1); }| archive { $$ = cast($1.type, $1); }| type { $$ = cast($1.type, $1); }| '(' expr ')' { $$ = $2; }| typecast BOOL { $$ = cast($1, make_bool($2)); }| typecast integer { $$ = cast($1, make_int($2)); }| typecast float { $$ = cast($1, make_float($2)); }| typecast STRING { $$ = cast($1, $2); }| typecast RAW { $$ = cast($1, $2); }| typecast array { $$ = cast($1, $2); }| typecast message { $$ = cast($1, $2); }| typecast archive { $$ = cast($1, $2); }| typecast type { $$ = cast($1, $2); }| typecast '(' expr ')' { $$ = cast($1, $3); };typecast: '(' ARRAY ')' { $$ = get_type("raw"); }| '(' MESSAGE ')' { $$ = get_type("message"); }| '(' ARCHIVE IDENT ')' { $$ = get_type("message"); free_mem($3); }| '(' IDENT ')' { $$ = get_type($2); free_mem($2); };datatype: ARRAY { $$ = get_type("raw"); }| MESSAGE { $$ = get_type("message"); }| ARCHIVE IDENT { $$ = get_type("message"); free_mem($2); }| IDENT { $$ = get_type($1); free_mem($1); };integer: INTEGER { $$ = $1; }| '-' INTEGER { $$ = -($2); };float: FLOAT { $$ = $1; }| '-' FLOAT { $$ = -($2); };%%//------------------------------------------------------------------------------voidyyerror(const char* msg){// This function is called by the parser when it encounters// an error, after which it aborts parsing and returns from// yyparse(). We never call yyerror() directly.rdef_err = RDEF_COMPILE_ERR;rdef_err_line = yylineno;strcpy(rdef_err_file, lexfile);strcpy(rdef_err_msg, msg);}voidadd_symbol(const char* name, int32 id){if (symbol_table.find(name) != symbol_table.end())abort_compile(RDEF_COMPILE_ERR, "duplicate symbol %s", name);symbol_table.insert(make_pair(name, id));}int32get_symbol(const char* name){sym_iter_t i = symbol_table.find(name);if (i == symbol_table.end())abort_compile(RDEF_COMPILE_ERR, "unknown symbol %s", name);return i->second;}static voidadd_builtin_type(type_code code, const char* name){type_t type;type.code = code;type.name = name;type.count = 0;type.fields = NULL;type.def_id = 1;type.def_name = NULL;type_table.insert(make_pair(name, type));}voidadd_user_type(res_id_t id, type_code code, const char* name, list_t list){if (type_table.find(name) != type_table.end())abort_compile(RDEF_COMPILE_ERR, "duplicate type %s", name);type_t type;type.code = code;type.name = name;type.count = list.count;type.fields = (field_t*) list.items;type.def_id = 1;type.def_name = NULL;if (id.has_id)type.def_id = id.id;if (id.has_name)type.def_name = id.name;type_table.insert(make_pair(name, type));}static boolis_builtin_type(type_t type){return type.count == 0;}static boolsame_type(type_t type1, type_t type2){return type1.name == type2.name; // no need for strcmp}type_tget_type(const char* name){type_iter_t i = type_table.find(name);if (i == type_table.end())abort_compile(RDEF_COMPILE_ERR, "unknown type %s", name);return i->second;}boolis_type(const char* name){return type_table.find(name) != type_table.end();}define_tget_define(const char* name){define_iter_t i = define_table.find(name);if (i == define_table.end())abort_compile(RDEF_COMPILE_ERR, "unknown define %s", name);return i->second;}data_tmake_data(size_t size, type_t type){data_t out;out.type = type;out.name = NULL;out.size = size;out.ptr = alloc_mem(size);return out;}data_tmake_bool(bool b){data_t out = make_data(sizeof(bool), get_type("bool"));*((bool*)out.ptr) = b;return out;}data_tmake_int(uint64 i){data_t out = make_data(sizeof(uint64), get_type("uint64"));*((uint64*)out.ptr) = i;return out;}data_tmake_float(double f){data_t out = make_data(sizeof(double), get_type("double"));*((double*)out.ptr) = f;return out;}data_timport_data(char* filename){data_t out;out.type = get_type("raw");out.name = NULL;char tmpname[B_PATH_NAME_LENGTH];if (open_file_from_include_dir(filename, tmpname)) {BFile file(tmpname, B_READ_ONLY);if (file.InitCheck() == B_OK) {off_t size;if (file.GetSize(&size) == B_OK) {out.size = (size_t) size;out.ptr = alloc_mem(size);if (file.Read(out.ptr, out.size) == (ssize_t) out.size) {free_mem(filename);return out;}}}}abort_compile(RDEF_COMPILE_ERR, "cannot import %s", filename);return out;}data_tresize_data(data_t data, size_t newSize){if (newSize == 0) {abort_compile(RDEF_COMPILE_ERR, "invalid size %lu", newSize);} else if (data.size != newSize) {void* newBuffer = alloc_mem(newSize);memset(newBuffer, 0, newSize);memcpy(newBuffer, data.ptr, min(data.size, newSize));if (data.type.code == B_STRING_TYPE)((char*)newBuffer)[newSize - 1] = '\0';free_mem(data.ptr);data.ptr = newBuffer;data.size = newSize;}return data;}BMessage*make_msg(list_t list){BMessage* msg = new BMessage;for (int32 t = 0; t < list.count; ++t) {data_t data = ((data_t*)list.items)[t];msg->AddData(data.name, data.type.code, data.ptr, data.size, false);free_mem(data.name);free_mem(data.ptr);}free_mem(list.items);return msg;}data_tflatten_msg(BMessage* msg){#ifndef B_BEOS_VERSION_DANOdata_t out = make_data(msg->FlattenedSize(), get_type("message"));msg->Flatten((char*)out.ptr, out.size);#elsedata_t out = make_data(msg->FlattenedSize(B_MESSAGE_VERSION_1),get_type("message"));msg->Flatten(B_MESSAGE_VERSION_1, (char*)out.ptr, out.size);#endifdelete msg;return out;}data_tmake_default(type_t type){data_t out;if (is_builtin_type(type)) {switch (type.code) {case B_BOOL_TYPE:out = make_data(sizeof(bool), type);*((bool*)out.ptr) = false;break;case B_INT8_TYPE:case B_UINT8_TYPE:out = make_data(sizeof(uint8), type);*((uint8*)out.ptr) = 0;break;case B_INT16_TYPE:case B_UINT16_TYPE:out = make_data(sizeof(uint16), type);*((uint16*)out.ptr) = 0;break;case B_INT32_TYPE:case B_UINT32_TYPE:case B_SIZE_T_TYPE:case B_SSIZE_T_TYPE:case B_TIME_TYPE:out = make_data(sizeof(uint32), type);*((uint32*)out.ptr) = 0;break;case B_INT64_TYPE:case B_UINT64_TYPE:case B_OFF_T_TYPE:out = make_data(sizeof(uint64), type);*((uint64*)out.ptr) = 0;break;case B_FLOAT_TYPE:out = make_data(sizeof(float), type);*((float*)out.ptr) = 0.0f;break;case B_DOUBLE_TYPE:out = make_data(sizeof(double), type);*((double*)out.ptr) = 0.0;break;case B_STRING_TYPE:out = make_data(sizeof(char), type);*((char*)out.ptr) = '\0';break;case B_RAW_TYPE:out = make_data(0, type);break;case B_MESSAGE_TYPE:out = flatten_msg(new BMessage);break;}} else {// For user-defined types, we copy the default values of the fields// into a new data_t object. There is no need to call resize_data()// here, because the default values were already resized to their// proper length when we added them to the type.size_t size = 0;for (int32 t = 0; t < type.count; ++t) {size += type.fields[t].data.size;}out = make_data(size, type);uint8* ptr = (uint8*) out.ptr;for (int32 t = 0; t < type.count; ++t) {data_t field_data = type.fields[t].data;memcpy(ptr, field_data.ptr, field_data.size);ptr += field_data.size;}}return out;}static data_t*fill_slots(type_t type, list_t list){data_t* slots = (data_t*)alloc_mem(type.count * sizeof(data_t));memset(slots, 0, type.count * sizeof(data_t));for (int32 t = 0; t < list.count; ++t) {data_t data = ((data_t*)list.items)[t];if (data.name == NULL) {bool found = false;for (int32 k = 0; k < type.count; ++k) {if (slots[k].ptr == NULL) {slots[k] = cast(type.fields[k].type, data);found = true;break;}}if (!found)abort_compile(RDEF_COMPILE_ERR, "too many fields");} else {// named fieldbool found = false;for (int32 k = 0; k < type.count; ++k) {if (strcmp(type.fields[k].name, data.name) == 0) {if (slots[k].ptr != NULL)free_mem(slots[k].ptr);slots[k] = cast(type.fields[k].type, data);free_mem(data.name);found = true;break;}}if (!found)abort_compile(RDEF_COMPILE_ERR, "unknown field %s", data.name);}}return slots;}static data_tconvert_slots(type_t type, data_t* slots){size_t size = 0;for (int32 k = 0; k < type.count; ++k) {if (slots[k].ptr == NULL) {// default valuesize += type.fields[k].data.size;} else if (type.fields[k].resize != 0)size += type.fields[k].resize;elsesize += slots[k].size;}data_t out = make_data(size, type);uint8* ptr = (uint8*) out.ptr;for (int32 k = 0; k < type.count; ++k) {if (slots[k].ptr == NULL) {// default valuememcpy(ptr, type.fields[k].data.ptr, type.fields[k].data.size);ptr += type.fields[k].data.size;} else if (type.fields[k].resize != 0) {data_t temp = resize_data(slots[k], type.fields[k].resize);memcpy(ptr, temp.ptr, temp.size);ptr += temp.size;free_mem(temp.ptr);} else {memcpy(ptr, slots[k].ptr, slots[k].size);ptr += slots[k].size;free_mem(slots[k].ptr);}}free_mem(slots);return out;}data_tmake_type(char* name, list_t list){// Some explanation is in order. The "list" contains zero or more data_t// items. Each of these items corresponds to a data field that the user// specified, but not necessarily to a field from the type definition.// So here we have to figure out which data item goes where. It is fairly// obvious where names items should go, but for items without a name we// simply use the first available slot. For any fields that the user did// not fill in we use the default value from the type definition. This// algorithm allows for variable size fields, such as strings and arrays.type_t type = get_type(name);data_t* slots = fill_slots(type, list);data_t out = convert_slots(type, slots);free_mem(name);free_mem(list.items);return out;}list_tmake_field_list(field_t field){list_t out;out.count = 1;out.items = alloc_mem(sizeof(field_t));*((field_t*)out.items) = field;return out;}list_tconcat_field_list(list_t list, field_t field){list_t out;out.count = list.count + 1;out.items = alloc_mem(out.count * sizeof(field_t));memcpy(out.items, list.items, list.count * sizeof(field_t));memcpy((field_t*)out.items + list.count, &field, sizeof(field_t));free_mem(list.items);return out;}list_tmake_data_list(data_t data){list_t out;out.count = 1;out.items = alloc_mem(sizeof(data_t));*((data_t*)out.items) = data;return out;}list_tconcat_data_list(list_t list, data_t data){list_t out;out.count = list.count + 1;out.items = (data_t*)alloc_mem(out.count * sizeof(data_t));memcpy(out.items, list.items, list.count * sizeof(data_t));memcpy((data_t*)out.items + list.count, &data, sizeof(data_t));free_mem(list.items);return out;}data_tconcat_data(data_t data1, data_t data2){data_t out = make_data(data1.size + data2.size, get_type("raw"));memcpy(out.ptr, data1.ptr, data1.size);memcpy((uint8*)out.ptr + data1.size, data2.ptr, data2.size);free_mem(data1.ptr);free_mem(data2.ptr);return out;}static data_tcast_to_uint8(type_t new_type, data_t data){data_t out = make_data(sizeof(uint8), new_type);switch (data.type.code) {case B_INT8_TYPE:case B_UINT8_TYPE:*((uint8*)out.ptr) = *(uint8*)data.ptr;break;case B_INT16_TYPE:case B_UINT16_TYPE:*((uint8*)out.ptr) = (uint8)*(uint16*)data.ptr;break;case B_INT32_TYPE:case B_UINT32_TYPE:case B_SIZE_T_TYPE:case B_SSIZE_T_TYPE:case B_TIME_TYPE:*((uint8*)out.ptr) = (uint8)*(uint32*)data.ptr;break;case B_INT64_TYPE:case B_UINT64_TYPE:case B_OFF_T_TYPE:*((uint8*)out.ptr) = (uint8)*(uint64*)data.ptr;break;default:abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");}free_mem(data.ptr);return out;}static data_tcast_to_uint16(type_t new_type, data_t data){data_t out = make_data(sizeof(uint16), new_type);switch (data.type.code) {case B_INT8_TYPE:case B_UINT8_TYPE:*((uint16*)out.ptr) = (uint16)*(uint8*)data.ptr;break;case B_INT16_TYPE:case B_UINT16_TYPE:*((uint16*)out.ptr) = *(uint16*)data.ptr;break;case B_INT32_TYPE:case B_UINT32_TYPE:case B_SIZE_T_TYPE:case B_SSIZE_T_TYPE:case B_TIME_TYPE:*((uint16*)out.ptr) = (uint16)*(uint32*)data.ptr;break;case B_INT64_TYPE:case B_UINT64_TYPE:case B_OFF_T_TYPE:*((uint16*)out.ptr) = (uint16)*(uint64*)data.ptr;break;default:abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");}free_mem(data.ptr);return out;}static data_tcast_to_uint32(type_t new_type, data_t data){data_t out = make_data(sizeof(uint32), new_type);switch (data.type.code) {case B_INT8_TYPE:case B_UINT8_TYPE:*((uint32*)out.ptr) = (uint32)*(uint8*)data.ptr;break;case B_INT16_TYPE:case B_UINT16_TYPE:*((uint32*)out.ptr) = (uint32)*(uint16*)data.ptr;break;case B_INT32_TYPE:case B_UINT32_TYPE:case B_SIZE_T_TYPE:case B_SSIZE_T_TYPE:case B_TIME_TYPE:*((uint32*)out.ptr) = *(uint32*)data.ptr;break;case B_INT64_TYPE:case B_UINT64_TYPE:case B_OFF_T_TYPE:*((uint32*)out.ptr) = (uint32)*(uint64*)data.ptr;break;default:abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");}free_mem(data.ptr);return out;}static data_tcast_to_uint64(type_t new_type, data_t data){data_t out = make_data(sizeof(uint64), new_type);switch (data.type.code) {case B_INT8_TYPE:case B_UINT8_TYPE:*((uint64*)out.ptr) = (uint64)*(uint8*)data.ptr;break;case B_INT16_TYPE:case B_UINT16_TYPE:*((uint64*)out.ptr) = (uint64)*(uint16*)data.ptr;break;case B_INT32_TYPE:case B_UINT32_TYPE:case B_SIZE_T_TYPE:case B_SSIZE_T_TYPE:case B_TIME_TYPE:*((uint64*)out.ptr) = (uint64)*(uint32*)data.ptr;break;case B_INT64_TYPE:case B_UINT64_TYPE:case B_OFF_T_TYPE:*((uint64*)out.ptr) = *(uint64*)data.ptr;break;default:abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");}free_mem(data.ptr);return out;}static data_tcast_to_float(type_t new_type, data_t data){data_t out = make_data(sizeof(float), new_type);switch (data.type.code) {case B_INT8_TYPE:case B_UINT8_TYPE:*((float*)out.ptr) = (float)*((uint8*)data.ptr);break;case B_INT16_TYPE:case B_UINT16_TYPE:*((float*)out.ptr) = (float)*((uint16*)data.ptr);break;case B_INT32_TYPE:case B_UINT32_TYPE:case B_SIZE_T_TYPE:case B_SSIZE_T_TYPE:case B_TIME_TYPE:*((float*)out.ptr) = (float)*((uint32*)data.ptr);break;case B_INT64_TYPE:case B_UINT64_TYPE:case B_OFF_T_TYPE:*((float*)out.ptr) = (float)*((uint64*)data.ptr);break;case B_DOUBLE_TYPE:*((float*)out.ptr) = (float)*((double*)data.ptr);break;default:abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");}free_mem(data.ptr);return out;}static data_tcast_to_double(type_t new_type, data_t data){data_t out = make_data(sizeof(double), new_type);switch (data.type.code) {case B_INT8_TYPE:case B_UINT8_TYPE:*((double*)out.ptr) = (double)*((uint8*)data.ptr);break;case B_INT16_TYPE:case B_UINT16_TYPE:*((double*)out.ptr) = (double)*((uint16*)data.ptr);break;case B_INT32_TYPE:case B_UINT32_TYPE:case B_SIZE_T_TYPE:case B_SSIZE_T_TYPE:case B_TIME_TYPE:*((double*)out.ptr) = (double)*((uint32*)data.ptr);break;case B_INT64_TYPE:case B_UINT64_TYPE:case B_OFF_T_TYPE:*((double*)out.ptr) = (double)*((uint64*)data.ptr);break;case B_FLOAT_TYPE:*((double*)out.ptr) = (double)*((float*)data.ptr);break;default:abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");}free_mem(data.ptr);return out;}data_tcast(type_t newType, data_t data){if (same_type(newType, data.type)) {// you can't cast bool, string,// message, or user-defined type// to another type, only to samereturn data;}if (is_builtin_type(newType)) {switch (newType.code) {case B_INT8_TYPE:case B_UINT8_TYPE:return cast_to_uint8(newType, data);case B_INT16_TYPE:case B_UINT16_TYPE:return cast_to_uint16(newType, data);case B_INT32_TYPE:case B_UINT32_TYPE:case B_SIZE_T_TYPE:case B_SSIZE_T_TYPE:case B_TIME_TYPE:return cast_to_uint32(newType, data);case B_INT64_TYPE:case B_UINT64_TYPE:case B_OFF_T_TYPE:return cast_to_uint64(newType, data);case B_FLOAT_TYPE:return cast_to_float(newType, data);case B_DOUBLE_TYPE:return cast_to_double(newType, data);case B_RAW_TYPE:// you can always cast anything to rawdata.type = newType;return data;}}abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");return data;}data_tunary_expr(data_t data, char oper){data_t op = cast_to_uint32(get_type("int32"), data);int32 i = *((int32*)op.ptr);data_t out;switch (oper) {case '~':out = make_int(~i);break;}free_mem(op.ptr);return cast(get_type("int32"), out);}data_tbinary_expr(data_t data1, data_t data2, char oper){data_t op1 = cast_to_uint32(get_type("int32"), data1);data_t op2 = cast_to_uint32(get_type("int32"), data2);int32 i1 = *((int32*) op1.ptr);int32 i2 = *((int32*) op2.ptr);data_t out;switch (oper) {case '+':out = make_int(i1 + i2);break;case '-':out = make_int(i1 - i2);break;case '*':out = make_int(i1 * i2);break;case '/':if (i2 == 0)abort_compile(RDEF_COMPILE_ERR, "division by zero");elseout = make_int(i1 / i2);break;case '%':if (i2 == 0)abort_compile(RDEF_COMPILE_ERR, "division by zero");elseout = make_int(i1 % i2);break;case '|':out = make_int(i1 | i2);break;case '^':out = make_int(i1 ^ i2);break;case '&':out = make_int(i1 & i2);break;}free_mem(op1.ptr);free_mem(op2.ptr);return cast(get_type("int32"), out);}voidadd_resource(res_id_t id, type_code code, data_t data){if (!id.has_id)id.id = data.type.def_id;if (!id.has_name)id.name = (char*)data.type.def_name;if (!(flags & RDEF_MERGE_RESOURCES) && rsrc.HasResource(code, id.id))abort_compile(RDEF_COMPILE_ERR, "duplicate resource");status_t err = rsrc.AddResource(code, id.id, data.ptr, data.size, id.name);if (err != B_OK) {rdef_err = RDEF_WRITE_ERR;rdef_err_line = 0;strcpy(rdef_err_file, rsrc_file);sprintf(rdef_err_msg, "cannot add resource (%s)", strerror(err));abort_compile();}if (id.has_name)free_mem(id.name);free_mem(data.ptr);}static voidadd_point_type(){field_t* fields = (field_t*)alloc_mem(2 * sizeof(field_t));fields[0].type = get_type("float");fields[0].name = "x";fields[0].resize = 0;fields[0].data = make_default(fields[0].type);fields[1].type = get_type("float");fields[1].name = "y";fields[1].resize = 0;fields[1].data = make_default(fields[1].type);type_t type;type.code = B_POINT_TYPE;type.name = "point";type.fields = fields;type.count = 2;type.def_id = 1;type.def_name = NULL;type_table.insert(make_pair(type.name, type));}static voidadd_rect_type(){field_t* fields = (field_t*)alloc_mem(4 * sizeof(field_t));fields[0].type = get_type("float");fields[0].name = "left";fields[0].resize = 0;fields[0].data = make_default(fields[0].type);fields[1].type = get_type("float");fields[1].name = "top";fields[1].resize = 0;fields[1].data = make_default(fields[1].type);fields[2].type = get_type("float");fields[2].name = "right";fields[2].resize = 0;fields[2].data = make_default(fields[2].type);fields[3].type = get_type("float");fields[3].name = "bottom";fields[3].resize = 0;fields[3].data = make_default(fields[3].type);type_t type;type.code = B_RECT_TYPE;type.name = "rect";type.fields = fields;type.count = 4;type.def_id = 1;type.def_name = NULL;type_table.insert(make_pair(type.name, type));}static voidadd_rgb_color_type(){field_t* fields = (field_t*)alloc_mem(4 * sizeof(field_t));fields[0].type = get_type("uint8");fields[0].name = "red";fields[0].resize = 0;fields[0].data = make_default(fields[0].type);fields[1].type = get_type("uint8");fields[1].name = "green";fields[1].resize = 0;fields[1].data = make_default(fields[1].type);fields[2].type = get_type("uint8");fields[2].name = "blue";fields[2].resize = 0;fields[2].data = make_default(fields[2].type);fields[3].type = get_type("uint8");fields[3].name = "alpha";fields[3].resize = 0;fields[3].data = make_default(fields[3].type);*((uint8*)fields[3].data.ptr) = 255;type_t type;type.code = B_RGB_COLOR_TYPE;type.name = "rgb_color";type.fields = fields;type.count = 4;type.def_id = 1;type.def_name = NULL;type_table.insert(make_pair(type.name, type));}static voidadd_app_signature_type(){field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));fields[0].type = get_type("string");fields[0].name = "signature";fields[0].resize = 0;fields[0].data = make_default(fields[0].type);type_t type;type.code = 'MIMS';type.name = "app_signature";type.fields = fields;type.count = 1;type.def_id = 1;type.def_name = "BEOS:APP_SIG";type_table.insert(make_pair(type.name, type));}static voidadd_app_name_catalog_entry(){field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));fields[0].type = get_type("string");fields[0].name = "catalog_entry";fields[0].resize = 0;fields[0].data = make_default(fields[0].type);type_t type;type.code = B_STRING_TYPE;type.name = "app_name_catalog_entry";type.fields = fields;type.count = 1;type.def_id = 1;type.def_name = "SYS:NAME";type_table.insert(make_pair(type.name, type));}static voidadd_app_flags(){field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));fields[0].type = get_type("uint32");fields[0].name = "flags";fields[0].resize = 0;fields[0].data = make_default(fields[0].type);type_t type;type.code = 'APPF';type.name = "app_flags";type.fields = fields;type.count = 1;type.def_id = 1;type.def_name = "BEOS:APP_FLAGS";type_table.insert(make_pair(type.name, type));}static voidadd_app_version(){field_t* fields = (field_t*)alloc_mem(7 * sizeof(field_t));fields[0].type = get_type("uint32");fields[0].name = "major";fields[0].resize = 0;fields[0].data = make_default(fields[0].type);fields[1].type = get_type("uint32");fields[1].name = "middle";fields[1].resize = 0;fields[1].data = make_default(fields[1].type);fields[2].type = get_type("uint32");fields[2].name = "minor";fields[2].resize = 0;fields[2].data = make_default(fields[2].type);fields[3].type = get_type("uint32");fields[3].name = "variety";fields[3].resize = 0;fields[3].data = make_default(fields[3].type);fields[4].type = get_type("uint32");fields[4].name = "internal";fields[4].resize = 0;fields[4].data = make_default(fields[4].type);fields[5].type = get_type("string");fields[5].name = "short_info";fields[5].resize = 64;fields[5].data = make_data(fields[5].resize, fields[5].type);fields[6].type = get_type("string");fields[6].name = "long_info";fields[6].resize = 256;fields[6].data = make_data(fields[6].resize, fields[6].type);memset(fields[5].data.ptr, '\0', fields[5].data.size);memset(fields[6].data.ptr, '\0', fields[6].data.size);type_t type;type.code = 'APPV';type.name = "app_version";type.fields = fields;type.count = 7;type.def_id = 1;type.def_name = "BEOS:APP_VERSION";type_table.insert(make_pair(type.name, type));}static voidadd_png_icon(){field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));fields[0].type = get_type("raw");fields[0].name = "icon";fields[0].resize = 0;fields[0].data = make_data(fields[0].resize, fields[0].type);type_t type;type.code = 'PNG ';type.name = "png_icon";type.fields = fields;type.count = 1;type.def_id = 101;type.def_name = "BEOS:ICON";type_table.insert(make_pair(type.name, type));}static voidadd_vector_icon(){field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));fields[0].type = get_type("raw");fields[0].name = "icon";fields[0].resize = 0;fields[0].data = make_data(fields[0].resize, fields[0].type);type_t type;type.code = 'VICN';type.name = "vector_icon";type.fields = fields;type.count = 1;type.def_id = 101;type.def_name = "BEOS:ICON";type_table.insert(make_pair(type.name, type));}static voidadd_large_icon(){field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));fields[0].type = get_type("raw");fields[0].name = "icon";fields[0].resize = 1024;fields[0].data = make_data(fields[0].resize, fields[0].type);type_t type;type.code = 'ICON';type.name = "large_icon";type.fields = fields;type.count = 1;type.def_id = 101;type.def_name = "BEOS:L:STD_ICON";type_table.insert(make_pair(type.name, type));}static voidadd_mini_icon(){field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));fields[0].type = get_type("raw");fields[0].name = "icon";fields[0].resize = 256;fields[0].data = make_data(fields[0].resize, fields[0].type);type_t type;type.code = 'MICN';type.name = "mini_icon";type.fields = fields;type.count = 1;type.def_id = 101;type.def_name = "BEOS:M:STD_ICON";type_table.insert(make_pair(type.name, type));}static voidadd_file_types(){field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));fields[0].type = get_type("message");fields[0].name = "types";fields[0].resize = 0;fields[0].data = make_default(fields[0].type);type_t type;type.code = 'MSGG';type.name = "file_types";type.fields = fields;type.count = 1;type.def_id = 1;type.def_name = "BEOS:FILE_TYPES";type_table.insert(make_pair(type.name, type));}static voidadd_define(const char* name, int32 value){define_t define;define.name = name;define.value = value;define_table.insert(make_pair(define.name, define));}voidinit_parser(){add_builtin_type(B_BOOL_TYPE, "bool");add_builtin_type(B_INT8_TYPE, "int8");add_builtin_type(B_UINT8_TYPE, "uint8");add_builtin_type(B_INT16_TYPE, "int16");add_builtin_type(B_UINT16_TYPE, "uint16");add_builtin_type(B_INT32_TYPE, "int32");add_builtin_type(B_UINT32_TYPE, "uint32");add_builtin_type(B_SIZE_T_TYPE, "size_t");add_builtin_type(B_SSIZE_T_TYPE, "ssize_t");add_builtin_type(B_TIME_TYPE, "time_t");add_builtin_type(B_INT64_TYPE, "int64");add_builtin_type(B_UINT64_TYPE, "uint64");add_builtin_type(B_OFF_T_TYPE, "off_t");add_builtin_type(B_FLOAT_TYPE, "float");add_builtin_type(B_DOUBLE_TYPE, "double");add_builtin_type(B_STRING_TYPE, "string");add_builtin_type(B_RAW_TYPE, "raw");add_builtin_type(B_RAW_TYPE, "buffer");add_builtin_type(B_MESSAGE_TYPE, "message");add_point_type();add_rect_type();add_rgb_color_type();add_app_signature_type();add_app_name_catalog_entry();add_app_flags();add_app_version();add_large_icon();add_mini_icon();add_vector_icon();add_png_icon();add_file_types();add_define("B_SINGLE_LAUNCH", 0x0);add_define("B_MULTIPLE_LAUNCH", 0x1);add_define("B_EXCLUSIVE_LAUNCH", 0x2);add_define("B_BACKGROUND_APP", 0x4);add_define("B_ARGV_ONLY", 0x8);add_define("B_APPV_DEVELOPMENT", 0x0);add_define("B_APPV_ALPHA", 0x1);add_define("B_APPV_BETA", 0x2);add_define("B_APPV_GAMMA", 0x3);add_define("B_APPV_GOLDEN_MASTER", 0x4);add_define("B_APPV_FINAL", 0x5);}voidclean_up_parser(){// The symbol table entries have several malloc'ed objects associated// with them (such as their name). They were allocated with alloc_mem(),// so we don't need to free them here; compile.cpp already does that// when it cleans up. However, we do need to remove the entries from// the tables, otherwise they will still be around the next time we are// asked to compile something.#ifdef DEBUG// Note that in DEBUG mode, we _do_ free these items, so they don't show// up in the mem leak statistics. The names etc of builtin items are not// alloc_mem()'d but we still free_mem() them. Not entirely correct, but// it doesn't seem to hurt, and we only do it in DEBUG mode anyway.for (sym_iter_t i = symbol_table.begin(); i != symbol_table.end(); ++i) {free_mem((void*) i->first);}for (type_iter_t i = type_table.begin(); i != type_table.end(); ++i) {free_mem((void*) i->first);type_t type = i->second;for (int32 t = 0; t < type.count; ++t) {free_mem((void*) type.fields[t].name);free_mem((void*) type.fields[t].data.ptr);}free_mem((void*) type.fields);free_mem((void*) type.name);free_mem((void*) type.def_name);}#endifsymbol_table.clear();type_table.clear();define_table.clear();}