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 ************************************************************************/
26 //#define YYLEX_PARAM &yylval, &yylloc
30 extern
int scdoclineno
;
31 extern
char *scdoctext
;
32 extern
int scdoc_start_token
;
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
, ...
);
47 static inline
bool stringEqual
(const char * a
, const char * b
)
49 return strcmp
(a
, b
) == 0;
61 // single line header tags that take text
62 %token CLASS TITLE SUMMARY RELATED CATEGORIES REDIRECT
63 // single line body tags that take text
64 %token CLASSTREE COPYMETHOD KEYWORD PRIVATE
65 // single line structural tags that take text, with children
66 %token SECTION SUBSECTION METHOD ARGUMENT
67 // single line structural tags with no text, with children
68 %token DESCRIPTION CLASSMETHODS INSTANCEMETHODS EXAMPLES RETURNS DISCUSSION
69 // nestable range tags with no text, with children
70 %token LIST TREE NUMBEREDLIST DEFINITIONLIST TABLE FOOTNOTE NOTE WARNING
71 // modal range tags that take multi-line text
72 %token CODE LINK ANCHOR SOFT IMAGE TELETYPE MATH STRONG EMPHASIS
73 %token CODEBLOCK
"CODE block" TELETYPEBLOCK
"TELETYPE block" MATHBLOCK
"MATH block"
75 %token TAGSYM
"::" BARS
"||" HASHES
"##"
76 // text and whitespace
77 %token
<str
> TEXT
"text" URL COMMA METHODNAME
"method name" METHODARGS
"arguments string"
78 %token NEWLINE
"newline" EMPTYLINES
"empty lines"
79 %token BAD_METHODNAME
"bad method name"
81 %token END
0 "end of file"
83 %type
<id
> headtag sectiontag listtag rangetag inlinetag blocktag
84 %type
<str
> anyword words anywordnl wordsnl anywordurl words2 nocommawords optMETHODARGS methodname
85 %type
<doc_node
> document arg optreturns optdiscussion body bodyelem
86 %type
<doc_node
> optsubsections optsubsubsections methodbody
87 %type
<doc_node
> dochead headline optsections sections section
88 %type
<doc_node
> subsections subsection subsubsection subsubsections
89 %type
<doc_node
> optbody optargs args listbody tablebody tablecells tablerow
90 %type
<doc_node
> prose proseelem blockA blockB commalist
91 %type
<doc_node
> deflistbody deflistrow defterms methnames
93 %token START_FULL START_PARTIAL START_METADATA
97 %destructor
{ doc_node_free_tree
($$
); } <doc_node
>
98 %destructor
{ free
($$
); } <str
>
101 //int scdoclex (YYSTYPE * yylval_param, struct YYLTYPE * yylloc_param );
107 start: document
{ topnode
= $1; }
108 | document
error { topnode
= NULL
; doc_node_free_tree
($1); }
111 document: START_FULL eateol dochead optsections
113 $$
= doc_node_create
("DOCUMENT");
114 doc_node_add_child
($$
, $3);
115 doc_node_add_child
($$
, $4);
117 | START_PARTIAL sections
119 $$
= doc_node_make_take_children
("BODY",NULL
,$2);
121 | START_METADATA dochead optsections
123 $$
= doc_node_create
("DOCUMENT");
124 doc_node_add_child
($$
, $2);
125 doc_node_add_child
($$
, $3);
133 dochead: dochead headline
{ $$
= doc_node_add_child
($1,$2); }
134 | headline
{ $$
= doc_node_make
("HEADER",NULL
,$1); }
137 headline: headtag words2 eol
{ $$
= doc_node_make
($1,$2,NULL
); }
138 | CATEGORIES commalist eol
{ $$
= doc_node_make_take_children
("CATEGORIES",NULL
,$2); }
139 | RELATED commalist eol
{ $$
= doc_node_make_take_children
("RELATED",NULL
,$2); }
142 headtag: CLASS
{ $$
= "TITLE"; } /* no need for the separate class:: tag actually. */
143 | TITLE
{ $$
= "TITLE"; }
144 | SUMMARY
{ $$
= "SUMMARY"; }
145 | REDIRECT
{ $$
= "REDIRECT"; }
148 sectiontag: CLASSMETHODS
{ $$
= "CLASSMETHODS"; method_type
= "CMETHOD"; }
149 | INSTANCEMETHODS
{ $$
= "INSTANCEMETHODS"; method_type
= "IMETHOD"; }
150 | DESCRIPTION
{ $$
= "DESCRIPTION"; method_type
= "METHOD"; }
151 | EXAMPLES
{ $$
= "EXAMPLES"; method_type
= "METHOD"; }
154 optsections: sections
155 |
{ $$
= doc_node_make
("BODY",NULL
,NULL
); }
158 sections: sections section
{ $$
= doc_node_add_child
($1,$2); }
159 | section
{ $$
= doc_node_make
("BODY",NULL
,$1); }
160 | subsubsections
{ $$
= doc_node_make_take_children
("BODY",NULL
,$1); } /* allow text before first section */
163 section: SECTION
{ method_type
= "METHOD"; } words2 eol optsubsections
{ $$
= doc_node_make_take_children
("SECTION",$3,$5); }
164 | sectiontag optsubsections
{ $$
= doc_node_make_take_children
($1, NULL
,$2); }
167 optsubsections: subsections
171 subsections: subsections subsection
{ $$
= doc_node_add_child
($1,$2); }
172 | subsection
{ $$
= doc_node_make
("(SUBSECTIONS)",NULL
,$1); }
176 subsection: SUBSECTION words2 eol optsubsubsections
{ $$
= doc_node_make_take_children
("SUBSECTION", $2, $4); }
179 optsubsubsections: subsubsections
183 subsubsections: subsubsections subsubsection
{ $$
= doc_node_add_child
($1,$2); }
184 | subsubsection
{ $$
= doc_node_make
("(SUBSUBSECTIONS)",NULL
,$1); }
185 | body
{ $$
= doc_node_make_take_children
("(SUBSUBSECTIONS)",NULL
,$1); }
188 subsubsection: METHOD methnames optMETHODARGS eol methodbody
190 $2->id
= "METHODNAMES";
191 $$
= doc_node_make
(method_type
,$3,$2);
192 doc_node_add_child
($$
, $5);
193 // doc_node_add_child($2, $3);
195 | COPYMETHOD words eol
{ $$
= doc_node_make
(
196 stringEqual
(method_type
, "CMETHOD") ?
"CCOPYMETHOD"
197 : (stringEqual
(method_type
, "IMETHOD") ?
"ICOPYMETHOD"
201 | PRIVATE commalist eoleof
{ $$
= doc_node_make_take_children
( stringEqual
(method_type
, "CMETHOD") ?
"CPRIVATE"
206 optMETHODARGS: { $$
= NULL
; }
209 // $$ = doc_node_make("ARGSTRING",$1,NULL);
211 if
(!stringEqual
(method_type
, "METHOD")) {
212 yyerror("METHOD argument string is not allowed inside CLASSMETHODS or INSTANCEMETHODS");
218 methodname: METHODNAME
220 char *p
= $1+strlen
($1)-1;
222 post
("WARNING: SCDoc: In %s\n Property setter %s should be documented without underscore.\n", scdoc_current_file
, $1);
229 methnames: methnames COMMA methodname
{ free
($2); $2 = NULL
; $$
= doc_node_add_child
($1, doc_node_make
("STRING",$3,NULL
)); }
230 | methodname
{ $$
= doc_node_make
("(METHODNAMES)",NULL
,doc_node_make
("STRING",$1,NULL
)); }
233 methodbody: optbody optargs optreturns optdiscussion
235 $$
= doc_node_make_take_children
("METHODBODY",NULL
,$1);
236 doc_node_add_child
($$
, $2);
237 doc_node_add_child
($$
, $3);
238 doc_node_add_child
($$
, $4);
250 args: args arg
{ $$
= doc_node_add_child
($1,$2); }
251 | arg
{ $$
= doc_node_make
("ARGUMENTS",NULL
,$1); }
254 arg: ARGUMENT words eol optbody
{ $$
= doc_node_make_take_children
("ARGUMENT", $2, $4); }
255 | ARGUMENT eol body
{ $$
= doc_node_make_take_children
("ARGUMENT", NULL
, $3); }
258 optreturns: RETURNS body
{ $$
= doc_node_make_take_children
("RETURNS",NULL
,$2); }
262 optdiscussion: DISCUSSION body
{ $$
= doc_node_make_take_children
("DISCUSSION",NULL
,$2); }
267 body contains a list of bodyelem's (A) and prose (B) such that
268 the list can start and end with either A or B, and A can repeat while B can not
275 blockA: blockB bodyelem
{ $$
= doc_node_add_child
($1,$2); }
276 | blockA bodyelem
{ $$
= doc_node_add_child
($1,$2); }
277 | bodyelem
{ $$
= doc_node_make
("(SECTIONBODY)",NULL
,$1); }
280 blockB: blockA prose
{ $$
= doc_node_add_child
($1,$2); }
281 | prose
{ $$
= doc_node_make
("(SECTIONBODY)",NULL
,$1); }
284 bodyelem: rangetag body TAGSYM
{ $$
= doc_node_make_take_children
($1,NULL
,$2); }
285 | listtag listbody TAGSYM
{ $$
= doc_node_make_take_children
($1,NULL
,$2); }
286 | TABLE tablebody TAGSYM
{ $$
= doc_node_make_take_children
("TABLE",NULL
,$2); }
287 | DEFINITIONLIST deflistbody TAGSYM
{ $$
= doc_node_make_take_children
("DEFINITIONLIST",NULL
,$2); }
288 | blocktag wordsnl TAGSYM
{ $$
= doc_node_make
($1,$2,NULL
); }
289 | CLASSTREE words eoleof
{ $$
= doc_node_make
("CLASSTREE",$2,NULL
); }
290 | KEYWORD commalist eoleof
{ $$
= doc_node_make_take_children
("KEYWORD",NULL
,$2);
291 // printf("keyword '%s'\n",$2->children[0]->text);
293 | EMPTYLINES
{ $$
= NULL
; }
294 | IMAGE words2 TAGSYM
{ $$
= doc_node_make
("IMAGE",$2,NULL
); }
297 prose: prose proseelem
{ $$
= doc_node_add_child
($1, $2); }
298 | proseelem
{ $$
= doc_node_make
("PROSE",NULL
,$1); }
301 proseelem: anyword
{ $$
= doc_node_make
(NODE_TEXT
,$1,NULL
); } // one TEXT for each word
302 | URL
{ $$
= doc_node_make
("LINK",$1,NULL
); }
303 | inlinetag words TAGSYM
{ $$
= doc_node_make
($1,$2,NULL
); }
304 | FOOTNOTE body TAGSYM
{ $$
= doc_node_make_take_children
("FOOTNOTE",NULL
,$2); }
305 | NEWLINE
{ $$
= doc_node_create
(NODE_NL
); }
308 inlinetag: LINK
{ $$
= "LINK"; }
309 | STRONG
{ $$
= "STRONG"; }
310 | SOFT
{ $$
= "SOFT"; }
311 | EMPHASIS
{ $$
= "EMPHASIS"; }
312 | CODE
{ $$
= "CODE"; }
313 | TELETYPE
{ $$
= "TELETYPE"; }
314 | MATH
{ $$
= "MATH"; }
315 | ANCHOR
{ $$
= "ANCHOR"; }
318 blocktag: CODEBLOCK
{ $$
= "CODEBLOCK"; }
319 | TELETYPEBLOCK
{ $$
= "TELETYPEBLOCK"; }
320 | MATHBLOCK
{ $$
= "MATHBLOCK"; }
323 listtag: LIST
{ $$
= "LIST"; }
324 | TREE
{ $$
= "TREE"; }
325 | NUMBEREDLIST
{ $$
= "NUMBEREDLIST"; }
328 rangetag: WARNING
{ $$
= "WARNING"; }
329 | NOTE
{ $$
= "NOTE"; }
332 listbody: listbody HASHES body
{ $$
= doc_node_add_child
($1, doc_node_make_take_children
("ITEM",NULL
,$3)); }
333 | HASHES body
{ $$
= doc_node_make
("(LISTBODY)",NULL
, doc_node_make_take_children
("ITEM",NULL
,$2)); }
336 tablerow: HASHES tablecells
{ $$
= doc_node_make_take_children
("TABROW",NULL
,$2); }
339 tablebody: tablebody tablerow
{ $$
= doc_node_add_child
($1,$2); }
340 | tablerow
{ $$
= doc_node_make
("(TABLEBODY)",NULL
,$1); }
343 tablecells: tablecells BARS optbody
{ $$
= doc_node_add_child
($1, doc_node_make_take_children
("TABCOL",NULL
,$3)); }
344 | optbody
{ $$
= doc_node_make
("(TABLECELLS)",NULL
, doc_node_make_take_children
("TABCOL",NULL
,$1)); }
347 defterms: defterms HASHES body
{ $$
= doc_node_add_child
($1,doc_node_make_take_children
("TERM",NULL
,$3)); }
348 | HASHES body
{ $$
= doc_node_make
("(TERMS)",NULL
,doc_node_make_take_children
("TERM",NULL
,$2)); }
351 deflistrow: defterms BARS optbody
353 $$
= doc_node_make_take_children
("DEFLISTITEM", NULL
, $1);
354 doc_node_add_child
($$
, doc_node_make_take_children
("DEFINITION", NULL
, $3));
358 deflistbody: deflistbody deflistrow
{ $$
= doc_node_add_child
($1,$2); }
359 | deflistrow
{ $$
= doc_node_make
("(DEFLISTBODY)",NULL
,$1); }
370 words: words anyword
{ $$
= strmerge
($1,$2); }
374 words2: words2 anywordurl
{ $$
= strmerge
($1,$2); }
387 | eol
{ $$
= strdup
("\n"); }
390 wordsnl: wordsnl anywordnl
{ $$
= strmerge
($1,$2); }
394 nocommawords: nocommawords TEXT
{ $$
= strmerge
($1,$2); }
395 | nocommawords URL
{ $$
= strmerge
($1,$2); }
400 commalist: commalist COMMA nocommawords
{ free
($2); $2=NULL
; $$
= doc_node_add_child
($1,doc_node_make
("STRING",$3,NULL
)); }
401 | nocommawords
{ $$
= doc_node_make
("(COMMALIST)",NULL
,doc_node_make
("STRING",$1,NULL
)); }
406 DocNode
* scdoc_parse_run
(int mode
) {
407 int modes
[] = {START_FULL
, START_PARTIAL
, START_METADATA
};
408 if
(mode
<0 || mode
>=sizeof
(modes
)) {
409 error("scdoc_parse_run(): unknown mode: %d\n",mode
);
411 scdoc_start_token
= modes
[mode
];
412 /* scdoc_start_token = START_FULL;
413 scdoc_metadata_mode = 0;
414 if(mode==SCDOC_PARSE_PARTIAL) {
415 scdoc_start_token = START_PARTIAL;
417 if(mode==SCDOC_PARSE_METADATA) {
418 scdoc_metadata_mode = 1;
421 method_type
= "METHOD";
422 if
(scdocparse
()!=0) {
428 void scdocerror
(const char *str
)
430 error("In %s:\n At line %d: %s\n\n",scdoc_current_file
,scdoclineno
,str
);
432 /* FIXME: this does not work well, since the reported linenumber is often *after* the actual error line
433 fseek(scdocin, 0, SEEK_SET);
436 while(line!=scdoclineno && !feof(scdocin)) {
437 int c = fgetc(scdocin);
440 txt = fgets(buf, 256, scdocin);
442 fprintf(stderr," %s\n-------------------\n", txt);