]> git.lyx.org Git - lyx.git/blob - src/Lexer.h
* src/frontends/qt4/GuiPrefs.cpp:
[lyx.git] / src / Lexer.h
1 // -*- C++ -*-
2 /**
3  * \file Lexer.h
4  * This file is part of LyX, the document processor.
5  * Licence details can be found in the file COPYING.
6  *
7  * \author Alejandro Aguilar Sierra
8  * \author Lars Gullik Bjønnes
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 //  Generalized simple lexical analizer.
14 //  It can be used for simple syntax parsers, like lyxrc,
15 //  texclass and others to come.
16
17 #ifndef LEXER_H
18 #define LEXER_H
19
20 #include "support/strfwd.h"
21
22
23 namespace lyx {
24
25 namespace support { class FileName; }
26
27 class PushPopHelper;
28
29 /** A helper structure to describe a keyword for the Lexer.
30         Usually used bundled in C style arrays and passed to the 
31         Lexer using a LexerKeywordTable object.
32 */
33 struct LexerKeyword
34 {
35         /// the string to be recognized
36         char const * tag;
37         /// a corresponding numerical id
38         int code;
39 };
40
41
42 /** Generalized simple lexical analizer.
43         Use the method isOK() to check if there is still data available
44         for lexing. Use one of the the operators void* or ! to test if
45         the last reading operation was successful.
46
47         Example:
48
49         int readParam(LyxLex & lex)
50         {
51                 int param = 1;    // default value
52                 if (lex.isOK()) { // the lexer has data to read
53                         int p;          // temporary variable
54                         lex >> p;
55                         if (lex)
56                                 param = p; // only use the input if reading was successful
57                 }
58                 return param;
59         }
60
61     @see LyXRC.cpp for an example of usage.
62   */
63 class Lexer
64 {
65 public:
66         /// initialize Lexer with no special keywords.
67         Lexer(); 
68         /// initialize Lexer with a bunch of keywords
69         template<int N> Lexer(LexerKeyword (&table)[N])
70                 : pimpl_(0) { init(table, N); }
71
72         ///
73         ~Lexer();
74
75         /// Lex basic codes
76         enum {
77                 ///
78                 LEX_UNDEF = -1,
79                 ///
80                 LEX_FEOF  = -2,
81                 ///
82                 LEX_DATA  = -3,
83                 ///
84                 LEX_TOKEN = -4
85         };
86
87         /// stream is open and end of stream is not reached
88         /// FIXME: test also if pushToken is not empty
89         /// FIXME: the method should be renamed to something like
90         ///        dataAvailable(), in order to reflect the real behavior
91         bool isOK() const;
92         /// FIXME: The next two operators should be replaced by one method
93         ///        called e.g. lastReadOk(), in order to reflect the real
94         ///        behavior
95         /// last read operation was successful.
96         operator void const *() const;
97         /// last read operation was not successful
98         bool operator!() const;
99         /// return true if able to open file, else false
100         bool setFile(support::FileName const & filename);
101         ///
102         void setStream(std::istream & is);
103         ///
104         std::istream & getStream();
105         /// Danger! Don't use it unless you know what you are doing.
106         void setLineNumber(int l);
107         /// Change the character that begins a comment. Default is '#'
108         void setCommentChar(char c);
109
110         /// returns a lex code
111         int lex();
112
113         /** Just read the next word. If esc is true remember that
114             some chars might be escaped: "\ atleast
115         */
116         bool next(bool esc = false);
117
118         /** Read next token. This one is almost the same as next,
119             but it will consider " as a regular character and always
120             split a word if it contains a backslash.
121         */
122         bool nextToken();
123         /// Push a token, that next token got from lyxlex.
124         void pushToken(std::string const &);
125
126         /// return the current line number
127         int lineNumber() const;
128
129         ///
130         int getInteger() const;
131         ///
132         bool getBool() const;
133         ///
134         double getFloat() const;
135         ///
136         std::string const getString() const;
137
138         ///
139         docstring const getDocString() const;
140
141         /** Get a long string, ended by the tag `endtag'.
142             This string can span several lines. The first line
143             serves as a template for how many spaces the lines
144             are indented. This much white space is skipped from
145             each following line. This mechanism does not work
146             perfectly if you use tabs.
147         */
148         std::string const getLongString(std::string const & endtag);
149
150         ///
151         bool eatLine();
152
153         /// Pushes a token list on a stack and replaces it with a new one.
154         template<int N> void pushTable(LexerKeyword (&table)[N])
155                 { pushTable(table, N); }
156
157         /** Pops a token list into void and replaces it with the one now
158             on top of the stack.
159         */
160         void popTable();
161
162         /** Prints an error message with the corresponding line number
163             and file name. If message contains the substring `$$Token',
164             it is replaced with the value of GetString()
165         */
166         void printError(std::string const & message) const;
167
168         /// Prints the current token table on the supplied ostream.
169         void printTable(std::ostream &);
170         /// Used to dispaly context information in case of errors.
171         void setContext(std::string const & functionName);
172
173         /// extract string
174         Lexer & operator>>(std::string &);
175         /// extract docstring
176         Lexer & operator>>(docstring &);
177         /// extract double
178         Lexer & operator>>(double &);
179         /// extract integer
180         Lexer & operator>>(int &);
181         /// extract unsigned integer
182         Lexer & operator>>(unsigned int &);
183         /// extract bool
184         Lexer & operator>>(bool &);
185
186         /// read and check a required token
187         Lexer & operator>>(char const * required);
188
189         /// Quotes a string so that reading it again with Lexer::next(true)
190         /// gets the original string
191         static std::string quoteString(std::string const &);
192
193 private:
194         /// noncopyable
195         Lexer(Lexer const &);
196         void operator=(Lexer const &);
197
198         ///
199         friend class PushPopHelper;
200
201         ///
202         void init(LexerKeyword *, int);
203         void pushTable(LexerKeyword *, int);
204
205         ///
206         class Pimpl;
207         ///
208         Pimpl * pimpl_;
209         ///
210         mutable bool lastReadOk_;
211 };
212
213
214 /// extract something constructable from a string, i.e. a LaTeX length
215 template <class T>
216 Lexer & operator>>(Lexer & lex, T & t)
217 {
218         if (lex.next())
219                 t = T(lex.getString());
220         return lex;
221 }
222
223
224 /** Use to enable multiple exit points.
225     This is needed to ensure that the pop is done upon exit from methods
226     with more than one exit point or that can return as a response to
227     exceptions.
228     @author Lgb
229 */
230 class PushPopHelper
231 {
232 public:
233         ///
234         template<int N>
235         PushPopHelper(Lexer & l, LexerKeyword (&table)[N])
236                 : lex(l)
237         {
238                 lex.pushTable(table, N);
239         }
240         ///
241         ~PushPopHelper()
242         {
243                 lex.popTable();
244         }
245         ///
246         Lexer & lex;
247 };
248 /** Avoid wrong usage of PushPopHelper.
249     To avoid wrong usage:
250     PushPopHelper(...); // wrong
251     PushPopHelper pph(...); // right
252 */
253 #define PushPopHelper(x, y, z) unnamed_PushPopHelper;
254 // Tip gotten from Bobby Schmidt's column in C/C++ Users Journal
255
256
257 } // namespace lyx
258
259 #endif