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 # destination: home dir..
#CC = cc # DEST = $(HOME)
DEST = $(PREFIX)/usr # 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 BINDIR = $(DEST)/bin
ARCHDIR = $(BINDIR)/$(ARCH)
MANDIR = $(DEST)/man/man1 MANDIR = $(DEST)/man/man1
CC = gcc
#CC = cc
CFLAGS = -g -UDEBUGGING -Wall CFLAGS = -g -UDEBUGGING -Wall
LDLIBS = LDLIBS =
EXECS = datadec EXECS = datadec
......
datadac-1.3, June 2018
Datadec takes inductive (or recursive) data types modelled on those found in Datadec takes inductive (or recursive) data types modelled on those found in
functional languages (Hope, Miranda, Haskell etc) and generates ANSI C code functional languages (Hope, Miranda, Haskell etc) and generates ISO/ANSI C
to implement them. code to implement them.
Duncan C. White, dcw@doc.ic.ac.uk Duncan C. White, d.white@imperial.ac.uk
19th March 2002 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 New June 2018! converted to use stdbool.h at last, and added new code to
28th May 2014 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 An Example of Datadec in Action
------------------------------- -------------------------------
...@@ -34,6 +40,7 @@ nil() and cons() are called constructors, and define different ...@@ -34,6 +40,7 @@ nil() and cons() are called constructors, and define different
"shapes" that objects of the type can take. "shapes" that objects of the type can take.
However, because the second argument of a cons() constructor is itself However, because the second argument of a cons() constructor is itself
an intlist, this type is said to be recursively or inductively defined. an intlist, this type is said to be recursively or inductively defined.
Functional programmers will recognise nil or cons() as the standard Functional programmers will recognise nil or cons() as the standard
way of defining a list, so more intuitively, intlist is simply way of defining a list, so more intuitively, intlist is simply
a list of integers! a list of integers!
...@@ -42,13 +49,13 @@ Reading on, an illist is declared as a list of intlists, ...@@ -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 and an idtree is declared as a binary tree where each leaf node
contains a (string, illist) pair. 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 module which implements all the data types, a constructor function for
each constructor, deconstructor functions to help you to take objects each constructor, deconstructor functions to help you to take objects
apart again and printing functions to help you with debugging. apart again and printing functions to help you with debugging.
(Plus, new May 2014: a tree-walking free function if you invoke datadec (Plus, new May 2014: a tree-walking free function for every type if you
with the new -f option). invoke datadec with the new -f option).
Building and Packaging datadec Building and Packaging datadec
------------------------------ ------------------------------
......
...@@ -8,17 +8,21 @@ ...@@ -8,17 +8,21 @@
* *
******* Description: ******* Description:
* *
* This program builds C or Modula-2 data declarations, * This program builds C data declarations,
* constructor and deconstructor functions and write functions * constructor and deconstructor functions and write functions
* from a series of HOPE/Miranda style recursive data declarations. * from a series of Haskell/Miranda/Hope style recursive data declarations.
* (with optional hints on printing) * (with optional hints on printing, and optionally, free_* functions)
* *
* The output produced is placed in pair of files (eg. x.c and x.h ) * 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 <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <string.h> #include <string.h>
#include "struct.h" #include "struct.h"
...@@ -28,7 +32,7 @@ ...@@ -28,7 +32,7 @@
#include "optimize.h" #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 NEED_ANOTHER_ARG MUSTBE( IS_ANOTHER_ARG )
#define REQUIRE_NO_MORE_ARGS MUSTBE( argc == arg ) #define REQUIRE_NO_MORE_ARGS MUSTBE( argc == arg )
...@@ -52,7 +56,7 @@ int main( int argc, char **argv ) ...@@ -52,7 +56,7 @@ int main( int argc, char **argv )
arg = 1; arg = 1;
NEED_ANOTHER_ARG; NEED_ANOTHER_ARG;
verbose = FALSE; opt = TRUE; verbose = false; opt = true;
while( *(s=argv[arg]) == '-' ) while( *(s=argv[arg]) == '-' )
{ {
for( s++; *s; s++ ) for( s++; *s; s++ )
...@@ -60,16 +64,16 @@ int main( int argc, char **argv ) ...@@ -60,16 +64,16 @@ int main( int argc, char **argv )
switch( *s ) switch( *s )
{ {
case 'v': case 'v':
verbose = TRUE; verbose = true;
break; break;
case 'f': case 'f':
makefree = TRUE; makefree = true;
break; break;
case 'n': case 'n':
opt = FALSE; opt = false;
break; break;
case 'o': case 'o':
opt = TRUE; opt = true;
break; break;
default: default:
fprintf( stderr, fprintf( stderr,
...@@ -103,22 +107,21 @@ int main( int argc, char **argv ) ...@@ -103,22 +107,21 @@ int main( int argc, char **argv )
REQUIRE_NO_MORE_ARGS; REQUIRE_NO_MORE_ARGS;
if( parse_data( exports, globals, begin, &declns ) ) 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
{ {
fprintf( stderr, "datadec: can't parse input properly\n" ); 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); exit(0);
/*NOTREACHED*/ /*NOTREACHED*/
} }
This diff is collapsed.
extern BOOL makefree; extern bool makefree;
extern void make_declns( char * , char * , char * , declnlist , char * ); extern void make_declns( char * , char * , char * , declnlist , char * );
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
...@@ -45,7 +46,7 @@ FILE *lexfile; ...@@ -45,7 +46,7 @@ FILE *lexfile;
/* ----------------- Private variables ---------------- */ /* ----------------- Private variables ---------------- */
static BOOL havepushedtok = FALSE; static bool havepushedtok = false;
static TOKEN curtok; static TOKEN curtok;
static char curid[ MAXIDSIZE ]; static char curid[ MAXIDSIZE ];
static int curint; static int curint;
...@@ -80,7 +81,7 @@ void ungettok( void ) ...@@ -80,7 +81,7 @@ void ungettok( void )
fprintf( stderr, "ungettok: can't push 2 tokens\n" ); fprintf( stderr, "ungettok: can't push 2 tokens\n" );
exit(1); exit(1);
} }
havepushedtok = TRUE; havepushedtok = true;
#ifdef DEBUGGING #ifdef DEBUGGING
printf( "lexer: ungot token %s\n", tokenname[ curtok ] ); printf( "lexer: ungot token %s\n", tokenname[ curtok ] );
#endif #endif
...@@ -94,7 +95,7 @@ TOKEN nexttok( void ) ...@@ -94,7 +95,7 @@ TOKEN nexttok( void )
if( havepushedtok ) if( havepushedtok )
{ {
havepushedtok = FALSE; havepushedtok = false;
} else } else
{ {
white_space(); white_space();
...@@ -184,7 +185,7 @@ printf( "returning token %s\n", tokenname[ curtok ] ); ...@@ -184,7 +185,7 @@ printf( "returning token %s\n", tokenname[ curtok ] );
} }
BOOL readnextline( char *line ) bool readnextline( char *line )
{ {
int c; int c;
char *s = line; char *s = line;
......
...@@ -33,4 +33,4 @@ extern FILE *lexfile; ...@@ -33,4 +33,4 @@ extern FILE *lexfile;
extern void ungettok( void ); extern void ungettok( void );
extern TOKEN nexttok( void ); extern TOKEN nexttok( void );
extern BOOL readnextline( char * line ); extern bool readnextline( char * line );
...@@ -3,18 +3,19 @@ ...@@ -3,18 +3,19 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <string.h> #include <string.h>
#include "struct.h" #include "struct.h"
#include "optimize.h" #include "optimize.h"
BOOL opt; /* opt == perform optimizations */ bool opt; /* opt == perform optimizations */
BOOL verbose; /* verbose == be verbose - diagnostics */ bool verbose; /* verbose == be verbose - diagnostics */
static void optimize_decln( decln ); static void optimize_decln( decln );
static BOOL tail_optimize( decln ); static bool tail_optimize( decln );
#define implies( a, b ) (!(a) || (b)) #define implies( a, b ) (!(a) || (b))
...@@ -29,8 +30,8 @@ void optimize( declnlist d ) ...@@ -29,8 +30,8 @@ void optimize( declnlist d )
optimize_decln( d ); optimize_decln( d );
} else } else
{ {
d->ManyShapes = d->TagField = d->Struct = d->Union = TRUE; d->ManyShapes = d->TagField = d->Struct = d->Union = true;
d->UseNull = d->PutLoop = FALSE; d->UseNull = d->PutLoop = false;
} }
} }
} }
...@@ -40,7 +41,7 @@ static void optimize_decln( decln d ) ...@@ -40,7 +41,7 @@ static void optimize_decln( decln d )
{ {
int t, e, ne; int t, e, ne;
shapelist s; shapelist s;
BOOL firstempty = d->shapes->params == NULL; bool firstempty = d->shapes->params == NULL;
e = ne = 0; e = ne = 0;
for( s = d->shapes; s != NULL; s = s->next ) for( s = d->shapes; s != NULL; s = s->next )
...@@ -120,10 +121,10 @@ static void optimize_decln( decln d ) ...@@ -120,10 +121,10 @@ static void optimize_decln( decln d )
This is when the last print item of any shape is a number corresponding 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. 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; shapelist s;
printlist pl; printlist pl;
...@@ -143,10 +144,10 @@ static BOOL tail_optimize( decln d ) ...@@ -143,10 +144,10 @@ static BOOL tail_optimize( decln d )
s->name, d->name ); s->name, d->name );
if( streq( p->type, d->name ) ) if( streq( p->type, d->name ) )
{ {
return TRUE; return true;
} }
} }
} }
} }
return FALSE; return false;
} }
/* optimize.h */ /* optimize.h */
extern BOOL opt; /* perform optimizations */ extern bool opt; /* perform optimizations */
extern BOOL verbose; /* be verbose */ extern bool verbose; /* be verbose */
extern void optimize( declnlist ); extern void optimize( declnlist );
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include "struct.h" #include "struct.h"
#include "lexer.h" #include "lexer.h"
#include "parser.h" #include "parser.h"
...@@ -36,20 +37,20 @@ ...@@ -36,20 +37,20 @@
#define COPYOF(new,old) {new=malloc(1+strlen(old));if(new)strcpy(new,old);} #define COPYOF(new,old) {new=malloc(1+strlen(old));if(new)strcpy(new,old);}
static BOOL parse_chunk( char * s ); static bool parse_chunk( char * s );
static BOOL parse_declns( declnlist * dp ); static bool parse_declns( declnlist * dp );
static void error( char * s ); static void error( char * s );
static BOOL parse_decln( char ** name, shapelist * shapes ); static bool parse_decln( char ** name, shapelist * shapes );
static BOOL parse_shapes( shapelist * sp ); static bool parse_shapes( shapelist * sp );
static BOOL parse_shape( char ** tagname, paramlist * pl, printlist * print ); static bool parse_shape( char ** tagname, paramlist * pl, printlist * print );
static BOOL parse_params( paramlist * pp ); static bool parse_params( paramlist * pp );
static BOOL parse_printlist( printlist * pp ); static bool parse_printlist( printlist * pp );
static BOOL parse_printitem( printitem * item ); static bool parse_printitem( printitem * item );
static BOOL neverfreetype( char * typename ); static bool neverfreetype( char * typename );
static BOOL parse_param( BOOL * dontfree, char ** type, char ** name ); 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 ); ...@@ -59,11 +60,11 @@ static BOOL parse_param( BOOL * dontfree, char ** type, char ** name );
* tTYPE tOPENCURLY declns tCLOSECURLY * 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( nexttok() == tEXPORT )
{ {
if( ! parse_chunk( exports ) ) return FALSE; if( ! parse_chunk( exports ) ) return false;
} else } else
{ {
*exports = '\0'; *exports = '\0';
...@@ -72,7 +73,7 @@ BOOL parse_data( char *exports, char *globals, char *begin, declnlist *dp ) ...@@ -72,7 +73,7 @@ BOOL parse_data( char *exports, char *globals, char *begin, declnlist *dp )
if( nexttok() == tGLOBAL ) if( nexttok() == tGLOBAL )
{ {
if( ! parse_chunk( globals ) ) return FALSE; if( ! parse_chunk( globals ) ) return false;
} else } else
{ {
*globals = '\0'; *globals = '\0';
...@@ -81,7 +82,7 @@ BOOL parse_data( char *exports, char *globals, char *begin, declnlist *dp ) ...@@ -81,7 +82,7 @@ BOOL parse_data( char *exports, char *globals, char *begin, declnlist *dp )
if( nexttok() == tBEGIN ) if( nexttok() == tBEGIN )
{ {
if( ! parse_chunk( begin ) ) return FALSE; if( ! parse_chunk( begin ) ) return false;
} else } else
{ {
*begin = '\0'; *begin = '\0';
...@@ -90,17 +91,17 @@ BOOL parse_data( char *exports, char *globals, char *begin, declnlist *dp ) ...@@ -90,17 +91,17 @@ BOOL parse_data( char *exports, char *globals, char *begin, declnlist *dp )
MUSTBE( tTYPE, "TYPE/EXPORT/GLOBAL/BEGIN expected" ); MUSTBE( tTYPE, "TYPE/EXPORT/GLOBAL/BEGIN expected" );
MUSTBE( tOPENCURLY, "{ expected" ); MUSTBE( tOPENCURLY, "{ expected" );
if( ! parse_declns( dp ) ) return FALSE; if( ! parse_declns( dp ) ) return false;
MUSTBE( tCLOSECURLY, "} expected" ); MUSTBE( tCLOSECURLY, "} expected" );
MUSTBE( tEOF, "Spurious characters found beyond EOF" ); MUSTBE( tEOF, "Spurious characters found beyond EOF" );
return TRUE; return true;
} }
/* chunk = tOPENCURLY list_of_lines tCLOSECURLY */ /* chunk = tOPENCURLY list_of_lines tCLOSECURLY */
static BOOL parse_chunk( char *s ) static bool parse_chunk( char *s )
{ {
char line[256]; char line[256];
int startlineno; int startlineno;
...@@ -117,20 +118,20 @@ static BOOL parse_chunk( char *s ) ...@@ -117,20 +118,20 @@ static BOOL parse_chunk( char *s )
fprintf( stderr, fprintf( stderr,
"Premature EOF after { - started at line %d\n", "Premature EOF after { - started at line %d\n",
startlineno ); startlineno );
return FALSE; return false;
} }
if( streq( line, "}" ) ) break; if( streq( line, "}" ) ) break;
strcat( s, line ); strcat( s, line );
strcat( s, "\n" ); strcat( s, "\n" );
} }
return TRUE; return true;
} }
/* declns = list*( decln ) */ /* declns = list*( decln ) */
/* NB: a decln starts with a tID */ /* NB: a decln starts with a tID */
static BOOL parse_declns( declnlist *dp ) static bool parse_declns( declnlist *dp )
{ {
char *name; char *name;
shapelist shapes; shapelist shapes;
...@@ -138,12 +139,12 @@ static BOOL parse_declns( declnlist *dp ) ...@@ -138,12 +139,12 @@ static BOOL parse_declns( declnlist *dp )
while( nexttok() == tID ) while( nexttok() == tID )
{ {
ungettok(); ungettok();
if( ! parse_decln( &name, &shapes ) ) return FALSE; if( ! parse_decln( &name, &shapes ) ) return false;
*dp = build_declnlist( name, shapes, (declnlist) NULL ); *dp = build_declnlist( name, shapes, (declnlist) NULL );
dp = &( (*dp)->next ); dp = &( (*dp)->next );
} }
ungettok(); ungettok();
return TRUE; return true;
} }
...@@ -155,44 +156,44 @@ static void error( char *s ) ...@@ -155,44 +156,44 @@ static void error( char *s )
/* decln = tID tEQ shapes tSEMI */ /* 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" ); MUSTBE( tID, "declaration expected" );
COPYOF( *name, lexidval ); COPYOF( *name, lexidval );
MUSTBE( tEQ, "'=' expected" ); MUSTBE( tEQ, "'=' expected" );
if( ! parse_shapes( shapes ) ) return FALSE; if( ! parse_shapes( shapes ) ) return false;
MUSTBE( tSEMI, "';' expected" ); MUSTBE( tSEMI, "';' expected" );
return TRUE; return true;
} }
/* shapes = sep-list+( shape, tOR ) */ /* shapes = sep-list+( shape, tOR ) */
static BOOL parse_shapes( shapelist *sp ) static bool parse_shapes( shapelist *sp )
{ {
char *tagname; char *tagname;
paramlist paras; paramlist paras;
printlist print; printlist print;
for(;;) { for(;;) {
if( ! parse_shape( &tagname, &paras, &print ) ) return FALSE; if( ! parse_shape( &tagname, &paras, &print ) ) return false;
*sp = build_shapelist( tagname, paras, *sp = build_shapelist( tagname, paras,
print, (shapelist) NULL ); print, (shapelist) NULL );
if( nexttok() != tOR ) break; if( nexttok() != tOR ) break;
sp = &( (*sp)->next ); sp = &( (*sp)->next );
} }
ungettok(); ungettok();
return TRUE;