C:/nobackup/private/physical_svn/trunk/source/parser.cpp

Go to the documentation of this file.
00001 
00002 /*=============================================================================
00003     physical quantities / units / constants
00004     Copyright (c) 2006, 2007 Martin Schulz
00005     http://physical.sourceforge.net
00006   
00007     This is private code by Martin Schulz.
00008   
00009     Use, modification and distribution is subject to the Boost Software
00010     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
00011     http://www.boost.org/LICENSE_1_0.txt)
00012 =============================================================================*/
00013 
00014 #include "physical/parser.hpp"
00015 #include "physical/dynamicphysical.hpp"
00016 #include "physical/unitsymbol.hpp"
00017 
00018 // boost spirit parser generator:
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); // special character?
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                                                    // Fixme what about celsius, Fahrenheit, reaumur ?
00103                                                    // Fixme what about day, hour, minute ?
00104                                                    // Fixme what about long unit names? (meter, second..)
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); // use some special character for mu?
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          }; // namespace detail
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          // FIXME: if you move the parser object into the class, define some scoped lock here 
00172          // (additional mutex in class) to protect grammar (closure!) from concurrent access.
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         }; // namespace parser
00186 
00187 }; // namespace physical

Generated on Mon Apr 2 22:25:05 2007 for physical_svn by  doxygen 1.5.1-p1
hosted on SourceForge.net Logo