Here's CIDL ("sid-el"), a CORBA-like IDL for D-BUS..

David A. Wheeler dwheeler at dwheeler.com
Sat Feb 5 20:02:38 PST 2005


I've been fiddling around and have ended up with a simple
filter ("dbus-cidl") that accepts a CORBA-like IDL, and generates
the XML introspection format.  I've named its input format
"CIDL" ("CORBA-like IDL"), pronounced "sid--el". I'll claim that
CIDL is the "sample format" used in the current D-BUS spec, with some
extensions to handle more of the XML Introspection format.

This CIDL processor is implemented in flex/bison, and uses
glib for a library. It works as a simple filter.
For example, if you run:

echo "interface wokka { void x(in int a, out int b); attribute int px; }" |
  ./dbus-cidl

The output is:
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<interface name="wokka">
   <method name="x">
     <arg name="a" type="int" direction="in"/>
     <arg name="b" type="int" direction="out"/>
   </method>
   <property name="px" type="int" access="readwrite"/>
</interface>

Notice that it's easier to create and read the CIDL format.
You're certainly welcome to add this to the D-BUS distribution as a tool.

Here's a specification of the CIDL syntax:
specification = definition+
definition = interface_spec
interface_spec = [ "deprecated" ] "interface" IDENTIFIER "{"
                  ( op_dcl | attr_dcl | signal_dcl )* "}" ";"
attr_dcl = [ "read" | "write" ] ( "property" | "attribute" )
             param_type_spec IDENTIFIER ( "," IDENTIFIER )* ";"
op_dcl: [ "oneway" ] op_type_spec IDENTIFIER '(' parameter_list ')' ";"
parameter_list = [ param_dcl ["," param_dcl ]* ]?
param_dcl = [ "in" | "out" | "inout" ] param_type_spec IDENTIFIER
signal_dcl = "signal" IDENTIFIER "(" out_parameter_list ")" ";"
out_parameter_list = [ out_param_dcl ["," out_parameter_dcl ]* ]?
out_param_dcl:  param_type_spec IDENTIFIER
param_type_spec:  IDENTIFIER  // int32, string, etc.

The yacc & lex files, a stupid makefile sufficient just for it,
and test input & output are attached.

Thoughts??  Would this be worth including as a tool in the distribution?
I think this kind of tool _IS_ worth it; XML is easy to
process by computers, but is a pain for humans.. specialized
formats like this are easier to read & understand.
It's like CORBA, so programs using CORBA can use their IDL as
a starting point.. and programmers familiar with CORBA will
find it easier to use too.
But if nothing else, you can use it to check the statements
in the specification... and if it's useful enough to use IN the
specification, that suggests it might be useful for users too.

Note that this includes the "oneway" attribute, as I mentioned
in a previous email.

Note that this doesn't currently have a type definition system,
nor a way to define error replies.. those would be good to add.
More error-checking would be a very good idea.

--- David A. Wheeler
-------------- next part --------------
%{
#include <stdio.h>
#include <glib.h>
/* 
 * (C) 2005 David A. Wheeler
 * Released under the GNU GPL (version 2 or greater) and AFL (1.1 or greater).
 * Implements an IDL as close to CORBA as plausible for D-BUS.
 *
 * specification = definition+
 * definition = interface_spec
 * interface_spec = [ "deprecated" ] "interface" IDENTIFIER "{"
 *                  ( op_dcl | attr_dcl | signal_dcl )* "}" ";"
 * attr_dcl = [ "read" | "write" ] ( "property" | "attribute" )
 *             param_type_spec IDENTIFIER ( "," IDENTIFIER )* ";"
 * op_dcl: [ "oneway" ] op_type_spec IDENTIFIER '(' parameter_list ')' ";"
 * parameter_list = [ param_dcl ["," param_dcl ]* ]?
 * param_dcl = [ "in" | "out" | "inout" ] param_type_spec IDENTIFIER
 * signal_dcl = "signal" IDENTIFIER "(" out_parameter_list ")" ";"
 * out_parameter_list = [ out_param_dcl ["," out_parameter_dcl ]* ]?
 * out_param_dcl:  param_type_spec IDENTIFIER
 * param_type_spec:  IDENTIFIER  // int32, string, etc.
 * 
 * NOTE: "oneway" is an addition; it sets oneway="yes" in the method.
 */

#include <stdio.h>
#include <string.h>

void process(char *s);
void yyerror(char *s);
void pindent(void);
void pproperties (gpointer data, gpointer user_data);
void free_string_list(GList *list_to_dealloc);
extern int linenum;

int indent = 0;
int yydebug=1;

const char xmlheader[] = "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n";

%}

%union {
    char *str;
    char *str_nofree; /* Do not free() this string. */
    GList *list_str; /* list of strings */
}


