SCDoc: Use proper static string constants instead of comparing string literals.
[supercollider.git] / SCDoc / SCDoc.y
bloba1235ecb58178a3853987688a485d606c101cfa4
1 %{
2 /************************************************************************
4 * Copyright 2012 Jonatan Liljedahl <lijon@kymatica.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 ************************************************************************/
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include "SCDoc.h"
26 //#define YYLEX_PARAM &yylval, &yylloc
28 int scdocparse();
30 extern int scdoclineno;
31 extern char *scdoctext;
32 extern int scdoc_start_token;
33 extern FILE *scdocin;
34 //extern struct YYLTYPE scdoclloc;
36 //int scdoc_metadata_mode;
38 static const char * method_type = NULL;
40 static DocNode * topnode;
42 void scdocerror(const char *str);
44 extern void error(const char *fmt, ...);
45 extern void post(const char *fmt, ...);
48 %locations
49 %error-verbose
50 %union {
51 int i;
52 const char *id;
53 char *str;
54 DocNode *doc_node;
56 // single line header tags that take text
57 %token CLASS TITLE SUMMARY RELATED CATEGORIES REDIRECT
58 // single line body tags that take text
59 %token CLASSTREE COPYMETHOD KEYWORD PRIVATE
60 // single line structural tags that take text, with children
61 %token SECTION SUBSECTION METHOD ARGUMENT
62 // single line structural tags with no text, with children
63 %token DESCRIPTION CLASSMETHODS INSTANCEMETHODS EXAMPLES RETURNS DISCUSSION
64 // nestable range tags with no text, with children
65 %token LIST TREE NUMBEREDLIST DEFINITIONLIST TABLE FOOTNOTE NOTE WARNING
66 // modal range tags that take multi-line text
67 %token CODE LINK ANCHOR SOFT IMAGE TELETYPE MATH STRONG EMPHASIS
68 %token CODEBLOCK "CODE block" TELETYPEBLOCK "TELETYPE block" MATHBLOCK "MATH block"
69 // symbols
70 %token TAGSYM "::" BARS "||" HASHES "##"
71 // text and whitespace
72 %token <str> TEXT "text" URL COMMA METHODNAME "method name" METHODARGS "arguments string"
73 %token NEWLINE "newline" EMPTYLINES "empty lines"
74 %token BAD_METHODNAME "bad method name"
76 %token END 0 "end of file"
78 %type <id> headtag sectiontag listtag rangetag inlinetag blocktag
79 %type <str> anyword words anywordnl wordsnl anywordurl words2 nocommawords optMETHODARGS methodname
80 %type <doc_node> document arg optreturns optdiscussion body bodyelem
81 %type <doc_node> optsubsections optsubsubsections methodbody
82 %type <doc_node> dochead headline optsections sections section
83 %type <doc_node> subsections subsection subsubsection subsubsections
84 %type <doc_node> optbody optargs args listbody tablebody tablecells tablerow
85 %type <doc_node> prose proseelem blockA blockB commalist
86 %type <doc_node> deflistbody deflistrow defterms methnames
88 %token START_FULL START_PARTIAL START_METADATA
90 %start start
92 %destructor { doc_node_free_tree($$); } <doc_node>
93 %destructor { free($$); } <str>
96 //int scdoclex (YYSTYPE * yylval_param, struct YYLTYPE * yylloc_param );
97 int scdoclex (void);
102 start: document { topnode = $1; }
103 | document error { topnode = NULL; doc_node_free_tree($1); }
106 document: START_FULL eateol dochead optsections
108 $$ = doc_node_create("DOCUMENT");
109 doc_node_add_child($$, $3);
110 doc_node_add_child($$, $4);
112 | START_PARTIAL sections
114 $$ = doc_node_make_take_children("BODY",NULL,$2);
116 | START_METADATA dochead optsections
118 $$ = doc_node_create("DOCUMENT");
119 doc_node_add_child($$, $2);
120 doc_node_add_child($$, $3);
124 eateol: eol
125 | /* empty */
128 dochead: dochead headline { $$ = doc_node_add_child($1,$2); }
129 | headline { $$ = doc_node_make("HEADER",NULL,$1); }
132 headline: headtag words2 eol { $$ = doc_node_make($1,$2,NULL); }
133 | CATEGORIES commalist eol { $$ = doc_node_make_take_children("CATEGORIES",NULL,$2); }
134 | RELATED commalist eol { $$ = doc_node_make_take_children("RELATED",NULL,$2); }
137 headtag: CLASS { $$ = "TITLE"; } /* no need for the separate class:: tag actually. */
138 | TITLE { $$ = "TITLE"; }
139 | SUMMARY { $$ = "SUMMARY"; }
140 | REDIRECT { $$ = "REDIRECT"; }
143 sectiontag: CLASSMETHODS { $$ = "CLASSMETHODS"; method_type = "CMETHOD"; }
144 | INSTANCEMETHODS { $$ = "INSTANCEMETHODS"; method_type = "IMETHOD"; }
145 | DESCRIPTION { $$ = "DESCRIPTION"; method_type = "METHOD"; }
146 | EXAMPLES { $$ = "EXAMPLES"; method_type = "METHOD"; }
149 optsections: sections
150 | { $$ = doc_node_make("BODY",NULL,NULL); }
153 sections: sections section { $$ = doc_node_add_child($1,$2); }
154 | section { $$ = doc_node_make("BODY",NULL,$1); }
155 | subsubsections { $$ = doc_node_make_take_children("BODY",NULL,$1); } /* allow text before first section */
158 section: SECTION { method_type = "METHOD"; } words2 eol optsubsections { $$ = doc_node_make_take_children("SECTION",$3,$5); }
159 | sectiontag optsubsections { $$ = doc_node_make_take_children($1, NULL,$2); }
162 optsubsections: subsections
163 | { $$ = NULL; }
166 subsections: subsections subsection { $$ = doc_node_add_child($1,$2); }
167 | subsection { $$ = doc_node_make("(SUBSECTIONS)",NULL,$1); }
168 | subsubsections
171 subsection: SUBSECTION words2 eol optsubsubsections { $$ = doc_node_make_take_children("SUBSECTION", $2, $4); }
174 optsubsubsections: subsubsections
175 | { $$ = NULL; }
178 subsubsections: subsubsections subsubsection { $$ = doc_node_add_child($1,$2); }
179 | subsubsection { $$ = doc_node_make("(SUBSUBSECTIONS)",NULL,$1); }
180 | body { $$ = doc_node_make_take_children("(SUBSUBSECTIONS)",NULL,$1); }
183 subsubsection: METHOD methnames optMETHODARGS eol methodbody
185 $2->id = "METHODNAMES";
186 $$ = doc_node_make(method_type,$3,$2);
187 doc_node_add_child($$, $5);
188 // doc_node_add_child($2, $3);
190 | COPYMETHOD words eol { $$ = doc_node_make(
191 method_type=="CMETHOD"?"CCOPYMETHOD":(method_type=="IMETHOD"?"ICOPYMETHOD":"COPYMETHOD"),
192 $2,NULL
193 ); }
194 | PRIVATE commalist eoleof { $$ = doc_node_make_take_children(method_type=="CMETHOD"?"CPRIVATE":"IPRIVATE",NULL,$2); }
197 optMETHODARGS: { $$ = NULL; }
198 | METHODARGS
200 // $$ = doc_node_make("ARGSTRING",$1,NULL);
201 $$ = $1;
202 if(method_type!="METHOD") {
203 yyerror("METHOD argument string is not allowed inside CLASSMETHODS or INSTANCEMETHODS");
204 YYERROR;
209 methodname: METHODNAME
211 char *p = $1+strlen($1)-1;
212 if(*p=='_') {
213 post("WARNING: SCDoc: In %s\n Property setter %s should be documented without underscore.\n", scdoc_current_file, $1);
214 *p = '\0';
216 $$ = $1;
220 methnames: methnames COMMA methodname { free($2); $2 = NULL; $$ = doc_node_add_child($1, doc_node_make("STRING",$3,NULL)); }
221 | methodname { $$ = doc_node_make("(METHODNAMES)",NULL,doc_node_make("STRING",$1,NULL)); }
224 methodbody: optbody optargs optreturns optdiscussion
226 $$ = doc_node_make_take_children("METHODBODY",NULL,$1);
227 doc_node_add_child($$, $2);
228 doc_node_add_child($$, $3);
229 doc_node_add_child($$, $4);
233 optbody: body
234 | { $$ = NULL; }
237 optargs: args
238 | { $$ = NULL; }
241 args: args arg { $$ = doc_node_add_child($1,$2); }
242 | arg { $$ = doc_node_make("ARGUMENTS",NULL,$1); }
245 arg: ARGUMENT words eol optbody { $$ = doc_node_make_take_children("ARGUMENT", $2, $4); }
246 | ARGUMENT eol body { $$ = doc_node_make_take_children("ARGUMENT", NULL, $3); }
249 optreturns: RETURNS body { $$ = doc_node_make_take_children("RETURNS",NULL,$2); }
250 | { $$ = NULL; }
253 optdiscussion: DISCUSSION body { $$ = doc_node_make_take_children("DISCUSSION",NULL,$2); }
254 | { $$ = NULL; }
258 body contains a list of bodyelem's (A) and prose (B) such that
259 the list can start and end with either A or B, and A can repeat while B can not
262 body: blockA
263 | blockB
266 blockA: blockB bodyelem { $$ = doc_node_add_child($1,$2); }
267 | blockA bodyelem { $$ = doc_node_add_child($1,$2); }
268 | bodyelem { $$ = doc_node_make("(SECTIONBODY)",NULL,$1); }
271 blockB: blockA prose { $$ = doc_node_add_child($1,$2); }
272 | prose { $$ = doc_node_make("(SECTIONBODY)",NULL,$1); }
275 bodyelem: rangetag body TAGSYM { $$ = doc_node_make_take_children($1,NULL,$2); }
276 | listtag listbody TAGSYM { $$ = doc_node_make_take_children($1,NULL,$2); }
277 | TABLE tablebody TAGSYM { $$ = doc_node_make_take_children("TABLE",NULL,$2); }
278 | DEFINITIONLIST deflistbody TAGSYM { $$ = doc_node_make_take_children("DEFINITIONLIST",NULL,$2); }
279 | blocktag wordsnl TAGSYM { $$ = doc_node_make($1,$2,NULL); }
280 | CLASSTREE words eoleof { $$ = doc_node_make("CLASSTREE",$2,NULL); }
281 | KEYWORD commalist eoleof { $$ = doc_node_make_take_children("KEYWORD",NULL,$2);
282 // printf("keyword '%s'\n",$2->children[0]->text);
284 | EMPTYLINES { $$ = NULL; }
285 | IMAGE words2 TAGSYM { $$ = doc_node_make("IMAGE",$2,NULL); }
288 prose: prose proseelem { $$ = doc_node_add_child($1, $2); }
289 | proseelem { $$ = doc_node_make("PROSE",NULL,$1); }
292 proseelem: anyword { $$ = doc_node_make(NODE_TEXT,$1,NULL); } // one TEXT for each word
293 | URL { $$ = doc_node_make("LINK",$1,NULL); }
294 | inlinetag words TAGSYM { $$ = doc_node_make($1,$2,NULL); }
295 | FOOTNOTE body TAGSYM { $$ = doc_node_make_take_children("FOOTNOTE",NULL,$2); }
296 | NEWLINE { $$ = doc_node_create(NODE_NL); }
299 inlinetag: LINK { $$ = "LINK"; }
300 | STRONG { $$ = "STRONG"; }
301 | SOFT { $$ = "SOFT"; }
302 | EMPHASIS { $$ = "EMPHASIS"; }
303 | CODE { $$ = "CODE"; }
304 | TELETYPE { $$ = "TELETYPE"; }
305 | MATH { $$ = "MATH"; }
306 | ANCHOR { $$ = "ANCHOR"; }
309 blocktag: CODEBLOCK { $$ = "CODEBLOCK"; }
310 | TELETYPEBLOCK { $$ = "TELETYPEBLOCK"; }
311 | MATHBLOCK { $$ = "MATHBLOCK"; }
314 listtag: LIST { $$ = "LIST"; }
315 | TREE { $$ = "TREE"; }
316 | NUMBEREDLIST { $$ = "NUMBEREDLIST"; }
319 rangetag: WARNING { $$ = "WARNING"; }
320 | NOTE { $$ = "NOTE"; }
323 listbody: listbody HASHES body { $$ = doc_node_add_child($1, doc_node_make_take_children("ITEM",NULL,$3)); }
324 | HASHES body { $$ = doc_node_make("(LISTBODY)",NULL, doc_node_make_take_children("ITEM",NULL,$2)); }
327 tablerow: HASHES tablecells { $$ = doc_node_make_take_children("TABROW",NULL,$2); }
330 tablebody: tablebody tablerow { $$ = doc_node_add_child($1,$2); }
331 | tablerow { $$ = doc_node_make("(TABLEBODY)",NULL,$1); }
334 tablecells: tablecells BARS optbody { $$ = doc_node_add_child($1, doc_node_make_take_children("TABCOL",NULL,$3)); }
335 | optbody { $$ = doc_node_make("(TABLECELLS)",NULL, doc_node_make_take_children("TABCOL",NULL,$1)); }
338 defterms: defterms HASHES body { $$ = doc_node_add_child($1,doc_node_make_take_children("TERM",NULL,$3)); }
339 | HASHES body { $$ = doc_node_make("(TERMS)",NULL,doc_node_make_take_children("TERM",NULL,$2)); }
342 deflistrow: defterms BARS optbody
344 $$ = doc_node_make_take_children("DEFLISTITEM", NULL, $1);
345 doc_node_add_child($$, doc_node_make_take_children("DEFINITION", NULL, $3));
349 deflistbody: deflistbody deflistrow { $$ = doc_node_add_child($1,$2); }
350 | deflistrow { $$ = doc_node_make("(DEFLISTBODY)",NULL,$1); }
353 anywordurl: anyword
354 | URL
357 anyword: TEXT
358 | COMMA
361 words: words anyword { $$ = strmerge($1,$2); }
362 | anyword
365 words2: words2 anywordurl { $$ = strmerge($1,$2); }
366 | anywordurl
369 eol: NEWLINE
370 | EMPTYLINES
373 eoleof: eol
374 | END
377 anywordnl: anyword
378 | eol { $$ = strdup("\n"); }
381 wordsnl: wordsnl anywordnl { $$ = strmerge($1,$2); }
382 | anywordnl
385 nocommawords: nocommawords TEXT { $$ = strmerge($1,$2); }
386 | nocommawords URL { $$ = strmerge($1,$2); }
387 | TEXT
388 | URL
391 commalist: commalist COMMA nocommawords { free($2); $2=NULL; $$ = doc_node_add_child($1,doc_node_make("STRING",$3,NULL)); }
392 | nocommawords { $$ = doc_node_make("(COMMALIST)",NULL,doc_node_make("STRING",$1,NULL)); }
397 DocNode * scdoc_parse_run(int mode) {
398 int modes[] = {START_FULL, START_PARTIAL, START_METADATA};
399 if(mode<0 || mode>=sizeof(modes)) {
400 error("scdoc_parse_run(): unknown mode: %d\n",mode);
402 scdoc_start_token = modes[mode];
403 /* scdoc_start_token = START_FULL;
404 scdoc_metadata_mode = 0;
405 if(mode==SCDOC_PARSE_PARTIAL) {
406 scdoc_start_token = START_PARTIAL;
407 } else
408 if(mode==SCDOC_PARSE_METADATA) {
409 scdoc_metadata_mode = 1;
411 topnode = NULL;
412 method_type = "METHOD";
413 if(scdocparse()!=0) {
414 return NULL;
416 return topnode;
419 void scdocerror(const char *str)
421 error("In %s:\n At line %d: %s\n\n",scdoc_current_file,scdoclineno,str);
423 /* FIXME: this does not work well, since the reported linenumber is often *after* the actual error line
424 fseek(scdocin, 0, SEEK_SET);
425 int line = 1;
426 char buf[256],*txt;
427 while(line!=scdoclineno && !feof(scdocin)) {
428 int c = fgetc(scdocin);
429 if(c=='\n') line++;
431 txt = fgets(buf, 256, scdocin);
432 if(txt)
433 fprintf(stderr," %s\n-------------------\n", txt);