📄 worldfile.cc
字号:
int ch; int len; char token[256]; len = 0; memset(token, 0, sizeof(token)); ch = fgetc(file); while (true) { ch = fgetc(file); if (ch == EOF || ch == '\n') { TOKEN_ERR("unterminated string constant", *line); return false; } else if (ch == '"') { AddToken(TokenString, token, include); return true; } else { token[len++] = ch; } } assert(false); return false;}///////////////////////////////////////////////////////////////////////////// Read in a whitespace tokenbool CWorldFile::LoadTokenSpace(FILE *file, int *line, int include){ int ch; int len; char token[256]; len = 0; memset(token, 0, sizeof(token)); while (true) { ch = fgetc(file); if (ch == EOF) { AddToken(TokenSpace, token, include); return true; } else if (isblank(ch)) { token[len++] = ch; } else { AddToken(TokenSpace, token, include); ungetc(ch, file); return true; } } assert(false); return false;}///////////////////////////////////////////////////////////////////////////// Save tokens to a file.bool CWorldFile::SaveTokens(FILE *file){ int i; CToken *token; for (i = 0; i < this->token_count; i++) { token = this->tokens + i; if (token->include > 0) continue; if (token->type == TokenString) fprintf(file, "\"%s\"", token->value); else fprintf(file, "%s", token->value); } return true;}///////////////////////////////////////////////////////////////////////////// Clear the token listvoid CWorldFile::ClearTokens(){ int i; CToken *token; for (i = 0; i < this->token_count; i++) { token = this->tokens + i; free(token->value); } free(this->tokens); this->tokens = 0; this->token_size = 0; this->token_count = 0;}///////////////////////////////////////////////////////////////////////////// Add a token to the token listbool CWorldFile::AddToken(int type, const char *value, int include){ if (this->token_count >= this->token_size) { this->token_size += 1000; this->tokens = (CToken*) realloc(this->tokens, this->token_size * sizeof(this->tokens[0])); } this->tokens[this->token_count].include = include; this->tokens[this->token_count].type = type; this->tokens[this->token_count].value = strdup(value); this->token_count++; return true;}///////////////////////////////////////////////////////////////////////////// Set a token value in the token listbool CWorldFile::SetTokenValue(int index, const char *value){ assert(index >= 0 && index < this->token_count); free(this->tokens[index].value); this->tokens[index].value = strdup(value); return true;}///////////////////////////////////////////////////////////////////////////// Get the value of a tokenconst char *CWorldFile::GetTokenValue(int index){ assert(index >= 0 && index < this->token_count); return this->tokens[index].value;}///////////////////////////////////////////////////////////////////////////// Dump the token list (for debugging).void CWorldFile::DumpTokens(){ int line; line = 1; printf("\n## begin tokens\n"); printf("## %4d : ", line); for (int i = 0; i < this->token_count; i++) { if (this->tokens[i].value[0] == '\n') printf("[\\n]\n## %4d : %02d ", ++line, this->tokens[i].include); else printf("[%s] ", this->tokens[i].value); } printf("\n"); printf("## end tokens\n");}///////////////////////////////////////////////////////////////////////////// Parse tokens into entities and properties.bool CWorldFile::ParseTokens(){ int i; int entity; int line; CToken *token; ClearEntities(); ClearProperties(); // Add in the "global" entity. entity = AddEntity(-1, ""); line = 1; for (i = 0; i < this->token_count; i++) { token = this->tokens + i; switch (token->type) { case TokenWord: if (strcmp(token->value, "include") == 0) { if (!ParseTokenInclude(&i, &line)) return false; } else if (strcmp(token->value, "define") == 0) { if (!ParseTokenDefine(&i, &line)) return false; } else { if (!ParseTokenWord(entity, &i, &line)) return false; } break; case TokenComment: break; case TokenSpace: break; case TokenEOL: line++; break; default: PARSE_ERR("syntax error 1", line); return false; } } return true;}///////////////////////////////////////////////////////////////////////////// Parse an include statementbool CWorldFile::ParseTokenInclude(int *index, int *line){ int i; CToken *token; for (i = *index + 1; i < this->token_count; i++) { token = this->tokens + i; switch (token->type) { case TokenString: break; case TokenSpace: break; case TokenEOL: *index = i; (*line)++; return true; default: PARSE_ERR("syntax error in include statement", *line); return false; } } PARSE_ERR("incomplete include statement", *line); return false;}///////////////////////////////////////////////////////////////////////////// Parse a macro definitionbool CWorldFile::ParseTokenDefine(int *index, int *line){ int i; int count; const char *macroname, *entityname; int starttoken; CToken *token; count = 0; macroname = NULL; entityname = NULL; starttoken = -1; for (i = *index + 1; i < this->token_count; i++) { token = this->tokens + i; switch (token->type) { case TokenWord: if (count == 0) { if (macroname == NULL) macroname = GetTokenValue(i); else if (entityname == NULL) { entityname = GetTokenValue(i); starttoken = i; } else { PARSE_ERR("extra tokens in macro definition", *line); return false; } } else { if (macroname == NULL) { PARSE_ERR("missing name in macro definition", *line); return false; } if (entityname == NULL) { PARSE_ERR("missing name in macro definition", *line); return false; } } break; case TokenOpenEntity: count++; break; case TokenCloseEntity: count--; if (count == 0) { AddMacro(macroname, entityname, *line, starttoken, i); *index = i; return true; } if (count < 0) { PARSE_ERR("misplaced ')'", *line); return false; } break; default: break; } } PARSE_ERR("missing ')'", *line); return false;}///////////////////////////////////////////////////////////////////////////// Parse something starting with a word; could be a entity or an property.bool CWorldFile::ParseTokenWord(int entity, int *index, int *line){ int i; CToken *token; for (i = *index + 1; i < this->token_count; i++) { token = this->tokens + i; switch (token->type) { case TokenComment: break; case TokenSpace: break; case TokenEOL: (*line)++; break; case TokenOpenEntity: return ParseTokenEntity(entity, index, line); case TokenNum: case TokenString: case TokenOpenTuple: return ParseTokenProperty(entity, index, line); default: PARSE_ERR("syntax error 2", *line); return false; } } return false;}///////////////////////////////////////////////////////////////////////////// Parse a entity from the token list.bool CWorldFile::ParseTokenEntity(int entity, int *index, int *line){ int i; int macro; int name; CToken *token; name = *index; macro = LookupMacro(GetTokenValue(name)); // If the entity name is a macro... if (macro >= 0) { // This is a bit of a hack int nentity = this->entity_count; int mindex = this->macros[macro].starttoken; int mline = this->macros[macro].line; if (!ParseTokenEntity(entity, &mindex, &mline)) return false; entity = nentity; for (i = *index + 1; i < this->token_count; i++) { token = this->tokens + i; switch (token->type) { case TokenOpenEntity: break; case TokenWord: if (!ParseTokenWord(entity, &i, line)) return false; break; case TokenCloseEntity: *index = i; return true; case TokenComment: break; case TokenSpace: break; case TokenEOL: (*line)++; break; default: PARSE_ERR("syntax error 3", *line); return false; } } PARSE_ERR("missing ')'", *line); } // If the entity name is not a macro... else { for (i = *index + 1; i < this->token_count; i++) { token = this->tokens + i; switch (token->type) { case TokenOpenEntity: entity = AddEntity(entity, GetTokenValue(name)); break; case TokenWord: if (!ParseTokenWord(entity, &i, line)) return false; break; case TokenCloseEntity: *index = i; return true; case TokenComment: break; case TokenSpace: break; case TokenEOL: (*line)++; break; default: PARSE_ERR("syntax error 3", *line); return false; } } PARSE_ERR("missing ')'", *line); } return false;}///////////////////////////////////////////////////////////////////////////// Parse an property from the token list.bool CWorldFile::ParseTokenProperty(int entity, int *index, int *line){ int i, property; int name, value, count; CToken *token; name = *index; value = -1; count = 0; for (i = *index + 1; i < this->token_count; i++) { token = this->tokens + i; switch (token->type) { case TokenNum: property = AddProperty(entity, GetTokenValue(name), *line); AddPropertyValue(property, 0, i); *index = i; return true; case TokenString: property = AddProperty(entity, GetTokenValue(name), *line); AddPropertyValue(property, 0, i); *index = i; return true; case TokenOpenTuple: property = AddProperty(entity, GetTokenValue(name), *line); if (!ParseTokenTuple(entity, property, &i, line)) return false; *index = i; return true; case TokenSpace: break; default: PARSE_ERR("syntax error 4", *line); return false; } } return true;}///////////////////////////////////////////////////////////////////////////// Parse a tuple.bool CWorldFile::ParseTokenTuple(int entity, int property, int *index, int *line){ int i, count; CToken *token; count = 0; for (i = *index + 1; i < this->token_count; i++) { token = this->tokens + i; switch (token->type) { case TokenNum: AddPropertyValue(property, count++, i); *index = i; break; case TokenString: AddPropertyValue(property, count++, i); *index = i; break; case TokenCloseTuple: *index = i; return true; case TokenSpace: break; default: PARSE_ERR("syntax error 5", *line); return false; } } return true;}///////////////////////////////////////////////////////////////////////////// Clear the macro listvoid CWorldFile::ClearMacros(){ free(this->macros); this->macros = NULL; this->macro_size = 0; this->macro_count = 0;}///////////////////////////////////////////////////////////////////////////// Add a macroint CWorldFile::AddMacro(const char *macroname, const char *entityname, int line, int starttoken, int endtoken){ if (this->macro_count >= this->macro_size) { this->macro_size += 100; this->macros = (CMacro*) realloc(this->macros, this->macro_size * sizeof(this->macros[0])); } int macro = this->macro_count; this->macros[macro].macroname = macroname;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -