%{ /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ * */ /* $Id: scan.l,v 1.1 2000/09/21 21:35:06 alaffin Exp $ */ /* * Lex rules for input processing. * * This handles all of the input parsing. The rules liste here properly * store or process the pertenant input data in the proper ways. The rules * for the various patterns maintains a "state" to determine if corrupted * input is seen (%Start keys + internal ones that only flag errors). * * See scanner.c for routines called from the actions. * * States: * SCAN_OUTSIDE * start-up state, inbetween tests * SCAN_RTSKEY valid from SCAN_OUTSIDE * from rts_keyword_start to _end * accompanied by lex KEY state. * SCAN_TSTKEY valid from SCAN_OUTSIDE * test_start to test_output or test_end, * execution_status to test_end * accompanied by lex KEY state. * SCAN_OUTPUT * test_output to execution_status. * accompanied by lex OUT or CUTS states. */ #include #include #include #include #include "scan.h" #include "reporter.h" #include "symbol.h" #include "tag_report.h" int scan_mode = SCAN_OUTSIDE; /* current mode */ char *key, *cont; /* keyword pieces */ SYM keys=NULL; /* stored keywords */ SYM ctag=NULL; /* temporary - for storing current tag's info */ SYM alltags; /* entire tag database. set to scanner 'tags' param.*/ SYM k; /* temporary sym pointer -- for key removal */ char info[KEYSIZE]; /* tmp string for inserting line numbers */ static int test_output( SYM, SYM); static int check_mode(int, int, ...); /* * Lex Definitions: * UI Unsigned Integer * A Alphabetic * W "Word" characters (Alpha, Numeric, Hyphens, Underscores) * S Space characters */ %} %option noc++ %option noinput %option nolex-compat %option nounput %option yylineno UI [0-9]+ A [a-zA-Z]+ W [a-zA-Z0-9_-]+ S [ \t]+ %Start KEY OUT CUTS %% ^<<>>$ { BEGIN KEY; check_mode(scan_mode, SCAN_OUTSIDE, 0); scan_mode = SCAN_RTSKEY; /* remove any keys that exist right now */ if(keys != NULL) sym_rm(keys, RM_KEY | RM_DATA); /* start a new table of keys */ keys = sym_open(0, 0, 0); return(KW_START); /* NOTREACHED */ } ^<<>>$ { BEGIN 0; check_mode(scan_mode, SCAN_RTSKEY, 0); scan_mode = SCAN_OUTSIDE; #ifdef DEBUGGING DEBUG(D_SCAN_LEX, 10) { printf("RTS Keywords:\n"); sym_dump_s(keys, 0); } #endif /* remove _RTS key, if it exists, before replacing it */ if( (k=(SYM)sym_get(alltags, "_RTS")) != NULL) { sym_rm(k, RM_KEY | RM_DATA); } sym_put(alltags, "_RTS", (void *)keys, PUT_REPLACE); keys = NULL; return(KW_END); /* NOTREACHED */ } ^<<>>$ { BEGIN KEY; check_mode(scan_mode, SCAN_OUTSIDE, 0); scan_mode = SCAN_TSTKEY; /* * set up new "tag" and "keys" tables * to put the new data into. */ /* remove any keys that exist right now */ if(keys != NULL) sym_rm(keys, RM_KEY | RM_DATA); keys = sym_open(0, 0, 0); sprintf(info, "%d", yylineno); sym_put(keys, "_Start_line", strdup(info), 0); /* remove any tag info that exists right now */ if(ctag != NULL) sym_rm(ctag, RM_KEY | RM_DATA); ctag = sym_open(0, 0, 0); return(TEST_START); /* NOTREACHED */ } ^<<>>$ { BEGIN OUT; check_mode(scan_mode, SCAN_TSTKEY, 0); scan_mode = SCAN_OUTPUT; test_output(ctag, keys); return(TEST_OUTPUT); /* NOTREACHED */ } ^<<>>$ { BEGIN KEY; check_mode(scan_mode, SCAN_TSTKEY, SCAN_OUTPUT, 0); scan_mode = SCAN_TSTKEY; return(EXEC_STATUS); /* NOTREACHED */ } ^<<>>$ { BEGIN 0; check_mode(scan_mode, SCAN_TSTKEY, 0); scan_mode = SCAN_OUTSIDE; sprintf(info, "%d", yylineno); sym_put(keys, "_End_line", strdup(info), 0); #ifdef DEBUGGING DEBUG(D_SCAN_LEX, 10) { printf("Tag's Keywords:\n"); sym_dump_s(keys, 0); } #endif test_end(alltags, ctag, keys); ctag = keys = NULL; return(TEST_END); /* NOTREACHED */ } [a-zA-Z_-]+=\"[^\"\n]+\" { key = yytext; cont = strchr(yytext, '='); *cont++ = '\0'; if(*cont == '"') cont++; if(yytext[yyleng-1] == '"') yytext[yyleng-1] = '\0'; #ifdef DEBUGGING DEBUG(D_SCAN_LEX, 5) printf("A quoted keyword: %s = %s\n", key, cont); #endif sym_put(keys, key, strdup(cont), 0); return(KEYWORD_QUOTED); /* NOTREACHED */ } [a-zA-Z_-]+=[^\t \n]+ { key = yytext; cont = strchr(yytext, '='); *cont++ = '\0'; #ifdef DEBUGGING DEBUG(D_SCAN_LEX, 5) printf("A keyword: %s = %s\n", key, cont); #endif sym_put(keys, key, strdup(cont), 0); return(KEYWORD); /* NOTREACHED */ } [ \t\n]* { return(SPACE); /* NOTREACHED */ } ^.+$ { #ifdef DEBUGGING DEBUG(D_SCAN_LEX, 5) printf("TEXT_LINE: %s\n", yytext); #endif return(TEXT_LINE); /* NOTREACHED */ } ^{W}{S}{UI}{S}{A}{S}":" { #ifdef DEBUGGING DEBUG(D_SCAN_LEX, 5) printf("CUTS Result: %s\n", yytext); #endif cuts_testcase(ctag, keys); return(CUTS_RESULT); /* NOTREACHED */ } ^{W}{S}{UI}-{UI}{S}{A}{S}":" { #ifdef DEBUGGING DEBUG(D_SCAN_LEX, 5) printf("CUTS Result: %s\n", yytext); #endif cuts_testcase(ctag, keys); return(CUTS_RESULT_R); /* NOTREACHED */ } . { return(SPACE); /* NOTREACHED */ } "\n" { return(SPACE); /* NOTREACHED */ } %% /* * the BEGIN macro only exists in the lex file, so define a routine to * BEGIN the CUTS state. */ int begin_cuts(void) { BEGIN CUTS; return 0; } /* * Calls lex repeatedly until all input is seen. */ int scanner(SYM tags) { alltags = tags; /* move into global scope for lex actions */ while(yylex()) ; return 0; } /* * Test-Output record * check if this is a CUTS test; if so, enter the lex "cuts" state; * otherwise do nothing and lex will be in a "data" mode that will just * toss all the output. */ static int test_output(SYM tag, SYM keys) { char *at; if((at=(char *)sym_get(keys, "analysis")) != NULL) { /* CUTS:number_of_testcases || CUTS-1:number_of_testcases */ if(strncasecmp("cuts", at, 4) == 0) { begin_cuts(); /*printf("CUTS output expected\n");*/ } } return 0; } /* Input Data State Check * RTS driver output goes thru specific * phases; this is used to verify that the new state is a legal state * to change to from the current state. * This accepts a variable number of arguments (valid states to be * in). The last argument MUST be zero */ struct parse_states { char *name; int bits; } parse_states[] = { { "outside", SCAN_OUTSIDE }, { "rts_keyword_start", SCAN_RTSKEY }, { "test_start | execution_status", SCAN_TSTKEY }, { "test_output", SCAN_OUTPUT }, { "unknown", 0 }, /*end sentinel: bits = 0 */ }; static int check_mode(int scan_mode, int fst, ...) { va_list ap; /* used for variable argument functions*/ int found=0; /* set to true if a valid state was found */ int ckm; /* Check Mode: the mode to look for */ register struct parse_states *ps; /* for looking thru parse_states */ char exp_mode[KEYSIZE]; /* expected mode list (for error message) */ extern int yylineno; /* Line number from Lex */ /* look thru parse_states; end sentinel is "bits" = 0 */ for(ps=parse_states; ps->bits && (ps->bits != fst);ps++) ; strcpy(exp_mode, ps->name); /* look at first variable argument */ if(fst == scan_mode) found++; else { /* not first... look at variable args */ va_start(ap, fst); while(((ckm = va_arg(ap, int)) != 0) && (ckm != scan_mode)) { for(ps=parse_states; ps->bits && (ps->bits != ckm);ps++) ; strcat(exp_mode, ", "); strcat(exp_mode, ps->name); } va_end(ap); if(ckm == scan_mode) found++; } if(!found) { for(ps=parse_states; ps->bits && (ps->bits != scan_mode);ps++) ; fprintf(stderr, "PARSE ERROR -- Line %d found %s in mode %s[%d] expected { %s }\n", yylineno, yytext, ps->name, scan_mode, exp_mode); } return 0; } /* * This part of the file contains subroutines called by a lex scanner which * is parsing rts-driver-format input and putting it into a multi-level * symbol table. */ /* * References to lex variables */ /*extern char yytext[]; / * text matched by last pattern */ /*extern long yyleng; / * length of above */ char **filenames; int lex_files(char **names) { /* lex */ extern FILE *yyin; filenames = names; if(*filenames != NULL) { #ifdef DEBUGGING DEBUG(D_SCAN, 1) printf("lex_files: first file is %s\n", *filenames); #endif if((yyin = fopen(*filenames, "r")) == NULL) { printf("Error opening %s for reading\n", *filenames); exit(1); } } return 0; } /* * Called by lex's end-of-file processing. * Open the next file on the command line. If there is no next file, * return "-1" and lex will end. */ int yywrap(void) { extern FILE *yyin; extern int yylineno; /* Line number from Lex */ if(*filenames != NULL) if(*++filenames != NULL) { #ifdef DEBUGGING DEBUG(D_SCAN, 1) printf("yywrap: next file is %s\n", *filenames); #endif yylineno=1; if((yyin = fopen(*filenames, "r")) != NULL) return(0); else { printf("Error opening %s for reading\n", *filenames); return(1); } } return(-1); }