Browse Source

Grammatical parser

test
Michael Uleysky 9 years ago
parent
commit
e29b8cc085
  1. 28
      src/Makefile
  2. 2
      src/debug.h
  3. 24
      src/globals.cpp
  4. 22
      src/globals.h
  5. 11
      src/init.cpp
  6. 4
      src/init.h
  7. 7
      src/main.cpp
  8. 6
      src/object.cpp
  9. 227
      src/object.h
  10. 107
      src/parser/grammatical.y
  11. 56
      src/parser/lexical.l
  12. 2
      src/parser/parser.h
  13. 19
      src/parser/yyloc.h

28
src/Makefile

@ -1,21 +1,33 @@
CFLAGS=-O2 -g
OBJECTS=main.o debug.o init.o parser/lexical.o
CFLAGS=-O2 -g -std=gnu++11
LDFLAGS=
CC=g++
SOURCE = $(wildcard *.cpp) parser/lexical.cpp parser/grammatical.cpp
DEPENDS = $(subst .cpp,.d,$(SOURCE))
OBJECTS = $(subst .cpp,.o,$(SOURCE))
makemap: $(OBJECTS)
g++ $(CFLAGS) -o $@ $(OBJECTS)
$(CC) $(LDFLAGS) -o $@ $(OBJECTS)
include $(DEPENDS)
%.o: %.cpp
$(CC) -c $(CFLAGS) -o $@ $<
main.o: debug.h init.h
init.o: parser/lexical.h parser/parser.h debug.h init.h
parser/lexical.o: parser/parser.h debug.h
%.d: %.cpp
$(CC) $(CFLAGS) -MM -MT $(subst .cpp,.o,$<) $< | sed 's%\(^.*\):%\1 $@ :%g' >$@
parser/grammatical.d: parser/lexical.h
parser/lexical.h parser/lexical.cpp: parser/lexical.l
cd parser && flex lexical.l
parser/grammatical.h parser/grammatical.cpp: parser/grammatical.y
cd parser && bison grammatical.y
clean:
rm -f *.o parser/*.o parser/lexical.{cpp,h}
rm -f *.o *.d parser/*.{o,d} parser/{lexical,grammatical}.{cpp,h}
distclean: clean
rm -f makemap

2
src/debug.h

@ -2,7 +2,7 @@
#define DEBUG_H
#include <iostream>
enum debug_level {INTERNALREQUEST,DEBUG,INFO,WARNING,ERROR};
enum debug_level {INTERNALREQUEST,MOREDEBUG,DEBUG,INFO,WARNING,ERROR};
std::ostream& COUT(debug_level dl);

24
src/globals.cpp

@ -0,0 +1,24 @@
#include "globals.h"
// Variables definitions
std::map<std::string,ObjectBase*> G_vars;
// Functions addresses
std::multimap<std::string,Func> G_funcs;
// List of objects to save
std::list<ObjectBase*> G_tosave;
// List of objects to print
std::list<ObjectBase*> G_toprint;
void ClearGlobals()
{
for(auto& it:G_vars) delete it.second;
for(auto& it:G_tosave) delete it;
for(auto& it:G_toprint) delete it;
G_vars.clear();
G_tosave.clear();
G_toprint.clear();
}

22
src/globals.h

@ -0,0 +1,22 @@
#ifndef GLOBALS_H
#define GLOBALS_H
#include <map>
#include <list>
#include <string>
#include "object.h"
// Variables definitions
extern std::map<std::string,ObjectBase*> G_vars;
// Functions addresses
typedef ObjectBase* (*Func)(ObjectList*);
extern std::multimap<std::string,Func> G_funcs;
// List of objects to save
extern std::list<ObjectBase*> G_tosave;
// List of objects to print
extern std::list<ObjectBase*> G_toprint;
void ClearGlobals();
#endif

11
src/init.cpp

@ -1,7 +1,10 @@
#include <inttypes.h>
#include "init.h"
#include "debug.h"
#include "parser/lexical.h"
#include "object.h"
#include "parser/parser.h"
#include "parser/grammatical.h"
#include "parser/lexical.h"
int ParseConfigFile(char* config)
{
@ -18,9 +21,13 @@ int ParseConfigFile(char* config)
extra.filename=config;
extra.inclevel=0;
extra.maxinclevel=10;
extra.curline=1;
extra.curpos=extra.curoffset=0;
conflex_init_extra(&extra,&scanner);
confset_in(conffd,scanner);
conflex(scanner);
// {YYSTYPE qqq; while(conflex(&qqq,scanner)>0);}
confparse(scanner);
conflex_destroy(scanner);
fclose(conffd);
return 0;
}

4
src/init.h

@ -1,5 +1,9 @@
#ifndef INIT_H
#define INIT_H
#ifndef YY_TYPEDEF_YY_SCANNER_T
#define YY_TYPEDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif
int ParseConfigFile(char* config);

7
src/main.cpp

@ -1,13 +1,18 @@
#include "debug.h"
#include "init.h"
#include "globals.h"
int main(int argc, char** argv)
{
if(argc!=2) return 1;
SetDebugLevel(DEBUG);
SetDebugLevel(INFO);
ParseConfigFile(argv[1]);
COUT(INFO)<<G_vars.size()<<std::endl;
for(auto& i: G_vars) COUT(INFO)<<i.first<<"="+i.second->Dump()<<";"<<std::endl;
ClearGlobals();
return 0;
}

6
src/object.cpp

@ -0,0 +1,6 @@
#include "object.h"
template<> std::string ObjectSimple<bool>::type="bool";
template<> std::string ObjectSimple<int64_t>::type="integer";
template<> std::string ObjectSimple<double>::type="real";
template<> std::string ObjectSimple<std::string>::type="string";

227
src/object.h

@ -0,0 +1,227 @@
#ifndef OBJECT_H
#define OBJECT_H
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>
#include <list>
#include <sstream>
#include <typeinfo>
#include <typeindex>
#include "debug.h"
// Check if pointer is ObjectBase derivative class
#define IS_OTYPE(quo,equ) (std::type_index(typeid(*quo))==std::type_index(typeid(equ)))
// Base class for all objects
class ObjectBase
{
protected:
// No save by default
virtual const int8_t* Blob(size_t* size) const { *size=0; return 0; }
virtual void DeallocBlob(const void* ptr) const {};
public:
ObjectBase() = default;
ObjectBase(const ObjectBase&) = delete;
virtual ~ObjectBase(){}
virtual std::string Type() const=0;
virtual bool Print() const=0;
bool Save(const char* fname) const
{
size_t size,offset=0,wr;
const int8_t* dptr;
FILE* fd;
int serrno;
fd=fopen(fname,"w");
serrno=errno;
if(0==fd)
{
COUT(ERROR)<<"Can't open file "<<fname<<" for writing: "<<strerror(serrno)<<std::endl;
return false;
}
dptr=Blob(&size);
if(0==dptr)
{
COUT(ERROR)<<"Can't get blob for writing to "<<fname<<std::endl;
fclose(fd);
return false;
}
while(offset!=size)
{
wr=fwrite(dptr+offset,1,size-offset,fd);
if(0==wr)
{
COUT(ERROR)<<"Failed to write in file "<<fname<<std::endl;
fclose(fd); DeallocBlob(dptr);
return false;
}
offset+=wr;
}
fclose(fd);
DeallocBlob(dptr);
return true;
}
virtual std::string Dump() const {return "%"+Type()+"%";}
};
// Template for objects without specific constructor/destructor
template<class T>
class ObjectSimple: public ObjectBase
{
private:
T val;
static std::string type;
const int8_t* Blob(size_t* size) const override
{
*size=sizeof(T);
return reinterpret_cast<const int8_t*>(&val);
}
public:
ObjectSimple(T t):val(t) {}
ObjectSimple(const T* t):val(*t) {}
~ObjectSimple() {}
bool Print() const override
{
COUT(INFO)<<"Object type: "<<Type()<<"."<<std::endl;
COUT(INFO)<<"Value: "<<val<<std::endl;
return true;
}
std::string Type() const override {return type;}
T Value() const {return val;}
void SetValue(T s) {val=s;}
std::string Dump() const override
{
std::stringstream s;
if(std::type_index(typeid(T))==std::type_index(typeid(std::string)))
s<<"\""<<val<<"\"";
else
s<<val;
return s.str();
}
};
// Simple objects
typedef ObjectSimple<bool> ObjectBool;
typedef ObjectSimple<int64_t> ObjectInt;
typedef ObjectSimple<double> ObjectReal;
typedef ObjectSimple<std::string> ObjectString;
template<>
inline const int8_t* ObjectSimple<std::string>::Blob(size_t* size) const
{
*size=val.length();
return reinterpret_cast<const int8_t*>(val.c_str());
}
// Class for name-value pair
class ObjectPair: public ObjectBase
{
private:
std::string name;
ObjectBase* val;
public:
ObjectPair():val(0) {}
ObjectPair(const std::string& n, ObjectBase* v):name(n),val(v) {}
ObjectPair(const std::string* n, ObjectBase* v):name(*n),val(v) {}
~ObjectPair()
{
if(val!=0) delete val;
val=0;
}
bool Exist() const {return 0==val;}
bool Print() const override
{
if(!Exist()) return false;
COUT(INFO)<<"Object type: "<<Type()<<"."<<std::endl;
COUT(INFO)<<"Name: "<<Name()<<std::endl;
COUT(INFO)<<"Value type: "<<val->Type()<<std::endl;
return true;
}
std::string Type() const override {return "pair";}
std::string Name() const {return name;}
const ObjectBase* Value() const {return val;}
void SetPair(const std::string& n, ObjectBase* v) {if(!Exist()) {name=n; val=v;}}
std::string Dump() const override { return Name()+"="+val->Dump(); }
};
// Class for objects list
class ObjectList: public ObjectBase
{
private:
std::list<ObjectBase*> vals;
public:
ObjectList() {}
ObjectList(ObjectBase* o) {PushBack(o);}
~ObjectList()
{
for(auto& i: vals) delete i;
vals.clear();
}
bool Exist() const {return 0==vals.size();}
bool Print() const override
{
if(!Exist()) return false;
COUT(INFO)<<"Object type: "<<Type()<<"."<<std::endl;
COUT(INFO)<<"Number of elements: "<<Size()<<std::endl;
return true;
}
std::list<ObjectBase*>::size_type Size() const {return vals.size();}
std::string Type() const override {return "list";}
ObjectList* PushFront(ObjectBase* p) {vals.push_front(p); return this;}
ObjectList* PushBack(ObjectBase* p) {vals.push_back(p); return this;}
std::string Dump() const override
{
std::string s("(");
for(auto& i: vals) s+=i->Dump()+", ";
if(vals.size()!=0) s.resize(s.length()-2);
return s+")";
}
};
// Class for storing identifiers
class OId: public ObjectBase
{
std::string name;
public:
OId(const std::string* t):name(*t) {}
~OId() {}
bool Print() const override {return false;}
std::string Type() const override {return "IDENT";}
std::string Name() const {return name;}
void SetName(std::string s) {name=s;}
std::string Dump() const override {return Name();};
};
// Class for storing functions
class OFunc: public ObjectBase
{
std::string name;
ObjectList* args;
public:
OFunc(const std::string* t, ObjectBase* p):name(*t)
{
if(IS_OTYPE(p,ObjectList)) args=dynamic_cast<ObjectList*>(p);
else args=new ObjectList(p);
}
OFunc(const char* t, ObjectBase* p):name(t)
{
if(IS_OTYPE(p,ObjectList)) args=dynamic_cast<ObjectList*>(p);
else args=new ObjectList(p);
}
~OFunc() {if(args!=0) delete args;}
bool Print() const override {return false;}
std::string Type() const override {return "FUNC";}
std::string Name() const {return name;}
void SetName(std::string s) {name=s;}
std::string Dump() const override {return Name()+args->Dump();};
};
#endif

107
src/parser/grammatical.y

@ -0,0 +1,107 @@
%name-prefix "conf"
%language "c"
%output "grammatical.cpp"
%defines "grammatical.h"
%param {yyscan_t scanner}
%define api.pure full
%define parse.lac full
%locations
//%no-lines
%{
#include <inttypes.h>
#include <algorithm>
#include "parser.h"
#include "../debug.h"
#include "../object.h"
#include "../globals.h"
#ifndef YY_TYPEDEF_YY_SCANNER_T
#define YY_TYPEDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif
#include "yyloc.h"
#include "grammatical.h"
inline void conferror(YYLTYPE *locp, yyscan_t sc, const char * str)
{
COUT(ERROR)<<str<<std::endl;
}
#include "lexical.h"
%}
%union
{
bool b;
int64_t i;
double r;
std::string* str;
ObjectBase* ob;
}
%token ASSIGN OBRACE CBRACE ENDL
%token <r> REAL
%token <b> BOOL
%token <i> INTEGER
%token <str> NAME
%token <str> IDENTIFIER
%token <str> STRING
%left '-' '+'
%left '*' '/'
%precedence UNARY /* negation--unary minus */
%right '^' /* exponentiation */
%type <ob> expression
%type <ob> call
%type <ob> object
%type <ob> pair
%type <ob> list
%%
input:
%empty {COUT(DEBUG)<<"Empty input\n";}
| input line {COUT(DEBUG)<<" input line\n";}
;
line:
NAME ASSIGN object ENDL {COUT(DEBUG)<<" NAME ASSIGN object ENDL\n"; if(G_vars.count(*$1)!=0) delete G_vars[*$1]; G_vars[*$1]=$3; delete $1;}
| NAME ASSIGN list ENDL {COUT(DEBUG)<<" NAME ASSIGN list ENDL\n"; if(G_vars.count(*$1)!=0) delete G_vars[*$1]; G_vars[*$1]=$3; delete $1;}
| NAME OBRACE list CBRACE ENDL {COUT(DEBUG)<<" NAME OBRACE list CBRACE ENDL\n"; transform($1->begin(),$1->end(),$1->begin(),::tolower); if(*$1=="save") G_tosave.push_back($3); if(*$1=="print") G_toprint.push_back($3); delete $1;}
| NAME OBRACE object CBRACE ENDL {COUT(DEBUG)<<" NAME OBRACE object CBRACE ENDL\n"; transform($1->begin(),$1->end(),$1->begin(),::tolower); if(*$1=="save") G_tosave.push_back($3); if(*$1=="print") G_toprint.push_back($3); delete $1;}
;
list:
object object {COUT(DEBUG)<<" object object\n"; $$=(new ObjectList($1))->PushBack($2);}
| list object {COUT(DEBUG)<<" list object\n"; dynamic_cast<ObjectList*>($1)->PushBack($2); $$=$1;}
;
pair:
IDENTIFIER ASSIGN object {COUT(DEBUG)<<" IDENTIFIER ASSIGN object\n"; $$=new ObjectPair($1,$3);}
;
object:
STRING {COUT(DEBUG)<<" STRING\n"; $$=new ObjectString($1);}
| BOOL {COUT(DEBUG)<<" BOOL\n"; $$=new ObjectBool($1);}
| OBRACE list CBRACE {COUT(DEBUG)<<" OBRACE list CBRACE\n"; $$=$2;}
| expression {COUT(DEBUG)<<" expression\n"; $$=$1;}
| pair {COUT(DEBUG)<<" pair\n"; $$=$1;}
| OBRACE object CBRACE {COUT(DEBUG)<<" OBRACE object CBRACE\n"; $$=$2;}
;
call:
IDENTIFIER OBRACE object CBRACE {COUT(DEBUG)<<" IDENTIFIER OBRACE object CBRACE\n"; $$=new OFunc($1,$3); delete $1;}
| IDENTIFIER OBRACE list CBRACE {COUT(DEBUG)<<" IDENTIFIER OBRACE list CBRACE\n"; $$=new OFunc($1,$3); delete $1;}
expression:
IDENTIFIER {COUT(DEBUG)<<" IDENTIFIER\n"; $$=new OId($1); delete $1;}
| REAL {COUT(DEBUG)<<" REAL\n"; $$=new ObjectReal($1);}
| INTEGER {COUT(DEBUG)<<" INTEGER\n"; $$=new ObjectInt($1);}
| expression '-' expression {COUT(DEBUG)<<" -\n"; $$=new OFunc("SUB",(new ObjectList($1))->PushBack($3));}
| expression '+' expression {COUT(DEBUG)<<" +\n"; $$=new OFunc("ADD",(new ObjectList($1))->PushBack($3));}
| expression '/' expression {COUT(DEBUG)<<" /\n"; $$=new OFunc("DIV",(new ObjectList($1))->PushBack($3));}
| expression '*' expression {COUT(DEBUG)<<" *\n"; $$=new OFunc("MUL",(new ObjectList($1))->PushBack($3));}
| expression '^' expression {COUT(DEBUG)<<" ^\n"; $$=new OFunc("POW",(new ObjectList($1))->PushBack($3));}
| '-' expression %prec UNARY {COUT(DEBUG)<<" unary -\n"; $$=new OFunc("NEG",$2);}
| '+' expression %prec UNARY {COUT(DEBUG)<<" unary +\n"; $$=new OFunc("POS",$2);}
| OBRACE expression CBRACE {COUT(DEBUG)<<" OBRACE expression CBRACE\n"; $$=$2;}
| call {COUT(DEBUG)<<" call\n"; $$=$1;}
;

