Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/*	$NetBSD: scan.l,v 1.1 2017/04/10 02:28:23 phil Exp $ */

/*
 * Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
 * Copyright (C) 2016-2017 Philip A. Nelson.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The names Philip A. Nelson and Free Software Foundation may not be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY PHILIP A. NELSON ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL PHILIP A. NELSON OR THE FREE SOFTWARE FOUNDATION BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

/* scan.l: the (f)lex description file for the scanner. */

%{

#include "bcdefs.h"
#include "bc.h"
#include "global.h"
#include "proto.h"
#include <errno.h>

/* Using flex, we can ask for a smaller input buffer.  With lex, this
   does nothing! */

#ifdef SMALL_BUF
#undef YY_READ_BUF_SIZE
#define YY_READ_BUF_SIZE 512
#endif

/* Force . as last for now. */
#define DOT_IS_LAST

/* We want to define our own yywrap. */
#undef yywrap
int yywrap (void);

#if defined(LIBEDIT)
/* Support for the BSD libedit with history for
   nicer input on the interactive part of input. */

#include <histedit.h>

/* Have input call the following function. */
#undef  YY_INPUT
#define YY_INPUT(buf,result,max_size) \
		bcel_input((char *)buf, (yy_size_t *)&result, max_size)

/* Variables to help interface editline with bc. */
static const char *bcel_line = (char *)NULL;
static int   bcel_len = 0;

/* bcel_input puts upto MAX characters into BUF with the number put in
   BUF placed in *RESULT.  If the yy input file is the same as
   stdin, use editline.  Otherwise, just read it.
*/

static void
bcel_input (char *buf, yy_size_t  *result, int max)
{
  ssize_t rdsize;
  if (!edit || yyin != stdin)
    {
      while ( (rdsize = read( fileno(yyin), buf, max )) < 0 )
        if (errno != EINTR)
	  {
	    yyerror( "read() in flex scanner failed" );
	    bc_exit (1);
	  }
      *result = (yy_size_t) rdsize;
      return;
    }

  /* Do we need a new string? */
  if (bcel_len == 0)
    {
      bcel_line = el_gets(edit, &bcel_len);
      if (bcel_line == NULL) {
	/* end of file */
	*result = 0;
	bcel_len = 0;
	return;
      }
      if (bcel_len != 0)
	history (hist, &histev, H_ENTER, bcel_line); 
      fflush (stdout);
    }

  if (bcel_len <= max)
    {
      strncpy (buf, bcel_line, bcel_len);
      *result = bcel_len;
      bcel_len = 0;
    }
  else
    {
      strncpy (buf, bcel_line, max);
      *result = max;
      bcel_line += max;
      bcel_len -= max;
    }
}
#endif

#ifdef READLINE
/* Support for the readline and history libraries.  This allows
   nicer input on the interactive part of input. */

/* Have input call the following function. */
#undef  YY_INPUT
#define YY_INPUT(buf,result,max_size) \
		rl_input((char *)buf, &result, max_size)

/* Variables to help interface readline with bc. */
static char *rl_line = (char *)NULL;
static char *rl_start = (char *)NULL;
static int   rl_len = 0;

/* Definitions for readline access. */
extern FILE *rl_instream;

/* rl_input puts upto MAX characters into BUF with the number put in
   BUF placed in *RESULT.  If the yy input file is the same as
   rl_instream (stdin), use readline.  Otherwise, just read it.
*/

static void
rl_input (char *buf, int *result, int max)
{
  if (yyin != rl_instream)
    {
      while ( (*result = read( fileno(yyin), buf, max )) < 0 )
        if (errno != EINTR)
	  {
	    yyerror( "read() in flex scanner failed" );
	    bc_exit (1);
	  }
      return;
    }

  /* Do we need a new string? */
  if (rl_len == 0)
    {
      if (rl_start)
	free(rl_start);
      rl_start = readline ("");
      if (rl_start == NULL) {
	/* end of file */
	*result = 0;
	rl_len = 0;
	return;
      }
      rl_line = rl_start;
      rl_len = strlen (rl_line)+1;
      if (rl_len != 1)
	add_history (rl_line); 
      rl_line[rl_len-1] = '\n';
      fflush (stdout);
    }

  if (rl_len <= max)
    {
      strncpy (buf, rl_line, rl_len);
      *result = rl_len;
      rl_len = 0;
    }
  else
    {
      strncpy (buf, rl_line, max);
      *result = max;
      rl_line += max;
      rl_len -= max;
    }
}
#endif

#if !defined(READLINE) && !defined(LIBEDIT)

/* MINIX returns from read with < 0 if SIGINT is  encountered.
   In flex, we can redefine YY_INPUT to the following.  In lex, this
   does nothing! */
#undef  YY_INPUT
#define YY_INPUT(buf,result,max_size) \
	while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
	    if (errno != EINTR) \
		YY_FATAL_ERROR( "read() in flex scanner failed" );
#endif

%}
DIGIT [0-9A-Z]
LETTER [a-z]
%s slcomment
%%
"#"		{
 		  if (!std_only)
		    BEGIN(slcomment);
 		  else
		    yyerror ("illegal character: #");
		}
