OSDN Git Service

e18c59d8328a54696c3d4ee8c93be3e6ebb6275a
[trx-305dsp/dsp.git] / trx305 / kernel / cfg / base / parser.cpp
1 /*
2  *  TOPPERS/JSP Kernel
3  *      Toyohashi Open Platform for Embedded Real-Time Systems/
4  *      Just Standard Profile Kernel
5  * 
6  *  Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
7  *                              Toyohashi Univ. of Technology, JAPAN
8  * 
9  *  上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation 
10  *  によって公表されている GNU General Public License の Version 2 に記
11  *  述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
12  *  を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下,
13  *  利用と呼ぶ)することを無償で許諾する.
14  *  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
15  *      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
16  *      スコード中に含まれていること.
17  *  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
18  *      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
19  *      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
20  *      の無保証規定を掲載すること.
21  *  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
22  *      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
23  *      と.
24  *    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
25  *        作権表示,この利用条件および下記の無保証規定を掲載すること.
26  *    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
27  *        報告すること.
28  *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
29  *      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
30  * 
31  *  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
32  *  よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
33  *  含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
34  *  接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
35  * 
36  *  @(#) $Id: parser.cpp,v 1.2 2012/06/17 00:24:19 suikan Exp $
37  */
38
39
40
41 // $Header: /cvsroot/toppersjsp4bf/jsp/cfg/base/parser.cpp,v 1.2 2012/06/17 00:24:19 suikan Exp $
42
43 #include "base/defs.h"
44 #include "base/parser.h"
45 #include <sstream>
46 #include <set>
47 #include <map>
48 #include <iomanip>
49
50 using namespace std;
51
52 /*
53  *  先頭と末尾にある空白文字を取り除く
54  */
55 Token & Token::trim(void)
56 {
57     string::iterator scope;
58
59         /* あたま */
60     scope = begin();
61     while(*scope == ' ' || *scope == '\t' || *scope == '\r' || *scope == '\n')
62         ++ scope;
63     erase(begin(), scope);
64
65     if(!empty())
66     {
67             /* おしり */
68         scope = end();
69         do {
70             -- scope;
71         } while(*scope == ' ' || *scope == '\t' || *scope == '\r' || *scope == '\n');
72         ++ scope;
73         erase(scope, end());
74     }
75     return *this;
76 }
77
78
79  /*
80   *  文字列リテラルの展開 (ダブルクォートの取り除き + エスケープシーケンスの展開)
81   */
82 Token & Token::chopLiteral(void)
83 {
84     if(type != STRINGLITERAL)
85         return *this;
86
87     string::iterator scope;
88
89         //エラー処理のために非破壊処理をする
90     string src(*this);
91     string work;
92
93     if(src[0] != '"' || src[src.length()-1] != '"')
94         return *this;
95
96     src = src.substr(1, src.length()-2);
97
98     scope = src.begin();
99     while(scope != src.end())
100     {
101         if(*scope == '\\')
102         {
103                 //リテラルの末尾が\で終わることはないのでチェックしない
104             ++ scope;
105             switch(*scope)
106             {
107             case '"':   work += '"';   break;
108             case 't':   work += '\t';  break;
109             case 'r':   work += '\r';  break;
110             case 'n':   work += '\n';  break;
111             case 'b':   work += '\b';  break;
112             case '\\':   work += '\\';  break;
113             default:
114                 ExceptionMessage("Illegal escape sequence [\\%]","エスケープシーケンス[\\%]は不正です") << *scope << throwException;
115             }
116         }else
117             work += *scope;
118
119         ++ scope;
120     }
121
122     type = STRING;
123     assign(work);
124     value = this->length();
125
126     return *this;
127 }
128
129     /* 区切り文字 (一文字だけで意味を成す文字) */
130 const char * Parser::Punctuator =
131     ",;(){}";
132
133     /* 演算子 (特殊文字からなる文字) */
134 const char * Parser::Operator =
135     "+-*/&|%^~!?[]=:.#";
136
137 Token Parser::lastErrorToken;
138
139
140  /*
141   *  ストリームから一文字だけ切り出す
142   */
143 inline int Parser::getChar(void)
144 {
145     int work = current->stream->get();
146
147         /* 行番号の処理 */
148     if(work == '\n')
149         current->line ++;
150     
151         /* ストリームログのための処理 */
152     if(PutBackCount == 0)
153     {
154         if(LogBuffer != 0 && isenabled(LOGGING))
155             *LogBuffer += static_cast<char>(work);
156     }else
157         PutBackCount --;    //すでに読み込んでいる
158
159     return work;
160 }
161
162  /*
163   *  取り出しすぎた文字をストリームに返す
164   */
165 inline void Parser::putBack(int ch)
166 {
167         /* 行番号のための処理 */
168     if(ch == '\n')
169         current->line --;
170
171         /* ストリームログのための処理 */
172     PutBackCount ++;
173
174     current->stream->putback(ch);
175 }
176
177  /*
178   *  Parserクラスのデストラクタ
179   */
180 Parser::~Parser(void)
181 {
182     list<tagFile *>::iterator scope;
183
184         /* 最後までパースしてないなら、とりあえずスタックに入れておく */
185     if(current != 0)
186         fileStack.push_front(current);
187
188         /* スタックの中身全部を破棄 */
189     scope = fileStack.begin();
190     while(scope != fileStack.end())
191     {
192         if((*scope)->stream != 0 && (*scope)->stream != &cin)
193             delete (*scope)->stream;        //ストリームの破棄
194         delete (*scope);                    //構造体のデータ領域の破棄
195
196         ++ scope;
197     }
198
199         /* 念のため */
200     fileStack.clear();
201     TokenStack.clear();
202 }
203
204
205  /*
206   *  識別子の切出し (識別子 = [a-zA-Z_][0-9a-zA-Z_]*)
207   */
208 bool Parser::getIdentifier(Token & token,int ch)
209 {
210     token.value = 0;
211
212     do {
213         token.value ++;
214         token += static_cast<char>(ch);
215         ch = getChar();
216     } while( (ch >='a' && ch <= 'z') || (ch >='A' && ch <= 'Z') || (ch == '_') || (ch >= '0' && ch <= '9') );
217
218     if(ch != -1)
219         putBack(static_cast<char>(ch));
220
221     token.type = Token::IDENTIFIER;
222     return true;
223 }
224
225
226  /*
227   *  ディレクティブの切出しと処理
228   */
229 bool Parser::parseDirectives(Token & token, int ch, bool allow_space)
230 {
231     Token directive;
232     map<string, ParseUnit *>::iterator scope;
233
234         //空白読み飛ばし
235     do {
236         token += static_cast<char>(ch);
237         ch = getChar();
238     } while(ch == ' ' || ch == '\t');
239     
240     if(ch >= '0' && ch <= '9')
241     {
242             //GNU-cpp lineディレクティブ 対策
243         directive.assign("line");
244         this->putBack(ch);
245     }else
246     {
247             //ディレクティブの読み出し
248         putBack(ch);
249         getToken(directive);
250         token += directive;
251     }
252
253         //lineディレクティブの解析
254     if(directive.compare("line") == 0)
255     {
256         Token token;
257
258         getToken(token, Token::INTEGER);
259         setCurrentLine(token.value -1);
260
261         getToken(token, Token::STRINGLITERAL);
262         try {
263             token.chopLiteral();
264         }
265         catch(Exception &) {
266             token.assign("Unknown");
267         }
268         setStreamIdentifier(token);
269
270         return true;
271     }
272
273         //pragmaディレクティブの解析
274     if(directive.compare("pragma") == 0)    
275     {
276         getToken(directive);
277         token += " ";
278         token += directive;
279
280         if((scope = Directive::container().find(directive)) != Directive::container().end())
281         {
282             (*scope).second->body(directive, *Container, *this, string(""));
283
284                 //余分なトークンの読み飛ばし
285             if(!TokenStack.empty())
286             {
287                 do {
288                     token = TokenStack.front();
289                     TokenStack.pop_front();
290                 } while(!TokenStack.empty() && !allow_space && token.type == Token::SPACE);
291
292                 return true;
293             }
294         }
295     }
296
297         //includeディレクティブの解析
298     if(directive.compare("include") == 0)
299     {
300         cerr << getStreamLocation() << Message(": Configurator found 'include' directive\nKernel configuration file must be preprocessed.\n",": #includeディレクティブを発見しました\n カーネル構成ファイルはCプリプロセッサを通過させる必要があります\n");
301         ExceptionMessage("Illegal kernel configuration file","不正なカーネル構成ファイル").throwException();
302     }
303
304     putBack(directive);
305     return false;
306 }
307
308
309  /*
310   *  空白文字の切出し
311   *    ・スペース, タブ   ・#で始まって改行まで    ・C言語のコメントブロック
312   *    ・2連のスラッシュ(//)から改行まで
313   *    ・上の4つを組み合わせたもの
314   */
315 bool Parser::getWhitespace(Token & token, int ch, bool allow_space)
316 {
317     int prev;
318
319     token.type = Token::SPACE;
320     switch(ch)
321     {
322     case '/':
323         ch = getChar();
324
325         switch(ch)
326         {
327             /* コメントブロック */
328         case '*':
329             token += "/*";
330             prev = '\x0';
331             while( ((ch = getChar()) != '/') || (prev!='*'))
332             {
333                 token += static_cast<char>(ch);
334                 prev = ch;
335             }
336             token += static_cast<char>(ch);
337             break;
338
339             /* ダブルスラッシュ */
340         case '/':
341             token += '/';
342             do {
343                 token += static_cast<char>(ch);
344             } while( (ch = getChar()) != '\n' );
345             break;
346
347             /* ただ'/'で始まっただけでした */
348         default:
349             putBack(ch);
350             return getOperator(token, '/');;
351         }
352         break;
353
354         /* # で始まる行 */
355     case '#':
356             /* ディレクティブが無効 or そんなディレクティブは知らない */
357         if(! (isenabled(DIRECTIVE) && parseDirectives(token, ch, allow_space)) )
358         {
359                 //改行まで読み飛ばし
360             TokenStack.clear();
361             do {
362                 token += static_cast<char>(ch);
363                 ch = getChar();
364             } while(ch != '\n');
365             putBack(ch);
366         }
367         break;
368
369         /* 俗に言う空白文字 */
370     case ' ':
371     case '\t':
372     case '\n':
373     case '\r':
374         do {
375             token += static_cast<char>(ch);
376             ch = getChar();
377         } while((ch == ' ') || (ch == '\n') || (ch == '\r') || (ch == '\t'));
378         putBack(static_cast<char>(ch));
379         break;
380     }
381     return true;
382 }
383
384  /*
385   *  整数値の切出し (8/10/16進, 正数/負数)
386   *   ・2進は不評だったのでやめました
387   */
388 bool Parser::getInteger(Token & token, int ch)
389 {
390     bool minus = false; 
391
392     if(ch == '-')
393     {
394         minus = true;
395         ch = getChar();
396         if(ch < '0' || ch >'9')
397         {
398             putBack(static_cast<char>(ch));
399             return false;
400         }
401         token += "-";
402     }
403
404     token.type = Token::INTEGER;
405     token.value = 0;
406
407     if(ch == '0')
408     {
409         token += static_cast<char>(ch);
410         ch = getChar();
411         if(ch == 'x' || ch == 'X')
412         {
413             token += static_cast<char>(ch);
414             ch = getChar();
415             while((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))
416             {
417                 token += static_cast<char>(ch);
418                 if((ch -= '0') >= 10)
419                 {
420                     ch = ch + '0' - 'A' + 10;
421                     if(ch >= 16)
422                         ch = ch - ('a' - 'A');
423                 }
424                 token.value = token.value * 16 + ch;
425                 ch = getChar();
426             }
427         }else
428         {
429             while(ch >= '0' && ch <= '7')
430             {
431                 token += static_cast<char>(ch);
432                 token.value = token.value * 8 + ch - '0';
433                 ch = getChar();
434             }
435         }
436     }else
437     {
438         do {
439             token += static_cast<char>(ch);
440             token.value = token.value * 10 + ch - '0';
441             ch = getChar();
442         } while(ch >= '0' && ch <= '9');
443     }
444
445         /* integer-suffix */
446     if(ch != -1)
447     {
448         bool unsigned_suffix = false;
449         bool long_suffix     = false;
450
451         int  first_longsuffix;
452
453         if(ch == 'u' || ch == 'U')
454         {
455             unsigned_suffix = true;
456             token += static_cast<char>(ch);
457             ch = getChar();
458         }
459
460         if(ch == 'i' || ch == 'I')  //i8, i16, i32, i64
461         {
462             int  first, second;
463             bool accept = false;
464             const signed char suffix_list[10] = { -1, '6', -1, '2', -1, -1, '4', -1, 0, -1};    //8, 16, 32, 64のみを受理
465
466             first  = getChar();
467             second = -1;
468             if(first >= '0' && first <= '9')
469             {
470                 if(suffix_list[first - '0'] > 0)
471                 {
472                     second = getChar();
473                     if(second == suffix_list[first - '0'])
474                         accept = true;
475                 }else
476                     if(suffix_list[first - '0'] == 0)
477                         accept = true;
478             }
479
480             if(!accept)
481             {
482                 if(second != -1)
483                     putBack(second);
484                 putBack(first);
485             } else
486             {
487                 token += static_cast<char>(ch);
488                 token += static_cast<char>(first);
489                 if(second != -1)
490                     token += static_cast<char>(second);
491                 ch = getChar();
492             }
493         } else
494         {
495             if(ch == 'l' || ch == 'L')
496             {
497                 first_longsuffix = ch;
498                 long_suffix = true;
499
500                 token += static_cast<char>(ch);
501                 ch = getChar();
502                 if(ch == first_longsuffix)
503                 {
504                     token += static_cast<char>(ch);
505                     ch = getChar();
506                 }
507             }
508
509             if(!unsigned_suffix && (ch == 'u' || ch == 'U'))
510             {
511                 token += static_cast<char>(ch);
512                 ch = getChar();
513             }
514         }
515     }
516
517     if(minus)
518         token.value = - token.value;
519
520     if(ch != -1)
521         putBack(static_cast<char>(ch));
522
523     return true;
524 }
525
526
527  /*
528   *  オペレータ(特殊文字の組合せからなるトークン)の切出し
529   */
530 bool Parser::getOperator(Token & token, int ch)
531 {
532     const char * work;
533
534         /* chがオペレータ文字であるかどうか確かめる */
535     for(work = Operator;*work != '\x0' && *work != ch;work++);
536     if(*work == '\x0')
537         return false;
538
539         /* 後続する文字もオペレータ文字であるかどうか確かめる */
540     do {
541         token += static_cast<char>(ch);
542         ch = getChar();
543         for(work = Operator;*work != '\x0' && *work != ch;work++);
544     } while(*work != '\x0');
545
546     putBack(ch);
547     token.type = Token::OPERATOR;
548     return true;
549 }
550
551
552  /*
553   *  文字列リテラル (ダブルクォートで括られた文字)
554   *    ・シングルクォートも許すようにした
555   *
556   *    VisualStudio6.0でコンパイルした場合、改行がLFのファイルに対してtellg後に
557   *    getするとEOFが返るため、同処理をコメントアウトしておく。
558   */
559 bool Parser::getStringLiteral(Token & token, int delimitor)
560 {
561     int ch;
562     int prev;
563
564     ch = delimitor;
565
566     token.value = 1;
567     token.type = Token::STRINGLITERAL;
568     token.assign("");
569     token += static_cast<char>(ch);
570
571     while(!current->stream->bad() && !current->stream->eof())
572     {
573         prev = ch;
574         ch = getChar();
575         token += static_cast<char>(ch);
576         token.value ++;
577
578         if(ch == delimitor && prev != '\\')
579             return true;
580     }
581
582         //いったん閉じて再オープンして、リテラル開始の " の次に移動
583     
584     ExceptionMessage(ExceptionMessage::FATAL, "Unterminated string literal appeared.","閉じられていない文字リテラルを検出しました").throwException();
585     return false;
586 }
587
588
589  /*
590   *  トークンの切出し
591   */
592 enum Token::tagTokenType Parser::getToken(Token & token, bool allow_space)
593 {
594     int ch;
595     const char * work;
596
597     do {
598         token.erase();
599         token.type = Token::ERROR;
600         token.value = 0;
601
602             //トークンスタックから切り出す
603         if(!TokenStack.empty())
604         {
605             do {
606                 token = TokenStack.front();
607                 TokenStack.pop_front();
608             } while(!TokenStack.empty() && !allow_space && token.type == Token::SPACE);
609
610             if(!allow_space && token.type != Token::SPACE)
611                 return token.type;
612         }
613
614             //ストリームから切り出す
615         if(current == NULL || current->stream == NULL || current->stream->bad())
616         {
617             token.assign("<End of stream>");
618             return (token.type = Token::EOS);
619         }
620
621         ch = getChar();
622
623             //カレントのストリームが空になった
624         if(ch == -1)
625         {
626                 //ファイルスタックから次のストリームを取る
627             if(!fileStack.empty())
628             {
629                 if(current->stream != &cin)
630                     delete current->stream;
631                 delete current;
632                 
633                 current = *fileStack.begin();
634                 fileStack.pop_front();
635             }else
636             {
637                 token.assign("<End of stream>");
638                 return (token.type = Token::EOS);
639             }
640         }
641
642             //First(whitespaces) is [ \n\t\r/#]
643         if( (ch == ' ') || (ch == '\t') || (ch == '\n') || (ch == '\r') || (ch == '/') || (isHeadofLine && ch == '#'))
644         {
645             if(ch == '\n')
646                 isHeadofLine = true;
647
648             if(getWhitespace(token, ch, allow_space))
649                 if((token == Token::SPACE && allow_space) || !(token == Token::SPACE || token == Token::ERROR))
650                     return token.type;
651
652             continue;
653         }else
654             break;
655     }while(true);
656
657     isHeadofLine = false;
658
659     token.line = current->line;
660
661         //First(identifier) is [a-zA-Z_]
662     if( (ch >='a' && ch <= 'z') || (ch >='A' && ch <= 'Z') || (ch == '_') )
663         if(getIdentifier(token, ch))
664             return Token::IDENTIFIER;
665
666         //First(integer) is [\-0-9]
667     if( (ch >='0' && ch <='9') || (ch == '-') )
668         if(getInteger(token,ch))
669             return Token::INTEGER;
670
671         //First(string) is ["']
672     if( ch == '"' || ch == '\'')
673         if(getStringLiteral(token,ch))
674             return Token::STRINGLITERAL;
675
676         //Operator
677     if(getOperator(token,ch))
678         return Token::OPERATOR;
679
680         //Punctuator
681     work = Punctuator;
682     while(*work != '\x0')
683         if( *(work++) == ch )
684         {
685             token += static_cast<char>(ch);
686             return (token.type = Token::PUNCTUATOR);
687         }
688
689     token += static_cast<char>(ch);
690     token.type = Token::UNKNOWN;
691     return Token::UNKNOWN;
692 }
693
694
695  /*
696   *  トークン用 ストリームオペレータ (主にテスト目的)
697   */
698 ostream & operator << (ostream & out, Token & src)
699 {
700     switch(src.type)
701     {
702     case Token::IDENTIFIER:
703         out << "<IDENTIFIER:["; break;
704     case Token::INTEGER:
705         out << "<INTEGER:["; break;
706     case Token::STRINGLITERAL:
707         out << "<STRINGLITERAL:["; break;
708     case Token::STRING:
709         out << "<STRING:["; break;
710     case Token::OPERATOR:
711         out << "<OPERATOR:["; break;
712     case Token::PUNCTUATOR:
713         out << "<PUNCTUATOR:["; break;
714     case Token::RESERVEDWORD:
715         out << "<RESERVEDWORD:["; break;
716     case Token::SPECIAL:
717         out << "<SPECIAL:["; break;
718     case Token::SPACE:
719         out << "<SPACE:["; break;
720     case Token::UNKNOWN:
721         out << "<UNKNOWN>"; return out;
722     case Token::ERROR:
723         out << "<ERROR>"; return out;
724     default:
725         out << "<???:[";
726     }
727
728     return out << static_cast<string &>(src) << "]("<<src.value<<")>";
729 }
730
731  /*
732   *  予約語の切出し(というよりも確認)
733   */
734 void Parser::getToken(const char * term) throw(Exception)
735 {
736     Token token;
737
738     if(term == NULL)
739         ExceptionMessage("Internal: GetToken received an empty string as reserved word.","内部エラー: GetTokenに空文字列が渡されました").throwException();
740
741     getToken(token, false);
742     if(token.compare(term) != 0) {
743         lastErrorToken = token;
744         ExceptionMessage("Token [%] should be replaced by [%]","字句[%]は[%]であるべきです") << token << term << throwException;
745     }
746 }
747
748 void Parser::getToken(const char * first, const char * second, const char * third, const char * fourth) throw(Exception)
749 {
750     getToken(first);
751     if(second != NULL)
752         getToken(second);
753     if(third != NULL)
754         getToken(third);
755     if(fourth != NULL)
756         getToken(fourth);
757 }
758
759 string Parser::getStreamLocation(void)
760 {
761     list<tagFile *>::iterator scope;
762
763     string location;
764     char buffer[16];
765
766     if(current == 0)
767         return string("");
768
769     ::sprintf(buffer, ":%d", current->line);
770     location += current->identifier;
771     location += buffer;
772
773     if(!fileStack.empty())
774     {
775         location += " (included at ";
776
777         scope = fileStack.begin();
778         while(scope != fileStack.end())
779         {
780             ::sprintf(buffer, ":%d, ", (*scope)->line);
781             location += (*scope)->identifier;
782             location += buffer;
783
784             ++ scope;
785
786         }
787
788         location.erase(location.size()-2);
789         location += ")";
790     }
791
792     return location;
793 }
794
795 void Parser::pushStream(const std::string & filename, std::string strid)
796 {
797     fstream * fin;
798
799     if(current != 0)
800         fileStack.push_front(current);
801         
802     fin = new fstream(filename.c_str(),ios::in);
803
804     if(fin->is_open())
805     {
806         if(strid.size() == 0)
807             strid = filename;
808
809         current = new tagFile;
810         current->stream     = fin;
811         current->identifier = strid;
812         current->line       = 1;
813     }else
814     {       
815         ExceptionMessage("File operation failure : [%]","ファイル操作に失敗しました [%]") << filename << throwException;
816         delete fin;
817     }
818 }
819
820 void Parser::pushStdStream(std::string strid)
821 {
822     stringstream * work = new stringstream;
823     char buffer[1024];
824     int  count;
825
826         //標準入力の情報をすべて取り込む (エラー対処用に seekg/tellg を使いたい)
827     do {
828         cin.read(buffer, 1024);
829         count = cin.gcount();
830         work->write(buffer, count);
831     } while(count != 0);
832
833     if(current != 0)
834         fileStack.push_front(current);
835
836     current = new tagFile;
837     current->stream     = work;
838     current->identifier = strid;
839     current->line       = 1;
840 }
841
842 string * Parser::setLogBuffer(string * buffer)
843 {
844     string * old = LogBuffer;
845     LogBuffer = buffer;
846     PutBackCount = 0;
847     return old;
848 }
849
850 streampos Parser::getLogBufferPos(int offset)
851 {
852     streampos pos;
853     
854     pos = 0;
855     if(LogBuffer != 0)
856         pos = LogBuffer->size();
857     pos += static_cast<streampos>(offset - PutBackCount);
858     return pos;
859 }
860
861 #ifdef CALL_EXTERNAL_PROGRAM 
862 void Parser::doPreProcess(const char * cmd)
863 {
864     string         tempfilename;
865     char           buffer[1024];
866     int            count;
867     fstream        tempfile;
868     string         work;
869     stringstream * stream;
870
871     if(current == NULL || current->stream == NULL)
872         ExceptionMessage("No stream specified for processing","処理対象となるストリームが設定されていません").throwException();
873
874
875         /* 今のストリームの内容をすべてテンポラリに書き出す */
876
877     strcpy(buffer,"cfgXXXXXX");
878     mktemp(buffer);
879
880     tempfilename.assign(buffer);
881     tempfile.open(tempfilename.c_str(),ios::out);
882
883     if(!tempfile.is_open())
884         ExceptionMessage("Failed to open a temporary file","テンポラリファイルの作成に失敗しました").throwException();
885
886     do {
887         current->stream->read(buffer, 1024);
888         count = current->stream->gcount();
889         tempfile.write(buffer, count);
890     } while(count != 0);
891     tempfile.close();
892
893
894         /* ストリーム差し替え */
895
896     preprocessname = tempfilename;
897     originalname   = current->identifier;
898
899     if(current->stream != &cin)
900         delete current->stream;
901     stream = new stringstream;
902     current->stream = stream;
903
904
905         /* プリプロセッサの起動 & 出力の取り込み */
906
907     work  = string(cmd) + " " + tempfilename;
908     VerboseMessage(" Start the external preprocessor [%]\n"," 外部プログラムを起動します [%]\n") << work;
909
910     FILE * pipe = popen(work.c_str(),"r");
911     while(feof(pipe) == 0)
912         stream->put((char)fgetc(pipe));
913
914     pclose(pipe);
915     remove(tempfilename.c_str());
916     isHeadofLine = true;
917 }
918 #else
919 void Parser::doPreProcess(const char * cmd)
920 {}
921 #endif /* CALL_EXTERNAL_PROGRAM */
922
923
924 ParseUnit::ParseUnit(void * _container, const char * name)
925 {
926     map<string, ParseUnit *> * container;
927     string work(name);
928     string apiname;
929     string::size_type i,j;
930
931     i = 0;
932     container = reinterpret_cast<map<string, ParseUnit *> *>(_container);
933     
934     do {
935         j = work.find_first_of(',', i);
936         apiname = work.substr(i, j-i);
937
938         if(container->find(apiname) != container->end())
939             ExceptionMessage("Multiple registration of [%]\n","[%]が重複して登録されようとしています") << apiname << throwException;
940         (*container)[apiname] = this;
941         i = j + 1;
942     }while(j != string::npos);
943 }
944
945 void ParseUnit::printList(void * _container)
946 {
947     int i;
948     map<string, ParseUnit *> * container;
949     map<string, ParseUnit *>::iterator scope;
950
951     container = reinterpret_cast<map<string, ParseUnit *> *>(_container);
952     if(container->empty())
953     {
954         cerr << "  " << Message("None of element registed\n", "登録されている要素はありません\n");
955         return;
956     }
957
958     i = 0;
959     scope = container->begin();
960     while(scope != container->end())
961     {
962         cerr << '[' << (*scope).first << "] ";
963
964         if(i++ >= 6)
965         {
966             i = 0;
967             cerr << '\n';
968         }
969
970         ++ scope;
971     }
972
973     if(i != 0)
974         cerr << '\n';
975 }
976
977 Token & ParseUnit::parseParameter(Parser & p)
978 {
979     static Token result;
980     Token token;
981     int nest = 0;
982
983     result.type = Token::ERROR;
984     result.value = 0;
985     result.assign("");
986
987     do
988     {
989         p.getToken(token);
990         if(token == Token::PUNCTUATOR)
991         {
992             if(token.compare("(") == 0)
993                 nest ++;
994             else if(token.compare(")") == 0)
995                 nest --;
996             else if(nest == 0)
997                 break;
998             if(nest < 0)
999                 ExceptionMessage("')' appeared before '('.","対応しない閉じ括弧があります").throwException();
1000         }
1001
1002         if(result == Token::ERROR)
1003             result = token;
1004         else
1005         {
1006             result.type = Token::STRING;
1007             result += ' ';
1008             result += token;
1009         }
1010
1011     }while(true);
1012
1013     p.putBack(token);
1014     result.trim();
1015     return result;
1016 }
1017
1018 int ParseUnit::parseParameters(Parser & p, Directory * container, int min, int max)
1019 {
1020     Token work;
1021     int count = 0;
1022
1023     if(max == 0)
1024         max = min;
1025
1026     do
1027     {
1028         Token & token = parseParameter(p);
1029         if(token.type == Token::ERROR)
1030             break;
1031
1032         if(token == Token::INTEGER)
1033             container->addChild(new Directory(token.value));
1034         else
1035             container->addChild(new Directory((string &)token));
1036
1037         count ++;
1038         p.getToken(work);
1039     }while(work.compare(",")==0 && count < max);
1040
1041     if(count < min)
1042         ExceptionMessage("Too few parameters [%/%]","パラメータの数が少なすぎます [%/%]") << count << min << throwException;
1043
1044     p.putBack(work);
1045     return count;
1046 }
1047
1048 int ParseUnit::parseParameters(Parser & p, Directory * container, const char * paramlist)
1049 {
1050     Token work;
1051     int count;
1052     string list;
1053     string key;
1054     string::size_type head,tail;
1055
1056     list.assign(paramlist);
1057
1058     count = 0;
1059     head = 0;
1060     tail = list.find_first_of(',');
1061     key = list.substr(head,tail-head);
1062
1063     do
1064     {
1065         if(head == string::npos)
1066             ExceptionMessage("Too many parameters","パラメータの数が多すぎます").throwException();
1067
1068         Token & token = parseParameter(p);
1069         if(token.type == Token::ERROR)
1070             break;
1071
1072         if(token == Token::INTEGER)
1073             container->addChild(key,new Directory(token.value));
1074         else
1075             container->addChild(key,new Directory((string &)token));
1076
1077         if(tail != string::npos)
1078         {
1079             head = tail + 1;
1080             tail = list.find_first_of(',',head);
1081             key = list.substr(head,tail != string::npos ? tail-head : string::npos);
1082             count ++;
1083             p.getToken(work);
1084         }else
1085             break;
1086     }while(work.compare(",")==0);
1087
1088     if(tail != string::npos)
1089         ExceptionMessage("Too few parameters","パラメータの数が少なすぎます").throwException();
1090
1091     return count;
1092 }
1093
1094 //------
1095
1096 Directory * StaticAPI::last = NULL;
1097
1098 map<std::string, class ParseUnit *> & StaticAPI::container(void)
1099 {
1100     static map<std::string, class ParseUnit *> _container;
1101     return _container;
1102 }
1103
1104 Directory * StaticAPI::allocate(Directory & container, const Token & token, const char * id, bool regist)
1105 {
1106     static unsigned int assignment_count = 0;
1107     Directory * node;
1108
1109     if(!(token == Token::IDENTIFIER || token == Token::INTEGER))
1110         ExceptionMessage("Given token(%) is not suitable for an object identifier.","オブジェクトの識別名として利用できない字句(%)が指定されました") << token << throwException;
1111
1112     if(regist && (token == Token::INTEGER && token.value <= 0))
1113         ExceptionMessage("Cannot assign an ID number less or equal to 0.","0以下のID番号を設定することはできません").throwException();
1114
1115
1116     node = container.findChild(id);
1117     if(node != 0)
1118     {
1119         Directory::iterator scope;
1120
1121         scope = node->begin();
1122         while(scope != node->end())
1123         {
1124             if((*scope).first.compare(token) == 0)
1125                 ExceptionMessage("Identifier % is already used.","識別名%はすでに利用されています") << token << throwException;
1126             ++ scope;
1127         }
1128     }else
1129         node = container.addChild(id);
1130
1131     node = node->addChild(token);
1132     (*node)["#order"] = assignment_count++;
1133
1134     if(token == Token::IDENTIFIER)
1135     {
1136         if(regist)
1137         {
1138             Directory * scope = container.openChild("/","identifier",token.c_str(),NULL);
1139             if(*scope == Directory::INTEGER)
1140                 *node = scope->toInteger();
1141         }
1142     }else
1143         *node = token.value;
1144
1145     last = node;
1146     return node;
1147 }
1148
1149 //------
1150
1151 map<std::string, class ParseUnit *> & Directive::container(void)
1152 {
1153     static map<std::string, class ParseUnit *> _container;
1154     return _container;
1155 }
1156
1157 //------
1158
1159 ParserComponent::ParserComponent(void) throw() : Component(PARSER)
1160 {}
1161
1162 ParserComponent::~ParserComponent(void) throw()
1163 {}
1164
1165 void ParserComponent::parseOption(Directory & container)
1166 {
1167     if(findOption("h", "help"))
1168     {
1169         cerr << Message(
1170             "Static API parser\n"
1171             "  -s, --source=filename     : Specify the source file\n"
1172             "  -idir ,--ignore-directive : Ignore directives\n"
1173             "  -iapi ,--ignore-api       : Ignore unknown static api\n"
1174             "  -t, --through             : Get unprocessed APIs through\n"
1175             "  --print-api               : Show registered static api list\n", 
1176             "静的APIパーサ\n"
1177             "  -s, --source=ファイル名   : 入力ファイル名を指定します\n"
1178             "  -idir ,--ignore-directive : ディレクティブの解析を行いません\n"
1179             "  -iapi, --ignore-api       : 登録されていないAPIを無視します\n"
1180             "  -t, --through             : 処理しなかったAPIを通過させます\n"
1181             "  --print-api               : 登録されているAPIの一覧を表示します\n");
1182         return;
1183     }
1184
1185     if(findOption("-print-api"))
1186     {
1187         cerr << Message("List of Registerd Static API\n","静的API 一覧\n");
1188         StaticAPI::printList();
1189         return;
1190     }
1191
1192     checkOption("idir", "ignore-directive");
1193     checkOption("iapi", "ignore-api");
1194     checkOption("t", "through");
1195
1196     if(checkOption("s","source") || checkOption(DEFAULT_PARAMETER))
1197         activateComponent();
1198 }
1199
1200 bool ParserComponent::parseStaticAPI(Parser & p, Directory & container, Token token, const string domain)
1201 {
1202     bool isParseErrorOccured = false;
1203     map<string, ParseUnit *>::iterator api;
1204     Directory * node = NULL;
1205
1206     if(token.type != Token::IDENTIFIER)
1207         return false;
1208
1209     StaticAPI::clearLastObject();
1210     node = container[PARSERESULT].addChild();
1211
1212     try {
1213         node->addChild("api",new Directory(token));
1214         node->addChild("begin",new Directory((long)p.getLogBufferPos(-(int)token.size()-1)));
1215         if(!domain.empty())
1216             node->addChild("domain", new Directory(domain));
1217
1218         api = StaticAPI::container().find(token);
1219         if(api == StaticAPI::container().end())
1220         {
1221             if(ignoreUnknownAPI)
1222             {
1223                 cerr << Message("%: Unknown static api % was ignored. (skipped)\n","%: 非登録のAPI % は無視されます\n") << p.getStreamLocation() << token;
1224                 do {
1225                     p.getToken(token);
1226                 }while(token.compare(";") != 0);
1227                 node->addChild("end",new Directory((long)p.getLogBufferPos()));
1228                 (*node) = (long)0;
1229                 return true;
1230             }
1231             ExceptionMessage("Static API [%] is not registered in the configurator", "静的API[%]は未登録です") << token << throwException;
1232         }
1233
1234         DebugMessage("  StaticAPI [%]\n") << (*api).first;
1235
1236         p.getToken("(");
1237
1238         (*api).second->body(token, container, p, domain);
1239
1240         p.getToken(")");
1241         p.getToken(";");
1242
1243         node->addChild("end",new Directory((long)p.getLogBufferPos()));
1244         (*node) = (long)1;
1245     }
1246     catch(Exception & e)
1247     {
1248         int offset;
1249         string work;
1250         work = p.getStreamLocation() + Message(":[Error] ",":[エラー] ").str() + e.getDetails();
1251         isParseErrorOccured = true;
1252
1253         StaticAPI::dropLastObject();
1254         failCount ++;
1255
1256         offset = 0;
1257         token = p.getLastErrorToken();
1258         while (token != Token::ERROR && token != Token::EOS)
1259         {
1260             if( token == ";" )
1261                 break;
1262
1263                 //読み出したトークンが静的APIと同じ名前なら きっとセミコロン忘れ
1264             api = StaticAPI::container().find(token);
1265             if(api != StaticAPI::container().end())
1266             {
1267                 cerr << Message("<The following error must be occured by lack of ';' at the end of previous line>\n","<次のエラーは直前行の';'忘れによる可能性が高いです>\n");
1268                 offset = -(int)token.size();
1269                 p.putBack(token);
1270                 break;
1271             }
1272
1273             p.getToken(token);
1274         }
1275
1276         node->addChild("end",new Directory((long)p.getLogBufferPos(offset)));
1277         (*node) = (long)0;
1278
1279         cerr << work << '\n';
1280
1281         ExceptionMessage("Fatal error on Static API parsing","静的APIの構文解析に失敗しました").throwException();
1282     }
1283
1284     return true;
1285 }
1286
1287 /*
1288  *  処理できなかったAPIを標準出力に吐き出す
1289  */
1290 void ParserComponent::throughConfigurationFile(string & log, Directory & container)
1291 {
1292     Directory *        node;
1293     string::size_type  pos;
1294     string::size_type  begin;
1295     string::size_type  end;
1296
1297     pos = 0;
1298     end = 0;
1299
1300     node = container[PARSERESULT].getFirstChild();
1301     while(node != NULL)
1302     {
1303         begin = static_cast<string::size_type>((*node)["begin"].toInteger());
1304         end   = static_cast<string::size_type>((*node)["end"].toInteger());
1305
1306         if(pos < begin)
1307             cout << log.substr(pos, begin - pos);
1308
1309         if(node->toInteger() == 0)
1310         {
1311             cout << log.substr(begin, end - begin);
1312         }else
1313         {
1314             for(pos = begin; pos < end; ++pos)
1315                 if( log.at(pos) == '\n' )
1316                     cout << '\n';
1317         }
1318         node = node->getNext();
1319     }
1320
1321     if(end < log.size())
1322         cout << log.substr(end);
1323
1324     ExceptionMessage("","").throwException();
1325 }
1326
1327
1328 void ParserComponent::body(Directory & container)
1329 {
1330     Token token;
1331     Parser p(container);
1332     string logbuffer;
1333     OptionParameter::OptionItem item;
1334     unsigned int itemcount = 0;
1335
1336     failCount = 0;
1337     
1338         //idirオプションの処理
1339     if(findOption("idir","ignore-directive"))
1340         p.disable(Parser::DIRECTIVE);
1341
1342     ignoreUnknownAPI = findOption("iapi", "ignore-api");
1343
1344     if(findOption("t","through"))
1345     {
1346         p.setLogBuffer(&logbuffer);
1347         ignoreUnknownAPI = true;
1348     }
1349
1350         //入力ソース
1351     item = getOption("s", "source");
1352     item.mergeItem(getOption(DEFAULT_PARAMETER));
1353     if(item.countParameter() == 0)
1354     {
1355         p.pushStdStream(Message("Standard Input","標準入力").str());
1356         VerboseMessage("Starting parse with standard input\n","標準入力からの字句解析を開始しました\n");
1357     }
1358
1359     try{
1360         do {
1361             if(item.hasParameter())
1362             {
1363                 VerboseMessage("Starting parse with file[%]\n","ファイル[%]の字句解析を開始しました\n") << item[itemcount];
1364                 p.pushStream(item[itemcount]);
1365             }
1366
1367             this->parse(p, container);
1368
1369             if(p.getToken(token) != Token::EOS)
1370                 ExceptionMessage("Buffer has remaining tokens, parsing is not yet finished", "パースが中断されました").throwException();
1371
1372             if(failCount != 0)
1373                 ExceptionMessage("Total % failures found in this configuration.","%個の障害があります") << failCount << throwException;
1374
1375             VerboseMessage("Parse finished\n","字句解析は正常に終了しました\n");
1376
1377         } while(++itemcount < item.countParameter());
1378
1379         if(findOption("t","through"))
1380             throughConfigurationFile(logbuffer,container);
1381
1382         container[PARSERESULT].erase();
1383     }
1384     catch(Exception & e)
1385     {
1386         string work;
1387
1388         work = p.getStreamLocation() + Message(":[Error] ",":[エラー] ").str() + e.getDetails();
1389         ExceptionMessage(work.c_str()).throwException();
1390     }
1391 }
1392
1393     // オプションノードから割付方法を取得する
1394 enum Common::tagAssignmentOrder Common::parseOrder(Directory * node)
1395 {
1396     Directory * scope;
1397     int         i;
1398
1399         //割当パラメータ解析
1400     i = FCFS;
1401     if(node != 0)
1402     {
1403         scope = node->getFirstChild();
1404         while(scope != 0)
1405         {
1406             string param = scope->toString();
1407             if(param.compare("alphabetic") == 0 || param.compare("ALPHABETIC") == 0)
1408                 i = (i & 0xf0) | ALPHABETIC;
1409             else if(param.compare("fcfs") == 0 || param.compare("FCFS") == 0)
1410                 i = (i & 0xf0) | FCFS;
1411             else if(param.compare("reverse") == 0 || param.compare("REVERSE") == 0)
1412                 i |= REVERSE;
1413
1414             scope = scope->getNext();
1415         }
1416     }
1417
1418     return static_cast<enum tagAssignmentOrder>(i);
1419 }
1420
1421     // オプションノードから割付方法を取得する
1422 enum Common::tagAssignmentOrder Common::parseOrder(OptionParameter::OptionItem item)
1423 {
1424     Directory node;
1425     unsigned int i;
1426
1427     for(i=0;i<item.countParameter();++i)
1428         node.addChild(item[i]);
1429
1430     return parseOrder(&node);
1431 }
1432
1433     //ID値のアサインメント
1434     //  (他の場所からも使うのでここに移動)
1435 int Common::assignID(Directory & container, const char * category, const char * top, enum tagAssignmentOrder order)
1436 {
1437     Directory * node  = 0;
1438     Directory * scope = 0;
1439     Directory * work  = 0;
1440     set<int> idpool;
1441     map<int, Directory *> sorter;
1442     map<int, Directory *>::iterator p_sorter;
1443     int i;
1444
1445         //下準備
1446     node = container.findChild(top,category,NULL);
1447     if(node == 0)
1448         return 0;
1449
1450     for(i=1;i< (signed int) node->size() + 32; i++)
1451         idpool.insert(i);
1452
1453         //割付順の決定と,割当済みIDの削除
1454     i = 0;
1455     scope = node->getFirstChild();
1456     while(scope != 0)
1457     {
1458         if( *scope == Directory::INTEGER )
1459             idpool.erase(*scope);
1460         else
1461         {
1462                 //重複名称の存在チェック
1463             work = container.openChild("/","identifier",scope->getKey().c_str(),NULL);
1464             if( *work == Directory::INTEGER)
1465             {
1466                 VerboseMessage("Assigning the same ID (%) since the name (%[%]) is duplicated\n","ID番号(%)を異種同名のオブジェクト(%[%])に割り当てます.\n") << work->toInteger() << scope->getKey() << category;
1467                 idpool.erase(*scope = work->toInteger());
1468             } else
1469             {
1470                     //割当方法に従って割当候補に追加
1471                 switch(order)
1472                 {
1473                 case ALPHABETIC:
1474                     sorter[i++] = scope;
1475                     break;
1476                 case REVERSE_ALPHABETIC:
1477                     sorter[i--] = scope;
1478                     break;
1479                 case FCFS:
1480                 default:
1481                     sorter[scope->openChild("#order")->toInteger()] = scope;
1482                     break;
1483                 case REVERSE_FCFS:
1484                     sorter[-scope->openChild("#order")->toInteger()] = scope;
1485                     break;
1486                 }
1487             }
1488         }
1489         scope = scope->getNext();
1490     }
1491
1492         //ID割当
1493     p_sorter = sorter.begin();
1494     while(p_sorter != sorter.end())
1495     {
1496         scope = (*p_sorter).second;
1497         if( !(*scope == Directory::INTEGER) )
1498         {
1499             i = *(idpool.begin());
1500             idpool.erase(idpool.begin());
1501
1502             work = container.openChild("/","identifier",scope->getKey().c_str(),NULL);
1503             *work = i;
1504             *scope = i;
1505         }
1506         ++ p_sorter;
1507     }
1508
1509         //割当表作成
1510     if(node->size() != 0 && VerboseMessage::getVerbose())
1511     {
1512         VerboseMessage("Object ID assignment list [%]\n","オブジェクトID割付表 [%]\n") << category;
1513
1514         sorter.clear();
1515         scope = node->getFirstChild();
1516         while(scope != 0)
1517         {
1518             sorter[scope->toInteger()] = scope;
1519             scope = scope->getNext();
1520         }
1521
1522         p_sorter = sorter.begin();
1523         while(p_sorter != sorter.end())
1524         {
1525             VerboseMessage("  % : %\n") << setw(3) << (*p_sorter).first << (*p_sorter).second->getKey();
1526             ++ p_sorter;
1527         }
1528     }
1529
1530         //妥当性の判定
1531     if((signed)node->size()+1 != *(idpool.begin()))
1532         ExceptionMessage("Discontinuous % ID assignment occured","不連続なオブジェクトID(%)") << category << throwException;
1533
1534     return node->size();
1535 }
1536