From 930a17fd08f1044fa0c9684a7b194f5f1d748d77 Mon Sep 17 00:00:00 2001 From: Franck Wajsburt Date: Tue, 9 Apr 2002 12:33:07 +0000 Subject: [PATCH] importing exp (calculator for .rds files) --- alliance/src/exp/Makefile.am | 3 + alliance/src/exp/configure.in | 35 ++++ alliance/src/exp/doc/Makefile.am | 4 + alliance/src/exp/doc/exp.1 | 328 +++++++++++++++++++++++++++++++ alliance/src/exp/src/Makefile.am | 9 + alliance/src/exp/src/exp.h | 14 ++ alliance/src/exp/src/expl.l | 111 +++++++++++ alliance/src/exp/src/expy.y | 192 ++++++++++++++++++ alliance/src/exp/src/ht.c | 244 +++++++++++++++++++++++ alliance/src/exp/src/ht.h | 95 +++++++++ alliance/src/exp/src/main.c | 88 +++++++++ 11 files changed, 1123 insertions(+) create mode 100644 alliance/src/exp/Makefile.am create mode 100644 alliance/src/exp/configure.in create mode 100644 alliance/src/exp/doc/Makefile.am create mode 100644 alliance/src/exp/doc/exp.1 create mode 100644 alliance/src/exp/src/Makefile.am create mode 100644 alliance/src/exp/src/exp.h create mode 100644 alliance/src/exp/src/expl.l create mode 100644 alliance/src/exp/src/expy.y create mode 100644 alliance/src/exp/src/ht.c create mode 100644 alliance/src/exp/src/ht.h create mode 100644 alliance/src/exp/src/main.c diff --git a/alliance/src/exp/Makefile.am b/alliance/src/exp/Makefile.am new file mode 100644 index 00000000..ce9d1044 --- /dev/null +++ b/alliance/src/exp/Makefile.am @@ -0,0 +1,3 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = doc src diff --git a/alliance/src/exp/configure.in b/alliance/src/exp/configure.in new file mode 100644 index 00000000..444300cc --- /dev/null +++ b/alliance/src/exp/configure.in @@ -0,0 +1,35 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(src/expy.y) + +EXP_MAJOR_VERSION=1 +EXP_MINOR_VERSION=0 +EXP_VERSION=$EXP_MAJOR_VERSION.$EXP_MINOR_VERSION + +AC_SUBST(EXP_MAJOR_VERSION) +AC_SUBST(EXP_MINOR_VERSION) +AC_SUBST(EXP_VERSION) + +# For automake. +VERSION=$EXP_VERSION +PACKAGE=exp + +dnl Initialize automake stuff +AM_INIT_AUTOMAKE($PACKAGE, $VERSION) + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_RANLIB +AM_PROG_LEX +AC_PROG_YACC +AC_PROG_MAKE_SET + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +AM_ALLIANCE + +AC_OUTPUT([ +Makefile +doc/Makefile +src/Makefile +]) diff --git a/alliance/src/exp/doc/Makefile.am b/alliance/src/exp/doc/Makefile.am new file mode 100644 index 00000000..c45911fc --- /dev/null +++ b/alliance/src/exp/doc/Makefile.am @@ -0,0 +1,4 @@ +## Process this file with automake to produce Makefile.in + +man_MANS = exp.1 +EXTRA_DIST = $(man_MANS) diff --git a/alliance/src/exp/doc/exp.1 b/alliance/src/exp/doc/exp.1 new file mode 100644 index 00000000..52932088 --- /dev/null +++ b/alliance/src/exp/doc/exp.1 @@ -0,0 +1,328 @@ +.\" --------------------------------------------------------------------------- +.TH EXP 1.0 "March 18, 2002" "UPMC/ASIM/LIP6" +.\" $Id: exp.1,v 1.1 2002/04/09 12:33:07 franck Exp $ +.\" @(#)02/02/18 UPMC/ASIM/LIP6; Author: Franck Wajsburt +.\" --------------------------------------------------------------------------- +.\" Main useful commands +.\" -------------------- +.\" .TH Head and Foot of page +.\" .SH at the line begining is a Section Header +.\" .SS at the line begining is a Sub-Section Header +.\" .TP allows to present a list of items, the nextline is the title, +.\" the following lines is the corpus shifted of chars. +.\" if is omited, the default value is 7 +.\" .so filename allows to include a filename (absolute or relative to MANPATH) +.\" \fB is for Bold font \fP is to return to Previous font +.\" \fI is to underlined or to change to Italic font +.\" .B .I can be used for Bold or Italic, if place a the line beginning +.\" .br at the line begining break the line, a blank line put a blank line +.\" .nf Begins a Non-Formatted zone where each line-break is put as-is +.\" .fi Returns to Formatted mode .nf/.fi is usefull for example to draw tables +.\" --------------------------------------------------------------------------- + +.SH EXP +.\" --------------------------------------------------------------------------- + +exp - a multiple expession calculator. + +.so man1/origin.1 + +.SH SYNOPSIS +.\" --------------------------------------------------------------------------- + +\fBexp\fP [\fB-v\fPn\fI0..4\fP] [\fB-o\fP \fIoutput-file\fP] [\fIinput-file\fP] + +.SH DESCRIPTION +.\" --------------------------------------------------------------------------- + +Input is an ascii format file including numeric expessions with variables. +Input file can includes other input files thanks to an inclusion directive. +\fBexp\fP reads the input files to write it as is in the output file, but the +numeric expessions are replaced by their value. + +.SH OPTIONS +.\" --------------------------------------------------------------------------- + +.TP +.B -v +verbose mode +.br +0 : quiet mode +.br +1 : messages \fImess(...)\fP are printed +.br +2 : few statistics +.br +3 : all expressions are decomposed +.br +4 : yacc messages +.TP +.B -o \fIoutput-file\fP +where \fBexp\fP writes (stdout by default). +.TP +.I input-file +where \fBexp\fP reads (stdin by default). + +.SH EXP FORMAT FILES +.\" --------------------------------------------------------------------------- + +Except the expessionsi and offline comments, the output file is identical to the +flattened view of the input files whatever they are. +The expession forms can be either \fI[expessions]\fP or \fI{expessions}\fP. +The first form is for floating point expessions, the second one is for +integer expessions. By default, the print format is respectively %7.3f +and %4d (cf. \fIsprintf(3)\fP). +Offline comments begins with // and ends at the beginning of the next line. + +.I Examples +.IP \(bu 3 +[ 3.0 + 12.1] \fIprint\fP 15.100 +.IP \(bu 3 +{ 3.0 + 12.1} \fIprint\fP 15 +.P + +It is possible to have more that one expession separated by \fI;\fP +(semi-column). All the expessions of a list are computed, but only the last +one is printed. If the last expession is empty, \fBexp\fP do not print +anything (see Examples section). + +.I Examples +.IP \(bu 3 +[ 6. *2.0; +.br + 3.0 + 12.1 ] \fIprint\fP 15.100 +.IP \(bu 3 +[ 6. *2.0; +.br + 3.0 + 12.1; ] \fIprint\fP nothing +.P + +It is possible to have comments in expessions. A comment begins with \fI#\fP +(diese) and ends to the carriage return. +Comment in expression is not copied to the output file. + +.I Example +.IP \(bu 3 +[ 3.0 + 12.1 # comment +.br +] \fIprint\fP 15.100 + +.SS Expessions +.\" ---------- + +Expession is a multi-level numeric expession using numbers, variables, +arithmetic operators and numeric functions. + +.I Examples +.IP \(bu 3 +[ i=3.0; i*12.1] \fIprint\fP 15.100 + +.IP \(bu 3 +{i=3} \fIprint\fP 3 +.br +{i++} \fIprint\fP 4 +.P + +.SS Arithmetic Operators +.\" -------------------- +The operators, in order of increasing priority, are + +.TP +.B + - +Addition and subtraction. +.TP +.B * / +Multiplication and division. +.TP +.B ++ -- +post-incrementation of 1, post-decrementation of 1. +.TP +.B ( ) +Grouping +.TP +.B = +Variable affectation. The return value is the one affected. + +.SS Boolean Operators +.\" ----------------- +.TP +.B > < +respectively greater than and lower than +.TP +.B def(variable) +True whenever variable is defined yet +.TP +.B ndef(variable) +True whenever variable is not defined yet + +.SS Variables +.\" --------- + +Expession values may be stored in simple variables. +.\" or one dimension arrays. +There are three forms of variable name. +First, they can begin with a letter followed by any number of letters, digits +and underscores; second, they can begin with \fI"\fP (double quote) followed +by any number of any char and ended by a \fI"\fP; Third they can begin with +\fI\'\fP (quote) then a regular expression (see \fIregex(7)\fP) ended +by \fI\'\fP. \fBexp\fP is case sensitive. +.\" Array index is put between \fI()\fP. + +.I Examples +.IP \(bu 3 +[ VAR_1=3.0; # first form +.br + "variable numero 2"=12.0; # second form +.br +] \fIprint\fP nothing +.IP \(bu 3 +[ VAR_1 * "variable numero 2" ] \fIprint\fP 15.100 +.P + +When a variable appears in the right member of an affectation, \fBexp\fP +uses its value. If it has never been defined, this causes a fatal error. +If it appears the left member, the first time it is automatically created +and its value is set, or its value is changed. + +.SS Special variables +.\" ----------------- + +\fBfloat_fmt\fP, \fBinteger_fmt\fP and \fBstring_fmt\fP special variables to +redefine print format of floats, integers and strings. Defaults are %7.3f, +%-8s and %4d. Those variables are the only variables with a non numerical +value. + +.I Examples +.IP \(bu 3 +[\fBfloat_fmt\fP = "%7.1f";] \fIprint\fP nothing +.IP \(bu 3 +[ 3.0 + 12.1] \fIprint\fP 15.1 +.P + +\fBverbose\fP is the variable passed in argument list, which can be modified +by the program itself. + +.I Examples \fP get details of expression calculation +.IP \(bu 3 +[tmp = \fBverbose\fP; \fBverbose\fP = 3; \fI..expressions..\fP; +.br +\fBverbose\fP = tmp;] +.P + +.SS Numeric functions +.\" ----------------- + +Few numeric functions are available. The form is \fIfun(args)\fP. +The arguments take the form of a list of expessions, separated with a \fI,\fP +(comma). The number of arguments depends on functions. +It is possible to make a list of arguments with a regular expession +(see \fIregex(7)\fP). +Then all matching variable names are part of the list. +.TP +.B min\fI(args)\fP max\fI(args)\fP +The minimum (resp. maximum) value of its arguments. + +.I Examples +.RS 7 +.IP \(bu 3 +[min(3.0,12.1)] \fIprint\fP 3.000 +.IP \(bu 3 +[min('RW_ALU.*')] \fIprint\fP min value of all variables begining by RW_ALU +.RE + +.TP +.B inf\fI(step,val)\fP sup\fI(step,val)\fP +Two arguments. \fPinf\fP (resp. \fPsup\fP) function rounds the second argument +(val) downwards (resp. upwards) to an integer number of the first argument +(step). + +.I Examples +.RS 7 +.IP \(bu 3 +[step=0.3;value=1.6;inf(step,value)] \fIprint\fP 1.500 +.RE + +.SS Special functions and directives +.\" -------------------------------- + +.TP +.B if\fI(condition, expr1, expr2, ...)\fP +Calculates the condition if it is true (means greater than zero), the following +expressions are all calculated. +.TP +.B sort\fI(args)\fP rsort\fI(args)\fP +\fBsort\fP (resp. reverse \fBrsort\fP) numerically all its arguments, each +argument must be a variable, not directly a numeric expession. The return +value is the sorted list of its arguments. +.TP +.B message\fI(args)\fP +writes its arguments to stdout using \fIfloat_fmt\fP, one argument per line. +The form is : +\fIvariable_name = value;\fP, +value is omitted if the variable has never been defined. +.br +.I Examples +.RS 7 +.IP \(bu 3 +[message('"'this is a message'"');] \fIprint\fP +.br +this is a message +.IP \(bu 3 +[a1b=0; a2b=1O; a3b=5; message(a*b);] \fIprint\fP +.br +a1b = 0.000 +.br +a2b = 1O.000 +.br +a3b = 5.000 +.IP \(bu 3 +[string_fmt=%6s; message(sort(a*b));] \fIprint\fP +.br + a1b = 0.000 +.br + a3b = 5.000 +.br + a2b = 1O.000 +.RE + +.TP +\fB#include "filename"\fP +Opens the file in argument then returns to the current file as soon as the new +one is empty. + +.SH EXAMPLES +.\" --------------------------------------------------------------------------- + +.TP +.B Input file +.nf +# this is a test file +[ # few variables + WITDH = 2; + LENGTH = 25 ; +] +this message is unchanged but all expresions are computed + length_div_2 = [LENGTH/2] + length_mul_2 = {LENGTH*2} + result = [max ('leng.*')] +.fi +.TP +.B Output file +.nf +# this is a test file + +this message is unchanged but all expresions are computed + length_div_2 = 12.500 + length_mul_2 = 50 + result = 12.500 +.fi + +.SH AUTHOR + +Written by Franck Wajsburt. + +.SH SEE ALSO + +Alliance .rds file uses \fBexp\fP to be generated. + +.so man1/bug_report.1 diff --git a/alliance/src/exp/src/Makefile.am b/alliance/src/exp/src/Makefile.am new file mode 100644 index 00000000..52c2442f --- /dev/null +++ b/alliance/src/exp/src/Makefile.am @@ -0,0 +1,9 @@ +## Process this file with automake to produce Makefile.in + +bin_PROGRAMS = exp + +YACC = @YACC@ -d -v --debug +CFLAGS = @CFLAGS@ @ALLIANCE_CFLAGS@ +exp_LDADD = -lm -lfl + +exp_SOURCES = exp.h expy.y expl.l ht.c ht.h main.c diff --git a/alliance/src/exp/src/exp.h b/alliance/src/exp/src/exp.h new file mode 100644 index 00000000..3197b792 --- /dev/null +++ b/alliance/src/exp/src/exp.h @@ -0,0 +1,14 @@ +#ifndef _RDS_H_ +#define _RDS_H_ + +#include "ht.h" + +extern int yydebug; +extern int yyparse(void); +extern FILE *yyin; +extern FILE *yyout; +extern ht_t * dico; +extern int verbose; +extern char * expfname ; + +#endif diff --git a/alliance/src/exp/src/expl.l b/alliance/src/exp/src/expl.l new file mode 100644 index 00000000..1a4721fd --- /dev/null +++ b/alliance/src/exp/src/expl.l @@ -0,0 +1,111 @@ +%{ +#include +#include +#include +#include +#include "exp.h" +#include "expy.h" + +extern int lineno; +#define MAX_INCLUDE_DEPTH 10 +YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; +int lineno_stack[MAX_INCLUDE_DEPTH]; +char * fname_stack[MAX_INCLUDE_DEPTH]; +int include_stack_ptr = 0; + +%} +localcomment [ \t]*\/\/.*\n +comment ([ \t]*[#].*) +regex (\'[^'\n#]+\') +ident ([a-zA-Z][a-zA-Z0-9_]*)|(\"[^"\n#]+\") +number ([0-9]+|([0-9]+\.[0-9]*)|([0-9]*\.[0-9]+))([eE][+\-]?[0-9]+)? +blank [ \t]+ +if [iI][fF] +min [mM][iI][nN] +max [mM][aA][xX] +inf [iI][nN][fF] +sup [sS][uU][pP] +sort [sS][oO][rR][tT] +rsort [rR][sS][oO][rR][tT] +def [Dd][Ee][Ff] +ndef [Nn][Dd][Ee][Ff] +include [Ii][Nn][Cc][Ll][Uu][Dd][Ee] +message [Mm][Ee][Ss][Ss][Aa][Gg][Ee] +%x EXP INC +%% +{localcomment} {lineno++;} +[\[\{] {BEGIN(EXP);return *yytext;} +[\]}] {BEGIN(INITIAL);return *yytext;} + +\n {lineno++;ECHO;} +{comment} {ECHO;} +{include} {BEGIN(INC);} +{ident} { /* got the include file name */ + char * filename = yytext; + if (include_stack_ptr >= MAX_INCLUDE_DEPTH) { + fprintf (stderr, " %-3d %s : Includes nested too deeply\n", lineno, expfname); + exit (1); + } + if (*filename == '"') { + *(filename+yyleng-1)='\0'; + filename +=1; + } + if ((yyin = fopen( filename, "r" )) == NULL) { + fprintf (stderr, " %-3d %s : %s cannot be opened\n", + lineno, expfname, filename); + exit (1); + } + include_stack[include_stack_ptr] = YY_CURRENT_BUFFER; + lineno_stack[include_stack_ptr] = lineno; + fname_stack[include_stack_ptr++] = expfname; + if ((expfname = strdup (filename)) == NULL) { + fprintf (stderr, " %-3d %s : not enough memory\n", lineno, expfname, filename); + exit (1); + } + lineno = 1; + yy_switch_to_buffer( yy_create_buffer( yyin, YY_BUF_SIZE ) ); + BEGIN(INITIAL); + } +<> { if ( --include_stack_ptr < 0 ) + yyterminate(); + else { + yy_delete_buffer (YY_CURRENT_BUFFER ); + yy_switch_to_buffer (include_stack[include_stack_ptr] ); + expfname = fname_stack[include_stack_ptr]; + lineno = lineno_stack[include_stack_ptr]; + } + } +\n {lineno++;} +{comment} {} +{if} {return IF;} +{min} {return MIN;} +{max} {return MAX;} +{inf} {return INF;} +{sup} {return SUP;} +{def} {return DEF;} +{ndef} {return NDEF;} +{sort} {return SORT;} +{rsort} {return RSORT;} +{message} {return MESS;} +{regex} { + *(yytext+yyleng-1)='\0'; + yylval.e=htsetre(dico,yytext+1); + return REGEX; + } +{ident} { if (dico==NULL) dico=htinit(10000); + if (*yytext == '"') { + *(yytext+yyleng-1)='\0'; + yylval.e=htset(dico,yytext+1); + } + else + yylval.e=htset(dico,yytext); + return IDENT; + } +{number} {yylval.f=atof(yytext); return NUMBER;} +"++" {return PP;} +"--" {return MM;} +{blank} {} +. {return *yytext;} +. {ECHO;} +%% + diff --git a/alliance/src/exp/src/expy.y b/alliance/src/exp/src/expy.y new file mode 100644 index 00000000..3b3c24b7 --- /dev/null +++ b/alliance/src/exp/src/expy.y @@ -0,0 +1,192 @@ +%{ +#include +#include +#include +#include "exp.h" +#include "ht.h" + +#define VERBOSE (int)((htget(dico, "verbose")->VAL.f+EPSILON)) +#define EPSILON 0.00001 +#define anint(x) floor((x) + 0.5) +#define test_init(i) if (((i)->TYPE==0) && ((pcond==0) || (cond[pcond]>0.))) {\ + printf(" %-3d %s : <%s> undefined\n", lineno, expfname, (i)->KEY);\ + exit (1);}\ + (i)->USED = 1 +#define pa(v,e) if (VERBOSE>2) printf("%7.3f -> %s\n",e,v->KEY) +#define pi(e) if (VERBOSE>2) printf("%7.3f <- %s\n",e->VAL.f,e->KEY) +#define pe(s,n) if (VERBOSE>2) printf("%7.3f %s\n",n,s) +#define PCONDMAX 16 /* profondeur de la pile de conditions */ + +int lineno=1; +char * expfname; +ht_t * dico; + +static int pcond=0; +static double cond[PCONDMAX]; /* pile de conditions : +1:vrai, -1:faux */ +static char * string_fmt = "%-65s"; +static char * float_fmt = "%7.3f"; +static char * integer_fmt = "%4d"; +static htelt_t * ele; + +double limit (int fun, htelt_t * args) +{ + htelt_t *ele; + double res; + for (ele = args; ele && ele->TYPE == 0; ele = ele->NEXT); + if (ele == NULL) + { + printf(" %-3d %s : none variable defined\n", lineno, expfname);\ + exit (1); + } + res = ele->VAL.f; + for (; ele; ele = ele->NEXT) + if ((ele->TYPE != 0) && (((fun == MAX) && (res < ele->VAL.f)) || ((fun == MIN) && (res > ele->VAL.f)))) + res = ele->VAL.f; + eltremove (args); + return res; +} + +htelt_t *bsort (int sens, htelt_t * args) +{ + htelt_t *ele; + int bubble = 1; + if (args->NEXT) /* au moins de 2 elements dans la liste */ + while (bubble) + { + bubble = 0; + for (ele = args; ele->NEXT; ele = ele->NEXT) + if (((sens == SORT) && (((ele->VAL.e)->VAL.f) > (((ele->NEXT)->VAL.e)->VAL.f))) + || ((sens == RSORT) && (((ele->VAL.e)->VAL.f) < (((ele->NEXT)->VAL.e)->VAL.f))) + || ((sens == MESS) && (strcmp((ele->VAL.e)->KEY,((ele->NEXT)->VAL.e)->KEY)>0))) + { + htelt_t *tmp = ele->VAL.e; + ele->VAL.e = (ele->NEXT)->VAL.e; + (ele->NEXT)->VAL.e = tmp; + bubble = 1; + } + } + return args; +} + +htelt_t *mess (int type, char *fmt, htelt_t * args) +{ + htelt_t *ele; + if (VERBOSE) + { + for (ele = args; ele; ele = ele->NEXT) + { + if ((type == MESS) || ((ele->VAL.e)->TYPE == HT_FLOAT)) + { + printf (string_fmt, (ele->VAL.e)->KEY); + if ((ele->VAL.e)->TYPE == HT_FLOAT) + { + printf (" = "); + printf (fmt, (ele->VAL.e)->VAL.f); + } + printf ("\n"); + } + } + } + eltremove (args); +} + +%} +%union +{ + htelt_t * e; + double f; +} +%token IF PP MM MAX MIN SUP INF SORT RSORT MESS DEF NDEF +%token NUMBER +%token IDENT REGEX +%type exp cond +%type args idents +%right '=' +%right '<' '>' +%left '+' '-' +%left '*' '/' +%% +blocs : /* rien */ { if (VERBOSE>1) htstat(dico); return 1;} + | bloc blocs + ; +bloc : '[' exps exp ']' { fprintf (yyout, float_fmt, $3);} + | '{' exps exp '}' { fprintf (yyout, integer_fmt, (int)$3);} + | '[' exp ']' { fprintf (yyout, float_fmt, $2);} + | '{' exp '}' { fprintf (yyout, integer_fmt, (int)$2);} + | '[' SORT '(' idents ')' ']' { mess(SORT,float_fmt, bsort (SORT, $4));} + | '{' SORT '(' idents ')' '}' { mess(SORT,integer_fmt, bsort (SORT, $4));} + | '[' RSORT '(' idents ')' ']' { mess(SORT,float_fmt, bsort (RSORT, $4));} + | '{' RSORT '(' idents ')' '}' { mess(SORT,integer_fmt, bsort (RSORT, $4));} + | '[' MESS '(' idents ')' ']' { mess(MESS,float_fmt, bsort (MESS, $4));} + | '{' MESS '(' idents ')' '}' { mess(MESS,integer_fmt, bsort (MESS, $4));} + | '[' exps ']' { } + | '{' exps '}' { } + ; +exps : exp ';' { } + | exps exp ';' { } + ; +exp : IDENT '=' exp { if ((pcond==0) || (cond[pcond]>0.)) { + $1->VAL.f=$3; $1->TYPE=HT_FLOAT; + $1->FNAME=expfname; $1->FLINE=lineno; + $$=$3; pa($1,$$); + } + } + | NUMBER { $$ = $1; pe(" ",$$);} + | IDENT { test_init($1); $$ = $1->VAL.f; pi($1);} + | IDENT PP { test_init($1); $$ = $1->VAL.f; $1->VAL.f += 1.0;} + | IDENT MM { test_init($1); $$ = $1->VAL.f; $1->VAL.f -= 1.0;} + | exp '<' exp { $$ = ($1 < $3) ? 1. : -1.; pe(" < ",$$);} + | exp '>' exp { $$ = ($1 > $3) ? 1. : -1.; pe(" > ",$$);} + | exp '+' exp { $$ = $1 + $3; pe(" + ",$$);} + | exp '-' exp { $$ = $1 - $3; pe(" - ",$$);} + | exp '*' exp { $$ = $1 * $3; pe(" * ",$$);} + | exp '/' exp { $$ = $1 / $3; pe(" / ",$$);} + | '(' exp ')' { $$ = $2;} + | '-' exp { $$ = -$2; pe(" - ",$$);} + | IF '(' cond ',' args ')' { for (ele = $5; ele->NEXT; ele = ele->NEXT); + $$ = ele->VAL.f; + pcond--; eltremove ($5); + } + | SUP '(' exp ',' exp ')' { $$ = anint(($5+($3/2)-EPSILON)/$3)*$3; pe(" sup ",$$);} + | INF '(' exp ',' exp ')' { $$ = ((int)(floor(($5+EPSILON)/$3)))*$3; pe(" inf ",$$);} + | MAX '(' args ')' { $$ = limit (MAX, $3); pe(" max ",$$);} + | MIN '(' args ')' { $$ = limit (MIN, $3); pe(" min ",$$);} + | DEF '(' IDENT ')' { $$ = ($3->TYPE==0) ? -1. : +1.; pe($3,$$);} + | NDEF '(' IDENT ')' { $$ = ($3->TYPE==0) ? +1. : -1.; pe($3,$$);} + ; +cond : exp { if (pcond < PCONDMAX) + cond[++pcond] = $1; + else + yyerror ("too much conditions") + } + ; +idents : IDENT { $$ = eltadd (NULL,NULL); $$->VAL.e=$1;} + | IDENT ',' idents { $$ = eltadd ($3,NULL); $$->VAL.e=$1;} + | REGEX { $$ = $1->NEXT; $1->NEXT=NULL;} + | REGEX ',' idents { $$ = $1->NEXT; $1->NEXT=$3;} + ; +args : exp { $$ = eltadd (NULL,NULL); $$->VAL.f=$1; $$->TYPE=HT_FLOAT;pe(" , ",$1);} + | exp ',' args { $$ = eltadd ($3,NULL); $$->VAL.f=$1; $$->TYPE=HT_FLOAT;pe(" , ",$3);} + | REGEX { $$ = $1->NEXT; $1->NEXT=NULL; + for (ele = $$; ele; ele = ele->NEXT) + { + ele->VAL.e->USED = 1; + ele->TYPE = (ele->VAL.e)->TYPE; + ele->VAL.f = (ele->VAL.e)->VAL.f; + } + } + | REGEX ',' args { $$ = $1->NEXT; $1->NEXT=$3; + for (ele = $1; ele; ele = ele->NEXT) + { + ele->VAL.e->USED = 1; + ele->TYPE = (ele->VAL.e)->TYPE; + ele->VAL.f = ele->VAL.e->VAL.f; + } + } + ; +%% +int yyerror(char *s) +{ + printf(" %-3d %s : %s\n", lineno, expfname, s); + exit (1); +} diff --git a/alliance/src/exp/src/ht.c b/alliance/src/exp/src/ht.c new file mode 100644 index 00000000..ff8b557d --- /dev/null +++ b/alliance/src/exp/src/ht.c @@ -0,0 +1,244 @@ +#include +#include +#include +#include +#include "ht.h" + +/* gestion des entrees du dictionnaire +** ============================================================================= +*/ +static htelt_t *free_htelt = NULL; + +/* ajoute une entree (initialisé à 0) en tete de liste +** --------------------------------------------------- +*/ +htelt_t *eltadd (htelt_t * list, char *key) +{ + htelt_t *new_elt; + if (free_htelt) + { + new_elt = free_htelt; + free_htelt = free_htelt->NEXT; + } + else if ((new_elt = malloc (sizeof (htelt_t))) == NULL) + { + perror ("add elt in dictionnary"); + exit (1); + } + if (key) + if ((new_elt->KEY = strdup (key)) == NULL) + { + perror ("add elt in dictionnary"); + exit (1); + } + new_elt->NEXT = list; + new_elt->TYPE = 0; + new_elt->USED = 0; + new_elt->VAL.f = 0.; + return new_elt; +} + +/* replace une entree dans la liste des entrees libres +** rend le pointeur NEXT de l'entree effacée +** --------------------------------------------------- +*/ +htelt_t *eltdel (htelt_t * list) +{ + htelt_t *del_elt = NULL; + if (list) + { + del_elt = list->NEXT; + list->NEXT = free_htelt; + free_htelt = list; + } + return del_elt; +} + +/* efface une liste d'elements +** --------------------------- +*/ +void eltremove (htelt_t * list) +{ + htelt_t *elt; + for (elt = list; elt; elt = eltdel (elt)); +} + +/* efface le dictionnaire complet +** ------------------------------ +*/ +void htremove (ht_t * ht) +{ + int i; + for (i = 1; i < (int) ht[0]; i++) + eltremove (ht[i]); + free (ht); +} + +/* statistiques +** ------------ +*/ +void htstat (ht_t * ht) +{ + int i; + htelt_t *elt; + if (ht) + { + static int start=1; + for (i = 1; i < (int) ht[0]; i++) + for (elt = ht[i]; elt; elt = elt->NEXT) + if (elt->USED == 0) + { + if (start) + { + start=0; + printf ("Warning : following variables declared but never used :\n"); + } + printf (" %-3d %-20s : %s\n", elt->FLINE, elt->FNAME, elt->KEY); + } + printf ("\n"); + free (ht); + } +} + +/* entrees sorties du dictionnaire +** ============================================================================= +*/ + +static int primes[] = { + 101, 223, 311, 419, 547, 659, 727, 877, 967, + 1061, 2053, 3299, 4391, 5309, 6421, 7069, 8543, 9397, + 10337, 20143, 32423, 43151, 52223, 63179, 0 +}; + +/* creation d'un dictionnaire +** -------------------------- +*/ +ht_t *htinit (int size) +{ + int i; + ht_t *ht; + + /* prend le premier nombre premier au dela de size */ + for (i = 0; primes[i] && (size > primes[i]); i++); + if (primes[i] == 0) + { + fprintf (stderr, "Erreur : hash table trop grande (> %d)\n", primes[i - 1]); + exit (1); + } + size = primes[i]; + if ((ht = calloc (size + 1, sizeof (htelt_t *))) == NULL) + { + perror ("htinit"); + exit (1); + } + ht[0] = (htelt_t *) size; /* taille de la table dans premiere case */ + return ht; +} + +/* calcul de la valeur de hachage primaire +** --------------------------------------- +*/ +static int hash (ht_t * ht, char *key) +{ + int alveole = 0; + int length = strlen (key); + int segment; + int l; + + if (ht == NULL) + { + fprintf (stderr, "dictionnary not allocated\n"); + exit (1); + } + if ((key == NULL) || (length == 0)) + { + fprintf (stderr, "Error : hash (NULL)\n"); + exit (1); + } + for (l = 0; l < length; l += 2) + { + segment = 0xFFFF & ((key[l] << 8) | key[l + 1]); + alveole = alveole ^ ((segment << 1) | (segment >> 15)); + } + alveole %= (int) ht[0]; /* ht[0] == la taille de la table */ + return (alveole + 1); /* +1 car on ne doit rien mettre dans case 0 */ +} + +/* recherche d'une entree dans la table +** rend un pointeur sur l'element +** htget()->KEY pointe sur la cle key +** htget()->VAL.i contient la valeur int +** htget()->VAL.f contient la valeur double +** htget()->VAL.s contient la valeur char * +** ---------------------------------------- +*/ +htelt_t *htget (ht_t * ht, char *key) +{ + int alveole = hash (ht, key); + htelt_t *p; + + for (p = ht[alveole]; p && strcmp (p->KEY, key); p = p->NEXT); + return p; +} + +/* ajout d'une nouvelle entree dans la table +** NE VERIFIE PAS SI L'ELEMENT N'EST PAS DEJA PRESENT +** -------------------------------------------------- +*/ +htelt_t *htadd (ht_t * ht, char *key) +{ + int alveole = hash (ht, key); + + return ht[alveole] = eltadd (ht[alveole], key); +} + +/* recherche d'une entree dans la table et ajout si absente +** -------------------------------------------------------- +*/ +htelt_t *htset (ht_t * ht, char *key) +{ + int alveole = hash (ht, key); + htelt_t *p; + + for (p = ht[alveole]; p && strcmp (p->KEY, key); p = p->NEXT); + if (p) + return p; + return ht[alveole] = eltadd (ht[alveole], key); +} + +/* recherche d'une regexp dans la table et ajout si absente +** rend un pointeur sur la liste CIRCULAIRE d'element trouves +** NULL sinon +** -------------------------------------------------------- +*/ +htelt_t *htsetre (ht_t * ht, char *key) +{ + regex_t preg; + htelt_t *elt, *res = NULL; + int i; + + if (regcomp(&preg, key, REG_EXTENDED | REG_NOSUB) != 0) + return NULL; + if (ht) + for (i = 1; i < (int) ht[0]; i++) + for (elt = ht[i]; elt; elt = elt->NEXT) + if (regexec (&preg, elt->KEY, (size_t) 0, NULL, 0) == 0) + { + if (res) + { + htelt_t * new = eltadd (res->NEXT, NULL); + new->VAL.e = elt; + res->NEXT = new ; + res = new; + } + else + { + res = eltadd (NULL, NULL); + res->NEXT = res; + res->VAL.e = elt; + } + } + regfree (&preg); + return res; +} + diff --git a/alliance/src/exp/src/ht.h b/alliance/src/exp/src/ht.h new file mode 100644 index 00000000..be5d0cf1 --- /dev/null +++ b/alliance/src/exp/src/ht.h @@ -0,0 +1,95 @@ +#ifndef _HT_H_ +#define _HT_H_ + +/* declaration de types : +** 1) union de types pour la valeur d'une entree dans le dicionnaire +** 2) type d'une entree +** 3) type du dictionnaire +** ----------------------------------------------------------------- +*/ +typedef union +{ + struct htelt_st *e; + double f; + int i; + char *s; +} +elt_t; + +typedef struct htelt_st +{ + struct htelt_st * NEXT; + char *KEY; + int TYPE; + int USED; + int FLINE; + char * FNAME; + elt_t VAL; +} +htelt_t; + +typedef htelt_t * ht_t; + +enum htelt_e {HT_EMPTY, HT_INT, HT_STRING, HT_FLOAT}; + + +/* ajoute une entree (initialisé à 0) en tete de liste +** --------------------------------------------------- +*/ +extern htelt_t *eltadd (htelt_t * list, char *key); + +/* replace une entree dans la liste des entrees libres +** rend le pointeur NEXT de l'entree effacée +** --------------------------------------------------- +*/ +extern htelt_t *eltdel (htelt_t * list); + +/* efface une liste d'elements +** --------------------------- +*/ +extern void eltremove (htelt_t * list); + +/* donne des info sur l'usage du dico +** ---------------------------------- +*/ +extern void htremove (ht_t * ht); + +/* efface le dictionnaire complet +** ------------------------------ +*/ +extern void htremove (ht_t * ht); + +/* creation du dictionnaire +** ------------------------ +*/ +extern ht_t *htinit (int size); + +/* recherche d'une entree dans la table +** rend un pointeur sur l'element +** htget()->KEY pointe sur la cle key +** htget()->VAL.i contient la valeur int +** htget()->VAL.f contient la valeur double +** htget()->VAL.s contient la valeur char * +** ---------------------------------------- +*/ +extern htelt_t *htget (ht_t * ht, char *key); + +/* ajout d'une nouvelle entree dans la table +** NE VERIFIE PAS SI L'ELEMENT N'EST PAS DEJA PRESENT +** -------------------------------------------------- +*/ +extern htelt_t *htadd (ht_t * ht, char *key); + +/* recherche d'une entree dans la table et ajout si absente +** -------------------------------------------------------- +*/ +htelt_t *htset (ht_t * ht, char *key); + +/* recherche d'une regexp dans la table et ajout si absente +** rend un pointeur sur la liste CIRCULAIRE d'elements trouves +** NULL sinon +** -------------------------------------------------------- +*/ +htelt_t *htsetre (ht_t * ht, char *key); + +#endif diff --git a/alliance/src/exp/src/main.c b/alliance/src/exp/src/main.c new file mode 100644 index 00000000..5a5c9d6d --- /dev/null +++ b/alliance/src/exp/src/main.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include "exp.h" +#include "ht.h" + +void usage (char *av[]) +{ + printf ("Usage : %s [-h] [-v level] [-o outfile] [infile]\n\n", av[0]); + printf (" -h this help\n"); + printf (" -v verbose mode (level is 1:2:3:4)\n"); + printf (" -o define the output file (stdout by default)\n"); + printf (" infile define the input file (stdin by default)\n"); + printf ("\n"); + exit (1); +} + +void getoption (int ac, char *av[], FILE ** expout, FILE ** expin) +{ + char option; + int verbose; + *expin = stdin; + *expout = stdout; + yydebug = 0; + + dico=htinit(10000); + htset(dico,"verbose")->VAL.f = -1.0; + htget(dico,"verbose")->TYPE = HT_INT; + htget(dico,"verbose")->USED = 1; + + while ((option = getopt (ac, av, "hv:o:")) != EOF) + { + switch (option) + { + case 'v': + verbose = *optarg - '0'; + if ((verbose < 0)||(verbose > 9)) + usage (av); + yydebug = (verbose == 4) ? 1 : 0; + htset(dico,"verbose")->VAL.f = verbose; + break; + case 'o': + if ((*expout = fopen (optarg, "w")) == NULL) + usage (av); + break; + default: + usage (av); + } + } + if (optind < ac) + { + if ((*expin = fopen (av[optind], "r")) == NULL) + usage (av); + expfname = strdup (av[optind++]); + } + if (optind < ac) + usage (av); +} + +int main (int ac, char *av[]) +{ + getoption (ac, av, &yyout, &yyin); + if (htget(dico,"verbose")->VAL.f != 0) + { + puts(" "); + puts(" @@@@@ @@@@ @@@ @@@ @@@"); + puts(" @ @ @@ @ @@@ @@"); + puts(" @@ @@ @@ @ @@ @@"); + puts(" @@@@@@@@@ @@@ @@ @@"); + puts(" @@ @@@ @@ @@"); + puts(" @@ @ @ @@ @@ @@"); + puts(" @@ @@ @ @@ @@@ @@"); + puts(" @@@@ @@@ @@@@ @@ @@@"); + puts(" @@"); + puts(" @@@@"); + puts(" "); + puts(" multiple expressions calculator"); + puts(" "); + printf(" Alliance CAD System %-4s exp %-3s\n", + ALLIANCE_VERSION, VERSION); + puts(" Copyright (c) 2002, ASIM/LIP6/UPMC"); + puts(" E-mail support: alliance-support@asim.lip6.fr"); + puts(" "); + } + yyparse (); + return 0; +}