OpenSolaris_b135/cmd/genmsg/genmsg.y

%{
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdio.h>
#include <libintl.h>
#include <limits.h>	
#include "genmsg.h"
extern int is_cat_found;		/* from main.c */
extern int lineno;			/* genmsg.l */
extern int msg_line;			/* genmsg.l */
extern int end_of_cat;			/* from genmsg.l */
extern void set_linemsgid(int, int);	/* from genmsg.l */
extern void add_msg(int, int, char *, char *, int, int); /* from util.c */
extern void set_msgid(int, int);
extern int get_msgid(char *, int, int, char *);
extern void warning(char *);
extern void yyerror(char *);

static void do_catgets(int, int, char *);
static char *add_qstring(char *, char *);
%}

%union {
	char *str;
	int id;
}

%token CATGETS
%token CONST
%token CATD
%token INT, CHAR, INC
%token <str> STR
%token <id> SETID, MSGID, DIGIT
%token <str> QSTR

%type <id> cast_setid, setid, cast_msgid, msgid, cast_digit, digit
%type <str> catd, arg_list, arg_def, arg_func, arg_exp, str,
	cast_qstr, paren_qstr, qstr_list

%left '-' '+'
%left '*' '/'
%nonassoc UMINUS

%%

genmsg_list:	/* empty */
		{
			if (!IsActiveMode(ReplaceMode)) {
				src_err(srcfile, (lineno - 1),
				    gettext("catgets not found"));
			}
		}
	|	genmsg			{ is_cat_found = TRUE; }
	;

genmsg:		catgets			{ end_of_cat = TRUE; }
	|	genmsg catgets		{ end_of_cat = TRUE; }
	;

catgets:	CATGETS '(' catd ',' cast_setid ',' cast_msgid ',' cast_qstr ')'
		{
			do_catgets($5, $7, $9); free($9);
		}
	|	error
	;

catd:		'(' CATD ')' arg_list		{ $$ = $4; }
	|	'(' CONST CATD ')' arg_list	{ $$ = $5; }
	|	arg_list
	;

arg_list:	arg_def
	|	arg_list '-' '>' arg_def
	|	'(' arg_list '-' '>' arg_def ')' { $$ = $2; }
	;

arg_def:	arg_func
	|	arg_exp
	|	str
	;

arg_func:	'(' arg_func ')'	{ $$ = $2; }
	|	str '(' ')'
	|	str '(' str ')'
	|	str '(' cast_digit ')'
	|	str '(' cast_qstr ')'	{ free($3); }
	;

arg_exp:	'(' arg_exp ')'		{ $$ = $2; }
	|	str INC
	|	INC str			{ $$ = $2; }
	;

str:		'(' str ')'		{ $$ = $2; }
	|	'*' str			{ $$ = $2; }
	|	STR
	;

cast_setid:	'(' INT ')' setid	{ $$ = $4; }
	|	'(' CONST INT ')' setid	{ $$ = $5; }
	|	setid
	;

setid:		setid '+' setid		{ $$ = $1 + $3; }
	|	setid '-' setid		{ $$ = $1 - $3; }
	|	setid '*' setid		{ $$ = $1 * $3; }
	|	setid '/' setid
		{
			if ($3 == 0) {
				yyerror(gettext("zero divide"));
			} else {
				$$ = $1 / $3;
			}
		}
	|	'-' setid %prec UMINUS	{ $$ = -$2; }
	|	'(' setid ')'		{ $$ = $2; }
	|	SETID
	;

cast_msgid:	'(' INT ')' msgid	{ $$ = $4; }
	|	'(' CONST INT ')' msgid	{ $$ = $5; }
	|	msgid
	;

msgid:		msgid '+' msgid		{ $$ = $1 + $3; }
	|	msgid '-' msgid		{ $$ = $1 - $3; }
	|	msgid '*' msgid		{ $$ = $1 * $3; }
	|	msgid '/' msgid
		{
			if ($3 == 0) {
				yyerror(gettext("zero devide"));
			} else {
				$$ = $1 / $3;
			}
		}
	|	'-' msgid %prec UMINUS	{ $$ = -$2; }
	|	'(' msgid ')'		{ $$ = $2; }
	|	MSGID
	;

cast_digit:	'(' INT ')' digit	{ $$ = $4; }
	|	'(' CONST INT ')' digit	{ $$ = $5; }
	|	digit
	;

digit:		digit '+' digit		{ $$ = $1 + $3; }
	|	digit '-' digit		{ $$ = $1 - $3; }
	|	digit '*' digit		{ $$ = $1 * $3; }
	|	digit '/' digit
		{
			if ($3 == 0) {
				yyerror(gettext("zero divide"));
			} else {
				$$ = $1 / $3;
			}
		}
	|	'-' digit %prec UMINUS	{ $$ = -$2; }
	|	'(' digit ')'		{ $$ = $2; }
	|	DIGIT
	;

cast_qstr:	'(' CHAR '*' ')' paren_qstr		{ $$ = $5; }
	|	'(' CONST CHAR '*' ')' paren_qstr	{ $$ = $6; }
	|	paren_qstr
	;

paren_qstr:	'(' qstr_list ')'	{ $$ = $2; }
	|	qstr_list
	;

qstr_list:	QSTR
	|	qstr_list QSTR		{ $$ = add_qstring($1, $2); }
	;

%%

static void
do_catgets(int setid, int msgid, char *str)
{
	int id = msgid;
	if (IsActiveMode(ReplaceMode)) {
		return;
	}
	if (setid == 0 || setid > NL_SETMAX) {
		src_err(srcfile, lineno,
		    gettext("improper set number: %d"), setid);
		return;
	}
	if (IsActiveMode(ProjectMode)) {
		set_msgid(setid, id);
		add_msg(setid, id, str, srcfile, lineno, TRUE);
	} else if (IsActiveMode(ReverseMode)) {
		set_linemsgid(msg_line, NOMSGID);
	} else if (IsActiveMode(AutoNumMode)) {
		if (id == NOMSGID) {
			id = get_msgid(srcfile, msg_line, setid, str);
			set_linemsgid(msg_line, id);
		}
		if (id != NOMSGID) {
			set_msgid(setid, id);
			add_msg(setid, id, str, srcfile, lineno, FALSE);
		}
	} else if (id == NOMSGID) {
		warning(gettext("improper message number: -1"));
	} else {
		add_msg(setid, id, str, srcfile, lineno, FALSE);
	}
}

static char *
add_qstring(char *str, char *add)
{
	int len = strlen(str) + strlen(add) + 3;
	/* 3 includes '\', '\n' and '\0' */
	char *tmp = malloc(len);
	if (tmp == NULL) {
		prg_err(gettext("fatal: out of memory"));
		exit(EXIT_FAILURE);
	}
	(void) snprintf(tmp, len, "%s\\\n%s", str, add);
	free(str);
	free(add);
	return (tmp);
}