%{
/*
* mgllex.l - Lexer for Bootrom Menu Generation Language
*
* Copyright (C) 1997-2003 Gero Kuhlmann <gero@gkminix.han.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: mgllex.l,v 1.4 2003/01/25 23:29:44 gkminix Exp $
*/
#include "mknbi.h"
#include "mgl.h"
#include "gencode.h"
#include "y.tab.h"
/*
********************************************************************
*
* Definition of builtin data types. We need this here for the definition
* of internal functions.
*/
/* No type - used to catch errors in type definitions */
struct typesdef none_type = {
EXPR_NONE, 0, { { 0, 0, -1 } }, NULL
};
/* Integer type */
struct typesdef int_type = {
EXPR_NUM, 2, { { -MAX_INT, MAX_INT, -1 } }, &none_type
};
/* String type */
struct typesdef string_type = {
EXPR_STRING, MAX_STR_LEN, { { 0, 0, -1 } }, &int_type
};
/* Type for string index */
struct typesdef strindex_type = {
EXPR_NUM, 2, { { 0, 255, -1 } }, & string_type
};
/* Character type */
struct typesdef char_type = {
EXPR_CHAR, 1, { { 0, MAX_CHAR, -1 } }, &strindex_type
};
/* Boolean type */
struct typesdef bool_type = {
EXPR_BOOL, 1, { { 0, 1, -1 } }, &char_type
};
/* Table of names for predefined types */
struct {
char *name;
struct typesdef *t;
} predeftypes[] = {
{ "integer", &int_type },
{ "string", &string_type },
{ "char", &char_type },
{ "boolean", &bool_type },
{ "logical", &bool_type },
{ NULL, NULL }
};
/*
********************************************************************
*
* List of internally defined constants
*/
struct {
char *name;
char *strval;
int numval;
struct typesdef *t;
} predefconsts[] = {
{ "maxint", NULL, MAX_INT, &int_type },
{ "true", NULL, 1, &bool_type },
{ "false", NULL, 0, &bool_type },
{ "BOOTP_HOSTNAME", NULL, 12, &int_type },
{ "BOOTP_DOMAIN", NULL, 15, &int_type },
{ "BOOTP_ROOTPATH", NULL, 17, &int_type },
{ NULL, NULL, 0, NULL }
};
/*
********************************************************************
*
* List of internally defined variables.
*/
struct {
char *name;
long addr;
struct typesdef *t;
} predefvars[] = {
{ "servername", ADDR_SERVERNAME, &string_type },
{ "hostname", ADDR_HOSTNAME, &string_type },
{ NULL, 0, NULL }
};
/*
********************************************************************
*
* Definition of internal functions. To add a new internal function,
* simply assign a new CMD_* value to pass to the runtime module, and
* add a new entry here. You might optionally add a collapsing function
* into mglparse.y for constant arguments.
*/
struct {
char *name;
struct funcdef f;
} functab[] = {
/* This is a general scalar operation - int types are just dummies */
{ "pred", { 0, 0, CMD_PRED, 1, &int_type,
{ &int_type }, { ATTR_NONE } } },
/* This is a general scalar operation - int types are just dummies */
{ "succ", { 0, 0, CMD_SUCC, 1, &int_type,
{ &int_type }, { ATTR_NONE } } },
/* This is a general scalar operation - int types are just dummies */
{ "ord", { 0, 0, CMD_ORD, 1, &int_type,
{ &int_type }, { ATTR_NONE } } },
{ "odd", { 0, 0, CMD_ODD, 1, &bool_type,
{ &int_type }, { ATTR_NONE } } },
{ "chr", { 0, 0, CMD_CHR, 1, &char_type,
{ &int_type }, { ATTR_NONE } } },
{ "strlen", { 0, 0, CMD_STRLEN, 1, &int_type,
{ &string_type }, { ATTR_CONST } } },
{ "strsub", { 0, 0, CMD_STRSUB, 3, &string_type,
{ &string_type, &int_type, &int_type },
{ ATTR_CONST, ATTR_NONE, ATTR_NONE } } },
{ "abs", { 0, 0, CMD_ABS, 1, &int_type,
{ &int_type }, { ATTR_NONE } } },
{ "sqr", { 0, 0, CMD_SQR, 1, &int_type,
{ &int_type }, { ATTR_NONE } } },
{ "cls", { 0, 0, CMD_CLS, 0, NULL,
{ NULL }, { ATTR_NONE } } },
{ NULL, { 0, 0, CMD_NONE, 0, NULL,
{ NULL }, { ATTR_NONE } } }
};
/*
********************************************************************
*
* Some symbols are used internally by the lexer, and just return a
* token to the parser. This way, we can redefine the symbols in the
* user program, and still use them as tokens in the parser.
*/
struct {
char *name;
int token;
} specialtab[] = {
{ "at", AT },
{ "from", FROM },
{ "gateway", GATEWAY },
{ "get", GET },
{ "gotoxy", GOTOXY },
{ "load", LOAD },
{ "menu", MENU },
{ "print", PRINT },
{ "timeout", TIMEOUT },
{ NULL, 0 }
};
/*
********************************************************************
*
* Global variables
*/
char *curfile; /* Name of current input file */
/*
********************************************************************
*
* String buffer for C style strings
*/
static char string_buf[MAX_STR_LEN + 1]; /* string buffer */
static char *string_pos; /* current string position */
static int string_flag; /* flag if string too long */
/*
********************************************************************
*
* Routine to add a character to the constant string
*/
static void add_string(c)
char c;
{
if (string_pos >= &string_buf[MAX_STR_LEN]) {
if (!string_flag) {
warning("string too long, truncating");
string_flag++;
}
} else
*string_pos++ = c;
}
%}
/*
********************************************************************
*
* Define some generally useful regular expressions
*/
ws [ \t]+
comment #.*
id [a-zA-Z][a-zA-Z0-9_]*
intnum [0-9]+
hexnum [0-9a-fA-F]+
nl \n
cr \r
/*
********************************************************************
*
* Always use a pointer for yytext
*/
%pointer
/*
********************************************************************
*
* Define an exclusive start state for scanning C style strings
*/
%x Cstring Comment
%%
/*
********************************************************************
*
* Skip all whitespace and comments
*/
{ws} ;
{comment} ;
"(*" { BEGIN Comment; } /* Switch to comment mode */
<Comment>. ; /* Throw away any comment text */
<Comment>{nl} { lineno++; } /* We still have to count line numbers */
<Comment>"*)" { BEGIN INITIAL; } /* Return to regular mode */
/*
********************************************************************
*
* Parse an IP number
*/
{intnum}\.{intnum}\.{intnum}\.{intnum} {
#ifdef HAVE_INET
static struct in_addr addr;
if ((unsigned long)(addr.s_addr = inet_addr(yytext)) ==
(unsigned long)-1) {
warning("invalid IP address, assuming 0.0.0.0");
addr.s_addr = INADDR_ANY;
}
#else
static char addr[INADDR_SIZE];
warning("no IP address support available, assuming 0.0.0.0");
memset(addr, 0, INADDR_SIZE);
#endif
yylval.inaddr = (char *)&addr;
return(INADDR);
}
/*
********************************************************************
*
* Parse an integer number
*/
{intnum} {
/* Decimal number */
char *cp;
unsigned long result = 0;
for (cp = yytext; *cp; cp++) {
result = result * 10 + *cp - '0';
if (result > MAX_INT) {
warning("integer number too large, assuming maximum");
result = MAX_INT;
break;
}
}
yylval.intarg = result;
return(NUM);
}
${hexnum} {
/* Hex number */
char *cp;
unsigned long result = 0;
for (cp = yytext; *cp; cp++) {
if (*cp >= '0' && *cp <= '9')
result = result * 16 + *cp - '0';
else if (*cp >= 'a' && *cp <= 'f')
result = result * 16 + *cp + 10 - 'a';
else if (*cp >= 'A' && *cp <= 'F')
result = result * 16 + *cp + 10 - 'F';
if (result > MAX_INT) {
warning("integer number too large, assuming maximum");
result = MAX_INT;
break;
}
}
yylval.intarg = result;
return(NUM);
}
/*
********************************************************************
*
* Parse a C type string
*/
\" {
string_flag = 0;
string_pos = string_buf;
BEGIN Cstring;
}
<Cstring>\" {
/* All done at closing quote */
BEGIN INITIAL;
*string_pos = '\0';
yylval.string = string_buf;
return(QSTRING);
}
<Cstring>\n {
/* Unterminated string constant */
BEGIN INITIAL;
warning("unterminated string constant");
*string_pos = '\0';
yylval.string = string_buf;
return(QSTRING);
}
<Cstring>\\[0-7]{1,3} {
/* Octal escape sequence */
int result;
if (sscanf(yytext + 1, "%o", &result) != 1) {
warning("invalid octal number in string constant, "
"assuming \\377");
result = '\377';
}
if (result > 0xff) {
warning("octal number in string constant too large, "
"assuming \\377");
result = '\377';
}
add_string(result);
}
<Cstring>\\[0-9]+ {
/* Bad escape sequence */
warning("bad escape sequence, skipping");
}
<Cstring>\\n { add_string('\n'); }
<Cstring>\\t { add_string('\t'); }
<Cstring>\\r { add_string('\r'); }
<Cstring>\\b { add_string('\b'); }
<Cstring>\\f { add_string('\f'); }
<Cstring>\\(.|n) { add_string(yytext[1]); }
<Cstring>[^\\\n\"]+ {
char *yptr = yytext;
while (*yptr)
add_string(*yptr++);
}
/*
********************************************************************
*
* Parse a C type character value
*/
\'\\[0-7]{1,3}\' {
/* Octal escape sequence */
int result;
yytext[strlen(yytext) - 1] = '\0';
if (sscanf(yytext + 2, "%o", &result) != 1) {
warning("invalid octal number in character constant, "
"assuming \\377");
result = '\377';
}
if (result > 0xff) {
warning("octal number in character constant too large, "
"assuming \\377");
result = '\377';
}
yylval.chrarg = result & 0xff;
return(CHR);
}
\'\\[0-9]+\' {
/* Bad escape sequence */
warning("bad escape sequence, assuming \\377");
yylval.chrarg = 0xff;
return(CHR);
}
\'\\n\' { yylval.chrarg = '\n'; return(CHR); }
\'\\t\' { yylval.chrarg = '\t'; return(CHR); }
\'\\r\' { yylval.chrarg = '\r'; return(CHR); }
\'\\b\' { yylval.chrarg = '\b'; return(CHR); }
\'\\f\' { yylval.chrarg = '\f'; return(CHR); }
\'\\(.|n)\' { yylval.chrarg = yytext[2]; return(CHR); }
\'.\' {
yylval.chrarg = yytext[1];
return(CHR);
}
\'. {
warning("missing closing quote in character constant");
yylval.chrarg = yytext[1];
return(CHR);
}
/*
********************************************************************
*
* Rules to parse reserved names
*/
array { return(ARRAY); }
begin { return(CBEGIN); }
break { return(BREAK); }
const { return(CONST); }
default { return(DEFAULT); }
do { return(DO); }
else { return(ELSE); }
end { return(END); }
function { return(FUNCTION); }
if { return(IF); }
item { return(ITEM); }
of { return(OF); }
procedure { return(PROCEDURE); }
record { return(RECORD); }
repeat { return(REPEAT); }
restart { return(RESTART); }
return { return(RETURN); }
screen { return(SCREEN); }
select { return(SELECT); }
then { return(THEN); }
type { return(TYPE); }
until { return(UNTIL); }
var { return(VAR); }
while { return(WHILE); }
with { return(WITH); }
":=" { return(ASSIGN); }
"..." { return(DOTS); }
/*
********************************************************************
*
* Logical operations
*/
and { yylval.op = CMD_AND; return(ANDOP); }
not { yylval.op = CMD_NOT; return(NOTOP); }
or { yylval.op = CMD_OR; return(OROP); }
xor { yylval.op = CMD_XOR; return(XOROP); }
/*
********************************************************************
*
* Comparison rules
*/
"=" { yylval.op = CMD_EQ; return(COMPARISON); }
">" { yylval.op = CMD_GT; return(COMPARISON); }
">=" { yylval.op = CMD_GE; return(COMPARISON); }
"<" { yylval.op = CMD_LT; return(COMPARISON); }
"<=" { yylval.op = CMD_LE; return(COMPARISON); }
"<>" { yylval.op = CMD_NE; return(COMPARISON); }
/*
********************************************************************
*
* Arithmetic operations
*/
"-" { yylval.op = '-'; return(ADDOP); }
"+" { yylval.op = '+'; return(ADDOP); }
"*" { yylval.op = '*'; return(MULOP); }
"/" { yylval.op = '/'; return(MULOP); }
div { yylval.op = '/'; return(MULOP); }
"%" { yylval.op = '%'; return(MULOP); }
mod { yylval.op = '%'; return(MULOP); }
/*
********************************************************************
*
* Symbol names
*/
{id} {
struct sym *sp;
yylval.symbol = NULL;
if (strlen(yytext) > MAX_ID_LEN) {
warning("ID too long, truncating to 16 characters");
yytext[MAX_ID_LEN] = '\0';
}
/* Search if symbol already exists */
for (sp = symtab; sp != NULL; sp = sp->next)
if (!strcmp(sp->name, yytext))
break;
/* If it's a special symbol, return it's token */
if (isspecialsym(sp))
return(sp->def.s.token);
/* If symbol doesn't exist, create it. */
if (sp == NULL) {
sp = (struct sym *)nbmalloc(sizeof(struct sym));
sp->type = nosym;
sp->level = curlevel;
copystr(&(sp->name), yytext);
sp->next = symtab;
symtab = sp;
}
/* Return the symbol to the parser */
yylval.symbol = sp;
return(ID);
}
/*
********************************************************************
*
* Misc. rules: count lines and ignore \r, return all other
* characters as is to the parser.
*/
{cr} ;
{nl} { lineno++; }
. { return(yytext[0]); }
%%
/*
*****************************************************************************
*
* Print current token. This has to be here because the definition of yytext
* is in the lexer, and it's not consistent among different lex versions.
*/
void print_token()
{
fprintf(stderr, "'%s'", yytext);
}
/*
*****************************************************************************
*
* Initialize lexer
*/
void yylexinit(infile)
char *infile;
{
struct sym *sp;
long size;
int i;
/* Open input file */
if (infile == NULL || !*infile)
yyin = stdin;
else if ((yyin = fopen(infile, "r")) == NULL) {
perror(progname);
exit(EXIT_MGL_PROGOPEN);
}
/* Set name of current input file */
curfile = infile;
/* Preset the list of known types with builtin static type list */
typetab = &bool_type;
for (i = 0; predeftypes[i].name != NULL; i++) {
sp = (struct sym *)nbmalloc(sizeof(struct sym));
sp->type = typesym;
sp->name = predeftypes[i].name;
sp->level = -1;
sp->def.t = predeftypes[i].t;
sp->next = symtab;
symtab = sp;
}
/* The string type is special */
string_type.def.a.elementnum = MAX_STR_LEN;
string_type.def.a.indextype = &strindex_type;
string_type.def.a.basetype = &char_type;
/* Preset the list of internal functions */
for (i = 0; functab[i].name != NULL; i++) {
sp = (struct sym *)nbmalloc(sizeof(struct sym));
sp->type = funcsym;
sp->name = functab[i].name;
sp->level = -1;
sp->def.f = functab[i].f;
sp->next = symtab;
symtab = sp;
}
/* Preset the list of special symbols */
for (i = 0; specialtab[i].name != NULL; i++) {
sp = (struct sym *)nbmalloc(sizeof(struct sym));
sp->type = specialsym;
sp->name = specialtab[i].name;
sp->level = -1;
sp->def.s.token = specialtab[i].token;
sp->next = symtab;
symtab = sp;
}
/* Preset the list of internal constants */
for (i = 0; predefconsts[i].name != NULL; i++) {
sp = (struct sym *)nbmalloc(sizeof(struct sym));
sp->type = constsym;
sp->name = predefconsts[i].name;
sp->level = -1;
sp->def.c.t = predefconsts[i].t;
switch (predefconsts[i].t->type) {
case EXPR_NUM:
sp->def.c.val.i = predefconsts[i].numval;
break;
case EXPR_BOOL:
sp->def.c.val.b = predefconsts[i].numval;
break;
case EXPR_CHAR:
sp->def.c.val.c = predefconsts[i].numval;
break;
default:
break;
}
sp->next = symtab;
symtab = sp;
}
/* Preset the list of internally defined variables */
for (i = 0; predefvars[i].name != NULL; i++) {
#ifdef PARANOID
if (dataptr != predefvars[i].addr)
interror(118, "internal variable address doesn't match default");
#endif
size = predefvars[i].t->size;
if (predefvars[i].t->type == EXPR_STRING)
size++;
dataptr += (size + 1) & 0xfffe;
sp = (struct sym *)nbmalloc(sizeof(struct sym));
sp->type = varsym;
sp->name = predefvars[i].name;
sp->addr = predefvars[i].addr;
sp->level = -1;
sp->def.v.t = predefvars[i].t;
sp->def.v.attr = ATTR_CONST;
sp->next = symtab;
symtab = sp;
}
}
/*
*****************************************************************************
*
* Terminate lexer
*/
void yylexterm()
{
/* Close input file */
if (curfile != NULL && *curfile)
fclose(yyin);
}
/*
*****************************************************************************
*
* We don't want to need to use a library, so define yywrap here, if it's
* not a macro.
*/
#ifndef yywrap
int yywrap()
{
return(1);
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1