vcg.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. /*
  2. * Copright 2021
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. * These are the four essential freedoms with GNU GPL software:
  18. * 1: freedom to run the program, for any purpose
  19. * 2: freedom to study how the program works, and change it to make it do what you wish
  20. * 3: freedom to redistribute copies to help your Free Software friends
  21. * 4: freedom to distribute copies of your modified versions to your Free Software friends
  22. * , ,
  23. * / \
  24. * ((__-^^-,-^^-__))
  25. * `-_---' `---_-'
  26. * `--|o` 'o|--'
  27. * \ ` /
  28. * ): :(
  29. * :o_o:
  30. * "-"
  31. *
  32. * SPDX-License-Identifier: GPL-3.0+
  33. * License-Filename: LICENSE
  34. */
  35. /* parse the vcg data generated with gcc -fcallgraph-info option which is a subset of vcg language.
  36. * for other vcg data this file must be updated.
  37. * this does only handle the gcc ci file part which is a minimal vcg language
  38. * and this program has nothing todo with the vcg tool
  39. */
  40. #include "config.h"
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <zlib.h>
  45. #include "splay-tree.h"
  46. #include "main.h"
  47. #include "hier.h"
  48. #include "uniqnode.h"
  49. #include "uniqstr.h"
  50. #include "vcg.h"
  51. #include "vcgus.h"
  52. #include "vcgun.h"
  53. #include "vcg.yy.h"
  54. #include "vcg.tab.h"
  55. #include "dpmem.h"
  56. #include "dot.tab.h"
  57. /* like yydebug, set via lexer init */
  58. int vcgdebug = 0;
  59. /* current lexed token */
  60. static int vcgtoken = 0;
  61. /* set at parse error */
  62. static int vcgerror = 0;
  63. /* nodes list */
  64. static struct vcgn *vnl = NULL;
  65. static struct vcgn *vnlend = NULL;
  66. /* edges list */
  67. static struct vcge *vel = NULL;
  68. static struct vcge *velend = NULL;
  69. /* graph title */
  70. static char *graphtitle = NULL;
  71. /* current file name */
  72. static char *curfname = NULL;
  73. /* uniq node number */
  74. static int vcgnn = 0;
  75. /* uniq edge number */
  76. static int vcgen = 0;
  77. /* clear edge list */
  78. static void vel_clear(void)
  79. {
  80. struct vcge *pvnl = NULL;
  81. struct vcge *pvnlnext = NULL;
  82. pvnl = vel;
  83. while (pvnl) {
  84. pvnlnext = pvnl->next;
  85. pvnl = dp_free(pvnl);
  86. if (pvnl) {
  87. }
  88. pvnl = pvnlnext;
  89. }
  90. return;
  91. }
  92. /* clear node list */
  93. static void vnl_clear(void)
  94. {
  95. struct vcgn *pvnl = NULL;
  96. struct vcgn *pvnlnext = NULL;
  97. pvnl = vnl;
  98. while (pvnl) {
  99. pvnlnext = pvnl->next;
  100. pvnl = dp_free(pvnl);
  101. if (pvnl) {
  102. }
  103. pvnl = pvnlnext;
  104. }
  105. return;
  106. }
  107. /* clear all at parse error */
  108. static void vcgparse_clear(void)
  109. {
  110. /* clear edge list */
  111. vel_clear();
  112. /* clear node list */
  113. vnl_clear();
  114. /* in vcg.l */
  115. vcg_lex_clear();
  116. /* node db */
  117. clear_vcguniqnode();
  118. /* uniq strings db */
  119. vcg_clear_uniqstr();
  120. /* no debug */
  121. vcgdebug = 0;
  122. /* current lexed token */
  123. vcgtoken = 0;
  124. /* set at parse error */
  125. vcgerror = 0;
  126. /* nodes list */
  127. vnl = NULL;
  128. vnlend = NULL;
  129. /* edges list */
  130. vel = NULL;
  131. velend = NULL;
  132. /* global graph title */
  133. graphtitle = NULL;
  134. /* current filename */
  135. curfname = NULL;
  136. /* uniq node number */
  137. vcgnn = 0;
  138. /* uniq edge number */
  139. vcgen = 0;
  140. return;
  141. }
  142. /* handle graph title statement */
  143. static void vcggraphtitle(void)
  144. {
  145. vcgtoken = vcglex();
  146. if (vcgtoken != VCG_COLON) {
  147. memset(parsermessage, 0, 256);
  148. snprintf(parsermessage, (256 - 1), "vcg %s(): expected ':' after \"title\" at line %d in file %s\n", __func__,
  149. vcglineno, curfname);
  150. vcgerror = 1;
  151. return;
  152. }
  153. vcgtoken = vcglex();
  154. if (vcgtoken != VCG_STRING) {
  155. memset(parsermessage, 0, 256);
  156. snprintf(parsermessage, (256 - 1), "vcg %s(): expected string after \"title:\" at line %d in file %s\n", __func__,
  157. vcglineno, curfname);
  158. vcgerror = 1;
  159. return;
  160. }
  161. graphtitle = vcglaststring;
  162. return;
  163. }
  164. /* handle a node statement */
  165. static void vcgnode(void)
  166. {
  167. int shape = 0;
  168. char *title = NULL;
  169. char *label = NULL;
  170. struct vcgn *newnode = NULL;
  171. vcgtoken = vcglex();
  172. if (vcgtoken != VCG_COLON) {
  173. memset(parsermessage, 0, 256);
  174. snprintf(parsermessage, (256 - 1), "vcg %s(): expected ':' after \"node\" at line %d in file %s\n", __func__,
  175. vcglineno, curfname);
  176. vcgerror = 1;
  177. return;
  178. }
  179. vcgtoken = vcglex();
  180. if (vcgtoken != VCG_BO) {
  181. memset(parsermessage, 0, 256);
  182. snprintf(parsermessage, (256 - 1), "vcg %s(): expected '{' after \"node:\" at line %d in file %s\n", __func__,
  183. vcglineno, curfname);
  184. vcgerror = 1;
  185. return;
  186. }
  187. for (;;) {
  188. if (vcgerror) {
  189. break;
  190. }
  191. vcgtoken = vcglex();
  192. if (vcgtoken == EOF) {
  193. memset(parsermessage, 0, 256);
  194. snprintf(parsermessage, (256 - 1), "vcg %s(): unexpected end-of-file in \"node:\" at line %d in file %s\n",
  195. __func__, vcglineno, curfname);
  196. vcgerror = 1;
  197. break;
  198. }
  199. /* an brace close at end of node statement */
  200. if (vcgtoken == VCG_BC) {
  201. break;
  202. }
  203. if (vcgtoken == VCG_TITLE) {
  204. vcgtoken = vcglex();
  205. if (vcgtoken != VCG_COLON) {
  206. memset(parsermessage, 0, 256);
  207. snprintf(parsermessage, (256 - 1), "vcg %s(): expected ':' after \"title\" at line %d in file %s\n",
  208. __func__, vcglineno, curfname);
  209. vcgerror = 1;
  210. break;
  211. }
  212. vcgtoken = vcglex();
  213. if (vcgtoken != VCG_STRING) {
  214. memset(parsermessage, 0, 256);
  215. snprintf(parsermessage, (256 - 1),
  216. "vcg %s(): expected string after \"title:\" at line %d in file %s\n", __func__, vcglineno, curfname);
  217. vcgerror = 1;
  218. break;
  219. }
  220. title = vcglaststring;
  221. vcglaststring = NULL;
  222. } else if (vcgtoken == VCG_LABEL) {
  223. vcgtoken = vcglex();
  224. if (vcgtoken != VCG_COLON) {
  225. memset(parsermessage, 0, 256);
  226. snprintf(parsermessage, (256 - 1), "vcg %s(): expected ':' after \"label\" at line %d in file %s\n",
  227. __func__, vcglineno, curfname);
  228. vcgerror = 1;
  229. break;
  230. }
  231. vcgtoken = vcglex();
  232. if (vcgtoken != VCG_STRING) {
  233. memset(parsermessage, 0, 256);
  234. snprintf(parsermessage, (256 - 1),
  235. "vcg %s(): expected string after \"label:\" at line %d in file %s\n", __func__, vcglineno, curfname);
  236. vcgerror = 1;
  237. break;
  238. }
  239. label = vcglaststring;
  240. vcglaststring = NULL;
  241. } else if (vcgtoken == VCG_SHAPE) {
  242. vcgtoken = vcglex();
  243. if (vcgtoken != VCG_COLON) {
  244. memset(parsermessage, 0, 256);
  245. snprintf(parsermessage, (256 - 1), "vcg %s(): expected ':' after \"shape\" at line %d in file %s\n",
  246. __func__, vcglineno, curfname);
  247. vcgerror = 1;
  248. break;
  249. }
  250. vcgtoken = vcglex();
  251. if (vcgtoken != VCG_ELLIPSE) {
  252. memset(parsermessage, 0, 256);
  253. snprintf(parsermessage, (256 - 1),
  254. "vcg %s(): expected ellipse after \"shape:\" at line %d in file %s\n", __func__, vcglineno, curfname);
  255. vcgerror = 1;
  256. break;
  257. }
  258. shape = 1;
  259. } else {
  260. memset(parsermessage, 0, 256);
  261. snprintf(parsermessage, (256 - 1), "vcg %s(): unknown node statement `%s' at line %d in file %s\n",
  262. __func__, vcgtext, vcglineno, curfname);
  263. vcgerror = 1;
  264. break;
  265. }
  266. }
  267. if (vcgerror) {
  268. return;
  269. }
  270. if (title == NULL) {
  271. memset(parsermessage, 0, 256);
  272. snprintf(parsermessage, (256 - 1), "vcg %s(): node has no \"title:\" statement at line %d in file %s\n", __func__,
  273. vcglineno, curfname);
  274. vcgerror = 1;
  275. }
  276. /* when no label specified, use the node name */
  277. if (label == NULL) {
  278. label = title;
  279. }
  280. newnode = dp_calloc(1, sizeof(struct vcgn));
  281. if (newnode == NULL) {
  282. vcgerror = 1;
  283. return;
  284. }
  285. /* uniq node number starts at 1 */
  286. vcgnn++;
  287. newnode->nr = vcgnn;
  288. newnode->name = title;
  289. newnode->label = label;
  290. newnode->shape = shape;
  291. if (vnl == NULL) {
  292. vnl = newnode;
  293. vnlend = newnode;
  294. } else {
  295. vnlend->next = newnode;
  296. vnlend = newnode;
  297. }
  298. /* add node to db */
  299. vcguniqnode_add(newnode);
  300. return;
  301. }
  302. /* handle a edge statement */
  303. static void vcgedge(void)
  304. {
  305. struct vcge *newedge = NULL;
  306. char *sn = NULL;
  307. char *tn = NULL;
  308. char *label = NULL;
  309. vcgtoken = vcglex();
  310. if (vcgtoken != VCG_COLON) {
  311. memset(parsermessage, 0, 256);
  312. snprintf(parsermessage, (256 - 1), "vcg %s(): expected ':' after \"edge\" at line %d in file %s\n", __func__,
  313. vcglineno, curfname);
  314. vcgerror = 1;
  315. return;
  316. }
  317. vcgtoken = vcglex();
  318. if (vcgtoken != VCG_BO) {
  319. memset(parsermessage, 0, 256);
  320. snprintf(parsermessage, (256 - 1), "vcg %s(): expected '{' after \"edge:\" at line %d in file %s\n", __func__,
  321. vcglineno, curfname);
  322. vcgerror = 1;
  323. return;
  324. }
  325. for (;;) {
  326. if (vcgerror) {
  327. break;
  328. }
  329. vcgtoken = vcglex();
  330. if (vcgtoken == EOF) {
  331. memset(parsermessage, 0, 256);
  332. snprintf(parsermessage, (256 - 1), "vcg %s(): unexpected end-of-file in \"edge:\" at line %d in file %s\n",
  333. __func__, vcglineno, curfname);
  334. vcgerror = 1;
  335. break;
  336. }
  337. /* an brace close at end of node statement */
  338. if (vcgtoken == VCG_BC) {
  339. break;
  340. }
  341. if (vcgtoken == VCG_SOURCENAME) {
  342. vcgtoken = vcglex();
  343. if (vcgtoken != VCG_COLON) {
  344. memset(parsermessage, 0, 256);
  345. snprintf(parsermessage, (256 - 1),
  346. "vcg %s(): expected ':' after \"sourcename\" at line %d in file %s\n", __func__, vcglineno, curfname);
  347. vcgerror = 1;
  348. break;
  349. }
  350. vcgtoken = vcglex();
  351. if (vcgtoken != VCG_STRING) {
  352. memset(parsermessage, 0, 256);
  353. snprintf(parsermessage, (256 - 1),
  354. "vcg %s(): expected string after \"sourcename:\" at line %d in file %s\n", __func__, vcglineno, curfname);
  355. vcgerror = 1;
  356. break;
  357. }
  358. sn = vcglaststring;
  359. vcglaststring = NULL;
  360. } else if (vcgtoken == VCG_TARGETNAME) {
  361. vcgtoken = vcglex();
  362. if (vcgtoken != VCG_COLON) {
  363. memset(parsermessage, 0, 256);
  364. snprintf(parsermessage, (256 - 1),
  365. "vcg %s(): expected ':' after \"targetname\" at line %d in file %s\n", __func__, vcglineno, curfname);
  366. vcgerror = 1;
  367. break;
  368. }
  369. vcgtoken = vcglex();
  370. if (vcgtoken != VCG_STRING) {
  371. memset(parsermessage, 0, 256);
  372. snprintf(parsermessage, (256 - 1),
  373. "vcg %s(): expected string after \"targetname:\" at line %d in file %s\n", __func__, vcglineno, curfname);
  374. vcgerror = 1;
  375. break;
  376. }
  377. tn = vcglaststring;
  378. vcglaststring = NULL;
  379. } else if (vcgtoken == VCG_LABEL) {
  380. vcgtoken = vcglex();
  381. if (vcgtoken != VCG_COLON) {
  382. memset(parsermessage, 0, 256);
  383. snprintf(parsermessage, (256 - 1), "vcg %s(): expected ':' after \"label\" at line %d in file %s\n",
  384. __func__, vcglineno, curfname);
  385. vcgerror = 1;
  386. break;
  387. }
  388. vcgtoken = vcglex();
  389. if (vcgtoken != VCG_STRING) {
  390. memset(parsermessage, 0, 256);
  391. snprintf(parsermessage, (256 - 1),
  392. "vcg %s(): expected string after \"label:\" at line %d in file %s\n", __func__, vcglineno, curfname);
  393. vcgerror = 1;
  394. break;
  395. }
  396. label = vcglaststring;
  397. vcglaststring = NULL;
  398. } else {
  399. memset(parsermessage, 0, 256);
  400. snprintf(parsermessage, (256 - 1), "vcg %s(): unknown edge statement `%s' at line %d in file %s\n",
  401. __func__, vcgtext, vcglineno, curfname);
  402. vcgerror = 1;
  403. break;
  404. }
  405. }
  406. if (vcgerror) {
  407. return;
  408. }
  409. if (sn == NULL) {
  410. memset(parsermessage, 0, 256);
  411. snprintf(parsermessage, (256 - 1), "vcg %s(): edge has no \"sourcenode:\" statement at line %d in file %s\n",
  412. __func__, vcglineno, curfname);
  413. vcgerror = 1;
  414. }
  415. if (tn == NULL) {
  416. memset(parsermessage, 0, 256);
  417. snprintf(parsermessage, (256 - 1), "vcg %s(): edge has no \"targetnode:\" statement at line %d in file %s\n",
  418. __func__, vcglineno, curfname);
  419. vcgerror = 1;
  420. }
  421. if (vcgerror) {
  422. return;
  423. }
  424. newedge = dp_calloc(1, sizeof(struct vcge));
  425. if (newedge == NULL) {
  426. vcgerror = 1;
  427. return;
  428. }
  429. /* uniq edge number */
  430. vcgen++;
  431. newedge->nr = vcgen;
  432. newedge->fns = sn; /* uniq name from-node */
  433. newedge->fromnode = vcguniqnode(sn);
  434. newedge->tns = tn; /* uniq name to-node */
  435. newedge->tonode = vcguniqnode(tn);
  436. newedge->label = label;
  437. if (vel == NULL) {
  438. vel = newedge;
  439. velend = newedge;
  440. } else {
  441. velend->next = newedge;
  442. velend = newedge;
  443. }
  444. return;
  445. }
  446. /* check if all nodes in edges are defined */
  447. static void chkedges(void)
  448. {
  449. struct vcge *pvel = NULL;
  450. struct vcgn *pn = NULL;
  451. pvel = vel;
  452. while (pvel) {
  453. pn = vcguniqnode(pvel->fns);
  454. if (pn == NULL) {
  455. memset(parsermessage, 0, 256);
  456. snprintf(parsermessage, (256 - 1), "vcg %s(): sourcenode `%s' in edge not defined in file %s\n", __func__,
  457. pvel->fns, curfname);
  458. vcgerror = 1;
  459. break;
  460. }
  461. if (pvel->fromnode == NULL) {
  462. pvel->fromnode = pn;
  463. }
  464. /* set node number in edge */
  465. pvel->fnn = pn->nr;
  466. pn = vcguniqnode(pvel->tns);
  467. if (pn == NULL) {
  468. memset(parsermessage, 0, 256);
  469. snprintf(parsermessage, (256 - 1), "vcg %s(): targetnode `%s' in edge not defined in file %s\n", __func__,
  470. pvel->tns, curfname);
  471. vcgerror = 1;
  472. break;
  473. }
  474. if (pvel->tonode == NULL) {
  475. pvel->tonode = pn;
  476. }
  477. /* set node number in edge */
  478. pvel->tnn = pn->nr;
  479. pvel = pvel->next;
  480. }
  481. return;
  482. }
  483. /* copy checked edges and nodes now */
  484. static void copyall(struct gml_graph *g)
  485. {
  486. struct gml_node *fnn = NULL;
  487. struct gml_node *tnn = NULL;
  488. struct vcgn *pvnl = NULL;
  489. struct vcge *pvel = NULL;
  490. int nr = 0;
  491. pvnl = vnl;
  492. while (pvnl) {
  493. /* uniq node number starting at 1 */
  494. maingraph->nodenum++;
  495. nr = maingraph->nodenum;
  496. /* in vcg all nodes are located in rootgraph
  497. * use -1 for foundid then gml id check is not applied.
  498. */
  499. add_new_node(g, maingraph, nr, /* pvnl->nr */ (-1), uniqstr(pvnl->name), uniqstr(pvnl->label), /* ncolor */ 0x00ffffff, /* nbcolor */ 0, /* rlabel */
  500. NULL, /* hlabel */ NULL, /* fontcolor */ 0, /* ishtml */ 0);
  501. pvnl->finalnr = nr;
  502. pvnl = pvnl->next;
  503. }
  504. pvel = vel;
  505. while (pvel) {
  506. if (pvel->fromnode) {
  507. fnn = uniqnode(g, pvel->fromnode->finalnr);
  508. } else {
  509. fnn = NULL;
  510. }
  511. if (pvel->tonode) {
  512. tnn = uniqnode(g, pvel->tonode->finalnr);
  513. } else {
  514. tnn = NULL;
  515. }
  516. if (fnn && tnn) {
  517. if (fnn == tnn) {
  518. /* add selfedge count at this node */
  519. fnn->nselfedges++;
  520. } else {
  521. add_new_edge(g, maingraph, /* foundsource */ fnn->nr, /* foundtarget */ tnn->nr,
  522. uniqstr(pvel->label),
  523. /* ecolor */ 0, /* style */ 0, /* fcompass */ NULL, /* tcompass */ NULL,
  524. /* constraint */ 1, /* ishtml */ 0);
  525. }
  526. } else {
  527. printf("vcg %s(): missing nodes in edge between nodes ", __func__);
  528. if (pvel->fns) {
  529. printf("\"%s\" ", pvel->fns);
  530. }
  531. if (pvel->tns) {
  532. printf("\"%s\" ", pvel->tns);
  533. }
  534. printf("\n");
  535. }
  536. pvel = pvel->next;
  537. }
  538. return;
  539. }
  540. /* */
  541. int vcgparse(struct gml_graph *g, gzFile f, char *fname, char *argv0)
  542. {
  543. yydebug = 0;
  544. /* optional turn on debug */
  545. if (argv0) {
  546. if (strcmp(argv0, "gml4gtkd") == 0) {
  547. yydebug = 1;
  548. }
  549. }
  550. curfname = fname;
  551. /* uniq node number */
  552. vcgnn = 0;
  553. /* uniq edge number */
  554. vcgen = 0;
  555. /* no errors */
  556. vcgerror = 0;
  557. /* in vcg.l */
  558. vcg_lex_init(f, /* debugflag */ yydebug);
  559. /* expect "graph" as first token in vcg graph */
  560. vcgtoken = vcglex();
  561. if (vcgtoken != VCG_GRAPH) {
  562. memset(parsermessage, 0, 256);
  563. snprintf(parsermessage, (256 - 1), "vcg %s(): expected \"graph\" at start of graph in file %s\n", __func__, fname);
  564. vcgparse_clear();
  565. return (1);
  566. }
  567. /* expect : */
  568. vcgtoken = vcglex();
  569. if (vcgtoken != VCG_COLON) {
  570. memset(parsermessage, 0, 256);
  571. snprintf(parsermessage, (256 - 1), "vcg %s(): expected ':' after \"graph\" at start of graph in file %s\n",
  572. __func__, fname);
  573. vcgparse_clear();
  574. return (1);
  575. }
  576. /* expect brace open */
  577. vcgtoken = vcglex();
  578. if (vcgtoken != VCG_BO) {
  579. memset(parsermessage, 0, 256);
  580. snprintf(parsermessage, (256 - 1), "vcg %s(): expected '{' after \"graph:\" at start of graph in file %s\n",
  581. __func__, fname);
  582. vcgparse_clear();
  583. return (1);
  584. }
  585. /* parse until brace close */
  586. for (;;) {
  587. /* check if there was parse error */
  588. if (vcgerror) {
  589. break;
  590. }
  591. vcgtoken = vcglex();
  592. if (vcgtoken == EOF) {
  593. memset(parsermessage, 0, 256);
  594. snprintf(parsermessage, (256 - 1), "vcg %s(): unexpected end-of-file at line %d in file %s\n", __func__,
  595. vcglineno, fname);
  596. vcgerror = 1;
  597. break;
  598. }
  599. /* at brace close end of graph */
  600. if (vcgtoken == VCG_BC) {
  601. break;
  602. }
  603. /* at top level in graph is in gcc data
  604. * title: "string"
  605. * node: {...}
  606. * edge: {...}
  607. */
  608. if (vcgtoken == VCG_TITLE) {
  609. vcggraphtitle();
  610. } else if (vcgtoken == VCG_NODE) {
  611. vcgnode();
  612. } else if (vcgtoken == VCG_EDGE) {
  613. vcgedge();
  614. } else {
  615. memset(parsermessage, 0, 256);
  616. snprintf(parsermessage, (256 - 1), "vcg %s(): unknown graph statement `%s' at line %d in file %s\n",
  617. __func__, vcgtext, vcglineno, fname);
  618. vcgerror = 1;
  619. break;
  620. }
  621. }
  622. /* check if there was parse error */
  623. if (vcgerror) {
  624. vcgparse_clear();
  625. return (1);
  626. }
  627. /* if graph has no nodes, done with oke status */
  628. if (vnl == NULL) {
  629. vcgparse_clear();
  630. return (0);
  631. }
  632. /* check if all nodes in edges are defined */
  633. chkedges();
  634. /* check if there was parse error */
  635. if (vcgerror) {
  636. vcgparse_clear();
  637. return (1);
  638. }
  639. /* copy checked edges and nodes now */
  640. copyall(g);
  641. vcgparse_clear();
  642. return (0);
  643. }
  644. /* end */