View Javadoc

1   /*
2   $Id: LinearParser.java 770 2005-10-13 22:08:27Z paul $
3   */
4   
5   
6   /*
7   Copyright (C) 2001-2002 Mainline Project (I3S - ESSI - CNRS -UNSA)
8   
9   This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13  
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  Lesser General Public License for more details.
18  
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  
23  For further information on the GNU Lesser General Public License,
24  see: http://www.gnu.org/copyleft/lesser.html
25  For further information on this library, contact: mainline@essi.fr
26  */
27  
28  
29  package fr.ove.openmath.jome.ctrl.linear;
30  
31  import java.util.*;
32  
33  import org.util.activemath.JomeConstants;
34  
35  import fr.ove.openmath.jome.ctrl.linear.events.*;
36  import fr.ove.utils.*;
37  
38  /***
39  * A bean which parses, more precisely tokenizes, what we can call the linear form of an expression.<BR>
40  * For each specific token encountered, an event (@see LinearParserEvent) is fired to all the listeners
41  * (@see LinearParserListener) of the instance.<BR>
42  * The event fired is made of 2 parts :
43  * <UL>
44  * <LI> the token identifier (for example, for + (addition) the associated identifier is
45  * <CODE>LinearParserEvent.ADDITION</CODE>)</LI>
46  * <LI> the value of the token, if needed. (for example, when the digit 2 is encountered, the identifier
47  * has the <CODE>LinearParserEvent.INTEGER</CODE> value, and the token value is represented by the @see String "2")</LI>
48  * </UL>
49  * When the parsing starts, an event whith the identifier set to <CODE>LinearParserEvent.START_EXPRESSION</CODE> is
50  * fired.
51  * Similarly, when the parsing ends (the end of the linear form has been reached), an event whith the identifier
52  * set to <CODE>LinearParserEvent.END_EXPRESSION</CODE> is fired.<BR>
53  * In order to make distinctions between what should be variables and special keywords, a resources file
54  * (LinearParserResources.properties) is attached to the parser. This file contains the user defined keywords.<BR>
55  * To add your own keywords, edit this properties file with respect to the used format (see this file for further
56  * details).
57  *
58  * @author Ôø? 1999 DIRAT Laurent
59  * @version 1.0 27/09/1999
60  */
61  public class LinearParser implements java.io.Serializable {
62      /***
63      * The parser resources manager.<BR>
64      * Reads into the properties file (LinearParserResources.properties) to get the user defined specific
65      * keywords.
66      */
67      private ResourcesManager resourcesManager;
68      
69      /***
70      * The list of listeners of the instance
71      */
72      private Vector listeners = new Vector();
73  
74      /***
75      * The event sent to all the listeners of the instance during the parsing.
76      */
77      private LinearParserEvent linearParserEvent = new LinearParserEvent(this);
78      
79      /***
80      * The constructor.
81      */
82      public LinearParser() {
83          resourcesManager = new ResourcesManager("fr.ove.openmath.jome.ctrl.linear.LinearParserResources");
84      }
85      
86      /***
87      * Registers another listener of the instance.
88      * @param linearParserListener the listener to add.
89      */
90      public synchronized void addLinearParserListener(LinearParserListener linearParserListener) {
91          listeners.addElement(linearParserListener);
92      }
93  
94      /***
95      * Removes a listener.
96      * @param linearParserListener the listener to remove.
97      */
98      public synchronized void removeLinearParserListener(LinearParserListener linearParserListener) {
99          listeners.removeElement(linearParserListener);
100     }
101 
102     /***
103     * Fires a LinearParserEvent event to registered listeners.
104     * @param linearParserEvent event encapsulating relevant information.
105     */
106     public void fireLinearParserEvent(LinearParserEvent linearParserEvent) {
107         for (int i = 0; i < listeners.size(); i++)
108           ((LinearParserListener) listeners.elementAt(i)).consumeLinearParserEvent(linearParserEvent);
109     }
110 
111     /***
112     * Parses the specified linear form of the formula.
113     * @param expression the linear form of the formula.
114     */
115     public void parse(String expression) {
116         // Le nombre de tokens utilisÔø?s .
117         int nbTokenUsed = 0;
118         // On spÔø?cifie ici quels sont les tokens qui vont permettre de dÔø?couper
119         // l'expression passÔø?e en argument.
120         StringTokenizer theTokens = new StringTokenizer(expression, "+-/*^_()=<>;, {}[]//?!", true);
121         // Des tokens temporaires pour travailler sur le token suivant le token courant.
122         StringTokenizer tmpTokens = null;
123         // Le token courant
124         String token = null;
125         // Le token suivant le token courant
126         String nextToken = null;
127         
128         // On commence le parsing
129         linearParserEvent.setToken(LinearParserEvent.START_EXPRESSION, null);
130         fireLinearParserEvent(linearParserEvent);
131         
132         boolean isSpecial = false;
133 
134 		int tokenCount = theTokens.countTokens();        
135         while (theTokens.hasMoreTokens()) {
136             token = theTokens.nextToken();
137             nbTokenUsed++;
138 
139             if (token.equals(" "))
140                 continue;
141             else if (token.equals("+"))
142             	if ( isSpecial)
143             		linearParserEvent.setToken(LinearParserEvent.SYMBOL, token);
144                	else
145                		linearParserEvent.setToken(LinearParserEvent.ADDITION, token);
146             else if (token.equals("-"))
147             	if ( isSpecial)
148             		linearParserEvent.setToken(LinearParserEvent.SYMBOL, token);
149                	else
150                		linearParserEvent.setToken(LinearParserEvent.SUBSTRACTION, token);
151             else if (token.equals("*"))
152             	if ( isSpecial)
153             		linearParserEvent.setToken(LinearParserEvent.SYMBOL, token);
154                	else
155                		linearParserEvent.setToken(LinearParserEvent.MULTIPLICATION, token);
156             else if (token.equals("/"))
157             	if ( isSpecial)
158             		linearParserEvent.setToken(LinearParserEvent.SYMBOL, token);
159                	else
160                		linearParserEvent.setToken(LinearParserEvent.DIVISION, token);
161             else if (token.equals("^"))
162           		linearParserEvent.setToken(LinearParserEvent.POWER, token);
163             else if (token.equals("(")){
164 				//linearParserEvent.setToken(LinearParserEvent.SYMBOL, token);
165 				linearParserEvent.setToken(LinearParserEvent.FUNCTION2, token);
166 				fireLinearParserEvent(linearParserEvent);
167                	linearParserEvent.setToken(LinearParserEvent.SYMBOL, token);
168                	fireLinearParserEvent(linearParserEvent);
169                	linearParserEvent.setToken(LinearParserEvent.SEPARATOR, "");
170 
171 				//linearParserEvent.setToken(LinearParserEvent.FUNCTION, "");
172             }else if (token.equals(")"))
173                linearParserEvent.setToken(LinearParserEvent.CLOSE_PAREN, token);
174 				//linearParserEvent.setToken(LinearParserEvent.SYMBOL, token);
175             else if (token.equals("{"))
176                 //linearParserEvent.setToken(LinearParserEvent.GROUP_START, token);
177 				linearParserEvent.setToken(LinearParserEvent.FUNCTION2, token);
178             else if (token.equals("}"))
179                 //linearParserEvent.setToken(LinearParserEvent.GROUP_END, token);
180 				linearParserEvent.setToken(LinearParserEvent.CLOSE_CURLY, null);
181             else if (token.equals("[")){
182 				linearParserEvent.setToken(LinearParserEvent.FUNCTION2, token);
183 				fireLinearParserEvent(linearParserEvent);
184                 linearParserEvent.setToken(LinearParserEvent.OPEN_BRACKET, token);
185             }else if (token.equals("]"))
186                 linearParserEvent.setToken(LinearParserEvent.CLOSE_BRACKET, token);
187             else if (token.equals("_"))
188                linearParserEvent.setToken(LinearParserEvent.UNDERSCRIPT, token);
189             else if (token.equals(",") || token.equals(";"))
190                linearParserEvent.setToken(LinearParserEvent.SEPARATOR, token);
191             else if (token.equals("//")){
192 
193                 tmpTokens = new StringTokenizer(expression, "+-/*^_()=<>;, {}[]//?!", true );
194                 for (int i = 0; i < nbTokenUsed + 1; i++) {
195                     try {
196                         nextToken = tmpTokens.nextToken();
197                     }
198                     catch (NoSuchElementException  e) {
199                         nextToken = null;
200                     }
201                 }
202             	
203 					if (nextToken != null ) {
204 						String token2 = token+nextToken;
205 						String str2 = null;
206 					/*	if (nextToken.equals("{")) {
207 							theTokens.nextToken();
208 							nbTokenUsed++;
209 							//linearParserEvent.setToken(LinearParserEvent.OPEN_CURLY, "{");
210 							linearParserEvent.setToken(LinearParserEvent.FUNCTION2 , token);
211 							// On passe outre le token suivant, i.e. la parenthÔø?se ouvrante.
212 							//theTokens.nextToken();
213 							//nbTokenUsed++;
214 							fireLinearParserEvent(linearParserEvent);
215 							linearParserEvent.setToken(LinearParserEvent.OPEN_CURLY, "{");
216 							
217 							
218 						} else if (nextToken.equals("}")) {
219 							theTokens.nextToken();
220 							nbTokenUsed++;
221 							linearParserEvent.setToken(LinearParserEvent.CLOSE_CURLY, "}");
222 						} else*/ if (JomeConstants.SYMBOLS.containsKey(token2)){
223 							theTokens.nextToken();
224 							nbTokenUsed++;
225 							linearParserEvent.setToken(LinearParserEvent.SYMBOL, token2);
226 						}
227 						/*else if ( (str2 = resourcesManager.getResourceString(nextToken)) != null){
228 							theTokens.nextToken();
229 							nbTokenUsed++;
230 							linearParserEvent.setToken((str2.equals("RESERVED") ? LinearParserEvent.RESERVED : LinearParserEvent.SPECIALIZED), nextToken);
231 
232 						}*/else{
233 						//	linearParserEvent.setToken(LinearParserEvent.VARIABLE, nextToken);
234 						//	theTokens.nextToken();
235 						//	nbTokenUsed++;
236 							isSpecial = true;
237 							continue;
238 						}
239 						
240 					}
241             	
242             	
243             }else if (token.equals("<") || token.equals(">")) {
244                 // On re-tokenize l'expression pour rÔø?cupÔø?rer l'Ôø?lement suivant le token
245                 // (Ôø? dÔø?faut d'autre chose.... :o( )
246                 tmpTokens = new StringTokenizer(expression, "+-/*^_()=<>;, {}[]//?!", true );
247                 for (int i = 0; i < nbTokenUsed + 1; i++) {
248                     try {
249                         nextToken = tmpTokens.nextToken();
250                     }
251                     catch (NoSuchElementException  e) {
252                         nextToken = null;
253                     }
254                 }
255 
256                 if (token.equals("<")) {
257                     if (nextToken != null ) {
258                         if (nextToken.equals("=")) {
259                             theTokens.nextToken();
260                             nbTokenUsed++;
261                             linearParserEvent.setToken(LinearParserEvent.LESSEQUAL, "<=");
262                         }
263                         else if (nextToken.equals(">")) {
264                             theTokens.nextToken();
265                             nbTokenUsed++;
266                             linearParserEvent.setToken(LinearParserEvent.UNEQUAL, "<>");
267                         }
268                         else
269                             linearParserEvent.setToken(LinearParserEvent.LESS, token);
270                     }
271                     else
272                         linearParserEvent.setToken(LinearParserEvent.LESS, token);
273                 }
274                 else if(token.equals(">")) {
275                     if (nextToken != null ) {
276                         if (nextToken.equals("=")) {
277                             theTokens.nextToken();
278                             nbTokenUsed++;
279                             linearParserEvent.setToken(LinearParserEvent.GREATEREQUAL, ">=");
280                         }
281                         else
282                             linearParserEvent.setToken(LinearParserEvent.GREATER, token);
283                     }
284                     else
285                         linearParserEvent.setToken(LinearParserEvent.GREATER, token);
286                 }						else
287 							linearParserEvent.setToken(LinearParserEvent.SPECIALIZED, token);
288             }
289             else if (token.equals("="))
290             	if ( isSpecial)
291             		linearParserEvent.setToken(LinearParserEvent.SYMBOL, token);
292                	else
293                		linearParserEvent.setToken(LinearParserEvent.EQUAL, token);
294            // else if (token.equals("//")){
295 			//	linearParserEvent.setToken(LinearParserEvent.SPECIALIZED, token);
296            // }
297             else if (token.equals("?"))
298                 linearParserEvent.setToken(LinearParserEvent.SPECIALIZED, token);
299             else if (token.equals("!"))
300                 linearParserEvent.setToken(LinearParserEvent.SPECIALIZED, "fact");
301             else {
302                 if (NumberUtils.isNumber(token)) {
303                     if (NumberUtils.isFloat(token))
304                         linearParserEvent.setToken(LinearParserEvent.FLOAT, token);
305                     else
306                         linearParserEvent.setToken(LinearParserEvent.INTEGER, token);
307                 }
308                 else {
309                     // On a saisi des lettres. Il faut qu'on regarde si Ôø? la suite de ces
310                     // lettres, il n'y a pas comme token suivant une parenthÔø?se. Si tel est le cas,
311                     // c'est que l'on a voulu saisir une fonction.
312 
313                     // On re-tokenize l'expression pour rÔø?cupÔø?rer l'Ôø?lement suivant le token
314                     // (Ôø? dÔø?faut d'autre chose.... :o( )
315                     tmpTokens = new StringTokenizer(expression, "+-/*^_()=<>;, {}[]//?!", true );
316                     for (int i = 0; i < nbTokenUsed + 1; i++) {
317                         try {
318                             nextToken = tmpTokens.nextToken();
319                         }
320                         catch (NoSuchElementException  e) {
321                             nextToken = null;
322                         }
323                     }
324 
325                     if (nextToken != null) {
326                         if (nextToken.equals("(") && !isSpecial) {
327                             // C'est une fonction
328                             linearParserEvent.setToken(LinearParserEvent.FUNCTION , token);
329                             // On passe outre le token suivant, i.e. la parenthÔø?se ouvrante.
330                             //theTokens.nextToken();
331                             //nbTokenUsed++;
332 							//fireLinearParserEvent(linearParserEvent);
333 							//linearParserEvent.setToken(LinearParserEvent.VARIABLE,token);
334 							// On passe outre le token suivant, i.e. la parenthÔø?se ouvrante.
335 							theTokens.nextToken();
336 							nbTokenUsed++;
337 							//fireLinearParserEvent(linearParserEvent);
338 							
339                         }
340                         else {
341                             String str1 = resourcesManager.getResourceString(token);
342                             if (isSpecial || str1 == null)
343                                 // C'est une variable.
344                                 linearParserEvent.setToken(LinearParserEvent.VARIABLE, token);
345                             else
346                                 linearParserEvent.setToken(
347                                         (str1.equals("RESERVED") ? LinearParserEvent.RESERVED : LinearParserEvent.SPECIALIZED),
348                                         token);
349                         }
350                     }
351                     else {
352                             String str2 = resourcesManager.getResourceString(token);
353                             if (isSpecial || str2 == null)
354                                 // C'est une variable.
355                                 linearParserEvent.setToken(LinearParserEvent.VARIABLE, token);
356                             else
357                                 linearParserEvent.setToken(
358                                         (str2.equals("RESERVED") ? LinearParserEvent.RESERVED : LinearParserEvent.SPECIALIZED),
359                                         token);
360                     }
361                 }
362             }
363             
364             fireLinearParserEvent(linearParserEvent);
365             isSpecial = false;
366         }
367         
368         // On a fini le parsing
369         linearParserEvent.setToken(LinearParserEvent.END_EXPRESSION, null);
370         fireLinearParserEvent(linearParserEvent);
371     }
372     
373    
374     public static void main(String args[]) {
375         LinearParserListener l = new LinearParserListener() {
376             public void consumeLinearParserEvent(LinearParserEvent linearParserEvent) {
377                 System.out.println(linearParserEvent.toString());
378             }
379         };
380         
381         LinearParser lp = new LinearParser();
382         lp.addLinearParserListener(l);
383         lp.parse("1+2+23+C+in+pi+x_8");
384     }
385 }