Add a new machine for inner blocks
[mspang/inapt.git] / parser.rl
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <vector>
7
8 #include "inapt.h"
9 #include "util.h"
10
11 using namespace std;
12
13 #define xstrndup strndup
14
15 %%{
16     machine inapt;
17
18     action pkgstart { ts = p; }
19
20     action add_list {
21         inapt_action *tmp_action = new inapt_action;
22         tmp_action->package = xstrndup(ts, p - ts);
23         tmp_action->action = curaction;
24         tmp_action->linenum = curline;
25         tmp_action->filename = curfile;
26         cur_context->actions.push_back(tmp_action);
27     }
28
29     action install {
30         curaction = inapt_action::INSTALL;
31     }
32
33     action remove {
34         curaction = inapt_action::REMOVE;
35     }
36
37     action newline {
38         curline += 1;
39     }
40
41     action misc_error {
42         fprintf(stderr, "%s: %d: Syntax Error\n", curfile, curline);
43     }
44
45     action start_block {
46         fcall block_machine;
47     }
48
49     action end_block {
50         fret;
51     }
52
53     newline = '\n' %newline;
54     comment = '#' (any - newline)* newline;
55     whitespace = [\t\v\f\r ] | comment | newline;
56     package_name = ((lower | digit) (lower | digit | '+' | '-' | '.')+) >pkgstart;
57     package_list = ((whitespace+ package_name)+ %add_list whitespace*);
58     cmd_install = ('install' @install package_list ';');
59     cmd_remove = ('remove' @remove package_list ';');
60     simple_cmd = cmd_install | cmd_remove;
61     block = '{' @start_block;
62     cmd_if = 'if' whitespace+ alpha+ whitespace* block whitespace* ('else' whitespace* block)?;
63     cmd_list = (simple_cmd | cmd_if)* $err(misc_error);
64     block_machine := cmd_list '}' @end_block;
65     main := cmd_list;
66 }%%
67
68 %% write data;
69
70 #define BUFSIZE 128
71
72 void parser(const char *filename, inapt_context *top_context)
73 {
74     static char buf[BUFSIZE];
75     int fd;
76     int cs, have = 0;
77     int done = 0;
78     int curline = 1;
79     char *ts = 0, *te = 0;
80     inapt_context *cur_context = top_context;
81     int stack[100];
82     int top = 0; /* TODO: resize */
83
84     const char *curfile = filename;
85     enum inapt_action::action_t curaction = inapt_action::UNSET;
86
87     if (filename) {
88         fd = open(filename, O_RDONLY);
89         if (fd < 0)
90             fatalpe("open: %s", filename);
91     } else {
92         curfile = "stdin";
93         fd = 0;
94     }
95
96     %% write init;
97
98     while ( !done ) {
99         char *p = buf + have, *pe, *eof = 0;
100         int len, space = BUFSIZE - have;
101
102         if (space == 0) {
103             fprintf(stderr, "OUT OF BUFFER SPACE\n");
104             exit(1);
105         }
106
107         len = read(fd, p, space);
108         if (len < 0) {
109             fprintf(stderr, "IO ERROR\n");
110             exit(1);
111         }
112         pe = p + len;
113
114         if (!len) {
115             eof = pe;
116             done = 1;
117         }
118
119         %% write exec;
120
121         if (cs == inapt_error) {
122             fprintf(stderr, "PARSE ERROR\n");
123             exit(1);
124         }
125
126         have = 0;
127
128         if (ts) {
129             have = pe - ts;
130             memmove(buf, ts, have);
131             te = buf + (te - ts);
132             ts = buf;
133         }
134     }
135
136     if (cs < inapt_first_final) {
137        fprintf(stderr, "UNEXPECTED EOF\n");
138        exit(1);
139     }
140 }