(root)/
binutils-2.41/
binutils/
mclex.c
       1  /* mclex.c -- lexer for Windows mc files parser.
       2     Copyright (C) 2007-2023 Free Software Foundation, Inc.
       3  
       4     Written by Kai Tietz, Onevision.
       5  
       6     This file is part of GNU Binutils.
       7  
       8     This program is free software; you can redistribute it and/or modify
       9     it under the terms of the GNU General Public License as published by
      10     the Free Software Foundation; either version 3 of the License, or
      11     (at your option) any later version.
      12  
      13     This program is distributed in the hope that it will be useful,
      14     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16     GNU General Public License for more details.
      17  
      18     You should have received a copy of the GNU General Public License
      19     along with this program; if not, write to the Free Software
      20     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
      21     02110-1301, USA.  */
      22  
      23  /* This is a lexer used by the Windows rc file parser.
      24     It basically just recognized a bunch of keywords.  */
      25  
      26  #include "sysdep.h"
      27  #include "bfd.h"
      28  #include "bucomm.h"
      29  #include "libiberty.h"
      30  #include "safe-ctype.h"
      31  #include "windmc.h"
      32  #include "mcparse.h"
      33  
      34  #include <assert.h>
      35  
      36  /* Exported globals.  */
      37  bool mclex_want_nl = false;
      38  bool mclex_want_line = false;
      39  bool mclex_want_filename = false;
      40  
      41  /* Local globals.  */
      42  static unichar *input_stream = NULL;
      43  static unichar *input_stream_pos = NULL;
      44  static int input_line = 1;
      45  static const char *input_filename = NULL;
      46  
      47  void
      48  mc_set_content (const unichar *src)
      49  {
      50    if (!src)
      51      return;
      52    input_stream = input_stream_pos = unichar_dup (src);
      53  }
      54  
      55  void
      56  mc_set_inputfile (const char *name)
      57  {
      58    if (! name || *name == 0)
      59      input_filename = "-";
      60    else
      61      {
      62        const char *s1 = strrchr (name, '/');
      63        const char *s2 = strrchr (name, '\\');
      64  
      65        if (! s1)
      66  	s1 = s2;
      67        if (s1 && s2 && s1 < s2)
      68  	s1 = s2;
      69        if (! s1)
      70  	s1 = name;
      71        else
      72  	s1++;
      73        s1 = xstrdup (s1);
      74        input_filename = s1;
      75      }
      76  }
      77  
      78  static void
      79  show_msg (const char *kind, const char *msg, va_list argp)
      80  {
      81    fprintf (stderr, "In %s at line %d: %s: ", input_filename, input_line, kind);
      82    vfprintf (stderr, msg, argp);
      83    fprintf (stderr, ".\n");
      84  }
      85  
      86  void
      87  mc_warn (const char *s, ...)
      88  {
      89    va_list argp;
      90    va_start (argp, s);
      91    show_msg ("warning", s, argp);
      92    va_end (argp);
      93  }
      94  
      95  void
      96  mc_fatal (const char *s, ...)
      97  {
      98    va_list argp;
      99    va_start (argp, s);
     100    show_msg ("fatal", s, argp);
     101    va_end (argp);
     102    xexit (1);
     103  }
     104  
     105  
     106  static void
     107  mc_error (const char *s, ...)
     108  {
     109    va_list argp;
     110    va_start (argp, s);
     111    show_msg ("parser", s, argp);
     112    va_end (argp);
     113  }
     114  
     115  void
     116  yyerror (const char *s)
     117  {
     118    mc_error (s);
     119  }
     120  
     121  static unichar *
     122  get_diff (unichar *end, unichar *start)
     123  {
     124    unichar *ret;
     125    unichar save = *end;
     126  
     127    *end = 0;
     128    ret = unichar_dup (start);
     129    *end = save;
     130    return ret;
     131  }
     132  
     133  static rc_uint_type
     134  parse_digit (unichar ch)
     135  {
     136    rc_uint_type base = 10, v = 0, c;
     137  
     138    if (ch == '0')
     139      {
     140        base = 8;
     141        switch (input_stream_pos[0])
     142  	{
     143  	case 'x': case 'X': base = 16; input_stream_pos++; break;
     144  	case 'o': case 'O': base = 8; input_stream_pos++; break;
     145  	case 'b': case 'B': base = 2; input_stream_pos++; break;
     146  	}
     147      }
     148    else
     149      v = (rc_uint_type) (ch - '0');
     150  
     151    while ((ch = input_stream_pos[0]) != 0)
     152      {
     153        if (ch >= 'A' && ch <= 'F')
     154  	c = (rc_uint_type) (ch - 'A') + 10;
     155        else if (ch >= 'a' && ch <= 'f')
     156  	c = (rc_uint_type) (ch - 'a') + 10;
     157        else if (ch >= '0' && ch <= '9')
     158  	c = (rc_uint_type) (ch - '0');
     159        else
     160  	break;
     161        v *= base;
     162        v += c;
     163        ++input_stream_pos;
     164      }
     165    if (input_stream_pos[0] == 'U' || input_stream_pos[0] == 'u')
     166      input_stream_pos++;
     167    if (input_stream_pos[0] == 'L' || input_stream_pos[0] == 'l')
     168      input_stream_pos++;
     169    if (input_stream_pos[0] == 'L' || input_stream_pos[0] == 'l')
     170      input_stream_pos++;
     171    return v;
     172  }
     173  
     174  static mc_keyword *keyword_top = NULL;
     175  
     176  const mc_keyword *
     177  enum_facility (int e)
     178  {
     179    mc_keyword *h = keyword_top;
     180  
     181    while (h != NULL)
     182      {
     183        while (h && strcmp (h->group_name, "facility") != 0)
     184  	h = h->next;
     185        if (e == 0)
     186  	return h;
     187        --e;
     188        if (h)
     189  	h = h->next;
     190      }
     191    return h;
     192  }
     193  
     194  const mc_keyword *
     195  enum_severity (int e)
     196  {
     197    mc_keyword *h = keyword_top;
     198  
     199    while (h != NULL)
     200      {
     201        while (h && strcmp (h->group_name, "severity") != 0)
     202  	h = h->next;
     203        if (e == 0)
     204  	return h;
     205        --e;
     206        if (h)
     207  	h = h->next;
     208      }
     209    return h;
     210  }
     211  
     212  static void
     213  mc_add_keyword_ascii (const char *sz, int rid, const char *grp, rc_uint_type nv, const char *sv)
     214  {
     215    unichar *usz = NULL, *usv = NULL;
     216    rc_uint_type usz_len;
     217  
     218    unicode_from_codepage (&usz_len, &usz, sz, CP_ACP);
     219    if (sv)
     220      unicode_from_codepage (&usz_len, &usv, sv, CP_ACP);
     221    mc_add_keyword (usz, rid, grp, nv, usv);
     222  }
     223  
     224  void
     225  mc_add_keyword (unichar *usz, int rid, const char *grp, rc_uint_type nv, unichar *sv)
     226  {
     227    mc_keyword *p, *c, *n;
     228    size_t len = unichar_len (usz);
     229  
     230    c = keyword_top;
     231    p = NULL;
     232    while (c != NULL)
     233      {
     234        if (c->len > len)
     235  	break;
     236        if (c->len == len)
     237  	{
     238  	  int e = memcmp (usz, c->usz, len * sizeof (unichar));
     239  
     240  	  if (e < 0)
     241  	    break;
     242  	  if (! e)
     243  	    {
     244  	      if (! strcmp (grp, "keyword") || strcmp (c->group_name, grp) != 0)
     245  		fatal (_("Duplicate symbol entered into keyword list."));
     246  	      c->rid = rid;
     247  	      c->nval = nv;
     248  	      c->sval = (!sv ? NULL : unichar_dup (sv));
     249  	      if (! strcmp (grp, "language"))
     250  		{
     251  		  const wind_language_t *lag = wind_find_language_by_id ((unsigned) nv);
     252  
     253  		  if (lag == NULL)
     254  		    fatal ("Language ident 0x%lx is not resolvable.\n", (long) nv);
     255  		  memcpy (&c->lang_info, lag, sizeof (*lag));
     256  		}
     257  	      return;
     258  	    }
     259  	}
     260        c = (p = c)->next;
     261      }
     262    n = xmalloc (sizeof (mc_keyword));
     263    n->next = c;
     264    n->len = len;
     265    n->group_name = grp;
     266    n->usz = usz;
     267    n->rid = rid;
     268    n->nval = nv;
     269    n->sval = (!sv ? NULL : unichar_dup (sv));
     270    if (! strcmp (grp, "language"))
     271      {
     272        const wind_language_t *lag = wind_find_language_by_id ((unsigned) nv);
     273        if (lag == NULL)
     274  	fatal ("Language ident 0x%lx is not resolvable.\n", (long) nv);
     275        memcpy (&n->lang_info, lag, sizeof (*lag));
     276      }
     277    if (! p)
     278      keyword_top = n;
     279    else
     280      p->next = n;
     281  }
     282  
     283  static int
     284  mc_token (const unichar *t, size_t len)
     285  {
     286    static int was_init = 0;
     287    mc_keyword *k;
     288  
     289    if (! was_init)
     290      {
     291        was_init = 1;
     292        mc_add_keyword_ascii ("OutputBase", MCOUTPUTBASE, "keyword", 0, NULL);
     293        mc_add_keyword_ascii ("MessageIdTypedef", MCMESSAGEIDTYPEDEF, "keyword", 0, NULL);
     294        mc_add_keyword_ascii ("SeverityNames", MCSEVERITYNAMES, "keyword", 0, NULL);
     295        mc_add_keyword_ascii ("FacilityNames", MCFACILITYNAMES, "keyword", 0, NULL);
     296        mc_add_keyword_ascii ("LanguageNames", MCLANGUAGENAMES, "keyword", 0, NULL);
     297        mc_add_keyword_ascii ("MessageId", MCMESSAGEID, "keyword", 0, NULL);
     298        mc_add_keyword_ascii ("Severity", MCSEVERITY, "keyword", 0, NULL);
     299        mc_add_keyword_ascii ("Facility", MCFACILITY, "keyword", 0, NULL);
     300        mc_add_keyword_ascii ("SymbolicName", MCSYMBOLICNAME, "keyword", 0, NULL);
     301        mc_add_keyword_ascii ("Language", MCLANGUAGE, "keyword", 0, NULL);
     302        mc_add_keyword_ascii ("Success", MCTOKEN, "severity", 0, NULL);
     303        mc_add_keyword_ascii ("Informational", MCTOKEN, "severity", 1, NULL);
     304        mc_add_keyword_ascii ("Warning", MCTOKEN, "severity", 2, NULL);
     305        mc_add_keyword_ascii ("Error", MCTOKEN, "severity", 3, NULL);
     306        mc_add_keyword_ascii ("System", MCTOKEN, "facility", 0xff, NULL);
     307        mc_add_keyword_ascii ("Application", MCTOKEN, "facility", 0xfff, NULL);
     308        mc_add_keyword_ascii ("English", MCTOKEN, "language", 0x409, "MSG00001");
     309    }
     310    k = keyword_top;
     311    if (!len || !t || *t == 0)
     312      return -1;
     313    while (k != NULL)
     314      {
     315        if (k->len > len)
     316  	break;
     317        if (k->len == len)
     318  	{
     319  	  if (! memcmp (k->usz, t, len * sizeof (unichar)))
     320  	    {
     321  	      if (k->rid == MCTOKEN)
     322  		yylval.tok = k;
     323  	      return k->rid;
     324  	    }
     325  	}
     326        k = k->next;
     327      }
     328    return -1;
     329  }
     330  
     331  /* Skip characters in input_stream_pos up to and including a newline
     332     character.  Returns non-zero if the newline was found, zero otherwise.  */
     333  
     334  static int
     335  skip_until_eol (void)
     336  {
     337    while (input_stream_pos[0] != 0 && input_stream_pos[0] != '\n')
     338      ++input_stream_pos;
     339    if (input_stream_pos[0] == 0)
     340      return 0;
     341    if (input_stream_pos[0] == '\n')
     342      {
     343        ++input_stream_pos;
     344        input_line += 1;
     345      }
     346    return 1;
     347  }
     348  
     349  int
     350  yylex (void)
     351  {
     352    unichar *start_token;
     353    unichar ch;
     354  
     355    if (! input_stream_pos)
     356      {
     357        fatal ("Input stream not setuped.\n");
     358        return -1;
     359      }
     360  
     361    if (mclex_want_line)
     362      {
     363        start_token = input_stream_pos;
     364        if (input_stream_pos[0] == 0)
     365  	return -1;
     366        /* PR 26082: Reject a period followed by EOF.  */
     367        if (input_stream_pos[0] == '.' && input_stream_pos[1] == 0)
     368  	return -1;
     369        if (input_stream_pos[0] == '.'
     370  	  && (input_stream_pos[1] == '\n'
     371  	      || (input_stream_pos[1] == '\r' && input_stream_pos[2] == '\n')))
     372  	{
     373  	  mclex_want_line = false;
     374            return skip_until_eol () ? MCENDLINE : -1;
     375  	}
     376        if (!skip_until_eol ())
     377  	return -1;
     378        yylval.ustr = get_diff (input_stream_pos, start_token);
     379        return MCLINE;
     380      }
     381  
     382    while ((ch = input_stream_pos[0]) <= 0x20)
     383      {
     384        if (ch == 0)
     385  	return -1;
     386        ++input_stream_pos;
     387        if (ch == '\n')
     388  	input_line += 1;
     389        if (mclex_want_nl && ch == '\n')
     390  	{
     391  	  mclex_want_nl = false;
     392  	  return NL;
     393  	}
     394      }
     395    start_token = input_stream_pos;
     396    ++input_stream_pos;
     397    if (mclex_want_filename)
     398      {
     399        mclex_want_filename = false;
     400        if (ch == '"')
     401  	{
     402  	  start_token++;
     403  	  while ((ch = input_stream_pos[0]) != 0)
     404  	    {
     405  	      if (ch == '"')
     406  		break;
     407  	      ++input_stream_pos;
     408  	    }
     409  	  yylval.ustr = get_diff (input_stream_pos, start_token);
     410  	  if (ch == '"')
     411  	    ++input_stream_pos;
     412  	}
     413        else
     414  	{
     415  	  while ((ch = input_stream_pos[0]) != 0)
     416  	    {
     417  	      if (ch <= 0x20 || ch == ')')
     418  		break;
     419  	      ++input_stream_pos;
     420  	    }
     421  	  yylval.ustr = get_diff (input_stream_pos, start_token);
     422  	}
     423        return MCFILENAME;
     424      }
     425    switch (ch)
     426    {
     427    case ';':
     428      ++start_token;
     429      if (!skip_until_eol ())
     430        return -1;
     431      yylval.ustr = get_diff (input_stream_pos, start_token);
     432      return MCCOMMENT;
     433    case '=':
     434      return '=';
     435    case '(':
     436      return '(';
     437    case ')':
     438      return ')';
     439    case '+':
     440      return '+';
     441    case ':':
     442      return ':';
     443    case '0': case '1': case '2': case '3': case '4':
     444    case '5': case '6': case '7': case '8': case '9':
     445      yylval.ival = parse_digit (ch);
     446      return MCNUMBER;
     447    default:
     448      if (ch >= 0x40)
     449        {
     450  	int ret;
     451  	while (input_stream_pos[0] >= 0x40 || (input_stream_pos[0] >= '0' && input_stream_pos[0] <= '9'))
     452  	  ++input_stream_pos;
     453  	ret = mc_token (start_token, (size_t) (input_stream_pos - start_token));
     454  	if (ret != -1)
     455  	  return ret;
     456  	yylval.ustr = get_diff (input_stream_pos, start_token);
     457  	return MCIDENT;
     458        }
     459      mc_error ("illegal character 0x%x.", ch);
     460    }
     461    return -1;
     462  }