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