<slcomment>[^\n]* { BEGIN(INITIAL); }
<slcomment>"\n" { line_no++; BEGIN(INITIAL); return(ENDOFLINE); }
define return(Define);
break  return(Break);
quit   return(Quit);
length return(Length);
return return(Return);
for    return(For);
if     return(If);
while  return(While);
sqrt   return(Sqrt);
scale  return(Scale);
ibase  return(Ibase);
obase  return(Obase);
auto   return(Auto);
else   return(Else);
read   return(Read);
random return(Random);
halt   return(Halt);
last   return(Last);
void   return(Void); 
history {
#if defined(READLINE) || defined(LIBEDIT)
	  return(HistoryVar);
#else
	  yylval.s_value = strcopyof(yytext); return(NAME);
#endif
	}

warranty return(Warranty);
continue return(Continue);
print  return(Print);
limits return(Limits);
"." {
#ifdef DOT_IS_LAST
       return(Last);
#else
       yyerror ("illegal character: %s",yytext);
#endif
    }
"+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0]; 
					      return((int)yytext[0]); }
&& { return(AND); }
\|\| { return(OR); }
"!" { return(NOT); }
"*"|"/"|"%"|"&" { yylval.c_value = yytext[0]; return((int)yytext[0]); }
"="|\+=|-=|\*=|\/=|%=|\^=  { yylval.c_value = yytext[0]; return(ASSIGN_OP); }
=\+|=-|=\*|=\/|=%|=\^  { 
#ifdef OLD_EQ_OP
			 char warn_save;
			 warn_save = warn_not_std;
			 warn_not_std = TRUE;
			 ct_warn ("Old fashioned =<op>");
			 warn_not_std = warn_save;
			 yylval.c_value = yytext[1];
#else
			 yylval.c_value = '=';
			 yyless (1);
#endif
			 return(ASSIGN_OP);
		       }
==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof(yytext); return(REL_OP); }
\+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); }
"\n" { line_no++; return(ENDOFLINE); }
\\\n {  line_no++;  /* ignore a "quoted" newline */ }
[ \t]+  { /* ignore spaces and tabs */ }
"/*"  {
	int c;

	for (;;)
	  {
	    while ( ((c=input()) != '*') && (c != EOF)) 
	      /* eat it */
	      if (c == '\n') line_no++;
	    if (c == '*')
 	      {
		while ( (c=input()) == '*') /* eat it*/;
		if (c == '/') break; /* at end of comment */
		if (c == '\n') line_no++;
	      }
	    if (c == EOF)
	      {
		fprintf (stderr,"EOF encountered in a comment.\n");
		break;
	      }
	  }
      }
[a-z][a-z0-9_]* { yylval.s_value = strcopyof(yytext); return(NAME); }
\"[^\"]*\"  {
 	      const char *look;
	      int count = 0;
	      yylval.s_value = strcopyof(yytext);
	      for (look = yytext; *look != 0; look++)
		{
		  if (*look == '\n') line_no++;
		  if (*look == '"')  count++;
		}
	      if (count != 2) yyerror ("NUL character in string.");
	      return(STRING);
	    }
{DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* {
	      char *src, *dst;
	      int len;
	      /* remove a trailing decimal point. */
	      len = strlen(yytext);
	      if (yytext[len-1] == '.')
	        yytext[len-1] = 0;
	      /* remove leading zeros. */
	      src = yytext;
	      dst = yytext;
	      while (*src == '0') src++;
	      if (*src == 0) src--;
	      /* Copy strings removing the newlines. */
	      while (*src != 0)
		{
	          if (*src == '\\')
		    {
		      src++; src++;
		      line_no++;
		    }
		  if (*src == ',')
		    {
		      src++;
		      ct_warn("Commas in numbers");
		    }		    
		  else
		    *dst++ = *src++;
	        }
	      *dst = 0;
	      yylval.s_value = strcopyof(yytext); 
	      return(NUMBER);
	    }
.       {
	  if (yytext[0] < ' ')
	    yyerror ("illegal character: ^%c",yytext[0] + '@');
	  else
	    if (yytext[0] > '~')
	      yyerror ("illegal character: \\%03o", (int) yytext[0]);
	    else
	      yyerror ("illegal character: %s",yytext);
	}
%%



/* This is the way to get multiple files input into lex. */

int
yywrap(void)
{
  if (!open_new_file ()) return (1);	/* EOF on standard in. */
  return (0);          			/* We have more input. */
  yyunput(0,NULL);	/* Make sure the compiler think yyunput is used. */
}