-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.y
98 lines (76 loc) · 1.79 KB
/
parser.y
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//
// parser.y
// A basic parser for uci config files
//
// https://openwrt.org/docs/guide-user/base-system/uci#file_syntax
// Will catch all errors, but not necessarily report them very user-friendly
// Requires input to have a terminating newline
//
// (C) 2024 Thibaut VARENE
// License: GPLv2 - http://www.gnu.org/licenses/gpl-2.0.html
//
%{
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
void yyerror(const char *, ...);
extern int yylineno;
extern int yylex();
extern FILE *yyin;
static const char *filename;
static int retval = 0;
int no_nl = 0;
%}
%define parse.error verbose
%verbose
%token PACKAGE CONFIG OPTION NEWLINE
%token NAME IDENTIFIER TYPE VALUE
%%
start: stmtlist ;
stmtlist: /* empty */
| stmtlist NEWLINE
| stmtlist stmt NEWLINE
| stmtlist error NEWLINE { yyerrok; if (++retval >= 10) { fprintf(stderr, "TOO MANY ERRORS, ABORTING!\n"); YYABORT; } }
;
stmt: PACKAGE NAME
| CONFIG TYPE
| CONFIG TYPE IDENTIFIER
| OPTION IDENTIFIER values
;
/* handle implicit concatenation */
values: VALUE | values VALUE ;
%%
int main(int argc, char **argv)
{
int opt;
while ((opt = getopt(argc, argv, "n")) != -1) {
if ('n' == opt) // 'n' does not permit embedded new lines in string literals
no_nl = 1;
else {
fprintf(stderr, "Usage: %s [-n] file\n", argv[0]);
exit(-1);
}
}
if (optind >= argc) {
fprintf(stderr, "Missing filename!\n");
exit(-1);
}
filename = argv[optind];
if (!(yyin = fopen(filename, "r"))) {
perror(filename);
exit(-1);
}
retval += yyparse(); // catch unhandled errors
fclose(yyin);
return retval;
}
void yyerror(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
fprintf(stderr, "%s: error line %d: ", filename, yylineno);
vfprintf(stderr, msg, ap);
va_end(ap);
fprintf(stderr, "\n");
}