Back to index

texmacs  1.0.7.15
math_language.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : math_language.cpp
00004 * DESCRIPTION: mathematical languages
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "analyze.hpp"
00013 #include "hyphenate.hpp"
00014 #include "impl_language.hpp"
00015 #include "file.hpp"
00016 #include "iterator.hpp"
00017 #include "packrat_grammar.hpp"
00018 
00019 /******************************************************************************
00020 * Mathematical languages
00021 ******************************************************************************/
00022 
00023 struct math_language_rep: language_rep {
00024   hashmap<string,string>            group;
00025   hashmap<string,text_property_rep> tpr_class;
00026   hashmap<string,text_property_rep> tpr_member;
00027 
00028   math_language_rep (string name);
00029   void set_type (string cl, string s);
00030   void set_left_penalty (string cl, string s);
00031   void set_right_penalty (string cl, string s);
00032   void set_left_spacing (string cl, string s);
00033   void set_right_spacing (string cl, string s);
00034   void set_limits (string cl, string s);
00035 
00036   void skip_spaces (string s, int& pos, space fn_spc, space& spc);
00037   string next_word (string s, int& pos);
00038   text_property advance (tree t, int& pos);
00039   array<int> get_hyphens (string s);
00040   void hyphenate (string s, int after, string& left, string& right);
00041   string get_group (string s);
00042   array<string> get_members (string s);
00043 };
00044 
00045 /******************************************************************************
00046 * Load a mathematical language
00047 ******************************************************************************/
00048 
00049 void
00050 math_language_rep::set_type (string cl, string s) {
00051   int &ot= tpr_class(cl).op_type;
00052   if (s == "symbol") ot= OP_SYMBOL;
00053   else if (s == "unary") ot= OP_UNARY;
00054   else if (s == "binary") ot= OP_BINARY;
00055   else if (s == "n-ary") ot= OP_N_ARY;
00056   else if (s == "prefix") ot= OP_PREFIX;
00057   else if (s == "postfix") ot= OP_POSTFIX;
00058   else if (s == "infix") ot= OP_INFIX;
00059   else if (s == "separator") ot= OP_SEPARATOR;
00060   else if (s == "opening-bracket") ot= OP_OPENING_BRACKET;
00061   else if (s == "middle-bracket") ot= OP_MIDDLE_BRACKET;
00062   else if (s == "closing-bracket") ot= OP_CLOSING_BRACKET;
00063   else {
00064     cerr << "Attempt to associate type " << s << " to " << cl << "\n";
00065     FAILED ("invalid type");
00066   }
00067 }
00068 
00069 void
00070 math_language_rep::set_left_penalty (string cl, string s) {
00071   if (is_int (s)) tpr_class(cl).pen_before= as_int (s);
00072   else if (s == "panic")   tpr_class(cl).pen_before= HYPH_PANIC;
00073   else if (s == "invalid") tpr_class(cl).pen_before= HYPH_INVALID;
00074   else {
00075     cerr << "Attempt to associate left penalty " << s << " to " << cl << "\n";
00076     FAILED ("invalid penalty");
00077   }
00078 }
00079 
00080 void
00081 math_language_rep::set_right_penalty (string cl, string s) {
00082   if (is_int (s)) tpr_class(cl).pen_after= as_int (s);
00083   else if (s == "panic")   tpr_class(cl).pen_after= HYPH_PANIC;
00084   else if (s == "invalid") tpr_class(cl).pen_after= HYPH_INVALID;
00085   else {
00086     cerr << "Attempt to associate right penalty " << s << " to " << cl << "\n";
00087     FAILED ("invalid penalty");
00088   }
00089 }
00090 
00091 void
00092 math_language_rep::set_left_spacing (string cl, string s) {
00093   if      (s == "none")    tpr_class(cl).spc_before= SPC_NONE;
00094   else if (s == "half")    tpr_class(cl).spc_before= SPC_HALF;
00095   else if (s == "default") tpr_class(cl).spc_before= SPC_OPERATOR;
00096   else if (s == "big")     tpr_class(cl).spc_before= SPC_BIGOP;
00097   else {
00098     cerr << "Attempt to associate left spacing " << s << " to " << cl << "\n";
00099     FAILED ("invalid spacing");
00100   }
00101 }
00102 
00103 void
00104 math_language_rep::set_right_spacing (string cl, string s) {
00105   if      (s == "none")    tpr_class(cl).spc_after= SPC_NONE;
00106   else if (s == "half")    tpr_class(cl).spc_after= SPC_HALF;
00107   else if (s == "default") tpr_class(cl).spc_after= SPC_OPERATOR;
00108   else if (s == "big")     tpr_class(cl).spc_after= SPC_BIGOP;
00109   else {
00110     cerr << "Attempt to associate right spacing " << s << " to " << cl << "\n";
00111     FAILED ("invalid spacing");
00112   }
00113 }
00114 
00115 void
00116 math_language_rep::set_limits (string cl, string s) {
00117   if      (s == "none")    tpr_class(cl).limits= LIMITS_NONE;
00118   else if (s == "display") tpr_class(cl).limits= LIMITS_DISPLAY;
00119   else if (s == "always")  tpr_class(cl).limits= LIMITS_ALWAYS;
00120   else {
00121     cerr << "Attempt to associate limits " << s << " to " << cl << "\n";
00122     FAILED ("invalid limits");
00123   }
00124 }
00125 
00126 //math_language_rep::math_language_rep (string name, string s):
00127 math_language_rep::math_language_rep (string name):
00128   language_rep (name),
00129   group ("symbol"),
00130   tpr_class (text_property_rep ()),
00131   tpr_member (text_property_rep ())
00132 {
00133   language::instances (name)= (pointer) this;
00134   tpr_class("symbol").op_type = OP_SYMBOL;
00135 
00136   packrat_grammar gr= find_packrat_grammar (name);
00137   hashmap<D,string> props= gr->properties;
00138   hashmap<string,bool> cls (false);
00139   iterator<D> it= iterate (props);
00140   while (it->busy ()) {
00141     D key = it->next ();
00142     C prop= ((C) (key >> 32));
00143     C sym = ((C) (key & 0xffffffff)) ^ prop;
00144     ASSERT (is_compound (packrat_decode[sym], "symbol", 1) &&
00145            is_compound (packrat_decode[prop], "property", 1),
00146            "invalid symbol or property");
00147     string cl = packrat_decode[sym ][0]->label;
00148     string var= packrat_decode[prop][0]->label;
00149     string val= props[key];
00150     //cout << cl << ", " << var << " -> " << val << "\n";
00151     if (var == "type") { set_type (cl, val); cls (cl)= true; }
00152     else if (var == "left-penalty") set_left_penalty (cl, val);
00153     else if (var == "right-penalty") set_right_penalty (cl, val);
00154     else if (var == "left-spacing") set_left_spacing (cl, val);
00155     else if (var == "right-spacing") set_right_spacing (cl, val);
00156     else if (var == "limits") set_limits (cl, val);
00157   }
00158 
00159   iterator<string> it2= iterate (cls);
00160   while (it2->busy ()) {
00161     string cl= it2->next ();
00162     array<string> a= gr->members (cl);
00163     for (int i=0; i<N(a); i++) {
00164       group (a[i])= cl;
00165       tpr_member (a[i])= tpr_class [cl];
00166     }
00167   }
00168 }
00169 
00170 /******************************************************************************
00171 * Advancing a word
00172 ******************************************************************************/
00173 
00174 string
00175 math_language_rep::next_word (string s, int& pos) {
00176   int start= pos;
00177 
00178   if (pos>=N(s)) return string ("");
00179 
00180   if ((s[pos]>='0') && (s[pos]<='9')) {
00181     while ((pos<N(s)) && is_numeric (s[pos])) pos++;
00182     while (s[pos-1]=='.') pos--;
00183     return s (start, pos);
00184   }
00185 
00186   if (is_alpha (s[pos])) {
00187     while ((pos<N(s)) && (is_alpha (s[pos]))) pos++;
00188     return s (start, pos);
00189   }
00190 
00191   if (s[pos]=='<') {
00192     while ((pos<N(s)) && (s[pos]!='>')) pos++;
00193     if (pos<N(s)) pos++;
00194     return s (start, pos);
00195   }
00196 
00197   pos++;
00198   return s (start, pos);
00199 }
00200 
00201 text_property
00202 math_language_rep::advance (tree t, int& pos) {
00203   string s= t->label;
00204   bool op_flag1=
00205     (pos==0) ||
00206     ((pos>=2) && is_alpha (s[pos-2]) && is_alpha (s[pos-1]));
00207   string r= next_word (s, pos);
00208   if (r == " ") {
00209     bool op_flag2=
00210       (pos==N(s)) ||
00211       (((pos+2)<N(s)) && is_alpha (s[pos]) && is_alpha (s[pos+1]));
00212     if (op_flag1 || op_flag2) return &tp_operator_rep;
00213     else return &tp_shortop_rep;
00214   }
00215   return &tpr_member(r);
00216 
00217   /****************************** variant *******************************
00218   string r= next_word (s, pos);
00219   if (r == " ") return &tp_operator_rep;
00220   else return &tpr_member(r);
00221   **********************************************************************/
00222 }
00223 
00224 /******************************************************************************
00225 * Hyphenation
00226 ******************************************************************************/
00227 
00228 array<int>
00229 math_language_rep::get_hyphens (string s) {
00230   ASSERT (N(s) != 0, "hyphenation of empty string");
00231   int i, n= N(s)-1;
00232   bool flag= is_numeric (s);
00233   array<int> penalty (n);
00234   for (i=0; i<n; i++) penalty[i]= (flag? HYPH_PANIC: HYPH_INVALID);
00235   if (n>0) penalty[0]= penalty[n-1]= HYPH_INVALID;
00236   if (n>2) penalty[1]= penalty[n-2]= HYPH_INVALID;
00237   if (n>4) penalty[2]= penalty[n-3]= HYPH_INVALID;
00238   return penalty;
00239 }
00240 
00241 void
00242 math_language_rep::hyphenate (string s, int after, string& left, string& right)
00243 {
00244   left = s (0, after+1) * string ("\\");
00245   right= s (after+1, N(s));
00246 }
00247 
00248 /******************************************************************************
00249 * Get the group (class) of a symbol
00250 ******************************************************************************/
00251 
00252 string
00253 math_language_rep::get_group (string s) {
00254   return group[s];
00255 }
00256 
00257 array<string>
00258 math_language_rep::get_members (string g) {
00259   array<string> r;
00260   iterator<string> it= iterate (group);
00261   while (it->busy ()) {
00262     string s= it->next ();
00263     if (group[s] == g) r << s;
00264   }
00265   return r;
00266 }
00267 
00268 /******************************************************************************
00269 * Interface
00270 ******************************************************************************/
00271 
00272 language
00273 math_language (string name) {
00274   if (language::instances -> contains (name)) return language (name);
00275   return tm_new<math_language_rep> (name);
00276 }
00277 
00278 string
00279 math_symbol_group (string sym, string lang) {
00280   language lan= math_language (lang);
00281   return lan->get_group (sym);
00282 }
00283 
00284 array<string>
00285 math_group_members (string gr, string lang) {
00286   language lan= math_language (lang);
00287   return lan->get_members (gr);
00288 }
00289 
00290 string
00291 math_symbol_type (string sym, string lang) {
00292   int pos= 0;
00293   language lan= math_language (lang);
00294   text_property prop= lan->advance (tree (sym), pos);
00295   switch (prop->op_type) {
00296   case OP_UNKNOWN:
00297     return "unknown";
00298   case OP_SYMBOL:
00299     return "symbol";
00300   case OP_UNARY:
00301     return "unary";
00302   case OP_BINARY:
00303     return "binary";
00304   case OP_N_ARY:
00305     return "n-ary";
00306   case OP_PREFIX:
00307     return "prefix";
00308   case OP_POSTFIX:
00309     return "postfix";
00310   case OP_INFIX:
00311     return "infix";
00312   case OP_SEPARATOR:
00313     return "separator";
00314   case OP_OPENING_BRACKET:
00315     return "opening-bracket";
00316   case OP_MIDDLE_BRACKET:
00317     return "middle-bracket";
00318   case OP_CLOSING_BRACKET:
00319     return "closing-bracket";
00320   }
00321   return "unknown";
00322 }