source: cfg_itronx+oil_gcc/toppers/oil/preprocess.cpp@ 165

Last change on this file since 165 was 54, checked in by ertl-ishikawa, 12 years ago

cfg+oil対応コンフィギュレータを追加

File size: 7.7 KB
Line 
1/*
2 * TOPPERS Software
3 * Toyohashi Open Platform for Embedded Real-Time Systems
4 *
5 * Copyright (C) 2007-2008 by TAKAGI Nobuhisa
6 *
7 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
8 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
9 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
10 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
11 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
12 * スコード中に含まれていること.
13 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
14 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
15 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
16 * の無保証規定を掲載すること.
17 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
18 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
19 * と.
20 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
21 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
22 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
23 * 報告すること.
24 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
25 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
26 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
27 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
28 * 免責すること.
29 *
30 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
31 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
32 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
33 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
34 * の責任を負わない.
35 *
36 */
37#include <cstring>
38#include <algorithm>
39#include <iostream>
40#include <iterator>
41#include "toppers/io.hpp"
42#include "toppers/cpp.hpp"
43#include "toppers/global.hpp"
44#include "toppers/diagnostics.hpp"
45#include "toppers/oil/preprocess.hpp"
46#include <boost/spirit/include/classic_spirit.hpp>
47
48namespace toppers
49{
50 namespace oil
51 {
52
53 /*!
54 * \brief 静的API `INCLUDE'の展開
55 * \param[in] in 入力ファイルの内容
56 * \param[out] out 出力ファイルの内容
57 * \param[in] codeset 文字コード
58 * \param[out] dependencies 依存関係の格納先(NULLの場合は格納しない)
59 * \param[out] onces #pragma onceが記述されていたファイル名の格納先(NULLの場合は格納しない)
60 *
61 * `INCLUDE' の引数は、μITRON 仕様のものとは異なり、二重引用符で囲まずに #include 指令と
62 * 同じ形式を用いる。
63 */
64 void expand_include( text const& in, text& out, codeset_t codeset, std::set< std::string >* dependencies, std::set< std::string >* onces )
65 {
66 typedef text::container::const_iterator const_row_iterator;
67 typedef std::string::size_type size_type;
68 size_type const npos = std::string::npos;
69 const_row_iterator first( in.begin().get_row() ), last( in.end().get_row() );
70
71 out.set_line( first->line.file, first->line.line );
72 for ( const_row_iterator iter( first ); iter != last; ++iter )
73 {
74 std::string const& buf = iter->buf;
75 char state = 0;
76
77 for ( size_type i = 0, n = buf.size(); i != n; ++i )
78 {
79 char c = buf[i];
80 if ( c == '\'' || c == '\"' )
81 {
82 if ( state == 0 )
83 {
84 state = c; // 文字(列)リテラル開始
85 }
86 else if ( buf[i - 1] != '\\' ) // \' または \" ではない
87 {
88 state = 0; // 文字(列)リテラル終了
89 }
90 else if ( ( codeset == shift_jis ) && ( i >= 2 ) && is_lead< shift_jis >( buf[i - 2] ) )
91 {
92 state = 0;
93 }
94 out.push_back( c );
95 }
96 else if ( state != 0 ) // 文字(列)リテラル内
97 {
98 out.push_back( c );
99 }
100 else
101 {
102 using namespace boost::spirit::classic;
103 std::string headername;
104 if ( iter == last )
105 {
106 return;
107 }
108 text::const_iterator iter2( iter, i );
109 if ( iter2 == in.end() )
110 {
111 break;
112 }
113 parse_info< text::const_iterator > info
114 = parse( iter2, in.end(),
115 ( str_p( "#include" ) >> *space_p
116 >> '\"' >> ( +( anychar_p - '\"' ) )[ assign( headername ) ] >> '\"'
117 ) ); // 行番号がずれるので、スキップパーサは使用しない
118 if ( info.hit )
119 {
120 std::vector< std::string > include_paths = get_global< std::vector< std::string > >( "include-path" );
121 std::string hname = search_include_file( include_paths.begin(), include_paths.end(), headername );
122 if ( hname.empty() ) // ヘッダ名が見つからない
123 {
124 fatal( iter->line, _( "cannot open file `%1%\'" ), headername );
125 }
126 else if ( onces == 0 || onces->find( hname ) == onces->end() )
127 {
128 if ( dependencies != 0 )
129 {
130 dependencies->insert( hname );
131 }
132 out.push_back( ' ' ); // ダミーを挿入しておかないと行番号がずれる
133 preprocess( hname, out, codeset, dependencies, onces ); // ヘッダ名で指定されたファイルに対して前処理を再帰的に行う
134 iter = info.stop.get_row();
135 i = info.stop.get_col() - 1;
136 if ( iter != last )
137 {
138 out.set_line( iter->line.file, iter->line.line );
139 }
140 }
141 }
142 else
143 {
144 if ( iter2.get_col() == 0 )
145 {
146 info = parse( iter2, in.end(),
147 ( *( space_p - eol_p ) >>
148 ch_p( '#' ) >> *( space_p - eol_p ) >> "pragma" >> *( space_p - eol_p )
149 >> "once"
150 >> *( space_p - eol_p ) >> eol_p ) );
151 if ( info.hit )
152 {
153 if ( onces != 0 )
154 {
155 onces->insert( iter2.line().file );
156 }
157 out.push_back( ' ' );
158 iter = info.stop.get_row();
159 if ( iter != last )
160 {
161 out.set_line( iter->line.file, iter->line.line );
162 }
163 --iter; // インクリメントされるのでいったん戻す。
164 break;
165 }
166 }
167 if ( parse( iter2, in.end(),
168 ( str_p( "#include" ) >> *space_p >> '\"' >> +( anychar_p - ')' ) >> '\"') ).hit )
169 {
170 warning( iter->line, _( "probably, %1% argument of `%2%\' is illegal" ), _( "1st" ), "INCLUDE" );
171 }
172 out.push_back( c );
173 }
174 }
175 }
176 }
177 }
178
179 /*!
180 * \brief コンフィギュレーションファイルの前処理
181 * \param[in] file コンフィギュレーションファイル名
182 * \param[out] result 前処理後の内容
183 * \param[in] codeset 文字コード
184 * \param[out] dependencies 依存関係の格納先(NULLの場合は格納しない)
185 * \param[out] onces #pragma onceが記述されていたファイル名の格納先(NULLの場合は格納しない)
186 */
187 void preprocess( std::string const& file, text& result, codeset_t codeset, std::set< std::string >* dependencies, std::set< std::string >* onces )
188 {
189 std::string buf;
190 read( file, buf );
191 if ( buf.empty() )
192 {
193 return;
194 }
195 text txt;
196 txt.set_line( file, 1 );
197 remove_comment( buf.begin(), buf.end(), std::back_inserter( txt ), codeset );
198 expand_include( txt, result, codeset, dependencies, onces );
199 }
200
201 }
202}
Note: See TracBrowser for help on using the repository browser.