Commit 37d82980 authored by Duncan White's avatar Duncan White

datadec-1.3: converted the code (and the code generated) to use stdbool.h...

datadec-1.3: converted the code (and the code generated) to use stdbool.h throughout, and added code into decs.c to generate a .basename.dd file listing the types, the shapes, and the parameter types per shape.
parent 8ea91dcb
CC = gcc
#CC = cc
DEST = $(PREFIX)/usr
# destination: home dir..
# DEST = $(HOME)
# or can install into TOOLDIR (env var, eg ~/c-tools)
DEST = $(TOOLDIR)
# or can install systemwide, with optional $(PREFIX) support for packaging
# DEST = $(PREFIX)/usr
#
BINDIR = $(DEST)/bin
ARCHDIR = $(BINDIR)/$(ARCH)
MANDIR = $(DEST)/man/man1
CC = gcc
#CC = cc
CFLAGS = -g -UDEBUGGING -Wall
LDLIBS =
EXECS = datadec
......
datadac-1.3, June 2018
Datadec takes inductive (or recursive) data types modelled on those found in
functional languages (Hope, Miranda, Haskell etc) and generates ANSI C code
to implement them.
functional languages (Hope, Miranda, Haskell etc) and generates ISO/ANSI C
code to implement them.
Duncan C. White, dcw@doc.ic.ac.uk
Duncan C. White, d.white@imperial.ac.uk
19th March 2002
New! experimental free functions (run datadec with new -f option)
New May 2014! experimental free functions for every inductive data type
(run datadec with new -f option)
Duncan C. White, d.white@imperial.ac.uk
28th May 2014
New June 2018! converted to use stdbool.h at last, and added new code to
quietly write out a .basename.dd file listing all the types and shapes,
and for each shape, the parameter types. This will be useful for add-on
tools such as the experimental "CPM.perl" script, which tackles client
side use of datadec-generated types, translating C+Pattern Matches to C.
An Example of Datadec in Action
-------------------------------
......@@ -34,6 +40,7 @@ nil() and cons() are called constructors, and define different
"shapes" that objects of the type can take.
However, because the second argument of a cons() constructor is itself
an intlist, this type is said to be recursively or inductively defined.
Functional programmers will recognise nil or cons() as the standard
way of defining a list, so more intuitively, intlist is simply
a list of integers!
......@@ -42,13 +49,13 @@ Reading on, an illist is declared as a list of intlists,
and an idtree is declared as a binary tree where each leaf node
contains a (string, illist) pair.
Given this input, datadec can automatically construct an ANSI C
Given this input, datadec can automatically construct an ISO C
module which implements all the data types, a constructor function for
each constructor, deconstructor functions to help you to take objects
apart again and printing functions to help you with debugging.
(Plus, new May 2014: a tree-walking free function if you invoke datadec
with the new -f option).
(Plus, new May 2014: a tree-walking free function for every type if you
invoke datadec with the new -f option).
Building and Packaging datadec
------------------------------
......
......@@ -8,17 +8,21 @@
*
******* Description:
*
* This program builds C or Modula-2 data declarations,
* This program builds C data declarations,
* constructor and deconstructor functions and write functions
* from a series of HOPE/Miranda style recursive data declarations.
* (with optional hints on printing)
* from a series of Haskell/Miranda/Hope style recursive data declarations.
* (with optional hints on printing, and optionally, free_* functions)
*
* The output produced is placed in pair of files (eg. x.c and x.h )
* which together form a module provided the relevent data types.
* which together form a module provided the relevant data types.
* NEW in 2018: in addition, we write a useful summary of types,
* shapes and the types of the shape parameters into a .x.dd file,
* this can be used by experimental client-side tools such as "CPM.perl".
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "struct.h"
......@@ -28,7 +32,7 @@
#include "optimize.h"
#define MUSTBE(b) {if(!(b)){fprintf(stderr,"Usage: datadec [-vno] outfile [infile]\n");exit(1);}}
#define MUSTBE(b) {if(!(b)){fprintf(stderr,"Usage: datadec [-vnof] outfile [infile]\n");exit(1);}}
#define NEED_ANOTHER_ARG MUSTBE( IS_ANOTHER_ARG )
#define REQUIRE_NO_MORE_ARGS MUSTBE( argc == arg )
......@@ -52,7 +56,7 @@ int main( int argc, char **argv )
arg = 1;
NEED_ANOTHER_ARG;
verbose = FALSE; opt = TRUE;
verbose = false; opt = true;
while( *(s=argv[arg]) == '-' )
{
for( s++; *s; s++ )
......@@ -60,16 +64,16 @@ int main( int argc, char **argv )
switch( *s )
{
case 'v':
verbose = TRUE;
verbose = true;
break;
case 'f':
makefree = TRUE;
makefree = true;
break;
case 'n':
opt = FALSE;
opt = false;
break;
case 'o':
opt = TRUE;
opt = true;
break;
default:
fprintf( stderr,
......@@ -103,22 +107,21 @@ int main( int argc, char **argv )
REQUIRE_NO_MORE_ARGS;
if( parse_data( exports, globals, begin, &declns ) )
{
if( verbose )
{
printf( "datadec: declns are:\n\n" );
print_declnlist( declns );
printf( "exports = {%s}\n", exports );
printf( "globals = {%s}\n", globals );
printf( "begin = {%s}\n", begin );
}
optimize( declns );
make_declns( exports, globals, begin, declns, basename );
} else
if( ! parse_data( exports, globals, begin, &declns ) )
{
fprintf( stderr, "datadec: can't parse input properly\n" );
exit(1);
}
if( verbose )
{
printf( "datadec: declns are:\n\n" );
print_declnlist( declns );
printf( "exports = {%s}\n", exports );
printf( "globals = {%s}\n", globals );
printf( "begin = {%s}\n", begin );
}
optimize( declns );
make_declns( exports, globals, begin, declns, basename );
exit(0);
/*NOTREACHED*/
}
This diff is collapsed.
extern BOOL makefree;
extern bool makefree;
extern void make_declns( char * , char * , char * , declnlist , char * );
......@@ -17,6 +17,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
......@@ -45,7 +46,7 @@ FILE *lexfile;
/* ----------------- Private variables ---------------- */
static BOOL havepushedtok = FALSE;
static bool havepushedtok = false;
static TOKEN curtok;
static char curid[ MAXIDSIZE ];
static int curint;
......@@ -80,7 +81,7 @@ void ungettok( void )
fprintf( stderr, "ungettok: can't push 2 tokens\n" );
exit(1);
}
havepushedtok = TRUE;
havepushedtok = true;
#ifdef DEBUGGING
printf( "lexer: ungot token %s\n", tokenname[ curtok ] );
#endif
......@@ -94,7 +95,7 @@ TOKEN nexttok( void )
if( havepushedtok )
{
havepushedtok = FALSE;
havepushedtok = false;
} else
{
white_space();
......@@ -184,7 +185,7 @@ printf( "returning token %s\n", tokenname[ curtok ] );
}
BOOL readnextline( char *line )
bool readnextline( char *line )
{
int c;
char *s = line;
......
......@@ -33,4 +33,4 @@ extern FILE *lexfile;
extern void ungettok( void );
extern TOKEN nexttok( void );
extern BOOL readnextline( char * line );
extern bool readnextline( char * line );
......@@ -3,18 +3,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "struct.h"
#include "optimize.h"
BOOL opt; /* opt == perform optimizations */
BOOL verbose; /* verbose == be verbose - diagnostics */
bool opt; /* opt == perform optimizations */
bool verbose; /* verbose == be verbose - diagnostics */
static void optimize_decln( decln );
static BOOL tail_optimize( decln );
static bool tail_optimize( decln );
#define implies( a, b ) (!(a) || (b))
......@@ -29,8 +30,8 @@ void optimize( declnlist d )
optimize_decln( d );
} else
{
d->ManyShapes = d->TagField = d->Struct = d->Union = TRUE;
d->UseNull = d->PutLoop = FALSE;
d->ManyShapes = d->TagField = d->Struct = d->Union = true;
d->UseNull = d->PutLoop = false;
}
}
}
......@@ -40,7 +41,7 @@ static void optimize_decln( decln d )
{
int t, e, ne;
shapelist s;
BOOL firstempty = d->shapes->params == NULL;
bool firstempty = d->shapes->params == NULL;
e = ne = 0;
for( s = d->shapes; s != NULL; s = s->next )
......@@ -120,10 +121,10 @@ static void optimize_decln( decln d )
This is when the last print item of any shape is a number corresponding
to a field that is the same type as the decln itself.
Return TRUE if the optimization is possible.
Return true if the optimization is possible.
*/
static BOOL tail_optimize( decln d )
static bool tail_optimize( decln d )
{
shapelist s;
printlist pl;
......@@ -143,10 +144,10 @@ static BOOL tail_optimize( decln d )
s->name, d->name );
if( streq( p->type, d->name ) )
{
return TRUE;
return true;
}
}
}
}
return FALSE;
return false;
}
/* optimize.h */
extern BOOL opt; /* perform optimizations */
extern BOOL verbose; /* be verbose */
extern bool opt; /* perform optimizations */
extern bool verbose; /* be verbose */
extern void optimize( declnlist );
......@@ -28,6 +28,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include "struct.h"
#include "lexer.h"
#include "parser.h"
......@@ -36,20 +37,20 @@
#define COPYOF(new,old) {new=malloc(1+strlen(old));if(new)strcpy(new,old);}
static BOOL parse_chunk( char * s );
static BOOL parse_declns( declnlist * dp );
static bool parse_chunk( char * s );
static bool parse_declns( declnlist * dp );
static void error( char * s );
static BOOL parse_decln( char ** name, shapelist * shapes );
static BOOL parse_shapes( shapelist * sp );
static BOOL parse_shape( char ** tagname, paramlist * pl, printlist * print );
static BOOL parse_params( paramlist * pp );
static BOOL parse_printlist( printlist * pp );
static BOOL parse_printitem( printitem * item );
static BOOL neverfreetype( char * typename );
static BOOL parse_param( BOOL * dontfree, char ** type, char ** name );
static bool parse_decln( char ** name, shapelist * shapes );
static bool parse_shapes( shapelist * sp );
static bool parse_shape( char ** tagname, paramlist * pl, printlist * print );
static bool parse_params( paramlist * pp );
static bool parse_printlist( printlist * pp );
static bool parse_printitem( printitem * item );
static bool neverfreetype( char * typename );
static bool parse_param( bool * dontfree, char ** type, char ** name );
#define MUSTBE(t,mesg) if( nexttok() != (t) ) {error(mesg); return FALSE;}
#define MUSTBE(t,mesg) if( nexttok() != (t) ) {error(mesg); return false;}
/*
......@@ -59,11 +60,11 @@ static BOOL parse_param( BOOL * dontfree, char ** type, char ** name );
* tTYPE tOPENCURLY declns tCLOSECURLY
*/
BOOL parse_data( char *exports, char *globals, char *begin, declnlist *dp )
bool parse_data( char *exports, char *globals, char *begin, declnlist *dp )
{
if( nexttok() == tEXPORT )
{
if( ! parse_chunk( exports ) ) return FALSE;
if( ! parse_chunk( exports ) ) return false;
} else
{
*exports = '\0';
......@@ -72,7 +73,7 @@ BOOL parse_data( char *exports, char *globals, char *begin, declnlist *dp )
if( nexttok() == tGLOBAL )
{
if( ! parse_chunk( globals ) ) return FALSE;
if( ! parse_chunk( globals ) ) return false;
} else
{
*globals = '\0';
......@@ -81,7 +82,7 @@ BOOL parse_data( char *exports, char *globals, char *begin, declnlist *dp )
if( nexttok() == tBEGIN )
{
if( ! parse_chunk( begin ) ) return FALSE;
if( ! parse_chunk( begin ) ) return false;
} else
{
*begin = '\0';
......@@ -90,17 +91,17 @@ BOOL parse_data( char *exports, char *globals, char *begin, declnlist *dp )
MUSTBE( tTYPE, "TYPE/EXPORT/GLOBAL/BEGIN expected" );
MUSTBE( tOPENCURLY, "{ expected" );
if( ! parse_declns( dp ) ) return FALSE;
if( ! parse_declns( dp ) ) return false;
MUSTBE( tCLOSECURLY, "} expected" );
MUSTBE( tEOF, "Spurious characters found beyond EOF" );
return TRUE;
return true;
}
/* chunk = tOPENCURLY list_of_lines tCLOSECURLY */
static BOOL parse_chunk( char *s )
static bool parse_chunk( char *s )
{
char line[256];
int startlineno;
......@@ -117,20 +118,20 @@ static BOOL parse_chunk( char *s )
fprintf( stderr,
"Premature EOF after { - started at line %d\n",
startlineno );
return FALSE;
return false;
}
if( streq( line, "}" ) ) break;
strcat( s, line );
strcat( s, "\n" );
}
return TRUE;
return true;
}
/* declns = list*( decln ) */
/* NB: a decln starts with a tID */
static BOOL parse_declns( declnlist *dp )
static bool parse_declns( declnlist *dp )
{
char *name;
shapelist shapes;
......@@ -138,12 +139,12 @@ static BOOL parse_declns( declnlist *dp )
while( nexttok() == tID )
{
ungettok();
if( ! parse_decln( &name, &shapes ) ) return FALSE;
if( ! parse_decln( &name, &shapes ) ) return false;
*dp = build_declnlist( name, shapes, (declnlist) NULL );
dp = &( (*dp)->next );
}
ungettok();
return TRUE;
return true;
}
......@@ -155,44 +156,44 @@ static void error( char *s )
/* decln = tID tEQ shapes tSEMI */
static BOOL parse_decln( char **name, shapelist *shapes )
static bool parse_decln( char **name, shapelist *shapes )
{
MUSTBE( tID, "declaration expected" );
COPYOF( *name, lexidval );
MUSTBE( tEQ, "'=' expected" );
if( ! parse_shapes( shapes ) ) return FALSE;
if( ! parse_shapes( shapes ) ) return false;
MUSTBE( tSEMI, "';' expected" );
return TRUE;
return true;
}
/* shapes = sep-list+( shape, tOR ) */
static BOOL parse_shapes( shapelist *sp )
static bool parse_shapes( shapelist *sp )
{
char *tagname;
paramlist paras;
printlist print;
for(;;) {
if( ! parse_shape( &tagname, &paras, &print ) ) return FALSE;
if( ! parse_shape( &tagname, &paras, &print ) ) return false;
*sp = build_shapelist( tagname, paras,
print, (shapelist) NULL );
if( nexttok() != tOR ) break;
sp = &( (*sp)->next );
}
ungettok();
return TRUE;
return true;
}
/* shape = tID [ tOPENBR params tCLOSEBR ] printlist */
static BOOL parse_shape( char **tagname, paramlist *pl, printlist *print )
static bool parse_shape( char **tagname, paramlist *pl, printlist *print )
{
*pl = (paramlist) NULL;
*print = (printlist) NULL;
......@@ -202,7 +203,7 @@ static BOOL parse_shape( char **tagname, paramlist *pl, printlist *print )
if( nexttok() == tOPENBR )
{
if( ! parse_params( pl ) ) return FALSE;
if( ! parse_params( pl ) ) return false;
MUSTBE( tCLOSEBR, "',' or ')' expected" );
} else
......@@ -216,27 +217,27 @@ static BOOL parse_shape( char **tagname, paramlist *pl, printlist *print )
/* params = sep-list+( param, tCOMMA ) */
static BOOL parse_params( paramlist *pp )
static bool parse_params( paramlist *pp )
{
char *type;
char *name;
BOOL dontfree;
bool dontfree;
for(;;) {
if( !parse_param( &dontfree, &type, &name ) ) return FALSE;
if( !parse_param( &dontfree, &type, &name ) ) return false;
*pp = build_paramlist( dontfree, type, name, (paramlist) NULL );
if( nexttok() != tCOMMA ) break;
pp = &( (*pp)->next );
}
ungettok();
return TRUE;
return true;
}
/* printlist = list( printitem ) */
/* NB: Never fails, cos items are one token long */
static BOOL parse_printlist( printlist *pp )
static bool parse_printlist( printlist *pp )
{
printitem item;
......@@ -247,13 +248,13 @@ static BOOL parse_printlist( printlist *pp )
*pp = build_printlist( item, (printlist) NULL );
pp = &( (*pp)->next );
}
return TRUE;
return true;
}
/* printitem = tSTR | tNUM */
static BOOL parse_printitem( printitem *item )
static bool parse_printitem( printitem *item )
{
char *temp;
......@@ -261,13 +262,13 @@ static BOOL parse_printitem( printitem *item )
case tSTR:
COPYOF( temp, lexidval );
*item = build_printitem_str( temp );
return TRUE;
return true;
case tNUM:
*item = build_printitem_num( lexintval );
return TRUE;
return true;
default:
ungettok();
return FALSE;
return false;
}
}
......@@ -275,6 +276,7 @@ static BOOL parse_printitem( printitem *item )
/* never free the following types - sorted list */
static char *neverfree[] = {
"BOOL",
"bool",
"char",
"int",
};
......@@ -282,23 +284,23 @@ static char *neverfree[] = {
#define NEVERFREE_NEL (sizeof(neverfree)/sizeof(char *))
static BOOL neverfreetype( char *typename )
static bool neverfreetype( char *typename )
{
int i;
for( i=0; i<NEVERFREE_NEL; i++ )
{
if( strcmp( neverfree[i], typename ) == 0 )
{
return TRUE;
return true;
}
}
return FALSE;
return false;
}
/* param = [tMINUS] tID tID */
static BOOL parse_param( BOOL *dontfree, char **type, char **name )
static bool parse_param( bool *dontfree, char **type, char **name )
{
*dontfree = nexttok() == tMINUS;
if( ! *dontfree )
......@@ -318,5 +320,5 @@ static BOOL parse_param( BOOL *dontfree, char **type, char **name )
COPYOF( *name, lexidval );
//printf( "debug: param(%s, %s): dontfree %d\n", *type, *name, *dontfree );
return TRUE;
return true;
}
extern BOOL parse_data( char * exports, char * globals, char * begin, declnlist * dp );
extern bool parse_data( char * exports, char * globals, char * begin, declnlist * dp );
......@@ -17,6 +17,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "struct.h"
......@@ -89,7 +90,7 @@ void print_shapelist( shapelist s )
}
paramlist build_paramlist( BOOL dontfree, char *type, char *id, paramlist next )
paramlist build_paramlist( bool dontfree, char *type, char *id, paramlist next )
{
paramlist new = NEW(paramlist);
......
......@@ -14,10 +14,10 @@
*/
typedef char BOOL;
#define FALSE 0
#define TRUE 1
//let's use stdbool.h now; we're in the 21st century..
//typedef char BOOL;
//#define FALSE 0
//#define TRUE 1
#define streq(a,b) (strcmp((a),(b))==0)
......@@ -57,7 +57,7 @@ struct paramlist {
paramlist next;
char *type;
char *name;
BOOL dontfree; /* exclude from freeing - eg shared ptr */
bool dontfree; /* exclude from freeing - eg shared ptr */
};
......@@ -73,7 +73,7 @@ struct declnlist {
declnlist next;
char *name;
shapelist shapes;
BOOL ManyShapes, TagField, Struct, Union, UseNull, PutLoop;
bool ManyShapes, TagField, Struct, Union, UseNull, PutLoop;
};
......@@ -87,7 +87,7 @@ extern void print_declnlist( declnlist d );
extern shapelist build_shapelist( char * id, paramlist p, printlist pl, shapelist next );
extern void print_shape( shapelist s );
extern void print_shapelist( shapelist s );
extern paramlist build_paramlist( BOOL dontfree, char * type, char * id, paramlist next );
extern paramlist build_paramlist( bool dontfree, char * type, char * id, paramlist next );
extern void print_paramlist( paramlist p );
extern printitem build_printitem_str( char * s );
extern printitem build_printitem_num( int n );
......
......@@ -2,9 +2,9 @@ DEST = $(TOOLDIR)
LIBDIR = $(DEST)/lib/$(ARCH)
INCDIR = $(DEST)/include
CFLAGS = -I. -I$(INCDIR) -g -UDEBUGGING -Wall
LDLIBS = -L$(LIBDIR) -lmem
LDLIBS = -L$(LIBDIR)
TESTEXECS = ctest
AUTOCRAP = ctest.o cx.[och]
AUTOCRAP = ctest.o cx.[och] .cx.dd
all: $(TESTEXECS)
......
......@@ -15,8 +15,6 @@ extern int lengthil( illist );