This commit was generated by cvs2svn to track changes on a CVS vendor
branch.
This commit is contained in:
commit
fd71db8218
|
@ -0,0 +1,3 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
SUBDIRS = doc src
|
|
@ -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
|
||||
])
|
|
@ -0,0 +1,4 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
man_MANS = exp.1
|
||||
EXTRA_DIST = $(man_MANS)
|
|
@ -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 <num> allows to present a list of items, the nextline is the title,
|
||||
.\" the following lines is the corpus shifted of <num> chars.
|
||||
.\" if <num> 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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,111 @@
|
|||
%{
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#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;}
|
||||
<EXP>[\]}] {BEGIN(INITIAL);return *yytext;}
|
||||
|
||||
<INITIAL>\n {lineno++;ECHO;}
|
||||
<INITIAL>{comment} {ECHO;}
|
||||
<INITIAL>{include} {BEGIN(INC);}
|
||||
<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);
|
||||
}
|
||||
<INITIAL><<EOF>> { 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];
|
||||
}
|
||||
}
|
||||
<EXP>\n {lineno++;}
|
||||
<EXP>{comment} {}
|
||||
<EXP>{if} {return IF;}
|
||||
<EXP>{min} {return MIN;}
|
||||
<EXP>{max} {return MAX;}
|
||||
<EXP>{inf} {return INF;}
|
||||
<EXP>{sup} {return SUP;}
|
||||
<EXP>{def} {return DEF;}
|
||||
<EXP>{ndef} {return NDEF;}
|
||||
<EXP>{sort} {return SORT;}
|
||||
<EXP>{rsort} {return RSORT;}
|
||||
<EXP>{message} {return MESS;}
|
||||
<EXP>{regex} {
|
||||
*(yytext+yyleng-1)='\0';
|
||||
yylval.e=htsetre(dico,yytext+1);
|
||||
return REGEX;
|
||||
}
|
||||
<EXP>{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;
|
||||
}
|
||||
<EXP>{number} {yylval.f=atof(yytext); return NUMBER;}
|
||||
<EXP>"++" {return PP;}
|
||||
<EXP>"--" {return MM;}
|
||||
<EXP,INC>{blank} {}
|
||||
<EXP>. {return *yytext;}
|
||||
. {ECHO;}
|
||||
%%
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
%{
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#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 <f>NUMBER
|
||||
%token <e>IDENT REGEX
|
||||
%type <f>exp cond
|
||||
%type <e>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);
|
||||
}
|
|
@ -0,0 +1,244 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <regex.h>
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -0,0 +1,88 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#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;
|
||||
}
|
Loading…
Reference in New Issue