{
token_type_ty type;
char *string; /* for token_type_string_literal, token_type_symbol */
+ refcounted_string_list_ty *comment; /* for token_type_string_literal */
int line_number;
};
+/* Free the memory pointed to by a 'struct token_ty'. */
+static inline void
+free_token (token_ty *tp)
+{
+ if (tp->type == token_type_string_literal || tp->type == token_type_symbol)
+ free (tp->string);
+ if (tp->type == token_type_string_literal)
+ drop_reference (tp->comment);
+}
+
/* 2. Combine characters into tokens. Discard comments and whitespace. */
buffer[bufpos] = 0;
tp->type = token_type_string_literal;
tp->string = xstrdup (buffer);
+ tp->comment = add_reference (savable_comment);
return;
case '+':
/* 3. Combine "# string_literal" and "# symbol" to a single token. */
-static token_ty phase3_pushback[1];
+static token_ty phase3_pushback[2];
static int phase3_pushback_length;
static void
if (token2.type == token_type_symbol
|| token2.type == token_type_string_literal)
{
+ if (token2.type == token_type_string_literal)
+ drop_reference (token2.comment);
tp->type = token_type_string_literal;
tp->string = token2.string;
+ tp->comment = add_reference (savable_comment);
}
else
phase2_unget (&token2);
}
}
-/* Supports only one pushback token. */
+/* Supports 2 pushback tokens. */
static void
phase3_unget (token_ty *tp)
{
}
+/* 4. String literal concatenation:
+ Combine "string1" , "string2" to "string1string2". */
+
+/* Concatenates two strings, and frees the first argument. */
+static char *
+string_concat_free1 (char *s1, const char *s2)
+{
+ size_t len1 = strlen (s1);
+ size_t len2 = strlen (s2);
+ size_t len = len1 + len2 + 1;
+ char *result = XNMALLOC (len, char);
+ memcpy (result, s1, len1);
+ memcpy (result + len1, s2, len2 + 1);
+ free (s1);
+ return result;
+}
+
+static token_ty phase4_pushback[1];
+static int phase4_pushback_length;
+
+static void
+phase4_get (token_ty *tp)
+{
+ if (phase4_pushback_length)
+ {
+ *tp = phase4_pushback[--phase4_pushback_length];
+ return;
+ }
+
+ phase3_get (tp);
+ if (tp->type == token_type_string_literal)
+ {
+ char *sum = tp->string;
+
+ for (;;)
+ {
+ token_ty token2;
+
+ phase3_get (&token2);
+ if (token2.type == token_type_symbol
+ && strcmp (token2.string, ",") == 0)
+ {
+ token_ty token3;
+
+ phase3_get (&token3);
+ if (token3.type == token_type_string_literal)
+ {
+ sum = string_concat_free1 (sum, token3.string);
+
+ free_token (&token3);
+ free_token (&token2);
+ continue;
+ }
+ phase3_unget (&token3);
+ }
+ phase3_unget (&token2);
+ break;
+ }
+ tp->string = sum;
+ }
+}
+
+/* Supports only one pushback token. */
+static void
+phase4_unget (token_ty *tp)
+{
+ if (tp->type != token_type_eof)
+ {
+ if (phase4_pushback_length == SIZEOF (phase4_pushback))
+ abort ();
+ phase4_pushback[phase4_pushback_length++] = *tp;
+ }
+}
+
+
/* ========================= Extracting strings. ========================== */
/* The file is broken into tokens. Scan the token stream, looking for the
phase2_pushback_length = 0;
phase3_pushback_length = 0;
+ phase4_pushback_length = 0;
/* Eat tokens until eof is seen. */
{
{
token_ty token;
- phase3_get (&token);
+ phase4_get (&token);
switch (token.type)
{
strcmp (token.string, "at:") == 0 && state == 1 ? 3 :
strcmp (token.string, "plural:") == 0 && state == 4 ? 5 :
0);
- free (token.string);
+ free_token (&token);
break;
case token_type_string_literal:
pos.line_number = token.line_number;
remember_a_message (mlp, NULL, token.string, false, false,
null_context_region (), &pos,
- NULL, savable_comment, false);
+ NULL, token.comment, false);
state = 0;
break;
}
pos.file_name = logical_file_name;
pos.line_number = token.line_number;
- phase3_get (&token2);
+ phase4_get (&token2);
plural_mp =
remember_a_message (mlp, NULL, token.string, false,
token2.type == token_type_symbol
&& strcmp (token.string, "plural:") == 0,
null_context_region (), &pos,
- NULL, savable_comment, false);
+ NULL, token.comment, false);
- phase3_unget (&token2);
+ phase4_unget (&token2);
state = 4;
break;
if (plural_mp != NULL)
remember_a_message_plural (plural_mp, token.string, false,
null_context_region (), &pos,
- savable_comment, false);
+ token.comment, false);
state = 0;
break;
}
state = 0;
- free (token.string);
+ free_token (&token);
break;
case token_type_uniq: