type_t *PR_ParseFunctionType (type_t *returnType) { type_t newtype; memset (&newtype, 0, sizeof(newtype)); newtype.type = ev_function; newtype.aux_type = returnType; newtype.num_parms = 0; if (PR_Check (")")) { // empty args return PR_GetType (&newtype); } do { if (PR_Check ("...")) { // variable args PR_Expect (")"); newtype.num_parms |= VA_BIT; return PR_GetType (&newtype); } if (newtype.num_parms >= MAX_PARMS) PR_ParseError ("too many parameters (max. %d allowed)", (int)MAX_PARMS); type_t *type = PR_ParseType (); char *name = PR_ParseName (); strlcpy (pr_parm_names[newtype.num_parms], name, sizeof(pr_parm_names[newtype.num_parms])); newtype.parm_types[newtype.num_parms] = type; newtype.num_parms++; } while (PR_Check (",")); PR_Expect (")"); return PR_GetType(&newtype); }
/* ============ PR_ParseImmediateStatements Parse a function body ============ */ function_t *PR_ParseImmediateStatements (type_t *type) { int i; function_t *f; def_t *defs[MAX_PARMS]; f = malloc (sizeof(function_t)); // // check for builtin function definition #1, #2, etc // if (PR_Check ("#")) { if (pr_token_type != tt_immediate || pr_immediate_type != &type_float || pr_immediate._float != (int)pr_immediate._float) PR_ParseError ("Bad builtin immediate"); f->builtin = (int)pr_immediate._float; PR_Lex (); return f; } f->builtin = 0; // // define the parms // for (i=0 ; i<type->num_parms ; i++) { defs[i] = PR_GetDef (type->parm_types[i], pr_parm_names[i], pr_scope, true); f->parm_ofs[i] = defs[i]->ofs; if (i > 0 && f->parm_ofs[i] < f->parm_ofs[i-1]) Error ("bad parm order"); } f->code = numstatements; // // check for a state opcode // if (PR_Check ("[")) PR_ParseState (); // // parse regular statements // PR_Expect ("{"); while (!PR_Check("}")) PR_ParseStatement (); // emit an end of statements opcode PR_Statement (pr_opcodes, 0,0); return f; }
/* ============ PR_ParseFunctionCall ============ */ def_t *PR_ParseFunctionCall (def_t *func) { def_t *e; int arg; type_t *t; t = func->type; if (t->type != ev_function) PR_ParseError ("not a function"); // copy the arguments to the global parameter variables arg = 0; if (!PR_Check(")")) { do { if (t->num_parms != -1 && arg >= t->num_parms) PR_ParseError ("too many parameters"); e = PR_Expression (TOP_PRIORITY); if (arg == 0 && func->name) { // save information for model and sound caching if (!strncmp(func->name,"precache_sound", 14)) PrecacheSound (e, func->name[14]); else if (!strncmp(func->name,"precache_model", 14)) PrecacheModel (e, func->name[14]); else if (!strncmp(func->name,"precache_file", 13)) PrecacheFile (e, func->name[13]); } if (t->num_parms != -1 && ( e->type != t->parm_types[arg] ) ) PR_ParseError ("type mismatch on parm %i", arg); // a vector copy will copy everything def_parms[arg].type = t->parm_types[arg]; PR_Statement (&pr_opcodes[OP_STORE_V], e, &def_parms[arg]); arg++; } while (PR_Check (",")); if (t->num_parms != -1 && arg != t->num_parms) PR_ParseError ("too few parameters"); PR_Expect (")"); } if (arg >8) PR_ParseError ("More than eight parameters"); PR_Statement (&pr_opcodes[OP_CALL0+arg], func, 0); def_ret.type = t->aux_type; return &def_ret; }
/* ============ PR_ParseType Parses a variable type, including field and functions types ============ */ type_t *PR_ParseType (void) { if (PR_Check (".")) { type_t newtype; memset (&newtype, 0, sizeof(newtype)); newtype.type = ev_field; newtype.aux_type = PR_ParseType (); return PR_GetType (&newtype); } type_t *type; bool constant = PR_Check ("const"); if (!strcmp (pr_token, "float") ) type = constant ? &type_const_float : &type_float; else if (!strcmp (pr_token, "vector") ) type = constant ? &type_const_vector : &type_vector; else if (!strcmp (pr_token, "entity") ) type = &type_entity; else if (!strcmp (pr_token, "string") ) type = constant ? &type_const_string : &type_string; else if (!strcmp (pr_token, "void") ) type = &type_void; else { PR_ParseError ("\"%s\" is not a type", pr_token); type = &type_void; // shut up compiler warning } PR_Lex (); if (PR_Check("(")) { // function type // go back to non-const types // FIXME: don't bother? Or force const types instead? if (type == &type_const_float) type = &type_float; else if (type == &type_const_vector) type = &type_vector; else if (type == &type_const_string) type = &type_string; return PR_ParseFunctionType(type); } return type; }
/* ============ PR_SkipToSemicolon For error recovery, also pops out of nested braces ============ */ void PR_SkipToSemicolon (void) { do { if (!pr_bracelevel && PR_Check (";")) return; PR_Lex (); } while (pr_token[0]); // eof will return a null token }
/* ============ PR_ParseFunctionCall ============ */ def_t *PR_ParseFunctionCall (def_t *func) { def_t *e; int arg; type_t *t; t = func->type; if (t->type != ev_function) PR_ParseError ("not a function"); // copy the arguments to the global parameter variables arg = 0; if (!PR_Check(")")) { do { if (arg >= t->num_parms || arg >= MAX_PARMS /* works properly with varargs */) PR_ParseError ("too many parameters"); e = PR_Expression (TOP_PRIORITY); if (arg < (t->num_parms & VA_MASK) && !CompareType(e->type, t->parm_types[arg])) PR_ParseError ("type mismatch on parm %i", arg); // a vector copy will copy everything def_parms[arg].type = t->parm_types[arg]; PR_Statement (&pr_opcodes[OP_STORE_V], e, &def_parms[arg]); arg++; } while (PR_Check (",")); if (arg < (t->num_parms & VA_MASK)) PR_ParseError ("too few parameters"); PR_Expect (")"); } if (arg > MAX_PARMS) PR_ParseError ("more than %d parameters", (int)MAX_PARMS); PR_Statement (&pr_opcodes[OP_CALL0+arg], func, 0); def_ret.type = t->aux_type; return &def_ret; }
/* ============ PR_Term ============ */ def_t *PR_Term (void) { def_t *e, *e2; etype_t t; if (PR_Check ("!")) { e = PR_Expression (NOT_PRIORITY); t = e->type->type; if (t == ev_float) e2 = PR_Statement (&pr_opcodes[OP_NOT_F], e, 0); else if (t == ev_string) e2 = PR_Statement (&pr_opcodes[OP_NOT_S], e, 0); else if (t == ev_entity) e2 = PR_Statement (&pr_opcodes[OP_NOT_ENT], e, 0); else if (t == ev_vector) e2 = PR_Statement (&pr_opcodes[OP_NOT_V], e, 0); else if (t == ev_function) e2 = PR_Statement (&pr_opcodes[OP_NOT_FNC], e, 0); else { e2 = NULL; // shut up compiler warning; PR_ParseError ("type mismatch for !"); } return e2; } if (PR_Check ("(")) { e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); return e; } return PR_ParseValue (); }
/* ============ PR_CompileFile compiles the 0 terminated text, adding defintions to the pr structure ============ */ bool PR_CompileFile (char *string, char *filename) { if (!pr.memory) Error ("PR_CompileFile: Didn't clear"); PR_ClearGrabMacros (); // clear the frame macros pr_file_p = string; s_file = CopyString (filename); pr_source_line = 0; PR_NewLine (); PR_Lex (); // read first token while (PR_Check(";")) ; // skip redundant semicolons while (pr_token_type != tt_eof) { if (setjmp(pr_parse_abort)) { if (++pr_error_count > MAX_ERRORS) return false; PR_SkipToSemicolon (); if (pr_token_type == tt_eof) return false; } pr_scope = NULL; // outside all functions PR_ParseDefs (); } return (pr_error_count == 0); }
/* ================ PR_ParseDefs Called at the outer layer and when a local statement is hit ================ */ void PR_ParseDefs (void) { char *name; type_t *type; def_t *def; function_t *f; dfunction_t *df; int i; int locals_start; type = PR_ParseType (); if (pr_scope && (type->type == ev_field || type->type == ev_function) ) PR_ParseError ("Fields and functions must be global"); do { name = PR_ParseName (); def = PR_GetDef (type, name, pr_scope, true); // check for an initialization if ( PR_Check ("=") ) { if (def->initialized) PR_ParseError ("%s redeclared", name); if (type->type == ev_function) { locals_start = locals_end = numpr_globals; pr_scope = def; f = PR_ParseImmediateStatements (type); pr_scope = NULL; def->initialized = 1; G_FUNCTION(def->ofs) = numfunctions; f->def = def; // if (pr_dumpasm) // PR_PrintFunction (def); // fill in the dfunction df = &functions[numfunctions]; numfunctions++; if (f->builtin) df->first_statement = -f->builtin; else df->first_statement = f->code; df->s_name = CopyString (f->def->name); df->s_file = s_file; df->numparms = f->def->type->num_parms; df->locals = locals_end - locals_start; df->parm_start = locals_start; for (i=0 ; i<df->numparms ; i++) df->parm_size[i] = type_size[f->def->type->parm_types[i]->type]; continue; } else if (pr_immediate_type != type) PR_ParseError ("wrong immediate type for %s", name); def->initialized = 1; memcpy (pr_globals + def->ofs, &pr_immediate, 4*type_size[pr_immediate_type->type]); PR_Lex (); } } while (PR_Check (",")); PR_Expect (";"); }
/* ============ PR_ParseStatement ============ */ void PR_ParseStatement (void) { def_t *e; dstatement_t *patch1, *patch2; if (PR_Check ("{")) { do { PR_ParseStatement (); } while (!PR_Check ("}")); return; } if (PR_Check("return")) { if (PR_Check (";")) { PR_Statement (&pr_opcodes[OP_RETURN], 0, 0); return; } e = PR_Expression (TOP_PRIORITY); PR_Expect (";"); PR_Statement (&pr_opcodes[OP_RETURN], e, 0); return; } if (PR_Check("while")) { PR_Expect ("("); patch2 = &statements[numstatements]; e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); patch1 = &statements[numstatements]; PR_Statement (&pr_opcodes[OP_IFNOT], e, 0); PR_ParseStatement (); junkdef.ofs = patch2 - &statements[numstatements]; PR_Statement (&pr_opcodes[OP_GOTO], &junkdef, 0); patch1->b = &statements[numstatements] - patch1; return; } if (PR_Check("do")) { patch1 = &statements[numstatements]; PR_ParseStatement (); PR_Expect ("while"); PR_Expect ("("); e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); PR_Expect (";"); junkdef.ofs = patch1 - &statements[numstatements]; PR_Statement (&pr_opcodes[OP_IF], e, &junkdef); return; } if (PR_Check("local")) { PR_ParseDefs (); locals_end = numpr_globals; return; } if (PR_Check("if")) { PR_Expect ("("); e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); patch1 = &statements[numstatements]; PR_Statement (&pr_opcodes[OP_IFNOT], e, 0); PR_ParseStatement (); if (PR_Check ("else")) { patch2 = &statements[numstatements]; PR_Statement (&pr_opcodes[OP_GOTO], 0, 0); patch1->b = &statements[numstatements] - patch1; PR_ParseStatement (); patch2->a = &statements[numstatements] - patch2; } else patch1->b = &statements[numstatements] - patch1; return; } PR_Expression (TOP_PRIORITY); PR_Expect (";"); }
def_t *PR_Expression (int priority) { opcode_t *op, *oldop; def_t *e, *e2; etype_t type_a, type_b, type_c; if (priority == 0) return PR_Term (); e = PR_Expression (priority-1); while (1) { if (priority == 1 && PR_Check ("(") ) return PR_ParseFunctionCall (e); for (op=pr_opcodes ; op->name ; op++) { if (op->priority != priority) continue; if (!PR_Check (op->name)) continue; if ( op->right_associative ) { // if last statement is an indirect, change it to an address of if ( (unsigned)(statements[numstatements-1].op - OP_LOAD_F) < 6 ) { statements[numstatements-1].op = OP_ADDRESS; def_pointer.type->aux_type = e->type; e->type = def_pointer.type; } e2 = PR_Expression (priority); } else e2 = PR_Expression (priority-1); // type check type_a = e->type->type; type_b = e2->type->type; if (op->name[0] == '.')// field access gets type from field { if (e2->type->aux_type) type_c = e2->type->aux_type->type; else type_c = -1; // not a field } else type_c = ev_void; oldop = op; while (type_a != op->type_a->type->type || type_b != op->type_b->type->type || (type_c != ev_void && type_c != op->type_c->type->type) ) { op++; if (!op->name || strcmp (op->name , oldop->name)) PR_ParseError ("type mismatch for %s", oldop->name); } if (type_a == ev_pointer && type_b != e->type->aux_type->type) PR_ParseError ("type mismatch for %s", op->name); if (op->right_associative) e = PR_Statement (op, e2, e); else e = PR_Statement (op, e, e2); if (type_c != ev_void) // field access gets type from field e->type = e2->type->aux_type; break; } if (!op->name) break; // next token isn't at this priority level } return e; }
/* ============ PR_ParseStatement ============ */ void PR_ParseStatement (void) { def_t *e = NULL; dstatement_t *patch1 = NULL; dstatement_t *patch2 = NULL; if (PR_Check(";")) return; if (PR_Check ("{")) { while (!PR_Check ("}")) PR_ParseStatement (); return; } if (PR_Check("return")) { if (PR_Check (";")) { PR_Statement (&pr_opcodes[OP_RETURN], 0, 0); return; } e = PR_Expression (TOP_PRIORITY); PR_Expect (";"); PR_Statement (&pr_opcodes[OP_RETURN], e, 0); return; } if (PR_Check("while")) { PR_Expect ("("); patch2 = &statements[numstatements]; e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); patch1 = &statements[numstatements]; PR_Statement (&pr_opcodes[OP_IFNOT], e, 0); PR_ParseStatement (); junkdef.ofs = patch2 - &statements[numstatements]; PR_Statement (&pr_opcodes[OP_GOTO], &junkdef, 0); patch1->b = (unsigned short)(&statements[numstatements] - patch1); return; } if (PR_Check("do")) { patch1 = &statements[numstatements]; PR_ParseStatement (); PR_Expect ("while"); PR_Expect ("("); e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); PR_Expect (";"); junkdef.ofs = patch1 - &statements[numstatements]; PR_Statement (&pr_opcodes[OP_IF], e, &junkdef); return; } if ( PR_Check("local") || !strcmp(pr_token, "const") || !strcmp(pr_token, "float") || !strcmp(pr_token, "vector") || !strcmp(pr_token, "entity") || !strcmp(pr_token, "string") || !strcmp(pr_token, "void")) { PR_ParseDefs (); locals_end = numpr_globals; return; } if (PR_Check("if")) { PR_Expect ("("); e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); patch1 = &statements[numstatements]; PR_Statement (&pr_opcodes[OP_IFNOT], e, 0); PR_ParseStatement (); if (PR_Check ("else")) { patch2 = &statements[numstatements]; PR_Statement (&pr_opcodes[OP_GOTO], 0, 0); patch1->b = (unsigned short)(&statements[numstatements] - patch1); PR_ParseStatement (); patch2->a = (unsigned short)(&statements[numstatements] - patch2); } else patch1->b = (unsigned short)(&statements[numstatements] - patch1); return; } if (PR_Check("else")) PR_ParseError ("illegal else without matching if"); PR_Expression (TOP_PRIORITY); PR_Expect (";"); }
/* ============== PR_Expression ============== */ def_t *PR_Expression (int priority) { opcode_t *op, *oldop; def_t *e, *e2; etype_t type_a, type_b, type_c; if (priority == 0) return PR_Term (); e = PR_Expression (priority-1); while (1) { if (priority == 1 && PR_Check ("(") ) return PR_ParseFunctionCall (e); for (op=pr_opcodes ; op->name ; op++) { if (op->priority != priority) continue; if (!PR_Check (op->name)) continue; if (op->name[0] == '.') { char *name = PR_ParseName (); if (e->type != &type_entity) PR_ParseError ("left of '.%s' must have entity type", name); e2 = PR_FindDef (name, pr_scope); if (!e2 || e2->type->type != ev_field) PR_ParseError ("'%s' is not a field", name); type_c = e2->type->aux_type->type; // we still allow ".void foo" so need to check if (type_c == ev_void) PR_ParseError ("tried to access a 'void' field"); assert (type_c != ev_pointer && type_c != ev_void); while (type_c != op->type_c) { op++; assert (op->name); } e = PR_Statement (op, e, e2); // field access gets type from field e->type = e2->type->aux_type; break; } if (op->right_associative) { if (e->type->constant) PR_ParseError ("assignment to constant"); // if last statement is an indirect, change it to an address of if ( (unsigned)(statements[numstatements-1].op - OP_LOAD_F) < 6 ) { statements[numstatements-1].op = (unsigned short)OP_ADDRESS; def_pointer.type->aux_type = e->type; e->type = def_pointer.type; } e2 = PR_Expression (priority); } else e2 = PR_Expression (priority-1); // type check type_a = e->type->type; type_b = e2->type->type; oldop = op; while (type_a != op->type_a || type_b != op->type_b ) { op++; if (!op->name || strcmp (op->name , oldop->name)) PR_ParseError ("type mismatch for %s", oldop->name); } if (type_a == ev_pointer && type_b != e->type->aux_type->type) PR_ParseError ("type mismatch for %s", op->name); #if 0 if (e->type->constant && e2->type->constant) { // try to calculate the expression at compile time eval_t result; if (PR_Calc(op - pr_opcodes, (eval_t *)(pr_globals + e->ofs), (eval_t *)(pr_globals + e2->ofs), &result)) { // printf ("line %i: folding %s %s %s into %s\n", pr_source_line, e->name, op->name, e2->name, // PR_ValueString(op->type_c, &val)); type_t *resulttype; switch (op->type_c) { case ev_float: resulttype = &type_const_float; break; //case ev_string: resulttype = &type_const_string; break; case ev_vector: resulttype = &type_const_vector; break; default: assert (false); } e = PR_GetImmediate (resulttype, result); break; } } #endif if (op->right_associative) e = PR_Statement (op, e2, e); else e = PR_Statement (op, e, e2); break; } if (!op->name) break; // next token isn't at this priority level } return e; }
/* ============ PR_Term ============ */ def_t *PR_Term (void) { if (pr_token_type != tt_punct) return PR_ParseValue (); def_t *e, *e2; etype_t t; if (PR_Check ("!")) { e = PR_Expression (NOT_PRIORITY); t = e->type->type; if (t == ev_float) e2 = PR_Statement (&pr_opcodes[OP_NOT_F], e, 0); else if (t == ev_string) e2 = PR_Statement (&pr_opcodes[OP_NOT_S], e, 0); else if (t == ev_entity) e2 = PR_Statement (&pr_opcodes[OP_NOT_ENT], e, 0); else if (t == ev_vector) e2 = PR_Statement (&pr_opcodes[OP_NOT_V], e, 0); else if (t == ev_function) e2 = PR_Statement (&pr_opcodes[OP_NOT_FNC], e, 0); else { PR_ParseError ("type mismatch for !"); return NULL; // shut up compiler } return e2; } if (PR_Check ("(")) { e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); return e; } if (PR_Check("-")) { e = PR_Expression (1 /* FIXME, correct? */); t = e->type->type; if (t == ev_float) { eval_t v; v._float = 0; def_t *imm = PR_GetImmediate (&type_const_float, v); e2 = PR_Statement (&pr_opcodes[OP_SUB_F], imm, e); } else if (t == ev_vector) { eval_t v; v.vector[0] = v.vector[1] = v.vector[2] = 0; def_t *imm = PR_GetImmediate (&type_const_vector, v); e2 = PR_Statement (&pr_opcodes[OP_SUB_V], imm, e); } else { PR_ParseError ("type mismatch for -"); return NULL; // shut up compiler } return e2; } if (PR_Check("+")) { e = PR_Expression (1 /* FIXME, correct? */); t = e->type->type; if (t != ev_float && t != ev_vector) { PR_ParseError ("type mismatch for +"); return NULL; // shut up compiler } return e; } PR_ParseError ("syntax error : '%s'", pr_token); return NULL; // shut up compiler }
/* ================ PR_ParseDefs Called at the outer layer and when a local statement is hit ================ */ void PR_ParseDefs (void) { type_t *type = PR_ParseType (); if (pr_scope && type->type == ev_field) PR_ParseError ("'%s': local field definitions are illegal", pr_token); int c_defs = 0; bool qc_style_function_def = false; // functions are always global def_t *defscope = (type->type == ev_function) ? NULL : pr_scope; do { char *name = PR_ParseName (); if (type->type != ev_function && PR_Check("(")) { // C-style function declaration char functionName[MAX_NAME]; if (strlen(name) >= (size_t)MAX_NAME) PR_ParseError ("name of function \"%s\" is too long (max. %d chars)", name, (int)(MAX_NAME - 1)); strcpy (functionName, name); type_t *functionType = PR_ParseFunctionType (type); def_t *def = PR_GetDef (functionType, functionName, NULL, pr_scope); if ((!c_defs && !strcmp(pr_token, "{")) || PR_Check("=")) { // C-style function definition (including builtin function definition #1, #2, etc.) PR_ParseFunctionBody (functionType, functionName, def); while (PR_Check(";")) ; // skip redundant semicolons return; } continue; } def_t *def = PR_GetDef (type, name, defscope, pr_scope); if (type->type == ev_void) { // end_sys_globals and end_sys_fields are special flags for structure dumping if (strcmp(name, "end_sys_globals") && strcmp(name, "end_sys_fields")) PR_ParseError ("'%s' : illegal use of type 'void'", name); } // check for an initialization if (PR_Check("=")) { if (type->type == ev_function) { // QuakeC-style function definition qc_style_function_def = true; PR_ParseFunctionBody (type, name, def); } else // variable initialization PR_ParseInitialization (type, name, def); } } while (c_defs++, PR_Check (",")); if (qc_style_function_def && c_defs == 1) ; // allow void() func = {} without semicolon else PR_Expect (";"); while (PR_Check(";")) ; // skip redundant semicolons }
/* ======================== PR_LexPrecomp parses and executes directives with a leading '#': #define #undef #ifdef #ifndef #else #endif #error #message #pragma message ======================== */ void PR_LexPrecomp (void) { // yeah it isn't quite Precompiler is it? pr_file_p++; // skip the hash if (!PR_SimpleGetToken ()) PR_ParseError ("Q534: Invalid preprocessor command"); // that's not possible if (!strcmp(pr_token, "ifdef")) { if (ifdefdepth > ignoredepth) { // inside another ignored "ifdef"/"ifndef" // -> ignore statements ifdefdepth++; return; } ifdefdepth++; ignoredepth = ifdefdepth; PR_Lex(); if (!PR_FindDefine(pr_token, true)) { // not defined // -> ignore statements until endif or else ignoredepth--; while(ifdefdepth > ignoredepth) PR_Lex(); return; } // defined // -> parse statements PR_Lex(); return; } else if (!strcmp(pr_token, "ifndef")) { if (ifdefdepth > ignoredepth) { // inside another ignored ifdef // -> ignore statements ifdefdepth++; return; } ifdefdepth++; ignoredepth = ifdefdepth; PR_Lex(); if (PR_FindDefine(pr_token, true)) { // defined // -> ignore statements ignoredepth--; while(ifdefdepth > ignoredepth) PR_Lex(); return; } PR_Lex(); return; } else if (!strcmp(pr_token, "endif")) { ifdefdepth--; if (ifdefdepth < 0) PR_ParseError ("Q119: Too many #endifs"); PR_Lex(); return; } else if (!strcmp(pr_token, "else")) { if (ifdefdepth == (ignoredepth + 1)) { // the "ifdef" or "ifndef" part has not been entered // -> parse the statements inside "else" //print("parsing statment %s in else on %s(%ld)", pr_token, s_file + strings, pr_source_line); ignoredepth = ifdefdepth; pr_token_type = tt_name; PR_Lex(); return; } // "ifdef" or "ifndef" part has already been entered // -> ignore statements in "else" part ignoredepth--; while (ifdefdepth > ignoredepth) PR_Lex(); return; } else if (ifdefdepth > ignoredepth) { //print("ignored %s on %s(%ld)", pr_token, s_file + strings, pr_source_line); return; } else if (PR_Check("error")) { if (pr_immediate_type != &type_string && pr_immediate_type != &type_const_string) PR_ParseError ("Q541: Error must be a string"); PR_ParseError ("User Error on %s(%ld): %s", s_file + strings, pr_source_line, pr_immediate_string); PR_Lex(); return; } else if (PR_Check("message")) { if (pr_immediate_type != &type_string && pr_immediate_type != &type_const_string) PR_ParseError ("Q541: Message must be a string"); printf ("Message on %s(%ld): %s\n", s_file + strings, (long)pr_source_line, pr_immediate_string); PR_Lex(); return; } else if (PR_Check("pragma")) { if (PR_Check("message")) { if (pr_immediate_type != &type_string && pr_immediate_type != &type_const_string) PR_ParseError ("Q541: Message must be a string"); printf ("Message on %s(%ld): %s\n", s_file + strings, (long)pr_source_line, pr_immediate_string); PR_Lex(); return; } // unknown pragma directive printf ("Warning on %s(%ld): unknown #pragma \"%s\" (will be ignored)", s_file + strings, (long)pr_source_line, pr_token); // skip to the end of the line while (PR_SimpleGetToken ()) ; PR_Lex(); return; } else if (PR_Check("define")) { char define_name[2048]; if (pr_token_type != tt_name) PR_ParseError ("Q543: #define: Invalid name"); // predefine it: strlcpy (define_name, pr_token, sizeof(define_name)); if (PR_AddDefine (define_name, &type_const_float, NULL, false) <= 0) PR_ParseError ("Q544: #define \"%s\": creation failed", define_name); // get the value of the define PR_Lex(); if (pr_token_type == tt_immediate) { if (pr_immediate_type != &type_float && pr_immediate_type != &type_const_float) PR_ParseError ("Q545: #define \"%s\": Invalid type of value", define_name); // finally fix the define (with given value) if (PR_AddDefine (define_name, pr_immediate_type, &pr_immediate, false) <= 0) PR_ParseError ("Q544: #define \"%s\": creation failed", define_name); PR_Lex(); } else { eval_t value; value._float = 1; // finally fix the define (with default-value) if (PR_AddDefine (define_name, &type_const_float, &value, false) <= 0) PR_ParseError ("Q544: #define \"%s\": creation failed", define_name); } return; } else if (PR_Check("undef")) { if (pr_token_type != tt_name) PR_ParseError ("Q544: #undef: Invalid name"); PR_DelDefine (pr_token, false); PR_Lex(); return; } } // END_FUNC PR_LexPrecomp