root/trunk/whisperlib/net/rpc/parser/rpc-parser.yy

Revision 7, 18.6 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1
2    /**********************************************************************/
3    /**********************************************************************/
4    /*                           DEFINITIONS                              */
5    /**********************************************************************/
6    /**********************************************************************/
7
8 %{
9 #define RPC_PARSER_YY_INCLUDED
10
11 #include <string>
12 #include <vector>
13 #include <list>
14 #include <iostream>
15 #include <stdarg.h>
16 #include "net/rpc/parser/rpc-parser.h"
17 #include "net/rpc/parser/rpc-ptypes.h"
18 #include "net/rpc/parser/export/rpc-base-types.h"
19 #include "common/base/log.h"
20 %}
21
22 %option noyywrap
23 %option yylineno
24 %option yyclass="rpc::Parser"
25
26  // The same definition order must be used in function StateName(..)
27 %x S_COMMENT
28 %x S_SERVICE_HEAD
29 %x S_SERVICE_BODY
30 %x S_FUNCTION_RETURN
31 %x S_FUNCTION_NAME
32 %x S_FUNCTION_PARAM_TYPE
33 %x S_FUNCTION_PARAM_NAME
34 %x S_CUSTOMTYPE_HEAD
35 %x S_CUSTOMTYPE_BODY
36 %x S_CUSTOMTYPE_ATTR
37 %x S_CUSTOMTYPE_ATTR_CODE
38 %x S_TYPE
39 %x S_VERBATIM_HEAD
40 %x S_VERBATIM_BODY
41
42  // ! All C/C++ code must be indented by at least 1 space
43  // or enclosed between %{}
44 %{
45
46 // Another name for start condition INITIAL
47 #define S_INITIAL 0 // INITIAL == 0
48
49 // Returns: name of the given start condition.
50 const char * StateName(int sc);
51
52 // Change start condition. This macro does not alter execution (like REJECT does).
53 // Current state is lost; the lexer goes in the newState state.
54 #define ChangeState(newState) {\
55   PRINT_INFO << "StateChange: " << StateName(YY_START) << " -> " << StateName(newState) << " at line " << lineno() << PRINT_END;\
56   BEGIN(newState);\
57 }
58
59 // Change start condition. This macro does not alter execution (like REJECT does).
60 // Current state is saved; the lexer goes to newState state; the old state can be restored with PopState.
61 #define PushState(newState) {\
62   PRINT_INFO << "StateChange: " << StateName(YY_START) << " -> " << StateName(newState) << " at line " << lineno() << PRINT_END;\
63   yy_push_state(newState); /* save current state and BEGIN(newState) */\
64 }
65
66 // Change back start condition to the one before the last PushState call.
67 #define PopState() {\
68   int old_sc = YY_START;\
69   yy_pop_state(); /* restore last saved state */\
70   int new_sc = YY_START;\
71   PRINT_INFO << "StateChange: " << StateName(old_sc) << " -> " << StateName(new_sc) << " at line " << lineno() << PRINT_END;\
72 }
73
74 #define SET_CRT_LOCATION(pfileinfo) { pfileinfo.filename_ = strFilename_; pfileinfo.lineno_ = lineno(); }
75
76 // parser log. This log uses lexer's current state information.
77 //
78 #define PRINT_ERROR   bErrorsFound_ = true; std::cerr << strFilename_ << ":" << lineno() << " error: "
79 #define PRINT_WARNING std::cerr << strFilename_ << ":" << lineno() << " warning: "
80 #define PRINT_INFO    if(!bPrintInfo_); else std::cout << strFilename_ << ":" << lineno() << " info: "
81 #define PRINT_END     std::endl;
82
83
84 %}
85
86 DIGIT    [0-9]
87 ALPHA    [a-zA-Z_]
88 NAME     [a-zA-Z_][a-zA-Z_0-9]*
89 INTEGER  {DIGIT}+
90 WS       [ \t]+
91 TOKEN    [^ \t\n]+
92
93  //SIMPLE_TYPENAME NAME
94  //ARRAY_TYPENAME  "array<"{NAME}">"
95  //MAP_TYPENAME    "map<"{NAME}
96
97  //TYPENAME  SIMPLE_TYPENAME | ARRAY_TYPENAME | MAP_TYPENAME
98
99     /********************************************************************/
100     /********************************************************************/
101 %%  /*                            RULES                                 */
102     /********************************************************************/
103     /********************************************************************/
104
105  // ! All C/C++ code must be indented by at least 1 space or enclosed between %{}
106  //   All code in this section is local to the yylex() routine and executed
107  //   every time yylex() is called.
108
109  PService crtService;           // the current service.
110  PFunction crtFunction;         // the current function.
111  PParam crtParam;               // the current function parameter.
112  PCustomType crtCustomType;     // the current custom type.
113  PAttribute crtAttribute;       // the current custom type's attribute.
114  bool crtAttributeRequirementSet = false; // true is "required" or "optional" was found. False otherwise.
115  PType crtType;                 // the current type.
116  PVerbatim crtVerbatim;         // current verbatim stuff
117  int verbatim_brackets = 0;
118
119  // the current subtype (of the current type). Points to a node under crtType tree.
120  // Used only by S_TYPE.
121  PType * pcrtSubtype = &crtType;
122
123  /*************************************/
124  /*          verbatim            */
125  /*************************************/
126 <S_VERBATIM_HEAD>{NAME} {
127   if (crtVerbatim.language_ != "") {
128     REJECT;
129   }
130   crtVerbatim.language_ = yytext;
131 }
132 <S_VERBATIM_HEAD>"{" {
133   PopState();
134   PushState(S_VERBATIM_BODY);
135   verbatim_brackets = 1;
136 }
137
138 <S_VERBATIM_BODY>"{" {
139   crtVerbatim.verbatim_ += "{";
140   verbatim_brackets++;
141 }
142 <S_VERBATIM_BODY>"}" {
143   verbatim_brackets--;
144   if ( verbatim_brackets <= 0 ) {
145     verbatim_.push_back(crtVerbatim);
146     crtVerbatim.Clear();
147     PopState();
148   } else {
149     crtVerbatim.verbatim_ += "}";
150   }
151 }
152 <S_VERBATIM_BODY>. {
153   crtVerbatim.verbatim_ += yytext;
154 }
155 <S_VERBATIM_BODY>{NAME} {
156   crtVerbatim.verbatim_ += yytext;
157 }
158
159
160 <*>"/""*"+             PushState(S_COMMENT); // save current state and BEGIN(S_COMMENT)
161 <S_COMMENT>[^*]*       /* eat anything that's not a '*' */
162 <S_COMMENT>"*"+[^/]    /* eat up '*'s not followed by '/'s */
163 <S_COMMENT>"*"+"/"     PopState(); // restore last saved state
164
165 <*>"//".*              { /* eat up one-line comments, without the \n terminator */
166   //yytext[yyleng-1]=0; // cut newline terminator
167   //PRINT_INFO << "one line comment, at line " << lieno() << ": \"" << yytext << "\"" << PRINT_END;
168 }
169
170 <*>{WS}                 /* eat up whitespace */
171
172 <*>"*/"                 PRINT_WARNING << "Bad Comment Terminator" << PRINT_END;
173
174
175  /*************************************/
176  /*             initial               */
177  /*************************************/
178 <INITIAL>"Service" {
179   crtService.Clear();
180   SET_CRT_LOCATION(crtService);
181   PushState(S_SERVICE_HEAD);
182 }
183 <INITIAL>"Type" {
184   crtCustomType.Clear();
185   SET_CRT_LOCATION(crtCustomType);
186   PushState(S_CUSTOMTYPE_HEAD);
187 }
188 <INITIAL>"Verbatim" {
189   crtVerbatim.Clear();
190   SET_CRT_LOCATION(crtVerbatim);
191   PushState(S_VERBATIM_HEAD);
192 }
193
194  /*************************************/
195  /*          serviceheader            */
196  /*************************************/
197 <S_SERVICE_HEAD>{NAME} {
198   if(crtService.name_ != "")
199   {
200     REJECT; // bad token after service name
201   }
202   crtService.name_ = yytext;
203   PRINT_INFO << "Service: '" << crtService.name_ << "'" << PRINT_END;
204 }
205
206 <S_SERVICE_HEAD>"{" {
207   PopState();                // exit S_SERVICE state
208   PushState(S_SERVICE_BODY); // upon returning from S_SERVICE_BODY
209 }
210
211  /*************************************/
212  /*           servicebody             */
213  /*************************************/
214 <S_SERVICE_BODY>""/{NAME} {
215   // found a function return type
216   PushState(S_FUNCTION_RETURN); // enter S_FUNCTION_RETURN
217 }
218 <S_SERVICE_BODY>"}" {
219   services_.push_back(crtService);
220   crtService.Clear();
221   PopState(); // end of S_SERVICE_BODY
222 }
223
224
225  /*************************************/
226  /*              function             */
227  /*************************************/
228 <S_FUNCTION_RETURN>""/{NAME} {
229   CHECK(crtFunction.output_.name_.empty());
230   CHECK(crtType.name_.empty());
231
232   // this is function return type
233   PopState();                 // exit  S_FUNCTION_RETURN now
234   PushState(S_FUNCTION_NAME); // enter S_FUNCTION_NAME
235   PushState(S_TYPE);          // enter S_TYPE (it will return to S_FUNCTION_NAME)
236 }
237
238 <S_FUNCTION_NAME>{NAME} {
239   if(!crtType.name_.empty())
240   {
241     CHECK(crtFunction.output_.name_.empty());
242
243     crtFunction.output_ = crtType;
244     crtType.Clear();
245   }
246
247   if(crtFunction.name_.empty())
248   {
249     // this is function name
250     crtFunction.name_ = yytext;
251     SET_CRT_LOCATION(crtFunction);
252     PRINT_INFO << "Function: '" << crtFunction.name_ << "'" << PRINT_END;
253   }
254   else
255   {
256     PRINT_ERROR << "in function '" << crtFunction.name_ << "': unexpected identifier '" << yytext << "' after function name" << PRINT_END;
257   }
258 }
259
260 <S_FUNCTION_NAME>"(" {
261   if(!crtFunction.input_.empty())
262   {
263     // this function already has params. e.g. "void Foo (int) (float)"
264     PRINT_ERROR << "in function '" << crtFunction.name_ << "': unexpected '(' after parameters list" << PRINT_END;
265     yyterminate(); // fatal. Parsing these parameters would add up. Ignoring will screw up the following text.
266   }
267   PushState(S_FUNCTION_PARAM_TYPE);
268 }
269
270 <S_FUNCTION_NAME>";" {
271   PRINT_INFO << "Function '" << crtFunction.name_ << "' declaration end" << PRINT_END;
272   crtService.functions_.push_back(crtFunction);
273   crtFunction.Clear();
274
275   // function declaration ended
276   PopState();
277 }
278
279 <S_FUNCTION_PARAM_TYPE>""/{NAME} {
280   ChangeState(S_FUNCTION_PARAM_NAME); // return to S_FUNCTION_PARAM_NAME
281   PushState(S_TYPE);                  // after reading type
282 }
283 <S_FUNCTION_PARAM_TYPE>")" {
284   CHECK(crtType.name_.empty());
285   if(crtFunction.input_.empty())
286   {    // no parameter at all. This is legal: e.g. "void Foo()"
287   }
288   else // no type after comma. This is bad: e.g. "void Foo(int,)"
289   {
290     PRINT_ERROR << "in function '" << crtFunction.name_ << "': expected type before ')'" << PRINT_END;
291   }
292   PopState();
293 }
294 <S_FUNCTION_PARAM_TYPE>"," { // e.g. "void Foo(,int)"
295   PRINT_ERROR << "in function '" << crtFunction.name_ << "': expected type before ','" << PRINT_END;
296 }
297
298 <S_FUNCTION_PARAM_NAME>{NAME} {
299   CHECK(!crtType.name_.empty()); // you cannot reach S_FUNCTION_PARAM_NAME without reading a type first
300   if(!crtParam.name_.empty())
301   {
302     // e.g. "void Foo(int x y);" // the 'y' was matched here.
303     PRINT_ERROR << "multiple parameter names. First was '" << crtParam.name_ << "' and now '" << yytext << "'." << PRINT_END;
304     break;
305   }
306   crtParam.name_ = yytext;
307   PRINT_INFO << "Param name: " << crtParam.name_ << PRINT_END;
308 }
309
310 <S_FUNCTION_PARAM_NAME>"," |
311 <S_FUNCTION_PARAM_NAME>")" {
312   CHECK(!crtType.name_.empty());
313
314   crtParam.type_ = crtType;
315   crtType.Clear();
316
317   // if not specified, auto-generate parameter name
318   if(crtParam.name_.empty())
319   {
320     char szName[8] = {0,};
321 #if __WORDSIZE == 64
322     snprintf(szName, sizeof(szName), "arg%ld", crtFunction.input_.size());
323 #else
324     snprintf(szName, sizeof(szName), "arg%d", crtFunction.input_.size());
325 #endif
326     crtParam.name_ = szName;
327   }
328   PRINT_INFO << "Add function parameter: '" << crtParam.type_ << " " << crtParam.name_ << "' on current symbol: '" << yytext << "'" << PRINT_END;
329   crtFunction.input_.push_back(crtParam);
330   crtParam.Clear();
331
332   if(yytext[0] == ',')
333   {
334     ChangeState(S_FUNCTION_PARAM_TYPE); // type expected after ','
335   }
336   else // yytext[0] == ')'
337   {
338     PopState(); // parameters list ended
339   }
340 }
341
342  /*************************************/
343  /*         custom type name          */
344  /*************************************/
345 <S_CUSTOMTYPE_HEAD>{NAME} {
346   if(crtCustomType.name_.empty())
347   {
348     crtCustomType.name_ = yytext;
349     PRINT_INFO << "CustomType: " << crtCustomType.name_ << PRINT_END;
350   }
351   else
352   { // e.g. "Type Person XXX {' // 'XXX' is matched here
353     PRINT_ERROR << "unexpected identifier '" << yytext << "' after custom type name" << PRINT_END;
354   }
355 }
356
357 <S_CUSTOMTYPE_HEAD>"{" {
358   CHECK(crtCustomType.attributes_.empty());
359   PopState();                   // exit current state
360   PushState(S_CUSTOMTYPE_BODY); // on return from body
361 }
362
363  /*************************************/
364  /*         custom type body          */
365  /*************************************/
366 <S_CUSTOMTYPE_BODY>""/{NAME} {
367   crtAttribute.Clear();
368   crtAttributeRequirementSet = false;
369   SET_CRT_LOCATION(crtAttribute);
370   PushState(S_CUSTOMTYPE_ATTR); // a new attribute begins
371 }
372 <S_CUSTOMTYPE_BODY>"}" {
373   customTypes_.push_back(crtCustomType);
374   crtCustomType.Clear();
375   PopState();
376 }
377
378 <S_CUSTOMTYPE_ATTR>"optional" |
379 <S_CUSTOMTYPE_ATTR>"required" {
380   if(crtAttributeRequirementSet)
381   {
382     // e.g. "optional required int x;" // matches the "required" keyword
383     PRINT_ERROR << "duplicate required/optional keyword" << PRINT_END;
384     break;
385   }
386   crtAttribute.isOptional_ = (yytext[0] == 'o');
387   crtAttributeRequirementSet = true;
388 }
389 <S_CUSTOMTYPE_ATTR>""/{NAME} {
390   if(!crtType.name_.empty() || !crtAttribute.type_.name_.empty())
391   {
392     REJECT; // type already found
393   }
394   PushState(S_TYPE);
395 }
396 <S_CUSTOMTYPE_ATTR>{NAME} {
397   if(!crtType.name_.empty()) // copy crtType to crtAttribute
398   {
399     CHECK(crtAttribute.type_.name_.empty());
400     crtAttribute.type_ = crtType;
401     crtType.Clear();
402   }
403
404   if(crtAttribute.name_.empty())
405   {
406     crtAttribute.name_ = yytext;
407     PRINT_INFO << "Attribute name: " << crtAttribute.name_ << PRINT_END;
408   }
409   else
410   {
411     // e.g. "int x y = 7" // 'y' is matched here
412     PRINT_ERROR << "missing ';' after \"" << crtAttribute.name_ << "\"" << PRINT_END;
413     PRINT_ERROR << "unexpected identifier '" << yytext << "' after attribute name '" << crtAttribute.name_ << "'" << PRINT_END;
414   }
415 }
416 <S_CUSTOMTYPE_ATTR>";" {
417   bool bError = false;
418   if(!crtType.name_.empty()) // copy crtType to crtAttribute
419   {
420     CHECK(crtAttribute.type_.name_.empty());
421     crtAttribute.type_ = crtType;
422     crtType.Clear();
423   }
424   if(crtAttribute.type_.name_.empty())
425   {
426     PRINT_ERROR << "missing attribute type before ';'" << PRINT_END;
427     bError = true;
428   }
429   if(crtAttribute.name_.empty())
430   {
431     PRINT_ERROR << "missing attribute name before ';'" << PRINT_END;
432     bError = true;
433   }
434
435   if(!bError)
436   {
437     crtCustomType.attributes_.push_back(crtAttribute);
438   }
439
440   crtAttribute.Clear();
441   crtAttributeRequirementSet = false;
442   PopState();
443 }
444 <S_CUSTOMTYPE_ATTR>"}" {
445   if(!crtType.name_.empty()) // copy crtType to crtAttribute
446   {
447     CHECK(crtAttribute.type_.name_.empty());
448     crtAttribute.type_ = crtType;
449     crtType.Clear();
450   }
451   CHECK(!crtAttribute.type_.name_.empty()); // we are inside an attribute, so at least the typename should have been matched
452   if(crtAttribute.name_.empty())
453   {
454     PRINT_ERROR << "missing identifier after type \"" << crtAttribute.type_.name_ << "\"" << PRINT_END;
455   }
456   PRINT_ERROR << "missing ';'" << PRINT_END;
457
458   crtAttribute.Clear();
459   crtAttributeRequirementSet = false;
460   PopState(); // exit S_CUSTOMTYPE_ATTR to S_CUSTOMTYPE_BODY
461   crtCustomType.Clear();
462   PopState(); // exit S_CUSTOMTYPE_BODY to INITIAL
463 }
464
465  /*************************************/
466  /*               type                */
467  /*************************************/
468 <S_TYPE>{NAME} {
469   if(crtType.name_.empty())
470   {
471     pcrtSubtype = &crtType; // begin from top level
472   }
473   if(!pcrtSubtype->name_.empty())
474   {
475     PRINT_ERROR << "unexpected identifier '" << yytext << "' while waiting for terminator '>'" << PRINT_END;
476     yyterminate(); // fatal. Forgeting a '>' => the rest of the text is interpreted as type.
477   }
478   pcrtSubtype->name_ = yytext;
479   PRINT_INFO << "Simple type name: " << pcrtSubtype->name_ << PRINT_END;
480   PopState();
481 }
482 <S_TYPE>"array<" { // cannot use RPC_ARRAY instead of "array". Flex analyzer does not expand macros.
483   pcrtSubtype->name_ = RPC_ARRAY;
484   pcrtSubtype->subtype1_ = new PType();
485   pcrtSubtype->subtype1_->parent_ = pcrtSubtype;
486   pcrtSubtype = pcrtSubtype->subtype1_;
487   PushState(S_TYPE);
488 }
489 <S_TYPE>"map<" {
490   pcrtSubtype->name_ = RPC_MAP;
491   pcrtSubtype->subtype1_ = new PType();
492   pcrtSubtype->subtype1_->parent_ = pcrtSubtype;
493   pcrtSubtype->subtype2_ = new PType();
494   pcrtSubtype->subtype2_->parent_ = pcrtSubtype;
495   pcrtSubtype = pcrtSubtype->subtype1_;
496   PushState(S_TYPE);
497 }
498 <S_TYPE>"," {
499   CHECK(pcrtSubtype->parent_);
500   if(pcrtSubtype->name_.empty())
501   {
502     PRINT_ERROR << "missing template parameter before ','" << PRINT_END;
503     PopState();
504   }
505   if(pcrtSubtype == pcrtSubtype->parent_->subtype2_)
506   {
507     PRINT_ERROR << "too many template parameters for type map" << PRINT_END;
508     yyterminate(); //PopState();
509   }
510   if(pcrtSubtype->parent_->subtype2_ == NULL)
511   {
512     PRINT_ERROR << "too many template parameters for type array" << PRINT_END;
513     yyterminate(); //PopState();
514   }
515   pcrtSubtype = pcrtSubtype->parent_;
516   pcrtSubtype = pcrtSubtype->subtype2_;
517   PushState(S_TYPE);
518 }
519
520 <S_TYPE>">" {
521   CHECK(pcrtSubtype->parent_);
522   if(pcrtSubtype->name_.empty())
523   {
524     PRINT_ERROR << "missing template parameter before '>'" << PRINT_END;
525     PopState();
526   }
527   pcrtSubtype = pcrtSubtype->parent_;
528   if(pcrtSubtype->subtype2_ && pcrtSubtype->subtype2_->name_.empty())
529   {
530     PRINT_ERROR << "type map needs 2 template parameters" << PRINT_END;
531     PopState();
532   }
533   PRINT_INFO << "Complex type name: " << (*pcrtSubtype) << PRINT_END;
534   PopState();
535 }
536
537  /*************************************/
538  /*  global rules with low priority   */
539  /*************************************/
540
541 <*>\n /* eat up line feeds */
542
543  /**
544   * Print an error for unmatched characters.
545   *
546   * NOTE: this MUST be the LAST rule!
547   * Because you may want to match correctly some simple characters like: + - = .
548   * using one of the above rules. The rule here takes action only if all the above
549   * rules failed.
550   */
551 <*>{NAME} PRINT_ERROR << "Bad syntax: unrecognized token \"" << yytext << "\"" << PRINT_END;
552 <*>.      PRINT_ERROR << "Bad syntax: unrecognized symbol \"" << yytext << "\"" << PRINT_END;
553
554    /********************************************************************/
555    /********************************************************************/
556 %% /*                          USER CODE                               */
557    /********************************************************************/
558    /********************************************************************/
559
560 const char * StateName(int sc)
561 {
562   switch(sc)
563   {
564   case S_INITIAL:              return "Initial";
565   case S_COMMENT:              return "Comment";
566   case S_SERVICE_HEAD:         return "ServiceHead";
567   case S_SERVICE_BODY:         return "ServiceBody";
568   case S_FUNCTION_RETURN:      return "FunctionReturn";
569   case S_FUNCTION_NAME:        return "FunctionName";
570   case S_FUNCTION_PARAM_TYPE:  return "FunctionParamType";
571   case S_FUNCTION_PARAM_NAME:  return "FunctionParamName";
572   case S_CUSTOMTYPE_HEAD:      return "CustomTypeHead";
573   case S_CUSTOMTYPE_BODY:      return "CustomTypeBody";
574   case S_CUSTOMTYPE_ATTR:      return "CustomTypeAttr";
575   case S_CUSTOMTYPE_ATTR_CODE: return "CustomTypeAttrCode";
576   case S_TYPE:                 return "Type";
577   default:                     return "Unrecognized state";
578   };
579 }
580
581 rpc::Parser::Parser(std::istream & input,
582                      std::ostream & output,
583                      PCustomTypeArray & customTypes,
584                      PServiceArray & services,
585                      PVerbatimArray & verbatim,
586                      const char * filename,
587                      bool bPrintInfo)
588   : yyFlexLexer(&input, &output),
589     customTypes_(customTypes),
590     services_(services),
591     verbatim_(verbatim),
592     strFilename_(filename),
593     bErrorsFound_(false),
594     bPrintInfo_(bPrintInfo)
595 {
596 }
597 rpc::Parser::~Parser()
598 {
599 }
600
601 bool rpc::Parser::Run()
602 {
603   while(yylex() != 0)
604     ;
605   return !bErrorsFound_;
606 }
Note: See TracBrowser for help on using the browser.