]> git.lyx.org Git - lyx.git/blob - src/Lexer.h
Provide proper fallback if a bibliography processor is not found
[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 #include <string>
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), lastReadOk_(false) { 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         /// Read the next string, as delimited by double quotes or
114         /// whitespace. If esc is true, then we remember that some chars
115         /// might be escaped: \" at least.
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         bool nextToken();
122
123         /// Puts the rest of the line in the buffer, where it will
124         /// be available via getString() or getDocString().
125         bool eatLine();
126
127         /// Push a token, that next token got from lyxlex.
128         void pushToken(std::string const &);
129
130         /// return the current line number
131         int lineNumber() const;
132
133         ///
134         int getInteger() const;
135         ///
136         bool getBool() const;
137         ///
138         double getFloat() const;
139         ///
140         std::string const getString(bool trim = false) const;
141         ///
142         docstring const getDocString(bool trim = false) const;
143         /** Get a long string, ended by the tag `endtag'.
144             This string can span several lines. The first line
145             serves as a template for how many spaces the lines
146             are indented. This much white space is skipped from
147             each following line. This mechanism does not work
148             perfectly if you use tabs.
149         */
150         docstring getLongString(docstring const & endtag);
151
152         /// Pushes a token list on a stack and replaces it with a new one.
153         template<int N> void pushTable(LexerKeyword (&table)[N])
154                 { pushTable(table, N); }
155
156         /** Pops a token list into void and replaces it with the one now
157             on top of the stack.
158         */
159         void popTable();
160
161         /** Prints an error message with the corresponding line number
162             and file name. If message contains the substring `$$Token',
163             it is replaced with the value of GetString()
164         */
165         void printError(std::string const & message) const;
166
167         /// Prints the current token table on the supplied ostream.
168         void printTable(std::ostream &);
169         /// Used to dispaly context information in case of errors.
170         void setContext(std::string const & functionName);
171
172         /// extract string
173         Lexer & operator>>(std::string &);
174         /// extract docstring
175         Lexer & operator>>(docstring &);
176         /// extract double
177         Lexer & operator>>(double &);
178         /// extract integer
179         Lexer & operator>>(int &);
180         /// extract unsigned integer
181         Lexer & operator>>(unsigned int &);
182         /// extract bool
183         Lexer & operator>>(bool &);
184         /// extract first char of the string
185         Lexer & operator>>(char &);
186
187         /// read and check a required token
188         Lexer & operator>>(char const * required);
189         /// check for an optional token and swallow it if present.
190         bool checkFor(char const * required);
191
192         /// Quotes a string so that reading it again with Lexer::next(true)
193         /// gets the original string
194         static std::string quoteString(std::string const &);
195         /// Quotes a docstring so that reading it again with Lexer::next(true)
196         /// gets the original string
197         static docstring quoteString(docstring const &);
198
199 private:
200         /// noncopyable
201         Lexer(Lexer const &);
202         void operator=(Lexer const &);
203
204         ///
205         friend class PushPopHelper;
206
207         ///
208         void init(LexerKeyword *, int);
209         void pushTable(LexerKeyword *, int);
210
211         ///
212         class Pimpl;
213         ///
214         Pimpl * pimpl_;
215         ///
216         mutable bool lastReadOk_;
217 };
218
219
220 /// extract something constructable from a string, i.e. a LaTeX length
221 template <class T>
222 Lexer & operator>>(Lexer & lex, T & t)
223 {
224         if (lex.next())
225                 t = T(lex.getString());
226         return lex;
227 }
228
229
230 /** Use to enable multiple exit points.
231     This is needed to ensure that the pop is done upon exit from methods
232     with more than one exit point or that can return as a response to
233     exceptions.
234     @author Lgb
235 */
236 class PushPopHelper
237 {
238 public:
239         ///
240         template<int N>
241         PushPopHelper(Lexer & l, LexerKeyword (&table)[N])
242                 : lex(l)
243         {
244                 lex.pushTable(table, N);
245         }
246         ///
247         ~PushPopHelper()
248         {
249                 lex.popTable();
250         }
251         ///
252         Lexer & lex;
253 };
254 /** Avoid wrong usage of PushPopHelper.
255     To avoid wrong usage:
256     PushPopHelper(...); // wrong
257     PushPopHelper pph(...); // right
258 */
259 #define PushPopHelper(x, y, z) unnamed_PushPopHelper;
260 // Tip gotten from Bobby Schmidt's column in C/C++ Users Journal
261
262
263 } // namespace lyx
264
265 #endif