2 Copyright (C) 2021 David Knapp (Cloudwalk)
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include "darkplaces.h"
27 // Tell the user that their stuff is broken, why it's broken, and where it's broken, so hopefully they fix it.
28 DP_FUNC_NORETURN void Parse_Error(struct qparser_state_s *state, qparser_err_t error, const char *expected)
34 Sys_Error("Parse_Error: Expected to expect something (expected == NULL)! Your parser is broken.");
35 Con_Printf(CON_ERROR "Parse Error: %s: Unexpected token '%c', expected %s. Line %i, column %i\n", state->name, *state->pos, expected, state->line, state->col);
39 Sys_Error("Parse_Error: expected != NULL when it should be NULL. Your parser is broken.");
40 Con_Printf(CON_ERROR "Parse Error: %s: Unexpected end-of-file\n", state->name);
43 Con_Printf(CON_ERROR "Parse Error: %s: This file is nested too deep. Max depth of %i reached.\n", state->name, PARSER_MAX_DEPTH);
46 Sys_Error("Parse_Error: Invalid error number %i. Your parser is broken.", error);
49 longjmp(parse_error, 1);
52 // Advance forward in the stream as many times as 'count', cleanly.
53 void Parse_Next(struct qparser_state_s *state, int count)
55 const char *next = Token_Next(state->pos, count);
63 Parse_Error(state, PARSE_ERR_EOF, NULL);
66 // Skips newlines, and handles different line endings.
67 static qbool Parse_Newline(struct qparser_state_s *state)
69 if(Token_Newline(&state->pos))
78 // Skip all whitespace, as we normally know it.
79 static inline qbool Parse_Skip_Whitespace(struct qparser_state_s *state)
82 // TODO: Some languages enforce indentation style. Add a callback to override this.
83 while(*state->pos == ' ' || *state->pos == '\t')
91 // Skips the current line. Only useful for comments.
92 static inline void Parse_Skip_Line(struct qparser_state_s *state)
94 while(!Parse_Newline(state))
98 static inline qbool Parse_Skip_Comments(struct qparser_state_s *state)
100 // Make sure these are both defined (or both not defined)
101 if((state->callback.CheckComment_Multiline_Start != NULL) ^ (state->callback.CheckComment_Multiline_End != NULL))
102 Sys_Error("Parse_Skip_Comments: CheckComment_Multiline_Start (or _End) == NULL. Your parser is broken.");
104 // Assume language doesn't support the respective comment types if one of these are NULL.
105 if(state->callback.CheckComment_SingleLine && state->callback.CheckComment_SingleLine(state))
106 Parse_Skip_Line(state);
107 else if(state->callback.CheckComment_Multiline_Start && state->callback.CheckComment_Multiline_Start(state))
111 Parse_Next(state, 1);
112 Parse_Newline(state);
113 } while (state->callback.CheckComment_Multiline_End(state));
121 // Skip all whitespace.
122 static inline void Parse_SkipToToken(struct qparser_state_s *state)
125 * Repeat this until we run out of whitespace, newlines, and comments.
126 * state->pos should be left on non-whitespace when this returns.
128 while(Parse_Skip_Comments(state) || Parse_Skip_Whitespace(state) || Parse_Newline(state));
131 // Skip to the next token. Advance the pointer at least 1 if we're not sitting on whitespace.
132 char Parse_NextToken(struct qparser_state_s *state, int skip)
135 state->pos = state->buf;
137 Parse_Next(state, 1 + skip);
139 Parse_SkipToToken(state);
144 qparser_state_t *Parse_New(const unsigned char *in)
146 qparser_state_t *out;
150 Con_Printf("Parse_New: FS_LoadFile() failed");
154 out = (qparser_state_t *)Z_Malloc(sizeof(qparser_state_t));
156 out->buf = (const char *)in;
165 qparser_state_t *Parse_LoadFile(const char *file)
167 return Parse_New(FS_LoadFile(file, tempmempool, false, NULL));