ViSP  3.0.0
vpLex.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2015 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See http://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Le module "lex.c" contient les procedures de gestion
32  * de l'analyse lexicale de l'analyseur lexicale "lex"
33  * d'un fichier source dont la grammaire possede
34  * les symboles terminaux suivants (ecrit en "LEX", UNIX) :
35  *
36  * Authors:
37  * Jean-Luc CORRE
38  *
39  *****************************************************************************/
40 
41 
42 
43 
44 #include <visp3/robot/vpMy.h>
45 #include <visp3/robot/vpToken.h>
46 #include <visp3/robot/vpKeyword.h>
47 
48 #include <ctype.h>
49 #include <math.h>
50 #include <stdio.h>
51 //#include <unistd.h>
52 #include <fcntl.h>
53 
54 
55 // #include <varargs.h> /* modif pour Fedora */
56 #include <stdarg.h>
57 
58 #include <stdlib.h>
59 #include <string.h>
60 #ifndef DOXYGEN_SHOULD_SKIP_THIS
61 
62 
63 static void count (void);
64 static void next_source (void);
65 
66 void lexerr (const char* path, ...);
67 
68 /* Codes des symboles terminaux */
69 
70 #define NULT 0 /* caractere non valide */
71 #define EOBT 1 /* fin de buffer */
72 #define EOFT 2 /* fin de fichier */
73 #define EOLT 3 /* fin de ligne */
74 #define CMTT 4 /* commentaire */
75 #define IDNT 5 /* identificateur */
76 #define INTT 6 /* nombre entier */
77 #define FPTT 7 /* nombre flottant */
78 #define SGNT 8 /* signe +/- */
79 #define SPCT 9 /* caractere blanc */
80 #define STGT 10 /* caractere de chaine */
81 #define NBRT 11 /* nombre de codes */
82 
83 /* Drapeaux des caracteres */
84 
85 #define _NULT 0x00 /* caractere non valide */
86 #define _CMTT 0x01 /* commentaire */
87 #define _FPTT 0x02 /* nombre flottant */
88 #define _IDNT 0x04 /* identificateur */
89 #define _INTT 0x08 /* nombre entier */
90 #define _SGNT 0x10 /* signe +/- */
91 #define _STGT 0x20 /* caractere de chaine */
92 
93 /* Caracteres sentinelles */
94 
95 #define ASCII_NBR 128 /* nombre de codes ASCII*/
96 
97 #ifndef EOB
98 #define EOB (-2) /* fin de buffer */
99 #endif
100 #ifndef EOF
101 #define EOF (-1) /* fin de fichier */
102 #endif
103 #ifndef EOL
104 #define EOL 10 /* fin de ligne */
105 #endif
106 
107 #define CHAR_NBR 130 /* nombre de caracteres */
108 
109 /* Tests des drapeaux */
110 
111 #define isnult(c) (scantbl[c] == _NULT)
112 #define iscmtt(c) (scantbl[c] & _CMTT)
113 #define isfptt(c) (scantbl[c] & _FPTT)
114 #define isidnt(c) (scantbl[c] & _IDNT)
115 #define isintt(c) (scantbl[c] & _INTT)
116 #define issgnt(c) (scantbl[c] & _SGNT)
117 #define isstgt(c) (scantbl[c] & _STGT)
118 
119 /*
120  * Codes des messages d'erreur de l'analyseur lexicale.
121  */
122 #define E_UNKNOWN 0
123 #define E_SYMBOL 1
124 #define E_CMT_EOF 2
125 #define E_FLOAT 3
126 #define E_INT 4
127 #define E_KEYWORD 5
128 #define E_STG_EOF 6
129 #define E_STG_EOL 7
130 #define E_STRING 8
131 #define E_9 9
132 
133 
134 const char *lex_errtbl[] = { /* table des messages d'erreur */
135  "error unknown",
136  "symbol undefined",
137  "unexpected EOF in comment",
138  "float expected",
139  "int expected",
140  "keyword expected",
141  "unexpected EOF in string or char constant",
142  "newline in string or char constant",
143  "string expected",
144  ""
145 };
146 
147 char *mytext = NULL;
148 int mylength = 0;
149 int mylineno = 1;
150 unsigned int mycolumno = 0;
151 float myfloat = 0.0;
152 int myint = 0;
153 
154 
155 static char *mysptr; /* tete de lecture de la ligne courante */
156 static char *myline; /* debut de la ligne courante */
157 static char *lastline; /* derniere ligne du buffer d'entree */
158 
159 static Byte *chtbl; /* premiers caracteres des terminaux */
160 static Byte *scantbl; /* caracteres suivants des terminaux */
161 
162 
163 /*
164  * La procedure "open_lex" alloue et initialise les variables utilisees
165  * par l'analyseur lexical "lex".
166  */
167 void open_lex (void)
168 {
169  static char proc_name[] = "open_lex";
170 
171  int i;
172 
173  if ((chtbl = (Byte *) malloc (CHAR_NBR * sizeof (Byte))) == NULL
174  || (scantbl = (Byte *) malloc (CHAR_NBR * sizeof (Byte))) == NULL) {
175  perror (proc_name);
176  exit (1);
177  }
178  chtbl += 2; /* 2 sentinelles non affichables */
179  scantbl += 2;
180 
181  /* initialise les premiers caracteres des symboles terminaux */
182 
183  for (i = 0; i < ASCII_NBR; i++) {
184  if (isalpha(i)) chtbl[i] = IDNT;
185  else if (isdigit(i)) chtbl[i] = INTT;
186  else if (isspace(i)) chtbl[i] = SPCT;
187  else switch (i) {
188  case '"' : chtbl[i] = STGT; break;
189  case '+' :
190  case '-' : chtbl[i] = SGNT; break;
191  case '.' : chtbl[i] = FPTT; break;
192  case '/' : chtbl[i] = CMTT; break;
193  case '_' : chtbl[i] = IDNT; break;
194  default : chtbl[i] = NULT; break;
195  }
196  }
197 
198  /* Initialise les sentinelles comme des terminaux. */
199 
200  chtbl[EOB] = EOBT;
201  chtbl[EOF] = EOFT;
202  chtbl[EOL] = EOLT;
203 
204  /* Initialise les caracteres suivants des symboles terminaux. */
205 
206  for (i = 0; i < ASCII_NBR; i++) {
207  if (isalpha(i)) scantbl[i] = _CMTT|_IDNT|_STGT;
208  else if (isdigit(i)) scantbl[i] = _CMTT|_IDNT|_INTT|_STGT;
209  else switch (i) {
210  case '"' : scantbl[i] = _CMTT; break;
211  case '+' :
212  case '-' : scantbl[i] = _CMTT|_SGNT|_STGT; break;
213  case '.' : scantbl[i] = _CMTT|_FPTT|_STGT; break;
214  case '/' : scantbl[i] = _STGT; break;
215  case '_' : scantbl[i] = _CMTT|_IDNT|_STGT; break;
216  default : scantbl[i] = _CMTT|_STGT; break;
217  }
218  }
219 
220  /* Initialise les sentinelles comme des terminaux. */
221 
222  scantbl[EOB] = _NULT;
223  scantbl[EOF] = _NULT;
224  scantbl[EOL] = _NULT;
225 }
226 
227 /*
228  * La procedure "close_lex" libere les variables utilisees
229  * par l'analyseur lexical "lex".
230  */
231 void close_lex (void)
232 {
233  free ((char *) (chtbl - 2)); /* voir "open_lex" pour "- 2" */
234  free ((char *) (scantbl - 2));
235 }
236 
237 
238 #define ECHO printf ("%c", *(mysptr))
239 #define CURC (*((signed char *)mysptr)) /* caractere courant */
240 #define NEXTC (*((signed char *)mysptr+1)) /* caractere suivant */
241 #define PREVC (*((signed char *)mysptr-1)) /* caractere precedent */
242 
243 
244 /*
245  * La procedure "lex" contient l'analyseur lexical.
246  * Note :
247  * La tete de lecture (mysptr) n'est pas systematiquement avancee apres lecture.
248  * Le caractere courant est celui sous la tete de lecture.
249  * Ainsi on accede de maniere symetrique aux caracteres precedent et suivant.
250  * Sortie :
251  * Code du symbole terminale analyse.
252  */
253 int lex (void)
254 {
255 lex_loop :
256 
257  for (; chtbl[(int)CURC] == SPCT; mysptr++) {}; /* saute les espaces */
258 
259  switch (chtbl[(int)CURC]) {
260 
261  case NULT :
262  mytext = mysptr; /* sauvegarde le jeton */
263  mysptr++;
264  return (*mytext);
265  break;
266  case EOBT :
267  next_source ();
268  goto lex_loop;
269  break;
270  case EOFT :
271  mytext = mysptr; /* sauvegarde le jeton */
272  return (T_EOF);
273  break;
274  case EOLT :
275  if (mysptr == lastline) next_source ();
276  else mysptr++;
277  mylineno++;
278  myline = mysptr;
279  goto lex_loop;
280  break;
281  case CMTT :
282  mytext = mysptr; /* sauvegarde le jeton */
283  mysptr++;
284  if (CURC != '*')
285  return (*mytext);
286  mysptr++;
287 comment :
288  for (; iscmtt((int)CURC); mysptr++) {};
289  switch (chtbl[(int)CURC]) {
290  case EOBT :
291  next_source ();
292  goto comment;
293  break;
294  case EOFT :
295  lexerr ("start", lex_errtbl[E_CMT_EOF], NULL);
296  return (T_EOF);
297  break;
298  case EOLT :
299  if (mysptr == lastline) next_source ();
300  else mysptr++;
301  mylineno++;
302  myline = mysptr;
303  goto comment;
304  break;
305  case CMTT :
306  if (PREVC == '*') { /* veritable fin */
307  mysptr++;
308  goto lex_loop;
309  }
310  mysptr++; /* pseudo fin */
311  goto comment;
312  break;
313  }
314  break;
315  case IDNT :
316  mytext = mysptr; /* sauvegarde le jeton */
317  mysptr++;
318  for (; isidnt((int)CURC); mysptr++) {};
319  mylength = (int)(mysptr - mytext);
320  return (get_symbol (mytext, mylength));
321  break;
322  case INTT :
323  mytext = mysptr; /* sauvegarde le jeton */
324 int_part :
325  myint = (int) (CURC - '0');
326  mysptr++;
327  for (; isintt((int)CURC); mysptr++)
328  myint = myint * 10 + (int) (CURC - '0');
329  switch (CURC) {
330  case '.' : /* lecture fraction */
331 float_part :
332  mysptr++;
333  for (; isintt((int)CURC); mysptr++) {};
334  if (CURC != 'E' && CURC != 'e') {
335  myfloat = (float) atof (mytext);
336 /* FC
337 printf("mytext %s, myfloat %f\n",mytext,myfloat);
338 */
339  return (T_FLOAT);
340  }
341  break;
342  case 'E' : /* lecture exposant */
343  case 'e' :
344  mysptr++;
345  if (isintt((int)CURC))
346  mysptr++;
347  else if (issgnt((int)CURC) && isintt((int)NEXTC))
348  mysptr +=2;
349  else {
350  mysptr--;
351  myfloat = (float) atof (mytext);
352  return (T_FLOAT);
353  }
354  for (; isintt((int)CURC); mysptr++) {};
355  myfloat = (float) atof (mytext);
356  return (T_FLOAT);
357  break;
358  default :
359  if (*mytext == '-')
360  myint = - myint;
361  return (T_INT);
362  break;
363  }
364  break;
365  case FPTT :
366  mytext = mysptr; /* sauvegarde le jeton */
367  mysptr++;
368  if (! isintt((int)CURC)) /* pas de fraction */
369  return (*mytext);
370  goto float_part;
371  break;
372  case SGNT :
373  mytext = mysptr; /* sauvegarde le jeton */
374  mysptr++;
375  if (isintt((int)CURC))
376  goto int_part;
377  if (isfptt((int)CURC) && isintt((int)NEXTC))
378  goto float_part;
379  return (*mytext);
380  break;
381  case STGT :
382  mytext = mysptr; /* sauvegarde le jeton */
383  mysptr++;
384 string :
385  for (; isstgt((int)CURC); mysptr++) {};
386  switch (chtbl[(int)CURC]) {
387  case EOBT :
388  next_source ();
389  goto string;
390  break;
391  case EOFT :
392  lexerr ("start", lex_errtbl[E_STG_EOF], NULL);
393  return ('\n');
394  break;
395  case EOLT :
396  lexerr ("start", lex_errtbl[E_STG_EOL], NULL);
397  return ('\n');
398  break;
399  case STGT :
400  if (PREVC != '\\') { /* veritable fin */
401  mytext++;
402  mylength = (int)(mysptr - mytext);
403  mysptr++;
404  return (T_STRING);
405  }
406  mysptr++; /* pseudo fin */
407  goto string;
408  break;
409  }
410  break;
411  default :
412  ECHO;
413  mysptr++;
414  goto lex_loop;
415  break;
416  }
417  return (T_EOF);
418 }
419 
420 /*
421  * La procedure "lexecho" contient l'analyseur lexical "lex" :
422  * 1 Analyse le fichier source,
423  * 2 Affiche le fichier source sur le fichier "f",
424  * 3 Stoppe devant le jeton "token".
425  * Note :
426  * La tete de lecture (mysptr) n'est pas systematiquement avancee apres lecture.
427  * Le caractere courant est celui sous la tete de lecture.
428  * Ainsi on accede de maniere symetrique aux caracteres precedent et suivant.
429  * Entree :
430  * f Fichier en sortie.
431  * token Jeton de fin de rechercher.
432  * Sortie :
433  * Code du symbole terminale analyse.
434  */
435 int lexecho (FILE *f, int token)
436 {
437 lex_loop :
438  for (; chtbl[(int)CURC] == SPCT; mysptr++) /* saute les espaces */
439  fwrite (mysptr, 1, 1, f);
440 
441  switch (chtbl[(int)CURC]) {
442 
443  case NULT :
444  mytext = mysptr; /* sauvegarde le jeton */
445  mysptr++;
446  if (token != *mytext)
447  fwrite (mytext, 1, 1, f);
448  return (*mytext);
449  break;
450  case EOBT :
451  next_source ();
452  goto lex_loop;
453  break;
454  case EOFT :
455  mytext = mysptr; /* sauvegarde le jeton */
456  return (T_EOF);
457  break;
458  case EOLT :
459  fwrite (mysptr, 1, 1, f);
460  if (mysptr == lastline) next_source ();
461  else mysptr++;
462  mylineno++;
463  myline = mysptr;
464  goto lex_loop;
465  break;
466  case CMTT :
467  fwrite (mysptr, 1, 1, f);
468  mytext = mysptr; /* sauvegarde le jeton */
469  mysptr++;
470  if (CURC != '*')
471  return (*mytext);
472  fwrite (mysptr, 1, 1, f);
473  mysptr++;
474 comment :
475  for (; iscmtt((int)CURC); mysptr++)
476  fwrite (mysptr, 1, 1, f);
477  switch (chtbl[(int)CURC]) {
478  case EOBT :
479  next_source ();
480  goto comment;
481  break;
482  case EOFT :
483  lexerr ("start", lex_errtbl[E_CMT_EOF], NULL);
484  return (T_EOF);
485  break;
486  case EOLT :
487  fwrite (mysptr, 1, 1, f);
488  if (mysptr == lastline) next_source ();
489  else mysptr++;
490  mylineno++;
491  myline = mysptr;
492  goto comment;
493  break;
494  case CMTT :
495  fwrite (mysptr, 1, 1, f);
496  if (PREVC == '*') { /* veritable fin */
497  mysptr++;
498  goto lex_loop;
499  }
500  mysptr++; /* pseudo fin */
501  goto comment;
502  break;
503  }
504  break;
505  case IDNT :
506  mytext = mysptr; /* sauvegarde le jeton */
507  mysptr++;
508  for (; isidnt((int)CURC); mysptr++) {};
509  mylength = (int)(mysptr - mytext);
510  if (token != get_symbol (mytext, mylength))
511  fwrite (mytext, (size_t)mylength, 1, f);
512  return (get_symbol (mytext, mylength));
513  break;
514  case INTT :
515  mytext = mysptr; /* sauvegarde le jeton */
516 int_part :
517  mysptr++;
518  for (; isintt((int)CURC); mysptr++) {};
519  switch (CURC) {
520  case '.' : /* lecture fraction */
521 float_part :
522  mysptr++;
523  for (; isintt((int)CURC); mysptr++) {};
524  if (CURC != 'E' && CURC != 'e') {
525  if (token != T_FLOAT)
526  fwrite (mytext, (size_t)(mysptr - mytext), 1, f);
527  return (T_FLOAT);
528  }
529  break;
530  case 'E' : /* lecture exposant */
531  case 'e' :
532  mysptr++;
533  if (isintt((int)CURC)) mysptr++;
534  else if (issgnt((int)CURC) && isintt((int)NEXTC)) mysptr +=2;
535  else {
536  mysptr--;
537  if (token != T_FLOAT)
538  fwrite (mytext, (size_t)(mysptr - mytext), 1, f);
539  return (T_FLOAT);
540  }
541  for (; isintt((int)CURC); mysptr++) {};
542  if (token != T_FLOAT)
543  fwrite (mytext, (size_t)(mysptr - mytext), 1, f);
544  return (T_FLOAT);
545  break;
546  default :
547  if (token != T_INT)
548  fwrite (mytext, (size_t)(mysptr - mytext), 1, f);
549  return (T_INT);
550  break;
551  }
552  break;
553  case FPTT :
554  mytext = mysptr; /* sauvegarde le jeton */
555  mysptr++;
556  if (! isintt((int)CURC)) { /* pas de fraction */
557  if (token != *mytext)
558  fwrite (mytext, 1, 1, f);
559  return (*mytext);
560  }
561  goto float_part;
562  break;
563  case SGNT :
564  mytext = mysptr; /* sauvegarde le jeton */
565  mysptr++;
566  if (isintt((int)CURC)) goto int_part;
567  if (isfptt((int)CURC) && isintt((int)NEXTC)) goto float_part;
568  if (token != *mytext)
569  fwrite (mytext, 1, 1, f);
570  return (*mytext);
571  break;
572  case STGT :
573  fwrite (mysptr, 1, 1, f);
574  mytext = mysptr; /* sauvegarde le jeton */
575  mysptr++;
576 string :
577  for (; isstgt((int)CURC); mysptr++)
578  fwrite (mysptr, 1, 1, f);
579  switch (chtbl[(int)CURC]) {
580  case EOBT :
581  next_source ();
582  goto comment;
583  break;
584  case EOFT :
585  lexerr ("start", lex_errtbl[E_STG_EOF], NULL);
586  return (T_EOF);
587  break;
588  case EOLT :
589  lexerr ("start", lex_errtbl[E_STG_EOL], NULL);
590  return ('\n');
591  break;
592  case STGT :
593  fwrite (mysptr, 1, 1, f);
594  if (PREVC != '\\') { /* veritable fin */
595  mytext++;
596  mylength = (int)(mysptr - mytext);
597  mysptr++;
598  return (T_STRING);
599  }
600  mysptr++; /* pseudo fin */
601  goto string;
602  break;
603  }
604  break;
605  default :
606  fwrite (mysptr, 1, 1, f);
607  mysptr++;
608  goto lex_loop;
609  break;
610  }
611  return (T_EOF);
612 }
613 
614 
615 #undef BUFSIZE
616 #undef LINESIZE
617 #undef TEXTSIZE
618 
619 #define BUFSIZE (BUFSIZ << 5)
620 #define LINESIZE (BUFSIZ-1)
621 #define TEXTSIZE (1 + LINESIZE + BUFSIZE + 1)
622 
623 
624 static FILE *fds; /* descripteur du fichier source */
625 static char *source; /* nom du fichier du programme source */
626 static char *botbuf; /* fond du buffer d'entree du fichier */
627 static char *buf; /* base du buffer d'entree du fichier */
628 static char *topbuf; /* sommet du buffer d'entree du fichier */
629 
630 
631 /*
632  * La procedure "unlex" recule la tete de lecture devant le dernier jeton.
633  */
634 void unlex (void)
635 {
636  mysptr = mytext;
637 }
638 
639 /*
640  * La procedure "open_source" alloue et initialise les variables utilisees
641  * pour la gestion des entrees du programme source.
642  * Entree :
643  * fd Fichier du programme source.
644  * sptr Nom du fichier du programme source.
645  */
646 void open_source (FILE *fd, const char *str)
647 {
648  static char proc_name[] = "open_source";
649 
650  if ((source = (char *) malloc((strlen(str)+1)*sizeof(char))) == NULL) {
651  perror (proc_name);
652  exit (1);
653  }
654  strcpy (source, str);
655  if ((botbuf = (char *) malloc (TEXTSIZE * sizeof (char))) == NULL) {
656  perror (proc_name);
657  exit (1);
658  }
659  fds = fd;
660  buf = botbuf + 1 + LINESIZE;
661  topbuf = buf + 1;
662  mylineno = 1;
663  next_source ();
664 }
665 
666 /*
667  * La procedure "close_source" libere les variables utilisees pour la gestion
668  * des entrees du programme source.
669  */
670 void close_source (void)
671 {
672  free ((char *) source);
673  free ((char *) botbuf);
674 }
675 
676 /*
677  * La procedure "next_source" remplit le buffer courant.
678  */
679 static void next_source (void)
680 {
681  size_t size;
682  char *bot = buf;
683  char *top = topbuf;
684 
685  /* recopie la derniere ligne devant "buf" */
686 
687  *bot = EOL; /* evite le debordement de "buf" */
688  while ((*--bot = *--top) != EOL) {};
689  myline = mysptr = bot + 1;
690 
691  size = fread (buf,sizeof (char), BUFSIZE,fds);
692  if (size == 0) {
693  topbuf = buf + 1;
694  *buf = EOF;
695  *topbuf = EOB; /* sentinelle de fin de fichier */
696  mysptr = buf;
697  }
698  else {
699  topbuf = buf + size;
700  *topbuf = EOB; /* sentinelle de fin de buffer */
701 
702  /* recherche de la derniere ligne */
703  top = topbuf;
704  while (*--top != EOL) {};
705  lastline = top;
706  }
707 }
708 
709 
710 /*
711  * ERR_STACK : Pile des messages d'erreur.
712  * La pile est geree par les procedures "poperr", "popuperr" et "pusherr".
713  * Les messages sont affiches par les procedures "count" et "lexerr".
714  */
715 #define ERR_STACK_MAX 32
716 
717 
718 static const char *err_stack[ERR_STACK_MAX];
719 static int size_stack = 0;
720 
721 
722 /*
723  * La procedure "count" calcule la distance en espaces entre
724  * le premier caractere "*mytext" et le caractere de debut de ligne "*myline".
725  */
726 static void count (void)
727 {
728  char *str;
729 
730  mycolumno = 0;
731  for (str = myline; str <= mytext; str++) {
732  (*str == '\t') ? mycolumno += 8 - (mycolumno % 8) : mycolumno++;
733  }
734 }
735 
736 /*
737  * La procedure "lexerr" affiche les messages d'erreur.
738  * 1 elle affiche la ligne d'erreur du fichier source.
739  * 2 elle indique la position de l'erreur dans la ligne.
740  * 3 elle affiche les messages d'erreur contenus dans la pile.
741  * 4 elle affiche les messages d'erreur en parametre.
742  * Entree :
743  * va_list Liste de messages d'erreur terminee par NULL.
744  */
745 
746 //lexerr (va_alist)
747 //va_dcl
748 
749 void lexerr (const char* path, ...)
750 {
751  va_list ap;
752  char *cp;
753  int i;
754 
755  /* Pointe sur le caractere fautif. */
756 
757  count ();
758  //write (STDERR, myline, mysptr - myline);
759  fprintf (stderr, "\n%*c\n\"%s\", line %d:\n",
760  mycolumno, '^', source, mylineno);
761 
762  /* Affiche les messages d'erreur de la pile. */
763 
764  for (i = 0; i < size_stack; i++)
765  fprintf (stderr, "%s", err_stack[i]);
766 
767  /* Affiche les messages d'erreur en parametres. */
768 
769  va_start(ap,path);
770  while ((cp = (char *) va_arg(ap, char *)) != NULL)
771  fprintf (stderr, "%s", cp);
772  fprintf (stderr,"\n");
773  va_end(ap);
774 
775  exit (1);
776 }
777 
778 /*
779  * La procedure "poperr" depile le message d'erreur du sommet de pile.
780  */
781 void poperr (void)
782 {
783  static char proc_name[] = "poperr";
784 
785  if (--size_stack < 0) {
786  fprintf (stderr, "%s: error stack underflow\n", proc_name);
787  exit (1);
788  }
789 }
790 
791 /*
792  * La procedure "popup_error" remplace le message d'erreur du sommet de pile.
793  */
794 void popuperr (const char *str)
795 {
796  static const char proc_name[] = "popuerr";
797 
798  if (size_stack <= 0) {
799  fprintf (stderr, "%s: error stack underflow\n", proc_name);
800  exit (1);
801  }
802  err_stack[size_stack-1] = str;
803 }
804 
805 /*
806  * La procedure "pusherr" empile le message d'erreur.
807  */
808 void pusherr (const char *str)
809 {
810  static const char proc_name[] = "pusherr";
811 
812  if (size_stack >= ERR_STACK_MAX) {
813  fprintf (stderr, "%s: error stack overflow\n", proc_name);
814  exit (1);
815  }
816  err_stack[size_stack++] = str;
817 }
818 
819 #endif