GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/bc/scan.l Lines: 40 89 44.9 %
Date: 2017-11-13 Branches: 32 70 45.7 %

Line Branch Exec Source
1
%{
2
/*      $OpenBSD: scan.l,v 1.30 2017/07/19 12:50:33 espie Exp $	*/
3
4
/*
5
 * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <err.h>
21
#include <histedit.h>
22
#include <signal.h>
23
#include <string.h>
24
#include <unistd.h>
25
26
#include "extern.h"
27
#include "pathnames.h"
28
#include "bc.h"
29
30
int		lineno;
31
bool		interactive;
32
33
HistEvent	 he;
34
EditLine	*el;
35
History		*hist;
36
37
static char	*strbuf = NULL;
38
static size_t	strbuf_sz = 1;
39
static bool	dot_seen;
40
static int	use_el;
41
static volatile sig_atomic_t skipchars;
42
43
static void	init_strbuf(void);
44
static void	add_str(const char *);
45
46
static int	 bc_yyinput(char *, int);
47
48
#undef YY_INPUT
49
#define YY_INPUT(buf,retval,max) \
50
	(retval = bc_yyinput(buf, max))
51
52
%}
53
54
%option always-interactive
55
56
DIGIT		[0-9A-F]
57
ALPHA		[a-z_]
58
ALPHANUM	[a-z_0-9]
59
60
%x		comment string number
61
62
%%
63
64
"/*"		BEGIN(comment);
65
<comment>{
66
	"*/"	BEGIN(INITIAL);
67
	\n	lineno++;
68
	\*	;
69
	[^*\n]+	;
70
	<<EOF>>	fatal("end of file in comment");
71
}
72
73
\"		BEGIN(string); init_strbuf();
74
<string>{
75
	[^"\n\\\[\]]+	add_str(yytext);
76
	\[	add_str("\\[");
77
	\]	add_str("\\]");
78
	\\	add_str("\\\\");
79
	\n	add_str("\n"); lineno++;
80
	\"	BEGIN(INITIAL); yylval.str = strbuf; return STRING;
81
	<<EOF>>	fatal("end of file in string");
82
}
83
84
{DIGIT}+	{
85
			BEGIN(number);
86
			dot_seen = false;
87
			init_strbuf();
88
			add_str(yytext);
89
		}
90
\.		{
91
			BEGIN(number);
92
			dot_seen = true;
93
			init_strbuf();
94
			add_str(".");
95
		}
96
<number>{
97
	{DIGIT}+	add_str(yytext);
98
	\.	{
99
			if (dot_seen) {
100
				BEGIN(INITIAL);
101
				yylval.str = strbuf;
102
				unput('.');
103
				return NUMBER;
104
			} else {
105
				dot_seen = true;
106
				add_str(".");
107
			}
108
		}
109
	\\\n[ \t]*	lineno++;
110
	[^0-9A-F\.]	{
111
			BEGIN(INITIAL);
112
			unput(yytext[0]);
113
			if (strcmp(strbuf, ".") == 0)
114
				return DOT;
115
			else {
116
				yylval.str = strbuf;
117
				return NUMBER;
118
			}
119
		}
120
}
121
122
"auto"		return AUTO;
123
"break"		return BREAK;
124
"continue"	return CONTINUE;
125
"define"	return DEFINE;
126
"else"		return ELSE;
127
"ibase"		return IBASE;
128
"if"		return IF;
129
"last"		return DOT;
130
"for"		return FOR;
131
"length"	return LENGTH;
132
"obase"		return OBASE;
133
"print"		return PRINT;
134
"quit"		return QUIT;
135
"return"	return RETURN;
136
"scale"		return SCALE;
137
"sqrt"		return SQRT;
138
"while"		return WHILE;
139
140
"^"		return EXPONENT;
141
"*"		return MULTIPLY;
142
"/"		return DIVIDE;
143
"%"		return REMAINDER;
144
145
"!"		return BOOL_NOT;
146
"&&"		return BOOL_AND;
147
"||"		return BOOL_OR;
148
149
"+"		return PLUS;
150
"-"		return MINUS;
151
152
"++"		return INCR;
153
"--"		return DECR;
154
155
"="		yylval.str = ""; return ASSIGN_OP;
156
"+="		yylval.str = "+"; return ASSIGN_OP;
157
"-="		yylval.str = "-"; return ASSIGN_OP;
158
"*="		yylval.str = "*"; return ASSIGN_OP;
159
"/="		yylval.str = "/"; return ASSIGN_OP;
160
"%="		yylval.str = "%"; return ASSIGN_OP;
161
"^="		yylval.str = "^"; return ASSIGN_OP;
162
163
"=="		return EQUALS;
164
"<="		return LESS_EQ;
165
">="		return GREATER_EQ;
166
"!="		return UNEQUALS;
167
"<"		return LESS;
168
">"		return GREATER;
169
170
","		return COMMA;
171
";"		return SEMICOLON;
172
173
"("		return LPAR;
174
")"		return RPAR;
175
176
"["		return LBRACKET;
177
"]"		return RBRACKET;
178
179
"{"		return LBRACE;
180
"}"		return RBRACE;
181
182
{ALPHA}{ALPHANUM}* {
183
			/* alloc an extra byte for the type marker */
184
			char *p = malloc(yyleng + 2);
185
			if (p == NULL)
186
				err(1, NULL);
187
			strlcpy(p, yytext, yyleng + 1);
188
			yylval.astr = p;
189
			return LETTER;
190
		}
191
192
\\\n		lineno++;
193
\n		lineno++; return NEWLINE;
194
195
#[^\n]*		;
196
[ \t]		;
197
<<EOF>>		return QUIT;
198
.		yyerror("illegal character");
199
200
%%
201
202
static void
203
init_strbuf(void)
204
{
205
	if (strbuf == NULL) {
206
6610
		strbuf = malloc(strbuf_sz);
207
90
		if (strbuf == NULL)
208
90
			err(1, NULL);
209
	}
210
	strbuf[0] = '\0';
211
3305
}
212
3305
213
static void
214
add_str(const char *str)
215
{
216
	size_t arglen;
217
218
	arglen = strlen(str);
219
7150
220
	if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
221
3575
		size_t newsize;
222
		char *p;
223
224
		newsize = strbuf_sz + arglen + 1;
225
185
		p = realloc(strbuf, newsize);
226
185
		if (p == NULL) {
227
185
			free(strbuf);
228
			err(1, NULL);
229
		}
230
		strbuf_sz = newsize;
231
185
		strbuf = p;
232
185
	}
233
185
	strlcat(strbuf, str, strbuf_sz);
234
3575
}
235
3575
236
/* ARGSUSED */
237
void
238
abort_line(int sig)
239
{
240
	static const char str1[] = "[\n]P\n";
241
	static const char str2[] = "[^C\n]P\n";
242
	int save_errno;
243
	const LineInfo *info;
244
245
	save_errno = errno;
246
	if (use_el) {
247
		write(STDOUT_FILENO, str2, sizeof(str2) - 1);
248
		info = el_line(el);
249
		skipchars = info->lastchar - info->buffer;
250
	} else
251
		write(STDOUT_FILENO, str1, sizeof(str1) - 1);
252
	errno = save_errno;
253
}
254
255
/*
256
 * Avoid the echo of ^D by the default code of editline and take
257
 * into account skipchars to make ^D work when the cursor is at start of
258
 * line after a ^C.
259
 */
260
unsigned char
261
bc_eof(EditLine *e, int ch)
262
{
263
	const struct lineinfo *info = el_line(e);
264
265
	if (info->buffer + skipchars == info->cursor &&
266
	    info->cursor == info->lastchar)
267
		return (CC_EOF);
268
	else
269
		return (CC_ERROR);
270
}
271
272
int
273
yywrap(void)
274
{
275
	static int state;
276
	static YY_BUFFER_STATE buf;
277
278
	if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
279

360
		filename = sargv[fileindex++];
280
		yyin = fopen(filename, "r");
281
		lineno = 1;
282
		if (yyin == NULL)
283
			err(1, "cannot open %s", filename);
284
		return (0);
285
	}
286
	if (state == 0 && cmdexpr[0] != '\0') {
287

360
		buf = yy_scan_string(cmdexpr);
288
		state++;
289
		lineno = 1;
290
		filename = "command line";
291
		return (0);
292
	} else if (state == 1) {
293
180
		yy_delete_buffer(buf);
294
		free(cmdexpr);
295
		state++;
296
	}
297
	if (yyin != NULL && yyin != stdin)
298
180
		fclose(yyin);
299
	if (fileindex < sargc) {
300
180
		filename = sargv[fileindex++];
301
		yyin = fopen(filename, "r");
302
		lineno = 1;
303
		if (yyin == NULL)
304
			err(1, "cannot open %s", filename);
305
		return (0);
306
	} else if (fileindex == sargc) {
307
180
		fileindex++;
308
90
		yyin = stdin;
309
90
		if (interactive) {
310
90
			signal(SIGINT, abort_line);
311
			signal(SIGTSTP, tstpcont);
312
		}
313
		lineno = 1;
314
90
		filename = "stdin";
315
90
		return (0);
316
90
	}
317
	return (1);
318
90
}
319
180
320
static int
321
bc_yyinput(char *buf, int maxlen)
322
{
323
	int num;
324
10270
325
	if (el != NULL)
326
5135
		el_get(el, EL_EDITMODE, &use_el);
327
328
	if (yyin == stdin && interactive && use_el) {
329

10270
		const char *bp;
330
		sigset_t oset, nset;
331
332
		if ((bp = el_gets(el, &num)) == NULL || num == 0)
333
			return (0);
334
		sigemptyset(&nset);
335
		sigaddset(&nset, SIGINT);
336
		sigprocmask(SIG_BLOCK, &nset, &oset);
337
		if (skipchars < num) {
338
			bp += skipchars;
339
			num -= skipchars;
340
		}
341
		skipchars = 0;
342
		sigprocmask(SIG_SETMASK, &oset, NULL);
343
		if (num > maxlen) {
344
			el_push(el, (char *)(void *)bp + maxlen);
345
			num = maxlen;
346
		}
347
		memcpy(buf, bp, num);
348
		history(hist, &he, H_ENTER, bp);
349
		el_get(el, EL_EDITMODE, &use_el);
350
	} else {
351
		int c = '*';
352
		for (num = 0; num < maxlen &&
353

174900
		    (c = getc(yyin)) != EOF && c != '\n'; ++num)
354

344575
			buf[num] = (char) c;
355
53165
		if (c == '\n')
356
5135
			buf[num++] = (char) c;
357
5045
		if (c == EOF && ferror(yyin))
358


5315
			YY_FATAL_ERROR( "input in flex scanner failed" );
359
	}
360
	return (num);
361
5135
}
362
5135
363