summaryrefslogtreecommitdiffstats
path: root/scripts/dtc
diff options
context:
space:
mode:
authorMasahiro Yamada <yamada.masahiro@socionext.com>2018-12-30 22:59:26 +0900
committerSascha Hauer <s.hauer@pengutronix.de>2019-01-03 10:17:16 +0100
commit273dbe5f87de8d6129a68ad40e87922fb6e783b6 (patch)
tree41f19d7c159df88aa1dee4bff084f3e57dfc18db /scripts/dtc
parentc17116dc3818b45cbc3997de72d05e64aab04cbe (diff)
downloadbarebox-273dbe5f87de8d6129a68ad40e87922fb6e783b6.tar.gz
barebox-273dbe5f87de8d6129a68ad40e87922fb6e783b6.tar.xz
kbuild: generate lexer and parser during build instead of shipping
Recent kernel versions run flex and bison to generate lexers and parsers from real source files such as *.l and *.y . This provides better maintainability than version-controlling pre-generated C files with a "_shipped" suffix. This commit imports flex and bison rules from Linux, and deletes pre-generated parsers and lexers. Refer to the following commits in Linux: - 033dba2ec06c ("kbuild: prepare to remove C files pre-generated by flex and bison") - 29c833061c1d ("kconfig: generate lexer and parser during build instead of shipping") - e039139be8c2 ("scripts/dtc: generate lexer and parser during build instead of shipping") Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'scripts/dtc')
-rw-r--r--scripts/dtc/dtc-lexer.l306
-rw-r--r--scripts/dtc/dtc-parser.y538
2 files changed, 0 insertions, 844 deletions
diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l
deleted file mode 100644
index fd825ebba6..0000000000
--- a/scripts/dtc/dtc-lexer.l
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- */
-
-%option noyywrap nounput noinput never-interactive
-
-%x BYTESTRING
-%x PROPNODENAME
-%s V1
-
-PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
-PATHCHAR ({PROPNODECHAR}|[/])
-LABEL [a-zA-Z_][a-zA-Z0-9_]*
-STRING \"([^\\"]|\\.)*\"
-CHAR_LITERAL '([^']|\\')*'
-WS [[:space:]]
-COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
-LINECOMMENT "//".*\n
-
-%{
-#include "dtc.h"
-#include "srcpos.h"
-#include "dtc-parser.tab.h"
-
-YYLTYPE yylloc;
-extern bool treesource_error;
-
-/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
-#define YY_USER_ACTION \
- { \
- srcpos_update(&yylloc, yytext, yyleng); \
- }
-
-/*#define LEXDEBUG 1*/
-
-#ifdef LEXDEBUG
-#define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
-#else
-#define DPRINT(fmt, ...) do { } while (0)
-#endif
-
-static int dts_version = 1;
-
-#define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
- BEGIN(V1); \
-
-static void push_input_file(const char *filename);
-static bool pop_input_file(void);
-static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
-
-%}
-
-%%
-<*>"/include/"{WS}*{STRING} {
- char *name = strchr(yytext, '\"') + 1;
- yytext[yyleng-1] = '\0';
- push_input_file(name);
- }
-
-<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
- char *line, *fnstart, *fnend;
- struct data fn;
- /* skip text before line # */
- line = yytext;
- while (!isdigit((unsigned char)*line))
- line++;
-
- /* regexp ensures that first and list "
- * in the whole yytext are those at
- * beginning and end of the filename string */
- fnstart = memchr(yytext, '"', yyleng);
- for (fnend = yytext + yyleng - 1;
- *fnend != '"'; fnend--)
- ;
- assert(fnstart && fnend && (fnend > fnstart));
-
- fn = data_copy_escape_string(fnstart + 1,
- fnend - fnstart - 1);
-
- /* Don't allow nuls in filenames */
- if (memchr(fn.val, '\0', fn.len - 1))
- lexical_error("nul in line number directive");
-
- /* -1 since #line is the number of the next line */
- srcpos_set_line(xstrdup(fn.val), atoi(line) - 1);
- data_free(fn);
- }
-
-<*><<EOF>> {
- if (!pop_input_file()) {
- yyterminate();
- }
- }
-
-<*>{STRING} {
- DPRINT("String: %s\n", yytext);
- yylval.data = data_copy_escape_string(yytext+1,
- yyleng-2);
- return DT_STRING;
- }
-
-<*>"/dts-v1/" {
- DPRINT("Keyword: /dts-v1/\n");
- dts_version = 1;
- BEGIN_DEFAULT();
- return DT_V1;
- }
-
-<*>"/plugin/" {
- DPRINT("Keyword: /plugin/\n");
- return DT_PLUGIN;
- }
-
-<*>"/memreserve/" {
- DPRINT("Keyword: /memreserve/\n");
- BEGIN_DEFAULT();
- return DT_MEMRESERVE;
- }
-
-<*>"/bits/" {
- DPRINT("Keyword: /bits/\n");
- BEGIN_DEFAULT();
- return DT_BITS;
- }
-
-<*>"/delete-property/" {
- DPRINT("Keyword: /delete-property/\n");
- DPRINT("<PROPNODENAME>\n");
- BEGIN(PROPNODENAME);
- return DT_DEL_PROP;
- }
-
-<*>"/delete-node/" {
- DPRINT("Keyword: /delete-node/\n");
- DPRINT("<PROPNODENAME>\n");
- BEGIN(PROPNODENAME);
- return DT_DEL_NODE;
- }
-
-<*>{LABEL}: {
- DPRINT("Label: %s\n", yytext);
- yylval.labelref = xstrdup(yytext);
- yylval.labelref[yyleng-1] = '\0';
- return DT_LABEL;
- }
-
-<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
- char *e;
- DPRINT("Integer Literal: '%s'\n", yytext);
-
- errno = 0;
- yylval.integer = strtoull(yytext, &e, 0);
-
- if (*e && e[strspn(e, "UL")]) {
- lexical_error("Bad integer literal '%s'",
- yytext);
- }
-
- if (errno == ERANGE)
- lexical_error("Integer literal '%s' out of range",
- yytext);
- else
- /* ERANGE is the only strtoull error triggerable
- * by strings matching the pattern */
- assert(errno == 0);
- return DT_LITERAL;
- }
-
-<*>{CHAR_LITERAL} {
- struct data d;
- DPRINT("Character literal: %s\n", yytext);
-
- d = data_copy_escape_string(yytext+1, yyleng-2);
- if (d.len == 1) {
- lexical_error("Empty character literal");
- yylval.integer = 0;
- } else {
- yylval.integer = (unsigned char)d.val[0];
-
- if (d.len > 2)
- lexical_error("Character literal has %d"
- " characters instead of 1",
- d.len - 1);
- }
-
- data_free(d);
- return DT_CHAR_LITERAL;
- }
-
-<*>\&{LABEL} { /* label reference */
- DPRINT("Ref: %s\n", yytext+1);
- yylval.labelref = xstrdup(yytext+1);
- return DT_REF;
- }
-
-<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */
- yytext[yyleng-1] = '\0';
- DPRINT("Ref: %s\n", yytext+2);
- yylval.labelref = xstrdup(yytext+2);
- return DT_REF;
- }
-
-<BYTESTRING>[0-9a-fA-F]{2} {
- yylval.byte = strtol(yytext, NULL, 16);
- DPRINT("Byte: %02x\n", (int)yylval.byte);
- return DT_BYTE;
- }
-
-<BYTESTRING>"]" {
- DPRINT("/BYTESTRING\n");
- BEGIN_DEFAULT();
- return ']';
- }
-
-<PROPNODENAME>\\?{PROPNODECHAR}+ {
- DPRINT("PropNodeName: %s\n", yytext);
- yylval.propnodename = xstrdup((yytext[0] == '\\') ?
- yytext + 1 : yytext);
- BEGIN_DEFAULT();
- return DT_PROPNODENAME;
- }
-
-"/incbin/" {
- DPRINT("Binary Include\n");
- return DT_INCBIN;
- }
-
-<*>{WS}+ /* eat whitespace */
-<*>{COMMENT}+ /* eat C-style comments */
-<*>{LINECOMMENT}+ /* eat C++-style comments */
-
-<*>"<<" { return DT_LSHIFT; };
-<*>">>" { return DT_RSHIFT; };
-<*>"<=" { return DT_LE; };
-<*>">=" { return DT_GE; };
-<*>"==" { return DT_EQ; };
-<*>"!=" { return DT_NE; };
-<*>"&&" { return DT_AND; };
-<*>"||" { return DT_OR; };
-
-<*>. {
- DPRINT("Char: %c (\\x%02x)\n", yytext[0],
- (unsigned)yytext[0]);
- if (yytext[0] == '[') {
- DPRINT("<BYTESTRING>\n");
- BEGIN(BYTESTRING);
- }
- if ((yytext[0] == '{')
- || (yytext[0] == ';')) {
- DPRINT("<PROPNODENAME>\n");
- BEGIN(PROPNODENAME);
- }
- return yytext[0];
- }
-
-%%
-
-static void push_input_file(const char *filename)
-{
- assert(filename);
-
- srcfile_push(filename);
-
- yyin = current_srcfile->f;
-
- yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
-}
-
-
-static bool pop_input_file(void)
-{
- if (srcfile_pop() == 0)
- return false;
-
- yypop_buffer_state();
- yyin = current_srcfile->f;
-
- return true;
-}
-
-static void lexical_error(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- srcpos_verror(&yylloc, "Lexical error", fmt, ap);
- va_end(ap);
-
- treesource_error = true;
-}
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y
deleted file mode 100644
index 44af170abf..0000000000
--- a/scripts/dtc/dtc-parser.y
+++ /dev/null
@@ -1,538 +0,0 @@
-/*
- * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- */
-%{
-#include <stdio.h>
-#include <inttypes.h>
-
-#include "dtc.h"
-#include "srcpos.h"
-
-extern int yylex(void);
-extern void yyerror(char const *s);
-#define ERROR(loc, ...) \
- do { \
- srcpos_error((loc), "Error", __VA_ARGS__); \
- treesource_error = true; \
- } while (0)
-
-extern struct dt_info *parser_output;
-extern bool treesource_error;
-%}
-
-%union {
- char *propnodename;
- char *labelref;
- uint8_t byte;
- struct data data;
-
- struct {
- struct data data;
- int bits;
- } array;
-
- struct property *prop;
- struct property *proplist;
- struct node *node;
- struct node *nodelist;
- struct reserve_info *re;
- uint64_t integer;
- unsigned int flags;
-}
-
-%token DT_V1
-%token DT_PLUGIN
-%token DT_MEMRESERVE
-%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
-%token DT_BITS
-%token DT_DEL_PROP
-%token DT_DEL_NODE
-%token <propnodename> DT_PROPNODENAME
-%token <integer> DT_LITERAL
-%token <integer> DT_CHAR_LITERAL
-%token <byte> DT_BYTE
-%token <data> DT_STRING
-%token <labelref> DT_LABEL
-%token <labelref> DT_REF
-%token DT_INCBIN
-
-%type <data> propdata
-%type <data> propdataprefix
-%type <flags> header
-%type <flags> headers
-%type <re> memreserve
-%type <re> memreserves
-%type <array> arrayprefix
-%type <data> bytestring
-%type <prop> propdef
-%type <proplist> proplist
-
-%type <node> devicetree
-%type <node> nodedef
-%type <node> subnode
-%type <nodelist> subnodes
-
-%type <integer> integer_prim
-%type <integer> integer_unary
-%type <integer> integer_mul
-%type <integer> integer_add
-%type <integer> integer_shift
-%type <integer> integer_rela
-%type <integer> integer_eq
-%type <integer> integer_bitand
-%type <integer> integer_bitxor
-%type <integer> integer_bitor
-%type <integer> integer_and
-%type <integer> integer_or
-%type <integer> integer_trinary
-%type <integer> integer_expr
-
-%%
-
-sourcefile:
- headers memreserves devicetree
- {
- parser_output = build_dt_info($1, $2, $3,
- guess_boot_cpuid($3));
- }
- ;
-
-header:
- DT_V1 ';'
- {
- $$ = DTSF_V1;
- }
- | DT_V1 ';' DT_PLUGIN ';'
- {
- $$ = DTSF_V1 | DTSF_PLUGIN;
- }
- ;
-
-headers:
- header
- | header headers
- {
- if ($2 != $1)
- ERROR(&@2, "Header flags don't match earlier ones");
- $$ = $1;
- }
- ;
-
-memreserves:
- /* empty */
- {
- $$ = NULL;
- }
- | memreserve memreserves
- {
- $$ = chain_reserve_entry($1, $2);
- }
- ;
-
-memreserve:
- DT_MEMRESERVE integer_prim integer_prim ';'
- {
- $$ = build_reserve_entry($2, $3);
- }
- | DT_LABEL memreserve
- {
- add_label(&$2->labels, $1);
- $$ = $2;
- }
- ;
-
-devicetree:
- '/' nodedef
- {
- $$ = name_node($2, "");
- }
- | devicetree '/' nodedef
- {
- $$ = merge_nodes($1, $3);
- }
- | DT_REF nodedef
- {
- /*
- * We rely on the rule being always:
- * versioninfo plugindecl memreserves devicetree
- * so $-1 is what we want (plugindecl)
- */
- if (!($<flags>-1 & DTSF_PLUGIN))
- ERROR(&@2, "Label or path %s not found", $1);
- $$ = add_orphan_node(name_node(build_node(NULL, NULL), ""), $2, $1);
- }
- | devicetree DT_LABEL DT_REF nodedef
- {
- struct node *target = get_node_by_ref($1, $3);
-
- if (target) {
- add_label(&target->labels, $2);
- merge_nodes(target, $4);
- } else
- ERROR(&@3, "Label or path %s not found", $3);
- $$ = $1;
- }
- | devicetree DT_REF nodedef
- {
- struct node *target = get_node_by_ref($1, $2);
-
- if (target) {
- merge_nodes(target, $3);
- } else {
- /*
- * We rely on the rule being always:
- * versioninfo plugindecl memreserves devicetree
- * so $-1 is what we want (plugindecl)
- */
- if ($<flags>-1 & DTSF_PLUGIN)
- add_orphan_node($1, $3, $2);
- else
- ERROR(&@2, "Label or path %s not found", $2);
- }
- $$ = $1;
- }
- | devicetree DT_DEL_NODE DT_REF ';'
- {
- struct node *target = get_node_by_ref($1, $3);
-
- if (target)
- delete_node(target);
- else
- ERROR(&@3, "Label or path %s not found", $3);
-
-
- $$ = $1;
- }
- ;
-
-nodedef:
- '{' proplist subnodes '}' ';'
- {
- $$ = build_node($2, $3);
- }
- ;
-
-proplist:
- /* empty */
- {
- $$ = NULL;
- }
- | proplist propdef
- {
- $$ = chain_property($2, $1);
- }
- ;
-
-propdef:
- DT_PROPNODENAME '=' propdata ';'
- {
- $$ = build_property($1, $3);
- }
- | DT_PROPNODENAME ';'
- {
- $$ = build_property($1, empty_data);
- }
- | DT_DEL_PROP DT_PROPNODENAME ';'
- {
- $$ = build_property_delete($2);
- }
- | DT_LABEL propdef
- {
- add_label(&$2->labels, $1);
- $$ = $2;
- }
- ;
-
-propdata:
- propdataprefix DT_STRING
- {
- $$ = data_merge($1, $2);
- }
- | propdataprefix arrayprefix '>'
- {
- $$ = data_merge($1, $2.data);
- }
- | propdataprefix '[' bytestring ']'
- {
- $$ = data_merge($1, $3);
- }
- | propdataprefix DT_REF
- {
- $$ = data_add_marker($1, REF_PATH, $2);
- }
- | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
- {
- FILE *f = srcfile_relative_open($4.val, NULL);
- struct data d;
-
- if ($6 != 0)
- if (fseek(f, $6, SEEK_SET) != 0)
- die("Couldn't seek to offset %llu in \"%s\": %s",
- (unsigned long long)$6, $4.val,
- strerror(errno));
-
- d = data_copy_file(f, $8);
-
- $$ = data_merge($1, d);
- fclose(f);
- }
- | propdataprefix DT_INCBIN '(' DT_STRING ')'
- {
- FILE *f = srcfile_relative_open($4.val, NULL);
- struct data d = empty_data;
-
- d = data_copy_file(f, -1);
-
- $$ = data_merge($1, d);
- fclose(f);
- }
- | propdata DT_LABEL
- {
- $$ = data_add_marker($1, LABEL, $2);
- }
- ;
-
-propdataprefix:
- /* empty */
- {
- $$ = empty_data;
- }
- | propdata ','
- {
- $$ = $1;
- }
- | propdataprefix DT_LABEL
- {
- $$ = data_add_marker($1, LABEL, $2);
- }
- ;
-
-arrayprefix:
- DT_BITS DT_LITERAL '<'
- {
- unsigned long long bits;
-
- bits = $2;
-
- if ((bits != 8) && (bits != 16) &&
- (bits != 32) && (bits != 64)) {
- ERROR(&@2, "Array elements must be"
- " 8, 16, 32 or 64-bits");
- bits = 32;
- }
-
- $$.data = empty_data;
- $$.bits = bits;
- }
- | '<'
- {
- $$.data = empty_data;
- $$.bits = 32;
- }
- | arrayprefix integer_prim
- {
- if ($1.bits < 64) {
- uint64_t mask = (1ULL << $1.bits) - 1;
- /*
- * Bits above mask must either be all zero
- * (positive within range of mask) or all one
- * (negative and sign-extended). The second
- * condition is true if when we set all bits
- * within the mask to one (i.e. | in the
- * mask), all bits are one.
- */
- if (($2 > mask) && (($2 | mask) != -1ULL))
- ERROR(&@2, "Value out of range for"
- " %d-bit array element", $1.bits);
- }
-
- $$.data = data_append_integer($1.data, $2, $1.bits);
- }
- | arrayprefix DT_REF
- {
- uint64_t val = ~0ULL >> (64 - $1.bits);
-
- if ($1.bits == 32)
- $1.data = data_add_marker($1.data,
- REF_PHANDLE,
- $2);
- else
- ERROR(&@2, "References are only allowed in "
- "arrays with 32-bit elements.");
-
- $$.data = data_append_integer($1.data, val, $1.bits);
- }
- | arrayprefix DT_LABEL
- {
- $$.data = data_add_marker($1.data, LABEL, $2);
- }
- ;
-
-integer_prim:
- DT_LITERAL
- | DT_CHAR_LITERAL
- | '(' integer_expr ')'
- {
- $$ = $2;
- }
- ;
-
-integer_expr:
- integer_trinary
- ;
-
-integer_trinary:
- integer_or
- | integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
- ;
-
-integer_or:
- integer_and
- | integer_or DT_OR integer_and { $$ = $1 || $3; }
- ;
-
-integer_and:
- integer_bitor
- | integer_and DT_AND integer_bitor { $$ = $1 && $3; }
- ;
-
-integer_bitor:
- integer_bitxor
- | integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
- ;
-
-integer_bitxor:
- integer_bitand
- | integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
- ;
-
-integer_bitand:
- integer_eq
- | integer_bitand '&' integer_eq { $$ = $1 & $3; }
- ;
-
-integer_eq:
- integer_rela
- | integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
- | integer_eq DT_NE integer_rela { $$ = $1 != $3; }
- ;
-
-integer_rela:
- integer_shift
- | integer_rela '<' integer_shift { $$ = $1 < $3; }
- | integer_rela '>' integer_shift { $$ = $1 > $3; }
- | integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
- | integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
- ;
-
-integer_shift:
- integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
- | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
- | integer_add
- ;
-
-integer_add:
- integer_add '+' integer_mul { $$ = $1 + $3; }
- | integer_add '-' integer_mul { $$ = $1 - $3; }
- | integer_mul
- ;
-
-integer_mul:
- integer_mul '*' integer_unary { $$ = $1 * $3; }
- | integer_mul '/' integer_unary
- {
- if ($3 != 0) {
- $$ = $1 / $3;
- } else {
- ERROR(&@$, "Division by zero");
- $$ = 0;
- }
- }
- | integer_mul '%' integer_unary
- {
- if ($3 != 0) {
- $$ = $1 % $3;
- } else {
- ERROR(&@$, "Division by zero");
- $$ = 0;
- }
- }
- | integer_unary
- ;
-
-integer_unary:
- integer_prim
- | '-' integer_unary { $$ = -$2; }
- | '~' integer_unary { $$ = ~$2; }
- | '!' integer_unary { $$ = !$2; }
- ;
-
-bytestring:
- /* empty */
- {
- $$ = empty_data;
- }
- | bytestring DT_BYTE
- {
- $$ = data_append_byte($1, $2);
- }
- | bytestring DT_LABEL
- {
- $$ = data_add_marker($1, LABEL, $2);
- }
- ;
-
-subnodes:
- /* empty */
- {
- $$ = NULL;
- }
- | subnode subnodes
- {
- $$ = chain_node($1, $2);
- }
- | subnode propdef
- {
- ERROR(&@2, "Properties must precede subnodes");
- YYERROR;
- }
- ;
-
-subnode:
- DT_PROPNODENAME nodedef
- {
- $$ = name_node($2, $1);
- }
- | DT_DEL_NODE DT_PROPNODENAME ';'
- {
- $$ = name_node(build_node_delete(), $2);
- }
- | DT_LABEL subnode
- {
- add_label(&$2->labels, $1);
- $$ = $2;
- }
- ;
-
-%%
-
-void yyerror(char const *s)
-{
- ERROR(&yylloc, "%s", s);
-}