Related articles |
---|
Looking for critique for a scripting language spec fei.liu@gmail.com (Fei Liu) (2008-02-01) |
From: | Fei Liu <fei.liu@gmail.com> |
Newsgroups: | comp.compilers |
Date: | Fri, 1 Feb 2008 10:09:30 -0800 (PST) |
Organization: | Compilers Central |
Keywords: | design, question |
Posted-Date: | 01 Feb 2008 20:50:24 EST |
Hello Group,
I am developing a simple scripting language (sql like) to be
embedded inside a tcp/ip server to experiment with an idea I had. To
allow a server to provide a simple interface to manipulate its data
through a terminal interface by a network client (like a database
server):
Following the post is the complete spec source code. If you want to
read the rational behind the design, it's all published here in a few
entries, the most relevant one is:
http://meditation-art.blogspot.com/2008/02/compilers-part-4-symbol-tables.html
I am asking for critique (what I did wrong, didn't do well) and
recommendation (how can I improve the spec) before I leave the spec as
it is and start working on streaming and IO part of my little project.
Thank you in advance,
Fei
[The first question has to be why did you invent another scripting language
rather than using python, tcl, rexx, lua, or any of the other well debugged
languages already available? -John]
#ifndef MAP_H
#define MAP_H
#include < string>
#include < iostream>
#include < map>
#include < boost/lambda/lambda.hpp>
typedef std::map< std::string, std::string> map_t;
// a value type that describe the value of a symbol table entry
// Essentially the symbol table entry data structure
struct value{
unsigned char type; // the first letter of corresponding union
type
union {
int ival;
float fval;
double dval;
char * sval;
map_t * mval;
} ivalue;
};
// The symbol table data structure
// Symbol table entry is keyed by the symbol string value
typedef std::map< std::string, value> symtab_t;
extern int yyerror(char *);
#endif
-------------------------------------------------------------------------
%{
#include "map.tab.h"
#include "map.h"
extern symtab_t symtab;
std::string line;
bool report_err;
int lineno;
int tokenpos;
%}
D [0-9]
N {D}+
L [a-zA-Z]
A [a-zA-Z0-9]
ID ({L}{A}*)
%%
select { tokenpos += yyleng; return SELECT; }
insert { tokenpos += yyleng; return INSERT; }
into { tokenpos += yyleng; return INTO; }
from { tokenpos += yyleng; return FROM; }
create { tokenpos += yyleng; return CREATE; }
table { tokenpos += yyleng; return TABLE; }
list { tokenpos += yyleng; return LIST; }
where { tokenpos += yyleng; return WHERE; }
key { tokenpos += yyleng; return KEY; }
value { tokenpos += yyleng; return VALUE; }
${ID} { tokenpos += yyleng; yylval.text = strdup(yytext+1);
return OBJECT; }
{ID} { tokenpos += yyleng; yylval.text = strdup(yytext); return
TEXT; }
[ \t] { tokenpos += yyleng; /* ignore white space */ }
. { tokenpos += yyleng; return yytext[0]; }
\n.* { report_err = true; tokenpos = 0; line = yytext+1;
yyless(1); lineno++; return '\n'; }
%%
int yyerror(char * s){
if(report_err){
std::cout << lineno << " : " << s << " at \n" << line << '\n';
printf("%*s\n", 1+tokenpos, "^");
}
}
-------------------------------------------------------------------------
%{
extern "C"{
#include < stdio.h>
#define YYDEBUG 1
}
extern int yyerror(char *);
extern int yylex();
#include "map.h"
symtab_t symtab;
bool where_by_key = false;
bool where_by_value = false;
std::string tablename;
std::string where;
%}
%union{
char * text;
}
%token < text> INSERT SELECT INTO TEXT OBJECT FROM CREATE TABLE LIST
%token < text> WHERE KEY VALUE
%%
statements: statements statement
| statement
;
statement: insert_stmt opt_semicolon '\n'
| select_stmt opt_semicolon '\n'
| create_stmt opt_semicolon '\n'
| assign_stmt opt_semicolon '\n'
| list_stmt opt_semicolon '\n'
| '\n'
| error '\n' { yyclearin; yyerrok; std::cout << "Enter another
command\n"; }
;
opt_semicolon:
| ';'
;
assign_stmt:
OBJECT '=' TEXT
{
// string variable assignment
symtab_t::iterator it = symtab.find($1);
if(it != symtab.end() && it->second.type == 's') //
Symbol found and type is correct
it->second.ivalue.sval = $3;
else{ // New symbol, add to symbol table
value v;
v.ivalue.sval = $3;
v.type = 's';
symtab[$1] = v;
}
}
;
create_stmt:
CREATE TABLE OBJECT
{
// Create a new dictionary
std::string symbol = $3;
symtab_t::iterator it = symtab.find(symbol);
if(it != symtab.end() && it->second.type == 'm'){ //
Symbol found and type is correct
std::cerr << "symbol: " << symbol << " already
exists\n";
}else{ // New symbol, create new map(table), add to
symbol table
value v;
v.ivalue.mval = new(map_t);
v.type = 'm';
symtab[symbol] = v;
}
}
;
insert_stmt:
INSERT INTO OBJECT '(' TEXT ',' TEXT ')'
{
// insert key, value pair into an existing dictionary
symtab_t::const_iterator it = symtab.find($3);
if(it != symtab.end() && it->second.type == 'm'){ //
Symbol found and type is correct
(*(it->second.ivalue.mval))[std::string($5)] =
std::string($7);
}else
std::cerr << "unknown symbol: " << $3 << " create
first\n";
}
;
select_stmt: simple_select_stmt
{
// go through all key, value pair of a dictionary
symtab_t::const_iterator it = symtab.find(tablename);
if(it != symtab.end() && it->second.type == 'm'){
map_t::const_iterator mit = it->second.ivalue.mval-
>begin();
for(; mit != it->second.ivalue.mval->end(); ++
mit)
std::cout << "key = " << mit->first << ' '
<< "value = " << mit->second << '\n';
}else
std::cerr << "invalid object\n";
}
| simple_select_stmt opt_where_stmt
{
// go through all key, value pair of a dictionary
// based on where criteria, search by key or value
symtab_t::const_iterator it = symtab.find(tablename);
if(it != symtab.end() && it->second.type == 'm'){
map_t::const_iterator mit = it->second.ivalue.mval-
>begin();
for(; mit != it->second.ivalue.mval->end(); ++
mit)
if( (where_by_key && mit->first == where) ||
(where_by_value && mit->second == where)
||
(!where_by_key && !where_by_value) )
std::cout << "key = " << mit->first << ' '
<< "value = " << mit->second << '\n';
}else
std::cerr << "invalid object\n";
where_by_key = where_by_value = false;
}
;
simple_select_stmt:
SELECT '*' FROM OBJECT { tablename = $4; }
;
opt_where_stmt: WHERE KEY '=' TEXT { where_by_key = true; where =
$4; }
| WHERE VALUE '=' TEXT { where_by_value = true; where =
$4; }
;
list_stmt:
LIST
{
// Dump the entire symbol table
// For dictionaries, dump all key, value pairs as well
//
// Iterate through the symbol table
symtab_t::const_iterator it = symtab.begin();
for(; it != symtab.end(); ++it){
std::cout << "symbol: " << it->first << ' ' << it-
>second.type << '\n';
switch(it->second.type){
case 's': std::cout << "value = " << it-
>second.ivalue.sval << '\n';
break;
case 'm': {
// iterate through the dictionary
map_t::const_iterator mit = it-
>second.ivalue.mval->begin();
for(; mit != it->second.ivalue.mval-
>end(); ++ mit)
std::cout << "key = " << mit-
>first << ' '
<< "value = " << mit->second
<< '\n';
}
break;
default:
std::cerr << "Unknown data type\n";
break;
}
}
}
;
%%
int main(){
extern int yydebug;
yydebug = 0;
yyparse();
}
-------------------------------------------------------------------------
A transcript of my parser in action:
./map
create table $sss;
list
symbol: sss m
insert into $sss (abc, efg)
list
symbol: sss m
key = abc value = efg
insret into $sss( ddd, hik)
4 : syntax error at
insret into $sss( ddd, hik)
^
insert into $sss (ddd, hik)
Enter another command
list
symbol: sss m
key = abc value = efg
key = ddd value = hik
select * from $sss;
key = abc value = efg
key = ddd value = hik
select * from $sss where key = ddd
key = ddd value = hik
./map
create table $sss;
list
symbol: sss m
insert into $sss (abc, efg)
list
symbol: sss m
key = abc value = efg
insret into $sss( ddd, hik)
4 : syntax error at
insret into $sss( ddd, hik)
^
insert into $sss (ddd, hik)
Enter another command
list
symbol: sss m
key = abc value = efg
key = ddd value = hik
select * from $sss;
key = abc value = efg
key = ddd value = hik
select * from $sss where key = ddd
key = ddd value = hik
Return to the
comp.compilers page.
Search the
comp.compilers archives again.