/* Free: */
%token <str> IDENTIFIER

/* Do not free: */
%token <str_nofree> IN OUT INOUT

%token INTERFACE
%token ONEWAY DEPRECATED
/* VOID itself doesn't produce something that needs freeing */
%token VOID
%token READONLY WRITEONLY ATTRIBUTE
%token SIGNAL

/* Free these (typically because they pass up IDENTIFIERs): */
%type <str> param_type_spec op_type_spec

/* Don't free these; these just pass up ptrs to constants */
%type <str_nofree> readwrite param_attribute is_deprecated op_attribute

%type <list_str> attr_list

%start specification

%%


param_type_spec: IDENTIFIER { $$ = $1; /* The default action. NOT VOID. */ }
                 ;

param_attribute: /* empty = IN */  { $$ = "i"; }
                 | IN              { $$ = "i"; }
                 | OUT             { $$ = "o"; }
                 | INOUT           { $$ = "b"; /* both in and out */ }
                 ;

param_dcl:  param_attribute param_type_spec
            IDENTIFIER             { /* FIXME: identifier is too broad */
                                     if (*($1) != 'o') {
                                        pindent();
                                        printf("<arg name=\"%s\" type=\"%s\" direction=\"in\"/>\n", $3, $2);
                                     }
                                     if (*($1) != 'i') {
                                        pindent();
                                        printf("<arg name=\"%s\" type=\"%s\" direction=\"out\"/>\n", $3, $2);
                                     }
                                     free($2);
                                     free($3);
                                   }
            ;

parameter_list_nonempty:  param_dcl
                          | parameter_list_nonempty ',' param_dcl ;

parameter_list:  /* empty */
                 | parameter_list_nonempty ;

op_attribute: /* empty */             { $$ = ""; }
              | ONEWAY                { $$ = " oneway=\"yes\""; }
              ;

op_type_spec: param_type_spec         { $$ = $1; }
              | VOID                  { $$ = strdup("void"); }
              ;

op_dcl: op_attribute op_type_spec IDENTIFIER '('
                                     {
                                        pindent();
                                        printf("<method name=\"%s\"%s>\n", $3, $1);
                                        indent++;
                                        if (strcmp($2,"void")) {
                                          /* FIXME: complain if oneway. */
                                          pindent();
                                          printf("<arg name=\"return\" type=\"%s\" direction=\"out\"/>\n", $2);
                                        }
                                     }
        parameter_list ')'
        /* raises_context_expr */
                                     {
                                        indent--;
                                        pindent();
                                        printf("</method>\n");
                                        free($2);
                                        free($3);
                                     }
        ;

attr_list: IDENTIFIER             { $$ = g_list_append( (GList *) NULL, $1); }
           | attr_list "," IDENTIFIER
                                  { $$ = g_list_append( $1, $3); }
           ;


readwrite: /* empty */            { $$ = "readwrite"; }
           | READONLY             { $$ = "read"; }
           | WRITEONLY            { $$ = "write";  /* CORBA lacks "writeonly". */}
           ;
attr_dcl: readwrite ATTRIBUTE param_type_spec
          attr_list /* attr_raises_expr */
                                     { GList *attribute_info;
                                       attribute_info = g_list_append(NULL, $1);
                                       attribute_info = g_list_append(attribute_info, $3);
                                       g_list_foreach($4, pproperties, attribute_info);
                                       free_string_list($4);
                                       g_list_free(attribute_info);
                                       /* frees g_list_last(attribute_info): */
                                       free($3);
                                     }
          ;


out_param_dcl:  param_type_spec IDENTIFIER
                                    { /* FIXME: identifier is too broad */
                                     pindent();
                                     printf("<arg name=\"%s\" type=\"%s\"/>\n", $2, $1);
                                     free($1);
                                     free($2);
                                   }
            ;

out_parameter_list_nonempty:  out_param_dcl
                          | out_parameter_list_nonempty ',' out_param_dcl ;

out_parameter_list:  /* empty */
                 | out_parameter_list_nonempty ;


signal_dcl: SIGNAL IDENTIFIER '('
                                     {
                                        pindent();
                                        printf("<signal name=\"%s\">\n", $2);
                                        indent++;
                                     }
        out_parameter_list ')'
        /* raises_context_expr */
                                     {
                                        indent--;
                                        pindent();
                                        printf("</signal>\n");
                                        free($2);
                                     }
        ;

export: op_dcl ';'
        | attr_dcl ';'
        | signal_dcl ';'
        ;

exports: /* empty */
         | exports export ;

interface_body: exports ;

is_deprecated: /* empty */   {$$ = "";}
               | DEPRECATED {$$ = " deprecated=\"yes\"";}
               ;

