Pierre Jouvelot
NewGen
CRI, Ecole des Mines (France)
LCS, MIT (U.S.A.)
name = expression ;
user = name:string x id:int x
passwd x shell:string ;
passwd = crypted:string +
clear:string ;
passwd_status = {crypted, clear} ;
node = information:int x
children:node* ;
group = elements:user{} ;
#define BUFFER_SIZE 100
buffer = first:int x lats:int x
elements:char[ BUFFER_SIZE ] ;
user pierre =
make_user( "jouvelot",
110,
passwd_undefined,
"/usr/local/bin/ksh" ) ;
char buffer[ 8 ] ;
passwd at_login =
make_passwd( is_passwd_encrypted,
crypt( gets( buffer ),
"a{\"a} )) ;
printf( "User %s logged on\n",
user_name( pierre )) ;
if( passwd_tag( at_login ) ==
is_passwd_encrypted ) {
check( passwd_crypted( at_login )) ;
}
if( passwd_encrypted_p( at_login )) {
check( passwd_crypted( at_login )) ;
}
passwd_tag( at_login ) =
is_passwd_clear ;
passwd_clear( at_login ) = "go ahead" ;
node = info:int x next:node ;
node n =
make_node( 1, node_undefined ) ;
next( n ) = n ;
user pierre = read_user( open_db()) ;
fprintf( stderr,
"Read data for user %s\n",
user_name( pierre )) ;
if( denied_access( pierre )) {
fprintf( sdterr,
"Permission denied: %s\n",
user_name( pierre )) ;
free_user( pierre ) ;
restart_top_level() ;
}
list logged_on = NIL ;
void add_to_users( u )
user u ;
{
logged_on =
CONS( USER, u, logged_on ) ;
}
printf( "Users logged on: " ) ;
MAPL( users, {
user u = USER( CAR( users )) ;
printf( "%s ", user_name( u )) ;
}, logged_on ) ;
CAR( logged_on ) = pierre ;
set_op( result, operand1, operand2 ) ;
set logged_on = set_undefined ;
void add_to_users( u )
user u ;
{
if( set_undefined_p( logged_on )) {
logged_on =
set_make( set_pointer) ;
}
set_add_element( logged_on,
logged_on,
u ) ;
}
printf( "Users logged on: " ) ;
SET_MAP( u, {
printf( "%s ", user_name( u )) ;
}, logged_on ) ;
#define SET_MAP(element,code,set) { \
HASH_MAP(_set_map_key, element, \
code, \
(set)->table); \
}
\title{SIMPLE Language Specifications}
\author{Pierre Jouvelot}
\begin{document}
\domain{expression = constant:int +
identifier:string +
binary +
let ;} {
An expression is either an integer constant,
an identifier, a binary expression, or a
nested let construct.
}
\domain{binary = operator:string x
lhs:expression x
rhs:expression ;} {
A binary expression consists of an operator
and two subexpressions.
}
\domain{let = bindings:binding* x
expression ;} {
A let construct includes a binding list and
a body expression.
}
\domain{binding = name:string x
value:expression ;} {
A binding binds a name to a value.
}
binary = operator:string x
lhs:expression x rhs:expression ;
binding = name:string x value:expression ;
expression = constant:int +
identifier:string +
binary + let ;
let = bindings:binding* x expression ;
. 1
. (+ x 1)
. (let ((x 1)) (+ x 2))
. (let ((x 1))
(let ((y (* 2 x)))
(+ x y)))
. make_expression(is_expression_constant,1)
. make_expression(
is_expression_binary,
make_binary(
"+",
make_expression(
is_expression_identifier,
"x"),
make_expression(
is_expression_constant,
1)))
%{
#include <stdio.h> /* Unix standard IO */
#include <string.h> /* String managt. */
#include "genC.h" /* Newgen basic
C library */
#include "expression.h" /* Newgen-generated
header files */
expression Top ;
%}
%token LP RP
%token LET
%term INT
%term STRING
%union {
expression expression ;
let let ;
list list ;
identifier identifier ;
string string ;
}
%type <expression> Axiom Expression
%type <let> Let
%type <identifier> Identifier
%type <list> Bindings
%type <string> String
%%
Axiom : Expression {
Top = $1 ;
}
;
Expression
: INT {
$$ = make_expression(
is_expression_constant,
atoi( yytext )) ;
}
| Identifier {
$$ = make_expression(
is_expression_identifier,$1);
}
| LP String Expression Expression RP {
binary b =
make_binary( $2, $3, $4 ) ;
$$ = make_expression(
is_expression_binary, b );
}
| Let {
$$ = make_expression(
is_expression_let, $1 ) ;
}
;
Let : LP LET LP Bindings RP Expression RP {
$$ = make_let( $4, $6 ) ;
}
;
Bindings
: {
$$ = NIL ;
}
| Bindings LP String Expression RP {
$$ = CONS( BINDING,
make_binding( $3, $4 ),
$1 ) ;
}
;
Identifier
: String {
$$ = make_identifier( $1 ) ;
}
;
String : STRING {
$$ = strdup( yytext ) ;
}
;
%%
% newgen -C expression.newgen GEN_READ_SPEC order: expression.spec % ls expression.newgen expression.h expression.spec %
#include <stdio.h>
#include "genC.h"
#include "expression.h"
expression Top ;
main()
{
gen_read_spec( "expression.spec",
(char*) NULL) ;
yyparse() ;
fprintf( stdout, "%d\n",
constant_fold( Top )) ;
free_expression( Top ) ;
}
int
constant_fold( e )
expression e ;
{
int value ;
tag t ;
switch( t = expression_tag( e )) {
case is_expression_constant:
value = expression_constant( e ) ;
break ;
case is_expression_binary:
binary b = expression_binary( e ) ;
int lhs = constant_fold(binary_lhs(b));
int rhs = constant_fold(binary_rhs(b));
value =
eval_primitive( binary_operator(b),
lhs, rhs ) ;
break ;
default:
fprintf( stderr,
"Unimplemented %d\n",
t ) ;
exit( 1 ) ;
}
return( value ) ;
}
int
eval_primitive( op, lhs, rhs )
char *op ;
int lhs, rhs ;
{
if( strcmp( op, "+" ) == 0 )
return( lhs+rhs ) ;
if( strcmp( op, "-" ) == 0 )
return( lhs-rhs ) ;
if( strcmp( op, "*" ) == 0 )
return( lhs*rhs ) ;
if( strcmp( op, "/" ) == 0 )
return( lhs/rhs ) ;
fprintf( stderr, "Primitive %s unknown\n",
op ) ;
exit( 1 ) ;
}
tabulated user = name:string x id:int x
passwd x shell:string ;
user pierre, francois, michel ;
list roots = CONS( USER, pierre,
CONS( USER, francois,
NIL )) ;
list admins = CONS( USER, michel,
CONS( USER, pierre,
NIL )) ;
group root = make_group( roots ) ;
group admin = make_group( admins ) ;
free_group( admin ) ;
--> CAR( group_elements( root )) ????
TABULATED_MAP( u, {
fprintf( stdout, "User %s\n",
user_name( u )) ;
}, user_domain ) ;
FILE *db = fopen("user.databas{\"e},"w");
gen_write_tabulated( db, user_domain ) ;
gen_free_tabulated( user_domain ) ;
-- network.newgen
import workstation from
"Include/workstation.newgen" ;
import gateway from
"Include/gateway.newgen" ;
network = nodes:node* ;
node = workstation + gateway +
repeater:node*;
% newgen -C network.newgen \ workstation.newgen gateway.newgen GEN_READ_SPEC order: workstation.spec gateway.spec network.spec %
external punch ;
import laser from "printers.newgen" ;
import daisy from "printers.newgen" ;
output_device = laser + daisy + punch ;
-- File identifier.newgen tabulated identifier = name:string ;
-- File expression.newgen
import identifier from "identifier.newgen" ;
external compacted ;
binary = operator:string x
lhs:expression x rhs:expression ;
binding = name:string x value:expression ;
expression = constant:int + identifier +
compacted + binary + let ;
let = bindings:binding* x expression ;
% newgen -C expression.newgen \ identifier.newgen GEN_READ_SPEC order identifier.spec expression.spec %
| Identifier {
$$ = make_expression(
is_expression_identifier,
make_identifier( $1 )) ;
}
void compacted_write( FILE *, compacted ) ;
compacted compacted_read( FILE *,
char (*)()) ;
void compacted_free( compacted ) ;
compacted compacted_copy( compacted ) ;
main()
{
gen_read_spec( "identifier.spec",
"expression.spec",
(char*) NULL) ;
gen_init_external( COMPACTED,
compacted_read,
compacted_write,
compacted_free,
compacted_copy ) ;
yyparse() ;
fprintf( stdout, "%d\n",
constant_fold( Top )) ;
#ifdef DEBUG
fprintf( stderr,"Bound Identifiers:\n");
TABULATED_MAP( i, {
fprintf( stderr, "%s,",
identifier_name( i )) ;
}, identifier_domain ) ;
#endif
free_expression( Top ) ;
gen_free_tabulated(identifier_domain);
}
void compacted_write( fd, c )
FILE *fd ;
compacted c ;
{
int val = *(int *)(char *)c ;
fprintf( fd, "%d",
(int)log2( (double)val )) ;
}
compacted
compacted_read( fd, read )
FILE *fd ;
char (*read)() ;
{
int *c = (int *)malloc( sizeof( int )) ;
fscanf( fd, "%d", c ) ;
return( (compacted)(char *)c ) ;
}
void
compacted_free( c )
compacted c ;
{
free( c ) ;
}
compacted
compacted_copy( c )
compacted c ;
{
int *cc = (int *)malloc( sizeof( int ));
*cc = *c ;
return( (compacted)(char *)cc ) ;
}
(setf pierre
(make-user
:name "jouvelot"
:id 110
:passwd passwd-undefined
:shell "/usr/local/bin/ksh"))
(setf (user-id pierre) 120)
(gen-switch (expression-tag e)
(is-expression-constant
(expression-constant e))
(:default
(error "~%Incorrect tag")))
(gen-switch (expression-tag e)
((is-expression-constant c) c)
(:default
(error "~%Incorrect tag")))
% newgen -lisp expression.newgen \ identifier.newgen REQUIRE order: identifier.cl expression.cl % ls expression.cl expression.spec identifier.cl identifier.spec %
(require "genLisplib") ; Newgen basic
; Lisp library
(require "identifier") ; Newgen-generated
; header files
(require "expression")
(use-package '(:newgen
:identifier
:expression))
(defun test (&optional (file *standard-input*))
"FILE contains the parser output."
(gen-read-spec)
(let ((*standard-input* (open file)))
(eval-expression (read-expression) '())))
(defun eval-expression (e env)
(gen-switch e
((is-expression-constant c) c)
((is-expression-identifier i)
(eval-identifier i env))
((is-expression-binary b)
(eval-binary b env))
((is-expression-let l)
(eval-let l env))))
(defun eval-identifier (i env)
(let ((var-val (assoc (identifier-name i) env
:test #'string-equal)))
(if (null var-val)
(error "~%Unbound identifier ~S"
(identifier-name i))
(cdr var-val))))
(defparameter operators
`((,"add" . ,\#'+)
(,"sub" . ,\#'-)
(,"times" . ,\#'*)
(,"cons" . ,\#'cons)
(,"eq" . ,\#'eq)))
(defun eval-binary (b env)
(let ((op (assoc (binary-operator b)
operators
:test #'string-equal)))
(if (null op)
(error "~\%Incorrect op code ~S"
(binary-operator b))
(funcall
(cdr op)
(eval-expression (binary-lhs b)
env)
(eval-expression (binary-rhs b)
env)))))
(defun eval-let (l env)
(let ((new-env
(mapcar
#'(lambda (b)
`(,(binding-name b) .
,(eval-expression
(binding-value b)
env)))
(let-bindings l))))
(eval-expression (let-expression l)
(append new-env env))))
(defun eval-expression (e env)
(gen-recurse e
((expression tag) tag)
(identifier
(cdr (assoc
(identifier-name i)
env
:test #'string-equal)))
((binary lhs rhs)
(funcall
(cdr (assoc
(binary-operator b)
operators
:test #'string-equal))
lhs rhs))))
(defun gensym ()
"Generate a brand new identifier."
(do ((i 0 (+ i 1)))
((gen-find-tabulated
(format nil "gensym-~D" i)
identifier-domain)
(make-identifier
:name (format nil "gensym-~D"
i)))))
-- Entities
tabulated entity = name:string x type x
value x storage ;
-- Expressions
expression = reference + range + call ;
reference = variable:entity x
indices:expression* ;
range = lower:expression x
upper:expression x
increment:expression ;
call = function:entity x
arguments:expression* ;
-- Statements
statement = label:entity x
number:int x
comments:string x
instruction ;
instruction = block:statement* + test +
loop + call + unstructured ;
test = condition:expression x
true:statement x
false:statement ;
loop = index:entity x
range x
body:statement x
label:entity ;
unstructured = control x exit:control ;
control = statement x
predecessors:control* x
successors:control* ;
typing = expression -> type ;