Line data Source code
1 : /* Copyright 1989-2020 Free Software Foundation, Inc.
2 : 2021-2025 G. Branden Robinson
3 :
4 : Written by James Clark (jjc@jclark.com)
5 :
6 : This file is part of groff, the GNU roff typesetting system.
7 :
8 : groff is free software; you can redistribute it and/or modify it under
9 : the terms of the GNU General Public License as published by the Free
10 : Software Foundation, either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 : for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 :
21 : #ifdef HAVE_CONFIG_H
22 : #include <config.h>
23 : #endif
24 :
25 : #include <assert.h>
26 :
27 : class charinfo;
28 : struct node;
29 :
30 : enum delimiter_context {
31 : DELIMITER_GROFF_EXPRESSION,
32 : DELIMITER_ATT_STRING_EXPRESSION,
33 : DELIMITER_ATT_NUMERIC_EXPRESSION,
34 : DELIMITER_ATT_OUTPUT_COMPARISON_EXPRESSION
35 : };
36 :
37 : class token {
38 : symbol nm;
39 : node *nd;
40 : unsigned char c;
41 : int val;
42 : units dim;
43 : enum token_type {
44 : TOKEN_BACKSPACE, // ^H
45 : TOKEN_BEGIN_TRAP,
46 : TOKEN_CHAR, // ordinary character
47 : TOKEN_DELIMITED_HORIZONTAL_MOTION, // \h
48 : TOKEN_DELIMITED_SPECIAL_CHAR, // \C
49 : TOKEN_DUMMY, // dummy character: \&
50 : TOKEN_EMPTY, // this is the initial value
51 : TOKEN_END_TRAP,
52 : TOKEN_EOF, // end of file
53 : TOKEN_ESCAPE, // \e
54 : TOKEN_HORIZONTAL_MOTION, // fixed horizontal motion: \|, \^, \0
55 : TOKEN_HYPHEN_INDICATOR, // \%
56 : TOKEN_INDEXED_CHAR, // \N
57 : TOKEN_INTERRUPT, // \c
58 : TOKEN_ITALIC_CORRECTION, // \/
59 : TOKEN_LEADER, // ^A
60 : TOKEN_LEFT_BRACE, // \{
61 : TOKEN_MARK_INPUT, // \k
62 : TOKEN_NEWLINE, // ^J
63 : TOKEN_NODE,
64 : TOKEN_PAGE_EJECTOR,
65 : TOKEN_REQUEST,
66 : TOKEN_RIGHT_BRACE, // \}
67 : TOKEN_SPACE, // ' ' -- ordinary space
68 : TOKEN_SPECIAL_CHAR, // \(, \[
69 : TOKEN_SPREAD, // \p -- break and spread output line
70 : TOKEN_STRETCHABLE_SPACE, // \~
71 : TOKEN_TAB, // ^I
72 : TOKEN_TRANSPARENT, // \!
73 : TOKEN_TRANSPARENT_DUMMY, // \)
74 : TOKEN_UNSTRETCHABLE_SPACE, // '\ '
75 : TOKEN_ZERO_WIDTH_BREAK // \:
76 : } type;
77 : public:
78 : token();
79 : ~token();
80 : token(const token &);
81 : void operator=(const token &);
82 : void next();
83 : void process();
84 : void skip_spaces();
85 : void diagnose_non_character();
86 : int nspaces(); // is_space() as integer
87 : bool is_node();
88 : bool is_eof();
89 : bool is_space();
90 : bool is_stretchable_space();
91 : bool is_unstretchable_space();
92 : bool is_horizontal_motion();
93 : bool is_horizontal_whitespace();
94 : bool is_any_character();
95 : // XXX: Do we need a `is_ordinary_character()`?
96 : bool is_special_character();
97 : bool is_indexed_character();
98 : bool is_newline();
99 : bool is_tab();
100 : bool is_leader();
101 : bool is_backspace();
102 : bool is_usable_as_delimiter(bool /* report_error */ = false,
103 : enum delimiter_context /* context */ = DELIMITER_GROFF_EXPRESSION);
104 : bool is_dummy();
105 : bool is_transparent_dummy();
106 : bool is_transparent();
107 : bool is_left_brace();
108 : bool is_right_brace();
109 : bool is_page_ejector();
110 : bool is_hyphen_indicator();
111 : bool is_zero_width_break();
112 : bool operator==(const token &); // for delimiters & conditional exprs
113 : bool operator!=(const token &); // ditto
114 : unsigned char ch();
115 : int character_index();
116 : charinfo *get_charinfo(bool /* required */ = false,
117 : bool /* suppress_creation */ = false);
118 : bool add_to_zero_width_node_list(node **);
119 : void make_space();
120 : void make_newline();
121 : void describe_node(char * /* buf */, size_t /* bufsz */);
122 : const char *description();
123 :
124 : friend void process_input_stack();
125 : friend node *do_overstrike();
126 : };
127 :
128 : extern token tok; // the current token
129 :
130 : extern bool has_arg(bool /* want_peek */ = false);
131 : extern void skip_line();
132 : extern symbol read_identifier(bool /* required */ = false);
133 : extern symbol read_long_identifier(bool /* required */ = false);
134 : extern void handle_initial_title();
135 : extern charinfo *read_character(); // TODO?: bool /* required */ = false
136 : extern char *read_rest_of_line_as_argument();
137 :
138 : enum char_mode {
139 : CHAR_NORMAL,
140 : CHAR_FALLBACK,
141 : CHAR_FONT_SPECIFIC_FALLBACK,
142 : CHAR_SPECIAL_FALLBACK
143 : };
144 :
145 : extern void define_character(char_mode,
146 : const char * /* font_name */ = 0 /* nullptr */);
147 :
148 : class hunits;
149 : extern void read_title_parts(node **part, hunits *part_width);
150 :
151 : extern bool read_measurement(units * /* result */,
152 : unsigned char /* scale indicator */,
153 : bool /* is_mandatory */ = false);
154 : extern bool read_integer(int *result);
155 :
156 : extern bool read_measurement(units *result, unsigned char si,
157 : units prev_value);
158 : extern bool read_integer(int *result, int prev_value);
159 :
160 : extern void interpolate_register(symbol, int);
161 :
162 93421550 : inline bool token::is_newline()
163 : {
164 93421550 : return (TOKEN_NEWLINE == type);
165 : }
166 :
167 123045884 : inline bool token::is_space()
168 : {
169 123045884 : return (TOKEN_SPACE == type);
170 : }
171 :
172 177469 : inline bool token::is_stretchable_space()
173 : {
174 177469 : return (TOKEN_STRETCHABLE_SPACE == type);
175 : }
176 :
177 445 : inline bool token::is_unstretchable_space()
178 : {
179 445 : return (TOKEN_UNSTRETCHABLE_SPACE == type);
180 : }
181 :
182 220 : inline bool token::is_horizontal_motion()
183 : {
184 220 : return ((TOKEN_HORIZONTAL_MOTION == type)
185 220 : || (TOKEN_DELIMITED_HORIZONTAL_MOTION == type));
186 : }
187 :
188 236 : inline bool token::is_special_character()
189 : {
190 236 : return ((TOKEN_SPECIAL_CHAR == type)
191 236 : || (TOKEN_DELIMITED_SPECIAL_CHAR == type));
192 : }
193 :
194 4586 : inline int token::nspaces()
195 : {
196 4586 : return int(TOKEN_SPACE == type);
197 : }
198 :
199 30957471 : inline bool token::is_horizontal_whitespace()
200 : {
201 30957471 : return (TOKEN_SPACE == type || TOKEN_TAB == type);
202 : }
203 :
204 : inline bool token::is_transparent()
205 : {
206 : return (TOKEN_TRANSPARENT == type);
207 : }
208 :
209 : inline bool token::is_page_ejector()
210 : {
211 : return (TOKEN_PAGE_EJECTOR == type);
212 : }
213 :
214 233483604 : inline unsigned char token::ch()
215 : {
216 233483604 : return ((TOKEN_CHAR == type) ? c : 0U); // TODO: grochar
217 : }
218 :
219 9462 : inline bool token::is_any_character()
220 : {
221 9462 : return ((TOKEN_CHAR == type)
222 5449 : || (TOKEN_SPECIAL_CHAR == type)
223 4 : || (TOKEN_DELIMITED_SPECIAL_CHAR == type)
224 14911 : || (TOKEN_INDEXED_CHAR == type));
225 : }
226 :
227 11 : inline bool token::is_indexed_character()
228 : {
229 11 : return (TOKEN_INDEXED_CHAR == type);
230 : }
231 :
232 1 : inline int token::character_index()
233 : {
234 1 : assert(TOKEN_INDEXED_CHAR == type);
235 1 : return val;
236 : }
237 :
238 : inline bool token::is_node()
239 : {
240 : return (TOKEN_NODE == type);
241 : }
242 :
243 58194407 : inline bool token::is_eof()
244 : {
245 58194407 : return (TOKEN_EOF == type);
246 : }
247 :
248 1645419 : inline bool token::is_dummy()
249 : {
250 1645419 : return (TOKEN_DUMMY == type);
251 : }
252 :
253 288 : inline bool token::is_transparent_dummy()
254 : {
255 288 : return (TOKEN_TRANSPARENT_DUMMY == type);
256 : }
257 :
258 6369661 : inline bool token::is_left_brace()
259 : {
260 6369661 : return (TOKEN_LEFT_BRACE == type);
261 : }
262 :
263 2503279 : inline bool token::is_right_brace()
264 : {
265 2503279 : return (TOKEN_RIGHT_BRACE == type);
266 : }
267 :
268 3244497 : inline bool token::is_tab()
269 : {
270 3244497 : return (TOKEN_TAB == type);
271 : }
272 :
273 : inline bool token::is_leader()
274 : {
275 : return (TOKEN_LEADER == type);
276 : }
277 :
278 : inline bool token::is_backspace()
279 : {
280 : return (TOKEN_BACKSPACE == type);
281 : }
282 :
283 1646004 : inline bool token::is_hyphen_indicator()
284 : {
285 1646004 : return (TOKEN_HYPHEN_INDICATOR == type);
286 : }
287 :
288 1469379 : inline bool token::is_zero_width_break()
289 : {
290 1469379 : return (TOKEN_ZERO_WIDTH_BREAK == type);
291 : }
292 :
293 : // Local Variables:
294 : // fill-column: 72
295 : // mode: C++
296 : // End:
297 : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:
|