00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "physical/parser.hpp"
00015 #include "physical/dynamicphysical.hpp"
00016 #include "physical/unitsymbol.hpp"
00017
00018
00019 #include <boost/spirit.hpp>
00020 #include <boost/spirit/phoenix/functions.hpp>
00021
00022 namespace physical {
00023
00028 namespace parser {
00029
00033 namespace detail {
00034
00035 namespace spirit=boost::spirit;
00036
00037 struct unit_closure: public spirit::closure<unit_closure, DynamicPhysical<SI> >
00038 {
00039 member1 val;
00040 };
00041
00042 struct quantity_power_impl
00043 {
00044 template <typename Quantity, typename Exponent>
00045 struct result
00046 {
00047 typedef DynamicPhysical<SI> type;
00048 };
00049
00050 template <typename Quantity, typename Exponent>
00051 DynamicPhysical<SI> operator()(const Quantity& q, Exponent const e) const
00052 {
00053 int n=e;
00054 DynamicPhysical<SI> r=1.;
00055 while(n>0) { --n; r = r * q;};
00056 while(n<0) { ++n; r = r / q;};
00057 return r;
00058 }
00059 };
00060
00061 phoenix::function<quantity_power_impl> const quantity_power = quantity_power_impl();
00062
00063 struct unit_parser : public spirit::grammar<unit_parser, unit_closure::context_t>
00064 {
00065 template <typename ScannerT>
00066 struct definition
00067 {
00068 spirit::symbols<physical::DynamicPhysical<SI> > symbol;
00069 spirit::symbols<physical::DynamicPhysical<SI> > prefix;
00070 typedef spirit::rule<ScannerT, unit_closure::context_t> rule_t;
00071 rule_t symbol_exp, unit, quantity, top;
00072
00073 definition(unit_parser const& self) {
00074 namespace unitsymbol=physical::unitsymbol_si_double;
00075
00076 symbol.add("m", unitsymbol::m);
00077 symbol.add("g", unitsymbol::g);
00078 symbol.add("s", unitsymbol::s);
00079 symbol.add("A", unitsymbol::A);
00080 symbol.add("K", unitsymbol::K);
00081 symbol.add("mol", unitsymbol::mol);
00082 symbol.add("cd", unitsymbol::cd);
00083 symbol.add("rad", unitsymbol::rad);
00084 symbol.add("sr", unitsymbol::sr);
00085 symbol.add("Hz", unitsymbol::Hz);
00086 symbol.add("N", unitsymbol::N);
00087 symbol.add("Pa", unitsymbol::Pa);
00088 symbol.add("J", unitsymbol::J);
00089 symbol.add("W", unitsymbol::W);
00090 symbol.add("C", unitsymbol::C);
00091 symbol.add("V", unitsymbol::V);
00092 symbol.add("Ohm", unitsymbol::Omega);
00093 symbol.add("S", unitsymbol::S);
00094 symbol.add("Wb", unitsymbol::Wb);
00095 symbol.add("T", unitsymbol::T);
00096 symbol.add("lm", unitsymbol::lm);
00097 symbol.add("lx", unitsymbol::lx);
00098 symbol.add("Bq", unitsymbol::Bq);
00099 symbol.add("Gy", unitsymbol::Gy);
00100 symbol.add("Sv", unitsymbol::Sv);
00101 symbol.add("kat", unitsymbol::kat);
00102
00103
00104
00105 prefix.add("Y", 1.e24);
00106 prefix.add("Z", 1.e21);
00107 prefix.add("E", 1.e18);
00108 prefix.add("P", 1.e15);
00109 prefix.add("T", 1.e12);
00110 prefix.add("G", 1.e9);
00111 prefix.add("M", 1.e6);
00112 prefix.add("k", 1.e3);
00113 prefix.add("h", 1.e2);
00114 prefix.add("da", 1.e1);
00115 prefix.add("d", 1.e-1);
00116 prefix.add("c", 1.e-2);
00117 prefix.add("m", 1.e-3);
00118 prefix.add("u", 1.e-6);
00119 prefix.add("mu", 1.e-6);
00120 prefix.add("n", 1.e-9);
00121 prefix.add("p", 1.e-12);
00122 prefix.add("f", 1.e-15);
00123 prefix.add("a", 1.e-18);
00124 prefix.add("z", 1.e-21);
00125 prefix.add("y", 1.e-24);
00126
00127 symbol_exp = spirit::epsilon_p[symbol_exp.val = unit_si_double::unity] >>
00128 (
00129 symbol[symbol_exp.val = phoenix::arg1]
00130 >> !('^' >> spirit::int_p[symbol_exp.val = quantity_power(symbol_exp.val, phoenix::arg1)])
00131 ) || (
00132 prefix[symbol_exp.val = phoenix::arg1]
00133 >> symbol[symbol_exp.val *= phoenix::arg1]
00134 >> !('^' >> spirit::int_p[symbol_exp.val = quantity_power(symbol_exp.val, phoenix::arg1)])
00135 );
00136
00137 unit = spirit::epsilon_p[unit.val = unit_si_double::unity] >>
00138 (
00139 spirit::str_p("[]") || spirit::str_p("[1]")
00140 ) || (
00141 "[" >> symbol_exp[unit.val = unit.val * phoenix::arg1]
00142 >> *( ("*" >> symbol_exp[unit.val = unit.val * phoenix::arg1] )
00143 || ("/" >> symbol_exp[unit.val = unit.val / phoenix::arg1] )
00144 ) >> "]"
00145 );
00146
00147 quantity = spirit::real_p[quantity.val = phoenix::arg1]
00148 >> !(unit[quantity.val = quantity.val * phoenix::arg1]);
00149
00150 top = quantity[self.val = phoenix::arg1];
00151 };
00152
00153 rule_t const& start() const { return top; }
00154 };
00155 };
00156
00157 };
00158
00159
00160
00161 parser_exception::parser_exception(const std::string& s, std::size_t n)
00162 : string_to_parse(s)
00163 , sucessfully_parsed_up_to(n)
00164 , std::runtime_error("physical parser error")
00165 { };
00166
00167
00168 DynamicPhysical<SI> Parser::parse(std::string formula) {
00169
00170 #ifdef BOOST_HAS_THREADS
00171
00172
00173 #endif
00174 physical::parser::detail::unit_parser g;
00175 physical::DynamicPhysical<SI> q;
00176
00177 boost::spirit::parse_info<> info = boost::spirit::parse(formula.c_str(), g[phoenix::var(q) = phoenix::arg1], boost::spirit::space_p);
00178
00179 if (info.full)
00180 return q;
00181 else
00182 throw parser_exception(formula, info.length);
00183 };
00184
00185 };
00186
00187 };