Line data Source code
1 : %code requires {
2 : /* Required to break a circular dependency introduced with bison 2.6 */
3 : typedef void* yyscan_t;
4 : }
5 : %code top {
6 : #include <errno.h>
7 : #include "lang.h"
8 : #include "lexer.h"
9 :
10 0 : static int yyerror(struct lgfs2_lang_state *state, yyscan_t lexer, const char *errorstr)
11 : {
12 0 : fprintf(stderr, "%d:%d: %s\n", state->ls_linenum, state->ls_colnum, errorstr);
13 0 : return 1;
14 : }
15 :
16 : }
17 : %defines
18 : %debug
19 : %define api.pure
20 : %parse-param { struct lgfs2_lang_state *state }
21 : %parse-param { yyscan_t lexer }
22 : %lex-param { yyscan_t lexer }
23 : %start script
24 : %token TOK_COLON
25 : %token TOK_COMMA
26 : %token TOK_ID
27 : %token TOK_LBRACE
28 : %token TOK_LBRACKET
29 : %token TOK_NUMBER
30 : %token TOK_OFFSET
31 : %token TOK_RBRACE
32 : %token TOK_RBRACKET
33 : %token TOK_SEMI
34 : %token TOK_SET
35 : %token TOK_GET
36 : %token TOK_STATE
37 : %token TOK_STRING
38 : %token TOK_PATH
39 : %%
40 : script: statements {
41 8 : state->ls_ast_root = $1;
42 8 : state->ls_interp_curr = $1;
43 : }
44 : | statements TOK_SEMI {
45 0 : state->ls_ast_root = $1;
46 0 : state->ls_interp_curr = $1;
47 : }
48 : ;
49 : statements: statements TOK_SEMI statement {
50 0 : state->ls_ast_tail->ast_left = $3;
51 0 : state->ls_ast_tail = $3;
52 0 : $$ = $1;
53 : }
54 : | statement {
55 8 : if (state->ls_ast_tail == NULL)
56 8 : state->ls_ast_tail = $1;
57 8 : $$ = $1;
58 : }
59 : ;
60 8 : statement: set_stmt { $$ = $1;}
61 0 : | get_stmt { $$ = $1; }
62 : ;
63 : set_stmt: TOK_SET blockspec structspec {
64 8 : $1->ast_right = $2;
65 8 : $2->ast_right = $3;
66 8 : $$ = $1;
67 : }
68 : | TOK_SET blockspec typespec structspec {
69 0 : $1->ast_right = $2;
70 0 : $2->ast_right = $3;
71 0 : $3->ast_right = $4;
72 0 : $$ = $1;
73 : }
74 : ;
75 : get_stmt: TOK_GET blockspec {
76 0 : $1->ast_right = $2; $$ = $1;
77 : }
78 : | TOK_GET blockspec TOK_STATE {
79 0 : $1->ast_right = $2;
80 0 : $2->ast_right = $3;
81 0 : $$ = $1;
82 : }
83 : ;
84 0 : blockspec: offset { $$ = $1; }
85 0 : | address { $$ = $1; }
86 1 : | path { $$ = $1; }
87 7 : | block_literal { $$ = $1; }
88 0 : | subscript { $$ = $1; }
89 : ;
90 : offset: blockspec TOK_OFFSET {
91 0 : $2->ast_left = $1;
92 0 : $$ = $2;
93 : }
94 : ;
95 : typespec: identifier {
96 0 : $1->ast_type = AST_EX_TYPESPEC;
97 0 : $$ = $1;
98 : }
99 : ;
100 7 : block_literal: identifier { $$ = $1; }
101 : ;
102 : subscript: block_literal TOK_LBRACKET index TOK_RBRACKET {
103 0 : $4->ast_left = $1;
104 0 : $1->ast_left = $3;
105 0 : $$ = $4;
106 : }
107 : ;
108 0 : index: number { $$ = $1; }
109 0 : | identifier { $$ = $1; }
110 : ;
111 : address: number {
112 0 : $1->ast_type = AST_EX_ADDRESS;
113 0 : $$ = $1;
114 : }
115 : ;
116 8 : structspec: TOK_LBRACE fieldspecs TOK_RBRACE { $$ = $2; }
117 0 : | TOK_LBRACE TOK_RBRACE { $$ = NULL; }
118 : ;
119 : fieldspecs: fieldspecs TOK_COMMA fieldspec {
120 0 : $1->ast_left = $3;
121 0 : $$ = $1;
122 : }
123 8 : | fieldspec { $$ = $1; }
124 : ;
125 : fieldspec: identifier TOK_COLON fieldvalue {
126 8 : $2->ast_right = $1;
127 8 : $1->ast_right = $3;
128 8 : $$ = $2;
129 : }
130 : ;
131 8 : fieldvalue: number { $$ = $1; }
132 0 : | string { $$ = $1; }
133 : ;
134 8 : number: TOK_NUMBER { $$ = $1; }
135 0 : string: TOK_STRING { $$ = $1; }
136 15 : identifier: TOK_ID { $$ = $1; }
137 1 : path: TOK_PATH { $$ = $1; }
138 : %%
139 :
140 : /**
141 : * Allocate and initialize a new parse state structure. The caller must free the
142 : * memory returned by this function.
143 : */
144 8 : struct lgfs2_lang_state *lgfs2_lang_init(void)
145 : {
146 : struct lgfs2_lang_state *state;
147 8 : state = calloc(1, sizeof(struct lgfs2_lang_state));
148 8 : if (state == NULL) {
149 0 : return NULL;
150 : }
151 8 : state->ls_linenum = 1;
152 8 : return state;
153 : }
154 :
155 8 : void lgfs2_lang_free(struct lgfs2_lang_state **state)
156 : {
157 8 : ast_destroy(&(*state)->ls_ast_root);
158 8 : free(*state);
159 8 : *state = NULL;
160 8 : }
161 :
162 8 : int lgfs2_lang_parsef(struct lgfs2_lang_state *state, FILE *src)
163 : {
164 8 : int ret = 0;
165 : yyscan_t lexer;
166 :
167 8 : ret = yylex_init_extra(state, &lexer);
168 8 : if (ret != 0) {
169 0 : fprintf(stderr, "Failed to initialize lexer.\n");
170 0 : return ret;
171 : }
172 :
173 8 : yyset_in(src, lexer);
174 8 : ret = yyparse(state, lexer);
175 8 : yylex_destroy(lexer);
176 8 : return ret;
177 : }
178 :
179 0 : int lgfs2_lang_parses(struct lgfs2_lang_state *state, const char *cstr)
180 : {
181 : int ret;
182 : FILE *src;
183 0 : char *str = strdup(cstr);
184 :
185 0 : if (str == NULL) {
186 0 : perror("Failed to duplicate source string");
187 0 : return 1;
188 : }
189 : /* coverity[alloc_strlen:SUPPRESS] False positive */
190 0 : src = fmemopen(str, strlen(str), "r");
191 0 : if (src == NULL) {
192 0 : perror("Failed to open string as source file");
193 0 : free(str);
194 0 : return 1;
195 : }
196 0 : ret = lgfs2_lang_parsef(state, src);
197 0 : fclose(src);
198 0 : free(str);
199 0 : if (ret != 0 || state->ls_errnum != 0) {
200 0 : return 1;
201 : }
202 0 : return 0;
203 : }
|