interface_spec: is_deprecated INTERFACE IDENTIFIER '{'
                          {
                            pindent();
                            printf("<interface name=\"%s\"%s>\n", $3, $1);
                            indent++;
                            free($3);
                          }
                interface_body '}'
                          {
                            indent--;
                            pindent();
                            printf("</interface>\n");
                          }
                ';'
                ;

definition: interface_spec /* | type_dcl | except_dcl | event */ ;

definitions: /* empty */
             | definitions definition ;

specification: { printf(xmlheader); } definitions ;

%%

void process(char *s) {
    fprintf(stdout, "%s\n", s);
}

void free_string_list(GList *list_to_dealloc) {
    /* FIXME: Deallocate. */
}

void yyerror(char *s) {
    fprintf(stdout, "-:%d: %s\n", linenum, s);
}

int main(void) {
    yyparse();
    return 0;
}

void pindent(void) {
    /* print an indent, using the 'indent' value. */
    int i;
    int realindent = indent * 2; /* # spaces per indent level */
    for (i = 0; i < realindent; i++) putchar(' ');
};

void pproperties (gpointer data, gpointer property_data) {
    pindent();
    printf("<property name=\"%s\" type=\"%s\" access=\"%s\"/>\n",
           data, g_list_last(property_data)->data,
           g_list_first(property_data)->data);
}

#ifdef UNUSED

#endif
-------------- next part --------------
%{
/* DBUS-CIDL lexer by David A. Wheeler.
   Released under the same terms as D-BUS;
   AFL 1.1 or later *OR* GNU GPL version 2 or later
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "y.tab.h"
extern void yyerror(char *message);
int linenum = 1;
%}

%x COMMENT

string          \"([^"]|\"\")*\"

element        [A-Za-z][A-Za-z0-9_]*
identifier     {element}[\.{element}]*

%%

"interface"      return INTERFACE;
"oneway"         return ONEWAY;
"void"           return VOID;
"deprecated"     return DEPRECATED;
"in"             return IN;
"In"             return IN;
"IN"             return IN;
"out"            return OUT;
"Out"            return OUT;
"OUT"            return OUT;
"inout"          return INOUT;
"Inout"          return INOUT;
"INOUT"          return INOUT;

"readonly"       return READONLY;
"writeonly"      return WRITEONLY;
"attribute"      return ATTRIBUTE; /* "attribute" used in CORBA */
"property"       return ATTRIBUTE; /* "property" used in D-BUS docs */

"signal"         return SIGNAL; /* "Signal" is what D-BUS uses */
"emits"          return SIGNAL; /* CORBA (though syntax different) */

{identifier}     yylval.str = (char *) strndup(yytext, yyleng); return IDENTIFIER; /* free this! */

[{};(),]	 return *yytext; /* Return the character */

[ \t]+           ;       /* ignore whitespace */
\/\/.*           ;       /* C++ style comment */
\/\*             { BEGIN COMMENT; /* C-style comment */ }
\n               linenum++;

.                yyerror("Unexpected character");

<COMMENT>\*\/    BEGIN 0;
<COMMENT>\n      linenum++;
<COMMENT>[^\*\n]* ;
<COMMENT>\*      ;

%%
int yywrap(void) {
    return 1;  /* Halt processing at end of text */
}


-------------- next part --------------

BISONFLAGS=
# For debugging:
# BISONFLAGS=--debug --verbose

test: dbus-cidl
	echo "interface wokka { void x(in int a, out int b); attribute int px; } ;"  | ./dbus-cidl
	echo
	./dbus-cidl < test.cidl
#	echo "interface wokka BAD { } ;"  | ./dbus-cidl

dbus-cidl: dbus-cidl.y dbus-cidl.l
	bison -y -v -d ${BISONFLAGS} dbus-cidl.y
	flex dbus-cidl.l
	gcc `pkg-config --cflags glib-2.0` -c y.tab.c lex.yy.c
	gcc y.tab.o lex.yy.o -o dbus-cidl `pkg-config --libs glib-2.0`

-------------- next part --------------
// This tests the CIDL processor
/* This is a comment.
 *
 */
interface wokka {
  void x(in int32 a, out int32 b);
  string demo9(in int32 a, inout int32 b, uint32 c);
  oneway void yell_loud();
  string zero_param();
  string one_param(int16 z);
  attribute int px;
  readonly  attribute int py;
  writeonly attribute int pz;
  signal i_woke_up();
  signal died (string error);
  signal died2(string error, int32 count);
};

deprecated interface wokka2 {
  int z();
};
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test.xml
Type: text/xml
Size: 1404 bytes
Desc: not available
Url : http://lists.freedesktop.org/archives/dbus/attachments/20050205/7a806d62/test-0001.bin


More information about the dbus mailing list