8#include <QtCore/QDebug>
10#include <QtCore/QStack>
11#include <QtCore/QStack>
12#include <QtCore/QString>
13#include <QtCore/QCoreApplication>
14#include <QtCore/QStringConverter>
15#include <QtCore/QTextStream>
23enum { Tok_Eof, Tok_class, Tok_return, Tok_tr,
24 Tok_translate, Tok_Ident, Tok_Package,
25 Tok_Comment, Tok_String, Tok_Colon, Tok_Dot,
26 Tok_LeftBrace, Tok_RightBrace, Tok_LeftParen,
27 Tok_RightParen, Tok_Comma, Tok_Semicolon,
28 Tok_Integer, Tok_Plus, Tok_PlusPlus, Tok_PlusEq, Tok_null };
48
49
50
76 return std::cerr << qPrintable(yyFileName) <<
':' << (line ? line :
yyLineNo) <<
": ";
81 if (
yyInPos >= yyInStr.size()) {
85 QChar c = yyInStr[yyInPos++];
86 if (c == QLatin1Char(
'\n'))
93 const char tab[] =
"bfnrt\"\'\\";
94 const char backTab[] =
"\b\f\n\r\t\"\'\\";
103 if (
yyCh.isLetter() || yyCh.toLatin1() ==
'_' ) {
107 }
while ( yyCh.isLetterOrNumber() || yyCh.toLatin1() ==
'_' );
109 if (
yyTok != Tok_Dot) {
110 switch (
yyIdent.at(0).toLatin1() ) {
112 if (
yyIdent == QLatin1String(
"return") )
116 if (
yyIdent == QLatin1String(
"class") )
120 if (
yyIdent == QLatin1String(
"null") )
125 switch (
yyIdent.at(0).toLatin1() ) {
127 if(
yyIdent == QLatin1String(
"package") )
131 if (
yyIdent == QLatin1String(
"tr") )
133 if (
yyIdent == QLatin1String(
"translate") )
134 return Tok_translate;
138 switch (
yyCh.toLatin1() ) {
142 if (
yyCh == QLatin1Char(
'/') ) {
148 }
while (yyCh != QLatin1Char(
'\n'));
151 }
else if (
yyCh == QLatin1Char(
'*') ) {
152 bool metAster =
false;
153 bool metAsterSlash =
false;
155 while ( !metAsterSlash ) {
158 yyMsg() <<
"Unterminated Java comment.\n";
164 if (
yyCh == QLatin1Char(
'*') )
166 else if ( metAster && yyCh == QLatin1Char(
'/') )
167 metAsterSlash =
true;
180 while (!
yyEOF && yyCh != QLatin1Char(
'\n') && yyCh != QLatin1Char(
'"')) {
182 if (
yyCh == QLatin1Char(
'\\') ) {
184 if (
yyCh == QLatin1Char(
'u') ) {
187 for (
int i = 4; i > 0; --i) {
188 unicode = unicode << 4;
189 if(
yyCh.isDigit() ) {
190 unicode += yyCh.digitValue();
193 int sub(
yyCh.toLower().toLatin1() - 87);
194 if( sub > 15 || sub < 10) {
195 yyMsg() <<
"Invalid Unicode value.\n";
204 else if (
yyCh == QLatin1Char(
'\n') ) {
208 yyString.append( QLatin1Char(backTab[strchr( tab, yyCh.toLatin1() ) - tab]) );
217 if (
yyCh != QLatin1Char(
'"') )
218 yyMsg() <<
"Unterminated string.\n";
230 if ( yyCh == QLatin1Char(
'\\') )
234 }
while (!
yyEOF && yyCh != QLatin1Char(
'\''));
239 return Tok_LeftBrace;
242 return Tok_RightBrace;
248 return Tok_LeftParen;
254 return Tok_RightParen;
263 return Tok_Semicolon;
266 if (
yyCh == QLatin1Char(
'+')) {
270 if(
yyCh == QLatin1Char(
'=') ){
287 ba += yyCh.toLatin1();
289 bool hex = yyCh == QLatin1Char(
'x');
291 ba += yyCh.toLatin1();
294 while ( hex ? isxdigit(yyCh.toLatin1()) : yyCh.isDigit() ) {
295 ba += yyCh.toLatin1();
300 if (ok)
return Tok_Integer;
313 bool matches = (
yyTok == t );
321 if (
yyTok != Tok_String )
326 while (
yyTok == Tok_Plus ) {
328 if (
yyTok == Tok_String)
332 "String used in translation can contain only literals"
333 " concatenated with other literals, not expressions or numbers.\n";
343 bool matches = matchString(s);
345 matches = (
yyTok == Tok_null);
353
354
355
356
357
358
359
360
361
362
363
364
365
373 while (
match(Tok_Ident
) || parenlevel > 0) {
374 if (
yyTok == Tok_RightParen) {
375 if (parenlevel == 0)
break;
378 }
else if (
yyTok == Tok_LeftParen) {
380 if (
yyTok == Tok_RightParen) {
385 }
else if (
yyTok == Tok_Ident) {
387 }
else if (parenlevel == 0) {
396 QString context(yyPackage);
397 bool innerClass =
false;
398 for (
int i = 0; i <
yyScope.size(); ++i) {
401 context.append(QLatin1String(
"$"));
403 context.append(QLatin1String(
"."));
405 context.append(yyScope.at(i)->name);
413 Translator *tor,
const QString &context,
const QString &text,
const QString &comment,
417 context, text, comment, QString(),
418 yyFileName,
yyLineNo, QStringList(),
420 msg.setExtraComment(extracomment.simplified());
428 QString extracomment;
434 while (
yyTok != Tok_Eof ) {
438 if(
yyTok == Tok_Ident) {
442 yyMsg() <<
"'class' must be followed by a class name.\n";
445 while (!
match(Tok_LeftBrace
)) {
452 if ( match(Tok_LeftParen) && matchString(text) ) {
458 }
else if (match(Tok_Comma) && matchStringOrNull(com)) {
466 recordMessage(tor, context(), text, com, extracomment, plural, cd);
471 QString contextOverride;
473 if ( match(Tok_LeftParen) &&
474 matchString(contextOverride) &&
476 matchString(text) ) {
482 if ( match(Tok_Comma) && matchStringOrNull(com)) {
495 recordMessage(tor, contextOverride, text, com, extracomment, plural, cd);
505 if (
yyComment.startsWith(QLatin1Char(
':'))) {
507 extracomment.append(yyComment);
514 yyMsg() <<
"Excess closing brace.\n";
518 extracomment.clear();
528 extracomment.clear();
543 yyMsg() <<
"'package' must be followed by package name.\n";
555 if ( !yyScope.isEmpty() )
556 yyMsg(yyScope.top()->line) <<
"Unbalanced opening brace.\n";
564 QFile file(filename);
565 if (!file.open(QIODevice::ReadOnly)) {
566 cd.appendError(QStringLiteral(
"Cannot open %1: %2").arg(filename, file.errorString()));
579 QTextStream ts(&file);
580 ts.setEncoding(cd.m_sourceIsUtf16 ? QStringConverter::Utf16 : QStringConverter::Utf8);
581 ts.setAutoDetectUnicode(
true);
Scope(const QString &name, Type type, int line)
void extend(const TranslatorMessage &msg, ConversionData &cd)
std::ostream & yyMsg(int line=0)
static bool matchString(QString &s)
static bool matchExpression()
bool loadJava(Translator &translator, const QString &filename, ConversionData &cd)
static void parse(Translator *tor, ConversionData &cd)
static QString yyFileName
static QStack< Scope * > yyScope
static bool matchStringOrNull(QString &s)
static const QString context()
static void recordMessage(Translator *tor, const QString &context, const QString &text, const QString &comment, const QString &extracomment, bool plural, ConversionData &cd)
static qlonglong yyInteger