Remove the new machine
[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 MAXDEPTH 3
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         fatal("%s: %d: Syntax Error\n", curfile, curline);
43     }
44
45     action start_block {
46         if (depth++ < MAXDEPTH) {
47             fcall main;
48         } else {
49             fatal("%s: %d: Syntax Error: Nesting Too Deep at '}'", curfile, curline);
50         }
51     }
52
53     action end_block {
54         if (depth--) {
55             fret;
56         } else {
57             fatal("%s: %d: Syntax Error: Unexpected '}'", curfile, curline);
58         }
59     }
60
61     newline = '\n' %newline;
62     comment = '#' (any - '\n')* newline;
63     whitespace = [\t\v\f\r ] | comment | newline;
64     package_name = ((lower | digit) (lower | digit | '+' | '-' | '.')+) >pkgstart;
65     package_list = ((whitespace+ package_name)+ %add_list whitespace*);
66     cmd_install = ('install' @install package_list ';');
67     cmd_remove = ('remove' @remove package_list ';');
68     simple_cmd = cmd_install | cmd_remove;
69     start_block = '{' @start_block;
70     end_block = '}' @end_block;
71     cmd_if = 'if' whitespace+ alpha+ whitespace* start_block whitespace* ('else' whitespace* start_block)?;
72     cmd_list = (simple_cmd | cmd_if | whitespace)* end_block?;
73     main := cmd_list $err(misc_error);
74 }%%
75
76 %% write data;
77
78 #define BUFSIZE 128
79
80 void parser(const char *filename, inapt_context *top_context)
81 {
82     static char buf[BUFSIZE];
83     int fd;
84     int cs, have = 0;
85     int done = 0;
86     int curline = 1;
87     char *ts = 0, *te = 0;
88     inapt_context *cur_context = top_context;
89     int stack[MAXDEPTH];
90     int top = 0; /* TODO: resize */
91     int depth = 0;
92
93     const char *curfile = filename;
94     enum inapt_action::action_t curaction = inapt_action::UNSET;
95
96     if (filename) {
97         fd = open(filename, O_RDONLY);
98         if (fd < 0)
99             fatalpe("open: %s", filename);
100     } else {
101         curfile = "stdin";
102         fd = 0;
103     }
104
105     %% write init;
106
107     while ( !done ) {
108         char *p = buf + have, *pe, *eof = 0;
109         int len, space = BUFSIZE - have;
110
111         if (space == 0) {
112             fprintf(stderr, "OUT OF BUFFER SPACE\n");
113             exit(1);
114         }
115
116         len = read(fd, p, space);
117         if (len < 0) {
118             fprintf(stderr, "IO ERROR\n");
119             exit(1);
120         }
121         pe = p + len;
122
123         if (!len) {
124             eof = pe;
125             done = 1;
126         }
127
128         %% write exec;
129
130         if (cs == inapt_error) {
131             fprintf(stderr, "PARSE ERROR\n");
132             exit(1);
133         }
134
135         have = 0;
136
137         if (ts) {
138             have = pe - ts;
139             memmove(buf, ts, have);
140             te = buf + (te - ts);
141             ts = buf;
142         }
143     }
144
145     if (cs < inapt_first_final) {
146        fprintf(stderr, "UNEXPECTED EOF\n");
147        exit(1);
148     }
149 }