1 /* xgettext PHP backend.
2 Copyright (C) 2001-2003, 2005-2010 Free Software Foundation, Inc.
4 This file was written by Bruno Haible <bruno@clisp.org>, 2002.
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
37 #define _(s) gettext(s)
39 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
42 /* The PHP syntax is defined in phpdoc/manual/langref.html.
43 See also php-4.1.0/Zend/zend_language_scanner.l
44 and php-4.1.0/Zend/zend_language_parser.y.
45 Note that variable and function names can contain bytes in the range
47 http://www.php.net/manual/en/language.variables.php
48 http://www.php.net/manual/en/language.functions.php */
51 /* ====================== Keyword set customization. ====================== */
53 /* If true extract all strings. */
54 static bool extract_all = false;
56 static hash_table keywords;
57 static bool default_keywords = true;
68 x_php_keyword (const char *name)
71 default_keywords = false;
75 struct callshape shape;
78 if (keywords.table == NULL)
79 hash_init (&keywords, 100);
81 split_keywordspec (name, &end, &shape);
83 /* The characters between name and end should form a valid C identifier.
84 A colon means an invalid parse in split_keywordspec(). */
85 colon = strchr (name, ':');
86 if (colon == NULL || colon >= end)
87 insert_keyword_callshape (&keywords, name, end - name, &shape);
91 /* Finish initializing the keywords hash table.
92 Called after argument processing, before each file is processed. */
98 /* When adding new keywords here, also update the documentation in
101 x_php_keyword ("gettext");
102 x_php_keyword ("dgettext:2");
103 x_php_keyword ("dcgettext:2");
104 /* The following were added in PHP 4.2.0. */
105 x_php_keyword ("ngettext:1,2");
106 x_php_keyword ("dngettext:2,3");
107 x_php_keyword ("dcngettext:2,3");
108 default_keywords = false;
113 init_flag_table_php ()
115 xgettext_record_flag ("_:1:pass-php-format");
116 xgettext_record_flag ("gettext:1:pass-php-format");
117 xgettext_record_flag ("dgettext:2:pass-php-format");
118 xgettext_record_flag ("dcgettext:2:pass-php-format");
119 xgettext_record_flag ("ngettext:1:pass-php-format");
120 xgettext_record_flag ("ngettext:2:pass-php-format");
121 xgettext_record_flag ("dngettext:2:pass-php-format");
122 xgettext_record_flag ("dngettext:3:pass-php-format");
123 xgettext_record_flag ("dcngettext:2:pass-php-format");
124 xgettext_record_flag ("dcngettext:3:pass-php-format");
125 xgettext_record_flag ("sprintf:1:php-format");
126 xgettext_record_flag ("printf:1:php-format");
130 /* ======================== Reading of characters. ======================== */
133 /* Real filename, used in error messages about the input file. */
134 static const char *real_file_name;
136 /* Logical filename and line number, used to label the extracted messages. */
137 static char *logical_file_name;
138 static int line_number;
140 /* The input file stream. */
144 /* 1. line_number handling. */
146 static unsigned char phase1_pushback[2];
147 static int phase1_pushback_length;
154 if (phase1_pushback_length)
155 c = phase1_pushback[--phase1_pushback_length];
163 error (EXIT_FAILURE, errno, _("error while reading \"%s\""),
175 /* Supports 2 characters of pushback. */
177 phase1_ungetc (int c)
184 if (phase1_pushback_length == SIZEOF (phase1_pushback))
186 phase1_pushback[phase1_pushback_length++] = c;
191 /* 2. Ignore HTML sections. They are equivalent to PHP echo commands and
192 therefore don't contain translatable strings. */
199 int c = phase1_getc ();
206 int c2 = phase1_getc ();
213 /* <?php is the normal way to enter PHP mode. <? and <?= are
214 recognized by PHP depending on a configuration setting. */
215 int c3 = phase1_getc ();
225 /* <% and <%= are recognized by PHP depending on a configuration
227 int c3 = phase1_getc ();
241 /* < script language = php >
242 < script language = "php" >
243 < script language = 'php' >
244 are always recognized. */
245 while (c2 == ' ' || c2 == '\t' || c2 == '\n' || c2 == '\r')
247 if (c2 != 's' && c2 != 'S')
253 if (c2 != 'c' && c2 != 'C')
259 if (c2 != 'r' && c2 != 'R')
265 if (c2 != 'i' && c2 != 'I')
271 if (c2 != 'p' && c2 != 'P')
277 if (c2 != 't' && c2 != 'T')
283 if (!(c2 == ' ' || c2 == '\t' || c2 == '\n' || c2 == '\r'))
290 while (c2 == ' ' || c2 == '\t' || c2 == '\n' || c2 == '\r');
291 if (c2 != 'l' && c2 != 'L')
297 if (c2 != 'a' && c2 != 'A')
303 if (c2 != 'n' && c2 != 'N')
309 if (c2 != 'g' && c2 != 'G')
315 if (c2 != 'u' && c2 != 'U')
321 if (c2 != 'a' && c2 != 'A')
327 if (c2 != 'g' && c2 != 'G')
333 if (c2 != 'e' && c2 != 'E')
339 while (c2 == ' ' || c2 == '\t' || c2 == '\n' || c2 == '\r')
347 while (c2 == ' ' || c2 == '\t' || c2 == '\n' || c2 == '\r')
424 while (c2 == ' ' || c2 == '\t' || c2 == '\n' || c2 == '\r')
438 static unsigned char phase2_pushback[1];
439 static int phase2_pushback_length;
446 if (phase2_pushback_length)
447 return phase2_pushback[--phase2_pushback_length];
455 int c2 = phase1_getc ();
458 /* ?> and %> terminate PHP mode and switch back to HTML mode. */
468 int c2 = phase1_getc ();
470 /* < / script > terminates PHP mode and switches back to HTML mode. */
471 while (c2 == ' ' || c2 == '\t' || c2 == '\n' || c2 == '\r')
477 while (c2 == ' ' || c2 == '\t' || c2 == '\n' || c2 == '\r');
478 if (c2 == 's' || c2 == 'S')
481 if (c2 == 'c' || c2 == 'C')
484 if (c2 == 'r' || c2 == 'R')
487 if (c2 == 'i' || c2 == 'I')
490 if (c2 == 'p' || c2 == 'P')
493 if (c2 == 't' || c2 == 'T')
497 while (c2 == ' ' || c2 == '\t'
498 || c2 == '\n' || c2 == '\r');
520 phase2_ungetc (int c)
524 if (phase2_pushback_length == SIZEOF (phase2_pushback))
526 phase2_pushback[phase2_pushback_length++] = c;
533 /* Accumulating comments. */
536 static size_t bufmax;
537 static size_t buflen;
548 if (buflen >= bufmax)
550 bufmax = 2 * bufmax + 10;
551 buffer = xrealloc (buffer, bufmax);
553 buffer[buflen++] = c;
557 comment_line_end (size_t chars_to_remove)
559 buflen -= chars_to_remove;
561 && (buffer[buflen - 1] == ' ' || buffer[buflen - 1] == '\t'))
563 if (chars_to_remove == 0 && buflen >= bufmax)
565 bufmax = 2 * bufmax + 10;
566 buffer = xrealloc (buffer, bufmax);
568 buffer[buflen] = '\0';
569 savable_comment_add (buffer);
573 /* 3. Replace each comment that is not inside a string literal with a
574 space character. We need to remember the comment for later, because
575 it may be attached to a keyword string. */
577 /* These are for tracking whether comments count as immediately before
579 static int last_comment_line;
580 static int last_non_comment_line;
582 static unsigned char phase3_pushback[1];
583 static int phase3_pushback_length;
591 if (phase3_pushback_length)
592 return phase3_pushback[--phase3_pushback_length];
599 bool last_was_qmark = false;
602 lineno = line_number;
606 if (c == '\n' || c == EOF)
608 comment_line_end (0);
611 if (last_was_qmark && c == '>')
613 comment_line_end (1);
617 /* We skip all leading white space, but not EOLs. */
618 if (!(buflen == 0 && (c == ' ' || c == '\t')))
620 last_was_qmark = (c == '?' || c == '%');
622 last_comment_line = lineno;
641 lineno = line_number;
642 last_was_star = false;
648 /* We skip all leading white space, but not EOLs. */
649 if (buflen == 0 && (c == ' ' || c == '\t'))
655 comment_line_end (1);
657 lineno = line_number;
658 last_was_star = false;
662 last_was_star = true;
668 comment_line_end (2);
674 last_was_star = false;
679 last_comment_line = lineno;
686 bool last_was_qmark = false;
689 lineno = line_number;
693 if (c == '\n' || c == EOF)
695 comment_line_end (0);
698 if (last_was_qmark && c == '>')
700 comment_line_end (1);
704 /* We skip all leading white space, but not EOLs. */
705 if (!(buflen == 0 && (c == ' ' || c == '\t')))
707 last_was_qmark = (c == '?' || c == '%');
709 last_comment_line = lineno;
720 phase3_ungetc (int c)
724 if (phase3_pushback_length == SIZEOF (phase3_pushback))
726 phase3_pushback[phase3_pushback_length++] = c;
732 /* ========================== Reading of tokens. ========================== */
738 token_type_lparen, /* ( */
739 token_type_rparen, /* ) */
740 token_type_comma, /* , */
741 token_type_lbracket, /* [ */
742 token_type_rbracket, /* ] */
743 token_type_dot, /* . */
744 token_type_operator1, /* * / % ++ -- */
745 token_type_operator2, /* + - ! ~ @ */
746 token_type_string_literal, /* "abc" */
747 token_type_symbol, /* symbol, number */
748 token_type_other /* misc. operator */
750 typedef enum token_type_ty token_type_ty;
752 typedef struct token_ty token_ty;
756 char *string; /* for token_type_string_literal, token_type_symbol */
757 refcounted_string_list_ty *comment; /* for token_type_string_literal */
762 /* Free the memory pointed to by a 'struct token_ty'. */
764 free_token (token_ty *tp)
766 if (tp->type == token_type_string_literal || tp->type == token_type_symbol)
768 if (tp->type == token_type_string_literal)
769 drop_reference (tp->comment);
773 /* 4. Combine characters into tokens. Discard whitespace. */
775 static token_ty phase4_pushback[3];
776 static int phase4_pushback_length;
779 phase4_get (token_ty *tp)
786 if (phase4_pushback_length)
788 *tp = phase4_pushback[--phase4_pushback_length];
795 tp->line_number = line_number;
800 tp->type = token_type_eof;
804 if (last_non_comment_line > last_comment_line)
805 savable_comment_reset ();
810 /* Ignore whitespace. */
814 last_non_comment_line = tp->line_number;
818 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
819 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
820 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
821 case 'V': case 'W': case 'X': case 'Y': case 'Z':
823 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
824 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
825 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
826 case 'v': case 'w': case 'x': case 'y': case 'z':
827 case 127: case 128: case 129: case 130: case 131: case 132: case 133:
828 case 134: case 135: case 136: case 137: case 138: case 139: case 140:
829 case 141: case 142: case 143: case 144: case 145: case 146: case 147:
830 case 148: case 149: case 150: case 151: case 152: case 153: case 154:
831 case 155: case 156: case 157: case 158: case 159: case 160: case 161:
832 case 162: case 163: case 164: case 165: case 166: case 167: case 168:
833 case 169: case 170: case 171: case 172: case 173: case 174: case 175:
834 case 176: case 177: case 178: case 179: case 180: case 181: case 182:
835 case 183: case 184: case 185: case 186: case 187: case 188: case 189:
836 case 190: case 191: case 192: case 193: case 194: case 195: case 196:
837 case 197: case 198: case 199: case 200: case 201: case 202: case 203:
838 case 204: case 205: case 206: case 207: case 208: case 209: case 210:
839 case 211: case 212: case 213: case 214: case 215: case 216: case 217:
840 case 218: case 219: case 220: case 221: case 222: case 223: case 224:
841 case 225: case 226: case 227: case 228: case 229: case 230: case 231:
842 case 232: case 233: case 234: case 235: case 236: case 237: case 238:
843 case 239: case 240: case 241: case 242: case 243: case 244: case 245:
844 case 246: case 247: case 248: case 249: case 250: case 251: case 252:
845 case 253: case 254: case 255:
849 if (bufpos >= bufmax)
851 bufmax = 2 * bufmax + 10;
852 buffer = xrealloc (buffer, bufmax);
854 buffer[bufpos++] = c;
858 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
859 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
860 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
861 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
864 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
865 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
866 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
867 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
869 case '0': case '1': case '2': case '3': case '4':
870 case '5': case '6': case '7': case '8': case '9':
871 case 127: case 128: case 129: case 130: case 131: case 132:
872 case 133: case 134: case 135: case 136: case 137: case 138:
873 case 139: case 140: case 141: case 142: case 143: case 144:
874 case 145: case 146: case 147: case 148: case 149: case 150:
875 case 151: case 152: case 153: case 154: case 155: case 156:
876 case 157: case 158: case 159: case 160: case 161: case 162:
877 case 163: case 164: case 165: case 166: case 167: case 168:
878 case 169: case 170: case 171: case 172: case 173: case 174:
879 case 175: case 176: case 177: case 178: case 179: case 180:
880 case 181: case 182: case 183: case 184: case 185: case 186:
881 case 187: case 188: case 189: case 190: case 191: case 192:
882 case 193: case 194: case 195: case 196: case 197: case 198:
883 case 199: case 200: case 201: case 202: case 203: case 204:
884 case 205: case 206: case 207: case 208: case 209: case 210:
885 case 211: case 212: case 213: case 214: case 215: case 216:
886 case 217: case 218: case 219: case 220: case 221: case 222:
887 case 223: case 224: case 225: case 226: case 227: case 228:
888 case 229: case 230: case 231: case 232: case 233: case 234:
889 case 235: case 236: case 237: case 238: case 239: case 240:
890 case 241: case 242: case 243: case 244: case 245: case 246:
891 case 247: case 248: case 249: case 250: case 251: case 252:
892 case 253: case 254: case 255:
901 if (bufpos >= bufmax)
903 bufmax = 2 * bufmax + 10;
904 buffer = xrealloc (buffer, bufmax);
907 tp->string = xstrdup (buffer);
908 tp->type = token_type_symbol;
912 /* Single-quoted string literal. */
917 if (c == EOF || c == '\'')
922 if (c != '\\' && c != '\'')
928 if (bufpos >= bufmax)
930 bufmax = 2 * bufmax + 10;
931 buffer = xrealloc (buffer, bufmax);
933 buffer[bufpos++] = c;
935 if (bufpos >= bufmax)
937 bufmax = 2 * bufmax + 10;
938 buffer = xrealloc (buffer, bufmax);
941 tp->type = token_type_string_literal;
942 tp->string = xstrdup (buffer);
943 tp->comment = add_reference (savable_comment);
947 /* Double-quoted string literal. */
948 tp->type = token_type_string_literal;
953 if (c == EOF || c == '"')
958 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
959 || c == '_' || c == '{' || c >= 0x7f)
961 /* String with variables. */
962 tp->type = token_type_other;
973 /* String with expressions. */
974 tp->type = token_type_other;
992 case '0': case '1': case '2': case '3':
993 case '4': case '5': case '6': case '7':
995 for (j = 0; j < 3; ++j)
1004 case '0': case '1': case '2': case '3':
1005 case '4': case '5': case '6': case '7':
1016 for (j = 0; j < 2; ++j)
1021 case '0': case '1': case '2': case '3': case '4':
1022 case '5': case '6': case '7': case '8': case '9':
1023 n = n * 16 + c - '0';
1025 case 'A': case 'B': case 'C': case 'D': case 'E':
1027 n = n * 16 + 10 + c - 'A';
1029 case 'a': case 'b': case 'c': case 'd': case 'e':
1031 n = n * 16 + 10 + c - 'a';
1043 phase1_ungetc ('x');
1066 if (bufpos >= bufmax)
1068 bufmax = 2 * bufmax + 10;
1069 buffer = xrealloc (buffer, bufmax);
1071 buffer[bufpos++] = c;
1073 if (bufpos >= bufmax)
1075 bufmax = 2 * bufmax + 10;
1076 buffer = xrealloc (buffer, bufmax);
1079 if (tp->type == token_type_string_literal)
1081 tp->string = xstrdup (buffer);
1082 tp->comment = add_reference (savable_comment);
1089 int c2 = phase1_getc ();
1092 /* ?> and %> terminate PHP mode and switch back to HTML
1095 tp->type = token_type_other;
1100 tp->type = (c == '%' ? token_type_operator1 : token_type_other);
1106 tp->type = token_type_lparen;
1110 tp->type = token_type_rparen;
1114 tp->type = token_type_comma;
1118 tp->type = token_type_lbracket;
1122 tp->type = token_type_rbracket;
1126 tp->type = token_type_dot;
1131 tp->type = token_type_operator1;
1137 int c2 = phase1_getc ();
1140 tp->type = token_type_operator1;
1145 tp->type = token_type_operator2;
1153 tp->type = token_type_operator2;
1158 int c2 = phase1_getc ();
1161 int c3 = phase1_getc ();
1164 /* Start of here document.
1165 Parse whitespace, then label, then newline. */
1168 while (c == ' ' || c == '\t' || c == '\n' || c == '\r');
1173 if (bufpos >= bufmax)
1175 bufmax = 2 * bufmax + 10;
1176 buffer = xrealloc (buffer, bufmax);
1178 buffer[bufpos++] = c;
1181 while (c != EOF && c != '\n' && c != '\r');
1182 /* buffer[0..bufpos-1] now contains the label. */
1184 /* Now skip the here document. */
1190 if (c == '\n' || c == '\r')
1194 while (bufidx < bufpos)
1199 if (c != buffer[bufidx])
1206 if (bufidx == bufpos)
1212 if (c == '\n' || c == '\r')
1218 /* FIXME: Ideally we should turn the here document into a
1219 string literal if it didn't contain $ substitution. And
1220 we should also respect backslash escape sequences like
1221 in double-quoted strings. */
1222 tp->type = token_type_other;
1228 /* < / script > terminates PHP mode and switches back to HTML
1230 while (c2 == ' ' || c2 == '\t' || c2 == '\n' || c2 == '\r')
1231 c2 = phase1_getc ();
1235 c2 = phase1_getc ();
1236 while (c2 == ' ' || c2 == '\t' || c2 == '\n' || c2 == '\r');
1237 if (c2 == 's' || c2 == 'S')
1239 c2 = phase1_getc ();
1240 if (c2 == 'c' || c2 == 'C')
1242 c2 = phase1_getc ();
1243 if (c2 == 'r' || c2 == 'R')
1245 c2 = phase1_getc ();
1246 if (c2 == 'i' || c2 == 'I')
1248 c2 = phase1_getc ();
1249 if (c2 == 'p' || c2 == 'P')
1251 c2 = phase1_getc ();
1252 if (c2 == 't' || c2 == 'T')
1255 c2 = phase1_getc ();
1256 while (c2 == ' ' || c2 == '\t'
1257 || c2 == '\n' || c2 == '\r');
1286 tp->type = token_type_other;
1291 /* Execution operator. */
1293 /* We could carefully recognize each of the 2 and 3 character
1294 operators, but it is not necessary, as we only need to recognize
1295 gettext invocations. Don't bother. */
1296 tp->type = token_type_other;
1302 /* Supports 3 tokens of pushback. */
1304 phase4_unget (token_ty *tp)
1306 if (tp->type != token_type_eof)
1308 if (phase4_pushback_length == SIZEOF (phase4_pushback))
1310 phase4_pushback[phase4_pushback_length++] = *tp;
1315 /* 5. Compile-time optimization of string literal concatenation.
1316 Combine "string1" . ... . "stringN" to the concatenated string if
1317 - the token before this expression is none of
1318 '+' '-' '.' '*' '/' '%' '!' '~' '++' '--' ')' '@'
1319 (because then the first string could be part of an expression with
1320 the same or higher precedence as '.', such as an additive,
1321 multiplicative, negation, preincrement, or cast expression),
1322 - the token after this expression is none of
1323 '*' '/' '%' '++' '--'
1324 (because then the last string could be part of an expression with
1325 higher precedence as '.', such as a multiplicative or postincrement
1328 static token_type_ty phase5_last;
1331 x_php_lex (token_ty *tp)
1334 if (tp->type == token_type_string_literal
1335 && !(phase5_last == token_type_dot
1336 || phase5_last == token_type_operator1
1337 || phase5_last == token_type_operator2
1338 || phase5_last == token_type_rparen))
1340 char *sum = tp->string;
1341 size_t sum_len = strlen (sum);
1347 phase4_get (&token2);
1348 if (token2.type == token_type_dot)
1352 phase4_get (&token3);
1353 if (token3.type == token_type_string_literal)
1355 token_ty token_after;
1357 phase4_get (&token_after);
1358 if (token_after.type != token_type_operator1)
1360 char *addend = token3.string;
1361 size_t addend_len = strlen (addend);
1363 sum = (char *) xrealloc (sum, sum_len + addend_len + 1);
1364 memcpy (sum + sum_len, addend, addend_len + 1);
1365 sum_len += addend_len;
1367 phase4_unget (&token_after);
1368 free_token (&token3);
1369 free_token (&token2);
1372 phase4_unget (&token_after);
1374 phase4_unget (&token3);
1376 phase4_unget (&token2);
1381 phase5_last = tp->type;
1385 /* ========================= Extracting strings. ========================== */
1388 /* Context lookup table. */
1389 static flag_context_list_table_ty *flag_context_list_table;
1392 /* The file is broken into tokens. Scan the token stream, looking for
1393 a keyword, followed by a left paren, followed by a string. When we
1394 see this sequence, we have something to remember. We assume we are
1395 looking at a valid C or C++ program, and leave the complaints about
1396 the grammar to the compiler.
1398 Normal handling: Look for
1399 keyword ( ... msgid ... )
1400 Plural handling: Look for
1401 keyword ( ... msgid ... msgid_plural ... )
1403 We use recursion because the arguments before msgid or between msgid
1404 and msgid_plural can contain subexpressions of the same form. */
1407 /* Extract messages until the next balanced closing parenthesis or bracket.
1408 Extracted messages are added to MLP.
1409 DELIM can be either token_type_rparen or token_type_rbracket, or
1410 token_type_eof to accept both.
1411 Return true upon eof, false upon closing parenthesis or bracket. */
1413 extract_balanced (message_list_ty *mlp,
1414 token_type_ty delim,
1415 flag_context_ty outer_context,
1416 flag_context_list_iterator_ty context_iter,
1417 struct arglist_parser *argparser)
1419 /* Current argument number. */
1421 /* 0 when no keyword has been seen. 1 right after a keyword is seen. */
1423 /* Parameters of the keyword just seen. Defined only in state 1. */
1424 const struct callshapes *next_shapes = NULL;
1425 /* Context iterator that will be used if the next token is a '('. */
1426 flag_context_list_iterator_ty next_context_iter =
1427 passthrough_context_list_iterator;
1428 /* Current context. */
1429 flag_context_ty inner_context =
1430 inherited_context (outer_context,
1431 flag_context_list_iterator_advance (&context_iter));
1433 /* Start state is 0. */
1443 case token_type_symbol:
1445 void *keyword_value;
1447 if (hash_find_entry (&keywords, token.string, strlen (token.string),
1451 next_shapes = (const struct callshapes *) keyword_value;
1458 flag_context_list_iterator (
1459 flag_context_list_table_lookup (
1460 flag_context_list_table,
1461 token.string, strlen (token.string)));
1462 free (token.string);
1465 case token_type_lparen:
1466 if (extract_balanced (mlp, token_type_rparen,
1467 inner_context, next_context_iter,
1468 arglist_parser_alloc (mlp,
1469 state ? next_shapes : NULL)))
1471 arglist_parser_done (argparser, arg);
1474 next_context_iter = null_context_list_iterator;
1478 case token_type_rparen:
1479 if (delim == token_type_rparen || delim == token_type_eof)
1481 arglist_parser_done (argparser, arg);
1484 next_context_iter = null_context_list_iterator;
1488 case token_type_comma:
1491 inherited_context (outer_context,
1492 flag_context_list_iterator_advance (
1494 next_context_iter = passthrough_context_list_iterator;
1498 case token_type_lbracket:
1499 if (extract_balanced (mlp, token_type_rbracket,
1500 null_context, null_context_list_iterator,
1501 arglist_parser_alloc (mlp, NULL)))
1503 arglist_parser_done (argparser, arg);
1506 next_context_iter = null_context_list_iterator;
1510 case token_type_rbracket:
1511 if (delim == token_type_rbracket || delim == token_type_eof)
1513 arglist_parser_done (argparser, arg);
1516 next_context_iter = null_context_list_iterator;
1520 case token_type_string_literal:
1523 pos.file_name = logical_file_name;
1524 pos.line_number = token.line_number;
1527 remember_a_message (mlp, NULL, token.string, inner_context,
1528 &pos, NULL, token.comment);
1530 arglist_parser_remember (argparser, arg, token.string,
1532 pos.file_name, pos.line_number,
1534 drop_reference (token.comment);
1536 next_context_iter = null_context_list_iterator;
1540 case token_type_dot:
1541 case token_type_operator1:
1542 case token_type_operator2:
1543 case token_type_other:
1544 next_context_iter = null_context_list_iterator;
1548 case token_type_eof:
1549 arglist_parser_done (argparser, arg);
1560 extract_php (FILE *f,
1561 const char *real_filename, const char *logical_filename,
1562 flag_context_list_table_ty *flag_table,
1563 msgdomain_list_ty *mdlp)
1565 message_list_ty *mlp = mdlp->item[0]->messages;
1568 real_file_name = real_filename;
1569 logical_file_name = xstrdup (logical_filename);
1572 last_comment_line = -1;
1573 last_non_comment_line = -1;
1575 phase5_last = token_type_eof;
1577 flag_context_list_table = flag_table;
1581 /* Initial mode is HTML mode, not PHP mode. */
1584 /* Eat tokens until eof is seen. When extract_balanced returns
1585 due to an unbalanced closing parenthesis, just restart it. */
1586 while (!extract_balanced (mlp, token_type_eof,
1587 null_context, null_context_list_iterator,
1588 arglist_parser_alloc (mlp, NULL)))
1591 /* Close scanner. */
1593 real_file_name = NULL;
1594 logical_file_name = NULL;