]> git.proxmox.com Git - mirror_frr.git/blame - lib/defun_lex.l
Merge pull request #7220 from idryzhov/fix-clear-isis
[mirror_frr.git] / lib / defun_lex.l
CommitLineData
29ad6f68
DL
1/*
2 * clippy (CLI preparator in python) C pseudo-lexer
3 * Copyright (C) 2016-2017 David Lamparter for NetDEF, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/* This is just enough of a lexer to make rough sense of a C source file.
21 * It handles C preprocessor directives, strings, and looks for FRR-specific
22 * idioms (aka DEFUN).
23 *
24 * There is some preliminary support for documentation comments for DEFUNs.
25 * They would look like this (note the ~): (replace \ by /)
26 *
27 * \*~ documentation for foobar_cmd
28 * * parameter does xyz
29 * *\
30 * DEFUN(foobar_cmd, ...)
31 *
32 * This is intended for user documentation / command reference. Don't put
33 * code documentation in it.
34 */
35
7b34167d
DL
36%top{
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40}
41%{
a37bd5e0 42/* ignore harmless bugs in old versions of flex */
29ad6f68 43#pragma GCC diagnostic ignored "-Wsign-compare"
a37bd5e0 44#pragma GCC diagnostic ignored "-Wunused-value"
29ad6f68
DL
45
46#include "config.h"
47#include <Python.h>
48#include <string.h>
49#include <stdlib.h>
50
51#include "command_graph.h"
52#include "clippy.h"
53
54#define ID 258
55#define PREPROC 259
56#define OPERATOR 260
57#define STRING 261
58#define COMMENT 262
59#define SPECIAL 263
60
61#define DEFUNNY 270
62#define INSTALL 271
63#define AUXILIARY 272
64
65int comment_link;
66char string_end;
67
68char *value;
69
70static void extendbuf(char **what, const char *arg)
71{
72 if (!*what)
73 *what = strdup(arg);
74 else {
75 size_t vall = strlen(*what), argl = strlen(arg);
76 *what = realloc(*what, vall + argl + 1);
77 memcpy(*what + vall, arg, argl);
78 (*what)[vall + argl] = '\0';
79 }
80}
81#define extend(x) extendbuf(&value, x)
82
83%}
84
85ID [A-Za-z0-9_]+
86OPERATOR [!%&/\[\]{}=?:^|\*.;><~'\\+-]
87SPECIAL [(),]
88
89%pointer
90%option yylineno
91%option noyywrap
92%option noinput
93%option nounput
4a121f99 94%option outfile="lib/defun_lex.c"
29ad6f68
DL
95%option prefix="def_yy"
96%option 8bit
97
98%s linestart
99%x comment
100%x linecomment
101%x preproc
102%x rstring
103%%
104 BEGIN(linestart);
105
106\n BEGIN(linestart);
107
108<INITIAL,linestart,preproc>"/*" comment_link = YY_START; extend(yytext); BEGIN(comment);
109<comment>[^*\n]* extend(yytext);
110<comment>"*"+[^*/\n]* extend(yytext);
111<comment>\n extend(yytext);
112<comment>"*"+"/" extend(yytext); BEGIN(comment_link); return COMMENT;
113
114<INITIAL,linestart,preproc>"//" comment_link = YY_START; extend(yytext); BEGIN(linecomment);
115<linecomment>[^\n]* extend(yytext);
116<linecomment>\n BEGIN((comment_link == INITIAL) ? linestart : comment_link); return COMMENT;
117
118<linestart># BEGIN(preproc);
119<preproc>\n BEGIN(INITIAL); return PREPROC;
120<preproc>[^\n\\]+ extend(yytext);
121<preproc>\\\n extend(yytext);
122<preproc>\\+[^\n] extend(yytext);
123
124[\"\'] string_end = yytext[0]; extend(yytext); BEGIN(rstring);
125<rstring>[\"\'] {
126 extend(yytext);
127 if (yytext[0] == string_end) {
128 BEGIN(INITIAL);
129 return STRING;
130 }
131 }
132<rstring>\\\n /* ignore */
133<rstring>\\. extend(yytext);
134<rstring>[^\\\"\']+ extend(yytext);
135
136"DEFUN" value = strdup(yytext); return DEFUNNY;
137"DEFUN_NOSH" value = strdup(yytext); return DEFUNNY;
138"DEFUN_HIDDEN" value = strdup(yytext); return DEFUNNY;
139"DEFPY" value = strdup(yytext); return DEFUNNY;
26d19c83 140"DEFPY_NOSH" value = strdup(yytext); return DEFUNNY;
e31f4dbe
QY
141"DEFPY_ATTR" value = strdup(yytext); return DEFUNNY;
142"DEFPY_HIDDEN" value = strdup(yytext); return DEFUNNY;
ca77b518
RW
143"DEFPY_YANG" value = strdup(yytext); return DEFUNNY;
144"DEFPY_YANG_NOSH" value = strdup(yytext); return DEFUNNY;
29ad6f68
DL
145"ALIAS" value = strdup(yytext); return DEFUNNY;
146"ALIAS_HIDDEN" value = strdup(yytext); return DEFUNNY;
147"install_element" value = strdup(yytext); return INSTALL;
148"VTYSH_TARGETS" value = strdup(yytext); return AUXILIARY;
149"VTYSH_NODESWITCH" value = strdup(yytext); return AUXILIARY;
150
151[ \t\n]+ /* ignore */
152\\ /* ignore */
153{ID} BEGIN(INITIAL); value = strdup(yytext); return ID;
154{OPERATOR} BEGIN(INITIAL); value = strdup(yytext); return OPERATOR;
155{SPECIAL} BEGIN(INITIAL); value = strdup(yytext); return SPECIAL;
156. /* printf("-- '%s' in init\n", yytext); */ BEGIN(INITIAL); return yytext[0];
157
158%%
159
160static int yylex_clr(char **retbuf)
161{
162 int rv = def_yylex();
163 *retbuf = value;
164 value = NULL;
165 return rv;
166}
167
3779776a 168static PyObject *get_args(const char *filename, int lineno)
29ad6f68
DL
169{
170 PyObject *pyObj = PyList_New(0);
171 PyObject *pyArg = NULL;
172
173 char *tval;
174 int depth = 1;
175 int token;
176
177 while ((token = yylex_clr(&tval)) != YY_NULL) {
178 if (token == SPECIAL && tval[0] == '(') {
179 free(tval);
180 break;
181 }
182 if (token == COMMENT) {
183 free(tval);
184 continue;
185 }
186 fprintf(stderr, "invalid input!\n");
187 exit(1);
188 }
189
190 while ((token = yylex_clr(&tval)) != YY_NULL) {
191 if (token == COMMENT) {
192 free(tval);
193 continue;
194 }
3779776a
DL
195 if (token == PREPROC) {
196 free(tval);
197 Py_DECREF(pyObj);
198 return PyErr_Format(PyExc_ValueError,
199 "%s:%d: cannot process CPP directive within argument list",
200 filename, lineno);
201 }
29ad6f68
DL
202 if (token == SPECIAL) {
203 if (depth == 1 && (tval[0] == ',' || tval[0] == ')')) {
204 if (pyArg)
205 PyList_Append(pyObj, pyArg);
206 pyArg = NULL;
207 if (tval[0] == ')') {
208 free(tval);
209 break;
210 }
211 free(tval);
212 continue;
213 }
214 if (tval[0] == '(')
215 depth++;
216 if (tval[0] == ')')
217 depth--;
218 }
219 if (!pyArg)
220 pyArg = PyList_New(0);
221 PyList_Append(pyArg, PyUnicode_FromString(tval));
222 free(tval);
223 }
224 return pyObj;
225}
226
227/* _clippy.parse() -- read a C file, returning a list of interesting bits.
228 * note this ditches most of the actual C code. */
229PyObject *clippy_parse(PyObject *self, PyObject *args)
230{
231 const char *filename;
232 if (!PyArg_ParseTuple(args, "s", &filename))
233 return NULL;
234
235 FILE *fd = fopen(filename, "r");
236 if (!fd)
237 return PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
238
239 char *tval;
240 int token;
241 yyin = fd;
242 value = NULL;
243
244 PyObject *pyCont = PyDict_New();
245 PyObject *pyObj = PyList_New(0);
246 PyDict_SetItemString(pyCont, "filename", PyUnicode_FromString(filename));
247 PyDict_SetItemString(pyCont, "data", pyObj);
248
249 while ((token = yylex_clr(&tval)) != YY_NULL) {
250 int lineno = yylineno;
251 PyObject *pyItem = NULL, *pyArgs;
252 switch (token) {
253 case DEFUNNY:
254 case INSTALL:
255 case AUXILIARY:
3779776a
DL
256 pyArgs = get_args(filename, lineno);
257 if (!pyArgs) {
258 free(tval);
259 Py_DECREF(pyCont);
260 return NULL;
261 }
29ad6f68
DL
262 pyItem = PyDict_New();
263 PyDict_SetItemString(pyItem, "type", PyUnicode_FromString(tval));
264 PyDict_SetItemString(pyItem, "args", pyArgs);
265 break;
266 case COMMENT:
267 if (strncmp(tval, "//~", 3) && strncmp(tval, "/*~", 3))
268 break;
269 pyItem = PyDict_New();
270 PyDict_SetItemString(pyItem, "type", PyUnicode_FromString("COMMENT"));
271 PyDict_SetItemString(pyItem, "line", PyUnicode_FromString(tval));
272 break;
273 case PREPROC:
274 pyItem = PyDict_New();
275 PyDict_SetItemString(pyItem, "type", PyUnicode_FromString("PREPROC"));
276 PyDict_SetItemString(pyItem, "line", PyUnicode_FromString(tval));
3779776a 277 lineno--;
29ad6f68
DL
278 break;
279 }
280 if (pyItem) {
281 PyDict_SetItemString(pyItem, "lineno", PyLong_FromLong(lineno));
282 PyList_Append(pyObj, pyItem);
283 }
284 free(tval);
285 }
286 def_yylex_destroy();
287 fclose(fd);
288 return pyCont;
289}