56
src/parser/lexical.l

@ -6,26 +6,36 @@
%option header-file="lexical.h"
%option outfile="lexical.cpp"
%option prefix="conf"
%option extra-type="const struct lexical_extra*"
%x STRING
%option extra-type="struct lexical_extra*"
%option bison-bridge
%option bison-locations
%x PSTRING
%x PARSE
%{
#if __cplusplus > 199711L
#define register // Deprecated in C++11.
#endif // #if __cplusplus > 199711L
#include <stdlib.h>
#include <string>
#include "../debug.h"
#include "../object.h"
#include "parser.h"
int nc;
#include "grammatical.h"
static std::string str;
%}
%%
include\(\".+\"\); {
<PARSE,INITIAL,PSTRING>\n yyextra->curline++; yyextra->curpos=0; yyextra->curoffset++; REJECT;
<PARSE,INITIAL,PSTRING>. yyextra->curpos++; yyextra->curoffset++; REJECT;
include\(\".+\"\); {/*
if(yyextra->inclevel>=yyextra->maxinclevel) { COUT(ERROR)<<"Max include level reached in file "<<yyextra->filename<<" at line "<<yylineno<<std::endl; return 1; }
yyscan_t scanner;
struct lexical_extra extra;
std::string fname(yytext+9,yyleng-12);
FILE* fd;
fd=fopen(fname.c_str(),"r");
if(fd==0) { COUT(ERROR)<<"Can't open file "<<fname<<std::endl; return 1; }
if(fd==0) { COUT(ERROR)<<"Can't open file "<<fname<<std::endl; return -1; }
COUT(DEBUG)<<"Include "<<fname<<std::endl;
extra.filename=fname.c_str();
extra.inclevel=yyextra->inclevel+1;
@ -36,23 +46,25 @@ include\(\".+\"\); {
yylex_destroy(scanner);
fclose(fd);
}
[a-zA-Z][a-zA-Z0-9_]* printf("NAME\n"); BEGIN(PARSE);
<PARSE>[+-]?[0-9]+ printf("INTEGER\n");
<PARSE>[+-]?[0-9]+(\.[0-9]*)?([eE][+-][0-9]+)? printf("REAL\n");
<PARSE>\( printf("OBRACE\n");
<PARSE>\) printf("CBRACE\n");
<PARSE>\; printf("ENDL\n"); BEGIN(0);
<PARSE>= printf("ASSIGN\n");
<PARSE>[a-zA-Z][a-zA-Z0-9_]* printf("IDENTIFIER\n");
*/}
[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<"NAME("<<yytext<<")"; BEGIN(PARSE); yylval_param->str=new std::string(yytext); return NAME;
<PARSE>[+\-*/^] COUT(MOREDEBUG)<<" OPERATION("<<yytext<<")"; return yytext[0];
<PARSE>[0-9]+ COUT(MOREDEBUG)<<" INTEGER("<<yytext<<")"; yylval_param->i=atoll(yytext); return INTEGER;
<PARSE>[0-9]+(\.[0-9]*)?([eE][+-][0-9]+)? COUT(MOREDEBUG)<<" REAL("<<yytext<<")"; yylval_param->r=atof(yytext); return REAL;
<PARSE>[TF] COUT(MOREDEBUG)<<" BOOL("<<yytext<<")"; yylval_param->b=(yytext[0]=='T')?true:false; return BOOL;
<PARSE>\( COUT(MOREDEBUG)<<" OBRACE()"; return OBRACE;
<PARSE>\) COUT(MOREDEBUG)<<" CBRACE()"; return CBRACE;
<PARSE>\; COUT(MOREDEBUG)<<" ENDL()"<<std::endl; BEGIN(0); return ENDL;
<PARSE>= COUT(MOREDEBUG)<<" ASSIGN()"; return ASSIGN;
<PARSE>([a-zA-Z][a-zA-Z0-9_]*\.)*[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<" IDENTIFIER("<<yytext<<")"; yylval_param->str=new std::string(yytext); return IDENTIFIER;
<PARSE,INITIAL>[ ,\n\t]
<PARSE,INITIAL>\#.*
<PARSE>\" BEGIN(STRING); nc=0;
<PARSE,INITIAL>. COUT(ERROR)<<"Unknown symbol "<<yytext<<" in file "<<yyextra->filename<<" at line "<<yylineno<<std::endl;
<STRING>\\\\ nc++;
<STRING>\\\" nc++;
<STRING>\" BEGIN(PARSE); printf("STRING%d\n",nc);
<STRING>. nc++;
<STRING><<EOF>> COUT(ERROR)<<"Unclosed quote!"<<std::endl; yyterminate();
<<EOF>> yyterminate();
<PARSE>\" BEGIN(PSTRING); str.erase();
<PARSE,INITIAL>. COUT(ERROR)<<"Unknown symbol "<<yytext<<" in file "<<yyextra->filename<<" at line "<<yylineno<<std::endl; yyterminate(); return -1;
<PSTRING>\\\\ str+='\\';
<PSTRING>\\\" str+='\"';
<PSTRING>\" BEGIN(PARSE); COUT(MOREDEBUG)<<" STRING("<<str<<")"; yylval_param->str=&str; return STRING;
<PSTRING>. str+=yytext[0];
<PSTRING><<EOF>> COUT(ERROR)<<"Unclosed quote!"<<std::endl; str.erase(); yyterminate(); return -1;
<<EOF>> str.erase(); yyterminate(); return 0;
%%

2
src/parser/parser.h

@ -5,5 +5,7 @@ struct lexical_extra
{
const char* filename;
unsigned int inclevel,maxinclevel;
unsigned int curline,curpos,curoffset;
};
#endif

19
src/parser/yyloc.h

@ -0,0 +1,19 @@
#ifndef PARSER_YYLOC_H
#define PARSER_YYLOC_H
#include <string.h>
#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
typedef struct YYLTYPE
{
int first_line;
int first_column;
int last_line;
int last_column;
std::string filename;
std::string token_type;
std::string token_value;
} YYLTYPE;
#define YYLTYPE_IS_DECLARED 1
#endif
#endif
Loading…
Cancel
Save