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 : }