/* =========================================================================== Copyright (C) 2025 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. OpenMoHAA source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // parsetree.cpp: Abstract Syntax Layer for Lexer/Parser #include "parsetree.h" #include "../fgame/gamecvars.h" #include "../qcommon/mem_tempalloc.h" MEM_TempAlloc parsetree_allocator; yyparsedata parsedata; sval_u node_none = {0}; char *str_replace(char *orig, const char *rep, const char *with) { char *result; // the return string char *ins; // the next insert point char *tmp; // varies size_t len_rep; // length of rep size_t len_with; // length of with size_t len_front; // distance between rep and end of last rep int count; // number of replacements if (!orig) { return NULL; } if (!rep) { rep = ""; } len_rep = strlen(rep); if (!with) { with = ""; } len_with = strlen(with); ins = orig; for (count = 0; (tmp = strstr(ins, rep)) != nullptr; ++count) { ins = tmp + len_rep; } // first time through the loop, all the variable are set correctly // from here on, // tmp points to the end of the result string // ins points to the next occurrence of rep in orig // orig points to the remainder of orig after "end of rep" tmp = result = (char *)parsetree_allocator.Alloc(strlen(orig) + (len_with - len_rep) * count + 1); if (!result) { return NULL; } while (count--) { ins = strstr(orig, rep); len_front = ins - orig; tmp = strncpy(tmp, orig, len_front) + len_front; tmp = strcpy(tmp, with) + len_with; orig += len_front + len_rep; // move to next "end of rep" } strcpy(tmp, orig); return result; } void parsetree_freeall() { parsetree_allocator.FreeAll(); if (g_showopcodes->integer) { gi.DPrintf("%d bytes freed\n", parsedata.total_length); } } void parsetree_init() { parsedata.total_length = 0; } size_t parsetree_length() { return parsedata.total_length; } #if 0 char* parsetree_string(const char* string) { //char *pszString = ( char * )parsetree_allocator.Alloc( strlen( string ) + 1 ); //strcpy( pszString, string ); char* buffer = str_replace((char*)string, "\\\"", "\""); if (buffer) { char* ptr = buffer; if (ptr[0] == '"') { ptr++; } int len = strlen(buffer); if (buffer[len - 1] == '"') { buffer[len - 1] = 0; } buffer = ptr; } return buffer; } #endif extern size_t yyleng; extern size_t prev_yyleng; char *parsetree_malloc(size_t s) { parsedata.total_length += s; return (char *)parsetree_allocator.Alloc(s); } sval_u append_lists(sval_u val1, sval_u val2) { val1.node[1].node[1] = val2.node[0]; val1.node[1] = val2.node[1]; return val1; } sval_u append_node(sval_u val1, sval_u val2) { sval_u *node; node = (sval_u *)parsetree_malloc(sizeof(sval_t[2])); node[1].node = NULL; node[0] = val2; val1.node[1].node[1].node = node; val1.node[1].node = node; return val1; } sval_u prepend_node(sval_u val1, sval_u val2) { sval_u *node; node = (sval_u *)parsetree_malloc(sizeof(sval_t[2])); node[0] = val1; node[1] = val2; val2.node = node; return val2; } sval_u linked_list_end(sval_u val) { sval_u *node; sval_u end; node = (sval_u *)parsetree_malloc(sizeof(sval_t[2])); node[0] = val; node[1].node = NULL; end.node = (sval_u *)parsetree_malloc(sizeof(sval_t[2])); end.node[0].node = node; end.node[1].node = node; return end; } sval_u node1_(int val1) { sval_u val; val.intValue = val1; return val; } sval_u node1b(int val1) { sval_u val; val.byteValue = val1; return val; } sval_u node_pos(unsigned int pos) { sval_u val; val.sourcePosValue = pos; return val; } sval_u node_string(char *text) { sval_u val; val.stringValue = text; return val; } sval_u node0(int type) { sval_u val; if (type == ENUM_NOP) { // memory optimization val.node = &node_none; } else { val.node = (sval_u *)parsetree_malloc(sizeof(sval_u)); val.node[0].node = NULL; val.node[0].type = type; } return val; } sval_u node1(int type, sval_u val1) { sval_u val; val.node = (sval_u *)parsetree_malloc(sizeof(sval_u[2])); val.node[0].type = type; val.node[1] = val1; return val; } sval_u node2(int type, sval_u val1, sval_u val2) { sval_u val; assert(type != ENUM_NOP); val.node = (sval_u *)parsetree_malloc(sizeof(sval_t[3])); val.node[0].type = type; val.node[1] = val1; val.node[2] = val2; return val; } sval_u node3(int type, sval_u val1, sval_u val2, sval_u val3) { sval_u val; assert(type != ENUM_NOP); val.node = (sval_u *)parsetree_malloc(sizeof(sval_t[4])); val.node[0].type = type; val.node[1] = val1; val.node[2] = val2; val.node[3] = val3; return val; } sval_u node4(int type, sval_u val1, sval_u val2, sval_u val3, sval_u val4) { sval_u val; assert(type != ENUM_NOP); val.node = (sval_u *)parsetree_malloc(sizeof(sval_t[5])); val.node[0].type = type; val.node[1] = val1; val.node[2] = val2; val.node[3] = val3; val.node[4] = val4; return val; } sval_u node5(int type, sval_u val1, sval_u val2, sval_u val3, sval_u val4, sval_u val5) { sval_u val; assert(type != ENUM_NOP); val.node = (sval_u *)parsetree_malloc(sizeof(sval_t[6])); val.node[0].type = type; val.node[1] = val1; val.node[2] = val2; val.node[3] = val3; val.node[4] = val4; val.node[5] = val5; return val; } sval_u node6(int type, sval_u val1, sval_u val2, sval_u val3, sval_u val4, sval_u val5, sval_u val6) { sval_u val; assert(type != ENUM_NOP); val.node = (sval_u *)parsetree_malloc(sizeof(sval_t[7])); val.node[0].type = type; val.node[1] = val1; val.node[2] = val2; val.node[3] = val3; val.node[4] = val4; val.node[5] = val5; val.node[6] = val6; return val; } sval_u node_listener(sval_u val1, sval_u val2) { if (!str::icmp(val1.stringValue, "self")) { return node2(ENUM_listener, node1_(method_self), val2); } else { return node2(ENUM_string, val1, val2); } }