Initial check-in of TF-Fuzz.
Author: Gary Morrison <gary.morrison@arm.com>
Signed-off-by: Gary Morrison <gary.morrison@arm.com>
Change-Id: I8f739c3403bf2a2808f33c28910c7bda6aca7887
diff --git a/tools/tf_fuzz/parser/README b/tools/tf_fuzz/parser/README
new file mode 100644
index 0000000..f5251a4
--- /dev/null
+++ b/tools/tf_fuzz/parser/README
@@ -0,0 +1,13 @@
+.../tf_fuzz/parser directory contents:
+
+tf_fuzz_grammar.l tf_fuzz_grammar.y
+
+--------------------------------------------------------------------------------
+
+This directory contains the Lex and YACC grammars for parsing the TF-Fuzz command
+"language," if it can be called that. The tf_fuzz_grammar.tab.cpp/.hpp files
+generated also form the executive for the entire parsing process.
+
+--------------
+
+*Copyright (c) 2019-2020, Arm Limited. All rights reserved.*
diff --git a/tools/tf_fuzz/parser/tf_fuzz_grammar.l b/tools/tf_fuzz/parser/tf_fuzz_grammar.l
new file mode 100644
index 0000000..d3f1cf6
--- /dev/null
+++ b/tools/tf_fuzz/parser/tf_fuzz_grammar.l
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+
+%{
+#include "class_forwards.hpp"
+#include "boilerplate.hpp"
+#include "gibberish.hpp"
+#include "compute.hpp"
+#include "string_ops.hpp"
+#include "data_blocks.hpp"
+#include "psa_asset.hpp"
+#include "sst_asset.hpp"
+#include "crypto_asset.hpp"
+#include "find_or_create_asset.hpp"
+#include "template_line.hpp"
+#include "tf_fuzz.hpp"
+#include "psa_call.hpp"
+#include "tf_fuzz_grammar.tab.hpp"
+
+int yycolumn = 1;
+
+//char *yytext;
+
+#define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno; \
+ yylloc.first_column = yycolumn; yylloc.last_column = yycolumn + yyleng - 1; \
+ yycolumn += yyleng; \
+ yylval.str = strdup(yytext);
+
+void yyerror (tf_fuzz_info *, const char *str)
+ /* not sure why it sends the yyparse() argument to yyerror(), but OK... */
+{
+ fprintf (stderr, "tf_fuzz template on line %d, at text = \"%s\": %s\n",
+ yylineno, yytext, str);
+ exit (1);
+}
+
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+%}
+
+%x BLOCK_COMMENT
+
+%option yylineno
+%option nodefault
+%option noyywrap
+%array
+
+%%
+
+\r ; /* ignore all \r */
+\/\/.*\n ; /* ignore C++-style line comments */
+purpose[ \t]+[^;]*; return PURPOSE;
+"/*" {BEGIN(BLOCK_COMMENT);}
+<BLOCK_COMMENT>"*/" {BEGIN(INITIAL);}
+<BLOCK_COMMENT>\n ;
+<BLOCK_COMMENT>. ;
+ /* Root commands: */
+set return SET;
+read return READ;
+remove return REMOVE;
+secure return SECURE;
+done return DONE;
+ /* PSA-asset types: */
+sst return SST;
+key return KEY;
+policy return POLICY;
+ /* Other root-command operands: */
+expect return EXPECT;
+pass return PASS;
+nothing return NOTHING;
+error return ERROR;
+\{ return OPEN_BRACE;
+\} return CLOSE_BRACE;
+; return SEMICOLON;
+name return NAME;
+uid return UID;
+data return DATA;
+\* return STAR;
+active return ACTIVE;
+deleted return DELETED;
+check return CHECK;
+assign return ASSIGN;
+print return PRINT;
+hash return HASH;
+neq return NEQ;
+dfname return DFNAME;
+shuffle return SHUFFLE;
+to return TO;
+of return OF;
+ /* Structure operands: */
+[a-zA-z][a-zA-Z_0-9]* {yylval.str = yytext; return IDENTIFIER_TOK;}
+[+-]?[0-9]* {yylval.valueN = atol(yytext); return NUMBER_TOK;}
+\'[a-zA-Z_0-9\/\.]+\' {yylval.str = yytext; return FILE_PATH_TOK;}
+\"[^\"]*\" {yylval.str = yytext; return LITERAL_TOK;}
+ /* inside quotes: anything but a quote, or nothing */
+[ \t\n\r] ; /* ignore white space */
+. yyerror ((tf_fuzz_info *) NULL, "Unexpected character");
+
+%%
+
diff --git a/tools/tf_fuzz/parser/tf_fuzz_grammar.y b/tools/tf_fuzz/parser/tf_fuzz_grammar.y
new file mode 100644
index 0000000..600cf53
--- /dev/null
+++ b/tools/tf_fuzz/parser/tf_fuzz_grammar.y
@@ -0,0 +1,1140 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+%{
+#include <iostream>
+#include <vector>
+#include <set>
+
+#include "class_forwards.hpp"
+#include "data_blocks.hpp"
+#include "boilerplate.hpp"
+#include "gibberish.hpp"
+#include "compute.hpp"
+#include "string_ops.hpp"
+#include "psa_asset.hpp"
+#include "find_or_create_asset.hpp"
+#include "template_line.hpp"
+#include "tf_fuzz.hpp"
+#include "sst_asset.hpp"
+#include "crypto_asset.hpp"
+#include "psa_call.hpp"
+#include "crypto_call.hpp"
+#include "sst_call.hpp"
+#include "security_call.hpp"
+#include "secure_template_line.hpp"
+#include "sst_template_line.hpp"
+#include "crypto_template_line.hpp"
+
+/* These items are defined in tf_fuzz_grammar.l. Note, however that, because
+ of "name mangling," defining them as extern "C" may or may not be ideal,
+ depending upon which compiler -- gcc vs. g++, compiles the output from lex.
+ So far, it seems best without the extern "C", including also compiling
+ under Visual Studio. */
+/* extern "C"
+{ */
+ extern int yylineno;
+ int yywrap() {return 1;}
+ extern char yytext[];
+ extern int yyleng;
+/* } */
+
+int yylex (void);
+void yyerror (tf_fuzz_info *, const char *);
+ /* not sure why it sends the yyparse() argument to yyerror(), but OK... */
+
+/* A few consts just to make code more comprehensible: */
+const bool yes_fill_in_template = true;
+const bool dont_fill_in_template = false;
+const bool yes_create_call = true;
+const bool dont_create_call = false;
+
+tf_fuzz_info *rsrc;
+
+/* These are object pointers used to parse the template and create the test. Ac-
+ tually, probably only templateLin will be used. */
+template_line *templateLin = nullptr;
+ sst_template_line *sstTemplateLin = nullptr;
+ set_sst_template_line *setSstTemplateLin = nullptr;
+ read_sst_template_line *reaSstTemplateLin = nullptr;
+ remove_sst_template_line *remSstTemplateLin = nullptr;
+ policy_template_line *polTemplateLin = nullptr;
+ set_policy_template_line *setPolTemplateLin = nullptr;
+ read_policy_template_line *reaPolTemplateLin = nullptr;
+ key_template_line *keyTemplateLin = nullptr;
+ set_key_template_line *setKeyTemplateLin = nullptr;
+ read_key_template_line *reaKeyTemplateLin = nullptr;
+ remove_key_template_line *remKeyTemplateLin = nullptr;
+ security_template_line *secTemplateLin = nullptr;
+ security_hash_template_line *secHasTemplateLin = nullptr;
+/* Call and asset objects are presumably not immediately needed, because the objects of
+ these types are within the resource object, *rsrc, but even if just to show class
+ hierarchy: */
+psa_call *psaCal = nullptr;
+ sst_call *sstCal = nullptr;
+ sst_set_call *sstSetCal = nullptr;
+ sst_get_call *sstGetCal = nullptr;
+ sst_remove_call *sstRemCal = nullptr;
+ crypto_call *cryCal = nullptr;
+ policy_call *polCal = nullptr;
+ policy_set_call *polSetCal = nullptr;
+ policy_get_call *polGetCal = nullptr;
+ key_call *keyCal = nullptr;
+ get_key_info_call *getKeyInfCal = nullptr;
+ set_key_call *makKeyCal = nullptr;
+ destroy_key_call *desKeyCal = nullptr;
+psa_asset *psaAst = nullptr;
+ sst_asset *sstAst = nullptr;
+ crypto_asset *cryAst = nullptr;
+ policy_asset *polAst = nullptr;
+ key_asset *keyAst = nullptr;
+
+/* For generating random, but readable/memorable, data: */
+gibberish gib;
+char gib_buff[4096]; // spew gibberish into here
+int rand_data_length = 0;
+
+/* General-utility variables: */
+string purp_str; /* test purpose */
+psa_asset_usage random_asset = psa_asset_usage::all; /* pick what type of asset at random */
+bool random_name; /* template didn't specify name, so it's generated randomly */
+string literal_data; /* literal data for an asset value */
+
+/* Holders for state in read commands: */
+expect_info expect; /* everything about expected results and data */
+set_data_info set_data; /* everything about setting the value of PSA-asset data */
+asset_name_id_info asset_id; /* everything about identifying assets */
+bool assign_data_var_specified;
+string assign_data_var;
+bool print_data; /* true to just print asset data to the test log */
+bool hash_data; /* true to just print asset data to the test log */
+
+/* The following are more tied to the template syntax than to the resulting PSA calls */
+string literal; /* temporary holder for all string literals */
+string identifier; /* temporary holder for strings representing identifiers */
+string var_name; /* a variable name */
+string asset_name; /* as parsed, not yet put into asset_id */
+string aid; /* string-typed holder for an asset ID in a list thereof */
+int nid; /* same idea as aid, but for asset ID# lists */
+size_t strFind1, strFind2; /* for searching through strings */
+
+/* Because of the parsing order, psa_calls of the specific type have to be
+ push_back()ed onto rsrc->calls before their expected results are known. Therefore,
+ inject those results after parsing the expected results. add_expect is a vector
+ index of where to start "back-filling" the expect information. */
+unsigned int add_expect = 0;
+
+/* Temporaries: */
+vector<psa_asset*>::iterator t_sst_asset;
+vector<psa_asset*>::iterator t_key_asset;
+vector<psa_asset*>::iterator t_policy_asset;
+sst_call *t_sst_call = nullptr;
+key_call *t_key_call = nullptr;
+policy_call *t_policy_call = nullptr;
+long number; /* temporary holder for a number, e.g., sting form of UID */
+int i, j, k;
+
+/* Relating to template-statement blocks: */
+vector<template_line*> template_block_vector; /* (must be *pointers to* templates) */
+vector<int> block_order; /* "statisticalized" order of template lines in a block */
+int nesting_level = 0;
+ /* how many levels deep in { } nesting currently. Initially only 0 or 1. */
+bool shuffle_not_pick;
+ /* true to shuffle statements in a block, rather than pick so-and-so
+ number of them at random. */
+int low_nmbr_lines = 1; /* if picking so-and-so number of template lines from a ... */
+int high_nmbr_lines = 1; /* ... block at random, these are fewest and most lines. */
+int exact_nmbr_lines = 1;
+
+/* Shortcuts, to reduce code clutter, and reduce risk of coding errors. */
+#define IVM(content) if(rsrc->verbose_mode){content} /* IVM = "If Verbose Mode" */
+
+using namespace std;
+
+/* randomize_template_lines() chooses a template-line order in cases where they are to
+ be randomized -- shuffled or random picked. */
+void randomize_template_lines (
+ bool shuffle_not_pick, /* true to perform a shuffle operation rather than pick */
+ int &low_nmbr_lines, /* if picking so-and-so number of template lines from a ... */
+ int &high_nmbr_lines, /* ... block at random, these are fewest and most lines. */
+ int &exact_nmbr_lines,
+ vector<template_line*> &template_block_vector,
+ vector<int> &block_order
+) {
+ set<int> template_used; /* used for shuffle */
+ low_nmbr_lines = (low_nmbr_lines < 0)? 0 : low_nmbr_lines;
+ high_nmbr_lines = (high_nmbr_lines < 0)? 0 : high_nmbr_lines;
+ if (low_nmbr_lines > high_nmbr_lines) {
+ int swap = low_nmbr_lines;
+ low_nmbr_lines = high_nmbr_lines;
+ high_nmbr_lines = swap;
+ }
+ template_used.clear();
+ if (shuffle_not_pick) {
+ /* Choose a random order in which to generate all of the
+ template lines in the block: */
+ while (template_used.size() < template_block_vector.size()) {
+ i = rand() % template_block_vector.size();
+ if (template_used.find (i) == template_used.end()) {
+ /* This template not already shuffled in. */
+ block_order.push_back (i);
+ template_used.insert (i);
+ }
+ }
+ /* Done shuffling; empty out the set: */
+ } else {
+ if (high_nmbr_lines == low_nmbr_lines) {
+ exact_nmbr_lines = low_nmbr_lines;
+ /* just in case the template says "3 to 3 of"... */
+ } else {
+ exact_nmbr_lines = low_nmbr_lines
+ + (rand() % ( high_nmbr_lines
+ - low_nmbr_lines + 1 ) );
+ }
+ for (int j = 0; j < exact_nmbr_lines; ++j) {
+ /* Repeatedly choose a random template line from the block: */
+ i = rand() % template_block_vector.size();
+ block_order.push_back (i);
+ }
+ }
+}
+
+/* interpret_template_line() fills in random data, locates PSA assets, (etc.) and
+ conditionally creates PSA calls for a given template line. Note that there needs
+ to be a single place where all of this is done, so that statement blocks can be
+ randomized and then dispatched from a single point. */
+void interpret_template_line (
+ template_line *templateLin, /* the template line to process */
+ tf_fuzz_info *rsrc, /* program resources in general */
+ set_data_info set_data, psa_asset_usage random_asset,
+ bool assign_data_var_specified, expect_info expect, bool print_data, bool hash_data,
+ string asset_name, string assign_data_var,
+ asset_name_id_info &asset_id, /* everything about the asset(s) involved */
+ bool create_call_bool, /* true to create the PSA call at this time */
+ bool create_asset_bool, /* true to create the PSA asset at this time */
+ bool fill_in_template, /* true to back-fill info into template */
+ int instance
+ /* if further differentiation to the names or IDs is needed, make this >0 */
+) {
+ const bool yes_fill_in_template = true; // just to clarify a call
+ vector<psa_asset*> *active_asset, *deleted_asset;
+ vector<psa_asset*>::iterator t_psa_asset;
+
+ if (fill_in_template) {
+ /* Set basic parameters from the template line: */
+ templateLin->asset_id.id_n_not_name = asset_id.id_n_not_name;
+ templateLin->set_data.random_data = set_data.random_data;
+ templateLin->asset_id.set_name (asset_name);
+ /* Fill in state parsed from the template below: */
+ templateLin->assign_data_var_specified = assign_data_var_specified;
+ templateLin->assign_data_var.assign (assign_data_var);
+ templateLin->expect.data_var_specified
+ = expect.data_var_specified;
+ templateLin->expect.data_var.assign (expect.data_var);
+ templateLin->expect.data_specified = expect.data_specified;
+ templateLin->expect.data = expect.data;
+ templateLin->print_data = print_data;
+ templateLin->hash_data = hash_data;
+ templateLin->random_asset = random_asset;
+ templateLin->set_data.string_specified = set_data.literal_data_not_file;
+ /* TODO: is this right for multiple assets? */
+ if (set_data.literal_data_not_file && !set_data.random_data) {
+ templateLin->set_data.set (literal_data);
+ }
+ /* Save names or IDs to the template-line tracker: */
+ for (auto id_no : asset_id.asset_id_n_vector) {
+ templateLin->asset_id.asset_id_n_vector.push_back (id_no);
+ }
+ asset_id.asset_id_n_vector.clear();
+ for (auto as_name : asset_id.asset_name_vector) {
+ templateLin->asset_id.asset_name_vector.push_back (as_name);
+ }
+ asset_id.asset_name_vector.clear();
+ }
+
+ switch (templateLin->asset_type) {
+ case psa_asset_type::sst:
+ active_asset = &(rsrc->active_sst_asset);
+ deleted_asset = &(rsrc->deleted_sst_asset);
+ /* Currently "invalid" assets aren't used */
+ break;
+ case psa_asset_type::key:
+ active_asset = &(rsrc->active_key_asset);
+ deleted_asset = &(rsrc->deleted_key_asset);
+ break;
+ case psa_asset_type::policy:
+ active_asset = &(rsrc->active_policy_asset);
+ deleted_asset = &(rsrc->deleted_policy_asset);
+ break;
+ default:
+ cerr << "\nError: Internal: Please report error "
+ << "#1502 to TF-Fuzz developers." << endl;
+ exit (1500);
+ }
+
+ if (templateLin->random_asset != psa_asset_usage::all) {
+ /* != psa_asset_usage::all means to choose some known asset at random: */
+ if (templateLin->random_asset == psa_asset_usage::active) {
+ if (active_asset->size() > 0) {
+ i = rand() % active_asset->size();
+ t_psa_asset = active_asset->begin() + i;
+ templateLin->how_asset_found = asset_search::found_active;
+ templateLin->asset_id.id_n = (*t_psa_asset)->asset_id.id_n;
+ templateLin->asset_ser_no = (*t_psa_asset)->asset_ser_no;
+ if (templateLin->is_remove) {
+ templateLin->set_data.string_specified
+ = (*t_psa_asset)->set_data.string_specified;
+ templateLin->asset_id.name_specified
+ = (*t_psa_asset)->asset_id.name_specified;
+ templateLin->asset_id.set_calc_name ((*t_psa_asset)->asset_id.get_name());
+ templateLin->set_data.set_calculated ((*t_psa_asset)->set_data.get());
+ }
+ templateLin->setup_call (set_data, templateLin->set_data.random_data,
+ yes_fill_in_template, create_call_bool,
+ templateLin, rsrc );
+ if (templateLin->is_remove) {
+ /* Move asset from active vector to deleted vector: */
+ if (templateLin->how_asset_found == asset_search::found_active) {
+ deleted_asset->push_back(*t_psa_asset);
+ active_asset->erase(t_psa_asset);
+ } /* if not active, deem the call expected to fail. */
+ }
+ } else {
+ cerr << "\nWarning: Request for random active asset, "
+ << "when no active assets of that type exist."
+ << " Request disregarded." << endl;
+ }
+ } else if (templateLin->random_asset == psa_asset_usage::deleted) {
+ if (deleted_asset->size() > 0) {
+ i = rand() % deleted_asset->size();
+ t_psa_asset = deleted_asset->begin() + i;
+ templateLin->how_asset_found = asset_search::found_deleted;
+ templateLin->asset_id.id_n = (*t_psa_asset)->asset_id.id_n;
+ templateLin->asset_ser_no = (*t_psa_asset)->asset_ser_no;
+ if (templateLin->is_remove) {
+ templateLin->set_data.string_specified
+ = (*t_psa_asset)->set_data.string_specified;
+ templateLin->asset_id.name_specified
+ = (*t_psa_asset)->asset_id.name_specified;
+ templateLin->asset_id.set_calc_name (
+ (*t_psa_asset)->asset_id.get_name() );
+ templateLin->set_data.set_calculated ((*t_psa_asset)->set_data.get());
+ }
+ templateLin->setup_call (set_data, templateLin->set_data.random_data,
+ yes_fill_in_template, create_call_bool,
+ templateLin, rsrc );
+ if (templateLin->is_remove && create_call_bool) {
+ /* Move asset from active vector to deleted vector: */
+ if (templateLin->how_asset_found == asset_search::found_active) {
+ deleted_asset->push_back(*t_psa_asset);
+ active_asset->erase(t_psa_asset);
+ } /* if not active, deem the call expected to fail. */
+ }
+ } else {
+ cerr << "\nWarning: Request for random deleted asset, "
+ << "when no deleted assets of that type exist."
+ << " Request disregarded." << endl;
+ }
+ } /* "invalid" assets are not used, so if not psa_asset_usage::active or
+ psa_asset_usage::deleted, then just ignore the template request */
+ } else {
+ if (asset_id.id_n_not_name) { /* Not random asset, asset by ID */
+ for (auto id_no : templateLin->asset_id.asset_id_n_vector) {
+ templateLin->asset_id.set_id_n(id_no);
+ asset_name = templateLin->asset_id.make_id_n_based_name (
+ id_no + (uint64_t) instance * 10000, asset_name );
+ templateLin->asset_id.set_calc_name (asset_name);
+ templateLin->how_asset_found = rsrc->find_or_create_psa_asset (
+ templateLin->asset_type, psa_asset_search::id,
+ psa_asset_usage::all, "",
+ (id_no + (uint64_t) instance * 10000),
+ templateLin->asset_ser_no, create_asset_bool,
+ t_psa_asset );
+ if (!templateLin->is_remove) {
+ /* Set asset's ID to what's being searched for (whether it's
+ already that because it's been found, or was just created): */
+ (*t_psa_asset)->asset_id.id_n = templateLin->asset_id.id_n;
+ templateLin->expect.data_var = var_name;
+ if (!set_data.literal_data_not_file) {
+ templateLin->set_data.set_file (set_data.file_path);
+ }
+ if (templateLin->how_asset_found != asset_search::not_found) {
+ templateLin->asset_id.id_n = (*t_psa_asset)->asset_id.id_n;
+ templateLin->asset_ser_no = (*t_psa_asset)->asset_ser_no;
+ }
+ templateLin->setup_call (set_data, templateLin->set_data.random_data,
+ fill_in_template, create_call_bool,
+ templateLin, rsrc );
+ }
+ }
+ } else { /* Not random asset, asset by name */
+ for (auto as_name : templateLin->asset_id.asset_name_vector) {
+ /* Also copy into template line object's local vector: */
+ string t_string, t_string2;
+ t_string.assign(as_name);
+ if (instance > 0) {
+ t_string += "_" + to_string (instance);
+ }
+ templateLin->asset_id.set_name (t_string);
+ templateLin->how_asset_found = rsrc->find_or_create_psa_asset (
+ templateLin->asset_type, psa_asset_search::name,
+ psa_asset_usage::all, t_string,
+ (uint64_t) 0, templateLin->asset_ser_no,
+ create_asset_bool, t_psa_asset );
+ if (!templateLin->is_remove) {
+ /* Give each occurrence a different UID: */
+ templateLin->asset_id.set_id_n (100 + (rand() % 10000));
+ /* TODO: unlikely, but this could alias! */
+ if (templateLin->how_asset_found != asset_search::not_found) {
+ templateLin->asset_id.id_n = (*t_psa_asset)->asset_id.id_n;
+ templateLin->asset_ser_no = (*t_psa_asset)->asset_ser_no;
+ }
+ templateLin->setup_call (set_data, templateLin->set_data.random_data,
+ yes_fill_in_template, create_call_bool,
+ templateLin, rsrc );
+ }
+ }
+ }
+ if (templateLin->is_remove) {
+ if (templateLin->how_asset_found != asset_search::not_found) {
+ templateLin->asset_ser_no = (*t_psa_asset)->asset_ser_no;
+ }
+ if (templateLin->how_asset_found == asset_search::unsuccessful) {
+ cerr << "\nError: Tool-internal: Please report error #109 "
+ << "to the TF-Fuzz developers." << endl;
+ exit(109);
+ }
+ templateLin->setup_call (set_data, templateLin->set_data.random_data,
+ dont_fill_in_template, create_call_bool,
+ templateLin, rsrc);
+ templateLin->copy_template_to_asset();
+ /* TODO: See comment in setup_call() */
+ if (create_call_bool && !templateLin->copy_template_to_call()) {
+ cerr << "\nError: Tool-internal: Please report error "
+ << "#602 to the TF-Fuzz developers." << endl;
+ exit(602);
+ }
+
+ /* TODO: This ideally would be done in an organized "simulate" stage. */
+ /* Move asset from active vector to deleted vector: */
+ if ( create_call_bool /* don't do this if just parsing */
+ && templateLin->how_asset_found == asset_search::found_active) {
+ rsrc->deleted_sst_asset.push_back(*t_psa_asset);
+ rsrc->active_sst_asset.erase(t_psa_asset);
+ } /* if not active, deem the call expected to fail. */
+ }
+ }
+}
+
+%}
+
+%start lines
+
+%union {int valueN; int tokenN; char *str;}
+%token <tokenN> PURPOSE RAW_TEXT
+%token <tokenN> SET READ REMOVE SECURE DONE /* root commands */
+%token <tokenN> SST KEY POLICY NAME UID STAR ACTIVE DELETED EQUAL DATA DFNAME
+%token <tokenN> CHECK ASSIGN HASH NEQ PRINT EXPECT PASS NOTHING ERROR /* expected results */
+%token <str> IDENTIFIER_TOK LITERAL_TOK FILE_PATH_TOK /* variables and content */
+%token <valueN> NUMBER_TOK /* variables and content */
+%token <tokenN> SEMICOLON SHUFFLE TO OF OPEN_BRACE CLOSE_BRACE /* block structure */
+
+%define parse.error verbose
+%locations
+%parse-param {tf_fuzz_info *rsrc}
+
+%%
+
+ /* Top-level syntax: */
+lines: /* nothing */
+ | line lines {
+ IVM(cout << "Lines: Line number " << yylineno << "." << endl;)
+ }
+ ;
+
+line:
+ PURPOSE {
+ IVM(cout << "Purpose line: " << flush;)
+ purp_str = yytext;
+ strFind1 = purp_str.find (" ");
+ purp_str = purp_str.substr (strFind1, purp_str.length());
+ purp_str.erase (0, 1); // (extra space)
+ strFind1 = purp_str.rfind (";");
+ purp_str = purp_str.substr (0, strFind1);
+ rsrc->test_purpose = purp_str;
+ IVM(cout << rsrc->test_purpose << endl;)
+ /* Just a precaution to make sure that these vectors start out empty.
+ Should be, and purpose is typically specified first: */
+ asset_id.asset_id_n_vector.clear();
+ asset_id.asset_name_vector.clear();
+ }
+ | block {
+ /* TODO: This code may not won't work with "secure hash neq ..." */
+ IVM(cout << "Block of lines." << endl;)
+ /* "Statisticalize" :-) the vector of template lines, then crank
+ the selected lines in order here. */
+ randomize_template_lines (shuffle_not_pick,
+ low_nmbr_lines, high_nmbr_lines, exact_nmbr_lines,
+ template_block_vector, block_order
+ );
+ IVM(cout << "Order of lines in block: " << flush;
+ for (auto i : block_order) {
+ cout << i << " ";
+ }
+ cout << endl;
+ )
+ /* Vector block_order contains the sequence of template lines to be
+ realized, in order. Pop the indicated template line off the
+ vector and generate code from it: */
+ k = 0; /* ID adder to at least help ensure uniqueness */
+ for (int i : block_order) {
+ templateLin = template_block_vector[i];
+ /* Note that temLin will have its fields filled in already. */
+ interpret_template_line (
+ templateLin, rsrc, set_data, random_asset,
+ assign_data_var_specified, expect, print_data, hash_data,
+ asset_name, assign_data_var, asset_id,
+ yes_create_call, /* did not create call nor asset earlier */
+ yes_create_asset,
+ dont_fill_in_template, /* but did fill it all in before */
+ k
+ );
+ k++;
+ for (; add_expect < rsrc->calls.size(); ++add_expect) {
+ templateLin->expect.copy_expect_to_call (rsrc->calls[add_expect]);
+ }
+ }
+ templateLin->asset_id.asset_id_n_vector.clear();
+ templateLin->asset_id.asset_name_vector.clear();
+ /* Done. Empty out the "statisticalization" vector: */
+ block_order.clear();
+ /* Empty out the vector of template lines; no longer needed. */
+ template_block_vector.clear();
+ --nesting_level;
+ IVM(cout << "Finished coding block of lines." << endl;)
+ }
+ | command SEMICOLON {
+ IVM(cout << "Command with no expect: \"" << flush;)
+ if (nesting_level == 0) { /* if laying down the code now... */
+ for (; add_expect < rsrc->calls.size(); ++add_expect) {
+ templateLin->expect.copy_expect_to_call (rsrc->calls[add_expect]);
+ }
+ delete templateLin; /* done with this template line */
+ } else {
+ /* The template line is now fully decoded, so stuff it onto
+ vector of lines to be "statisticalized": */
+ template_block_vector.push_back (templateLin);
+ }
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | command expect SEMICOLON {
+ IVM(cout << "Command with expect: \"" << flush;)
+ if (nesting_level == 0) {
+ for (; add_expect < rsrc->calls.size(); ++add_expect) {
+ templateLin->expect.copy_expect_to_call (rsrc->calls[add_expect]);
+ }
+ delete templateLin; /* done with this template line */
+ } else {
+ template_block_vector.push_back (templateLin);
+ }
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+command:
+ set_command {
+ IVM(cout << "Set command: \"" << yytext << "\"" << endl;)
+ }
+ | remove_command {
+ IVM(cout << "Remove command: \"" << yytext << "\"" << endl;)
+ }
+ | read_command {
+ IVM(cout << "Read command: \"" << yytext << "\"" << endl;)
+ }
+ | secure_command {
+ IVM(cout << "Security command: \"" << yytext << "\"" << endl;)
+ }
+ | done_command {
+ IVM(cout << "Done command: \"" << yytext << "\"" << endl;)
+ }
+ ;
+
+expect:
+ EXPECT PASS {
+ IVM(cout << "Expect pass clause: \"" << flush;)
+ templateLin->expect.set_pf_pass();
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | EXPECT NOTHING {
+ IVM(cout << "Expect nothing clause: \"" << flush;)
+ templateLin->expect.set_pf_nothing();
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | EXPECT IDENTIFIER {
+ IVM(cout << "Expect error clause: \"" << flush;)
+ templateLin->expect.set_pf_error (identifier);
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+ /* Root commands: */
+set_command:
+ SET sst_set_args {
+ IVM(cout << "Set SST command: \"" << flush;)
+ templateLin = new set_sst_template_line (rsrc);
+ interpret_template_line (
+ templateLin, rsrc, set_data, random_asset,
+ assign_data_var_specified, expect, print_data, hash_data,
+ asset_name, assign_data_var, asset_id,
+ nesting_level == 0 /* create call unless inside {} */,
+ nesting_level == 0 /* similarly, create asset unless inside {} */,
+ yes_fill_in_template, 0
+ );
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | SET key_set_args {
+ IVM(cout << "Set key command: \"" << flush;)
+ templateLin = new set_key_template_line (rsrc);
+ interpret_template_line (
+ templateLin, rsrc, set_data, random_asset,
+ assign_data_var_specified, expect, print_data, hash_data,
+ asset_name, assign_data_var, asset_id,
+ nesting_level == 0 /* create call unless inside {} */,
+ nesting_level == 0 /* similarly, create asset unless inside {} */,
+ yes_fill_in_template, 0
+ );
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | SET policy_set_args {
+ IVM(cout << "Set policy command: \"" << flush;)
+ templateLin = new set_policy_template_line (rsrc);
+ interpret_template_line (
+ templateLin, rsrc, set_data, random_asset,
+ assign_data_var_specified, expect, print_data, hash_data,
+ asset_name, assign_data_var, asset_id,
+ nesting_level == 0 /* create call unless inside {} */,
+ nesting_level == 0 /* similarly, create asset unless inside {} */,
+ yes_fill_in_template, 0
+ );
+ rsrc->calls.push_back (t_policy_call);
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+remove_command:
+ REMOVE sst_remove_args {
+ IVM(cout << "Remove SST command: \"" << flush;)
+ templateLin = new remove_sst_template_line (rsrc);
+ interpret_template_line (
+ templateLin, rsrc, set_data, random_asset,
+ assign_data_var_specified, expect, print_data, hash_data,
+ asset_name, assign_data_var, asset_id,
+ nesting_level == 0 /* create call unless inside {} */,
+ dont_create_asset /* don't create an asset being deleted */,
+ yes_fill_in_template, 0
+ );
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | REMOVE key_remove_args {
+ IVM(cout << "Remove key command: \"" << flush;)
+ templateLin = new remove_key_template_line (rsrc);
+ templateLin->asset_id.set_name (asset_name); // set in key_asset_name, below
+ interpret_template_line (
+ templateLin, rsrc, set_data, random_asset,
+ assign_data_var_specified, expect, print_data, hash_data,
+ asset_name, assign_data_var, asset_id,
+ nesting_level == 0 /* create call unless inside {} */,
+ dont_create_asset /* don't create an asset being deleted */,
+ yes_fill_in_template, 0
+ );
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+read_command:
+ READ SST sst_read_args {
+ IVM(cout << "Read SST command: \"" << flush;)
+ templateLin = new read_sst_template_line (rsrc);
+ interpret_template_line (
+ templateLin, rsrc, set_data, random_asset,
+ assign_data_var_specified, expect, print_data, hash_data,
+ asset_name, assign_data_var, asset_id,
+ nesting_level == 0 /* create call unless inside {} */,
+ dont_create_asset /* if no such asset exists, fail the call */,
+ yes_fill_in_template, 0
+ );
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | READ KEY key_read_args {
+ IVM(cout << "Read key command: \"" << flush;)
+ templateLin = new read_key_template_line (rsrc);
+ interpret_template_line (
+ templateLin, rsrc, set_data, random_asset,
+ assign_data_var_specified, expect, print_data, hash_data,
+ asset_name, assign_data_var, asset_id,
+ nesting_level == 0 /* create call unless inside {} */,
+ dont_create_asset /* if no such asset exists, fail the call */,
+ yes_fill_in_template, 0
+ );
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | READ POLICY policy_read_args {
+ IVM(cout << "Read policy command: \"" << flush;)
+ templateLin = new read_policy_template_line (rsrc);
+ interpret_template_line (
+ templateLin, rsrc, set_data, random_asset,
+ assign_data_var_specified, expect, print_data, hash_data,
+ asset_name, assign_data_var, asset_id,
+ nesting_level == 0 /* create call unless inside {} */,
+ dont_create_asset /* if no such asset exists, fail the call */,
+ yes_fill_in_template, 0
+ );
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+secure_command: SECURE HASH NEQ ASSET_IDENTIFIER_LIST {
+ /* TODO: This needs to allow not only SST assets, but mix and match with others
+ (keys especially) as well. */
+ templateLin = new security_hash_template_line (rsrc);
+ templateLin->asset_id.set_name (asset_name); // set in sst_asset_name, below
+ /* Fill in state parsed out below: */
+ templateLin->assign_data_var_specified = assign_data_var_specified;
+ templateLin->assign_data_var.assign (assign_data_var);
+/* TODO: Replace the below with templateLin->expect = expect? */
+ templateLin->expect.data_var_specified = expect.data_var_specified;
+ templateLin->expect.data_var.assign (expect.data_var);
+ templateLin->expect.data_specified = expect.data_specified;
+ templateLin->expect.data = literal;
+ templateLin->print_data = print_data;
+ templateLin->hash_data = hash_data;
+ templateLin->random_asset = random_asset;
+ /* Hash checks are different from the rest in that there's a single
+ "call" -- not a PSA call though -- for all of the assets cited in the
+ template line. In other cases, create a single call for each
+ asset cited by the template line, but not in this case. */
+ for (auto as_name : asset_id.asset_name_vector) {
+ /* Also copy into template line object's local vector: */
+ templateLin->asset_id.asset_name_vector.push_back (as_name);
+ }
+ /* Don't need to locate the assets, so no searches required. */
+ templateLin->expect.data_var = var_name;
+ templateLin->setup_call (set_data, set_data.random_data, yes_fill_in_template,
+ nesting_level == 0, templateLin, rsrc );
+ asset_id.asset_name_vector.clear();
+ IVM(cout << yytext << "\"" << endl;)
+
+
+ }
+ ;
+
+done_command: DONE {
+ if (nesting_level != 0) {
+ cerr << "\n\"done\" only available at outer-most { } nesting level."
+ << endl;
+ exit (702);
+ } else {
+ YYACCEPT;
+ }
+ }
+ ;
+
+ /* Root-command parameters: */
+sst_set_args:
+ SST sst_asset_name DATA LITERAL {
+ IVM(cout << "SST-create from literal data: \"" << flush;)
+ set_data.random_data = false;
+ set_data.literal_data_not_file = true;
+ literal.erase(0,1); // zap the ""s
+ literal.erase(literal.length()-1,1);
+ literal_data.assign (literal);
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | SST sst_asset_name DATA STAR { /* TF-Fuzz supplies random data */
+ IVM(cout << "SST-create from random data" << endl;)
+ set_data.random_data = true;
+ set_data.literal_data_not_file = true;
+ rand_data_length = 40 + (rand() % 256); /* Note: Multiple assets do get different data */
+ gib.sentence (gib_buff, gib_buff + rand_data_length - 1);
+ set_data.set (gib_buff);
+ literal.assign (gib_buff); /* just in case something uses literal */
+ }
+ | SST sst_asset_name DFNAME sst_asset_set_file_path {
+ set_data.literal_data_not_file = set_data.random_data = false;
+ IVM(cout << "SST-create from file: " << yytext << "\"" << endl;)
+ /* TODO: Need to decide whether the concept of using files to set SST
+ asset values has meaning, and then write code to write code to
+ set data appropriately from the file. */
+ }
+ ;
+
+sst_read_args:
+ sst_asset_name ASSIGN IDENTIFIER { /* dump to variable */
+ IVM(cout << "SST-read dump to variable: \"" << flush;)
+ /* TODO: set_data content probably doesn't need to be set here;
+ constructor probably sets it fine. */
+ set_data.random_data = false;
+ set_data.literal_data_not_file = true;
+ assign_data_var.assign (identifier);
+ assign_data_var_specified = true;
+ expect.data_specified = false;
+ expect.data_var_specified = false;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | sst_asset_name CHECK sst_read_args_var_name { /* check against variable */
+ IVM(cout << "SST-read check against variable: \""
+ << yytext << "\"" << endl;)
+ /* TODO: set_data content probably doesn't need to be set here;
+ constructor probably sets it fine. */
+ set_data.random_data = false;
+ set_data.literal_data_not_file = true; /* most importantly not file */
+ set_data.set (literal);
+ assign_data_var_specified = false;
+ expect.data_specified = false;
+ expect.data_var_specified = true;
+ expect.data_var = identifier;
+ }
+ | sst_asset_name CHECK LITERAL { /* check against literal */
+ IVM(cout << "SST-read check against literal: " << flush;)
+ /* TODO: set_data content probably doesn't need to be set here;
+ constructor probably sets it fine. */
+ set_data.random_data = false;
+ set_data.literal_data_not_file = true;
+ expect.data.assign (literal);
+ expect.data.erase(0,1); // zap the ""s
+ expect.data.erase(expect.data.length()-1,1);
+ assign_data_var_specified = false;
+ expect.data_specified = true;
+ expect.data_var_specified = false;
+ IVM(cout << yytext << endl;)
+ }
+ | sst_asset_name PRINT { /* print out content in test log */
+ IVM(cout << "SST-read log to test log: \"" << flush;)
+ /* TODO: set_data content probably doesn't need to be set here;
+ constructor probably sets it fine. */
+ set_data.random_data = false;
+ set_data.literal_data_not_file = true;
+ assign_data_var_specified = false;
+ expect.data_specified = false;
+ expect.data_var_specified = false;
+ print_data = true;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | sst_asset_name HASH { /* hash the data and save for later comparison */
+ IVM(cout << "SST-read hash for future data-leak detection: \"" << flush;)
+ /* TODO: set_data content probably doesn't need to be set here;
+ constructor probably sets it fine. */
+ set_data.random_data = false;
+ set_data.literal_data_not_file = true;
+ assign_data_var_specified = false;
+ expect.data_specified = false;
+ expect.data_var_specified = false;
+ hash_data = true;
+ rsrc->include_hashing_code = true;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | sst_asset_name DFNAME sst_asset_dump_file_path { /* dump to file */
+ IVM(cout << "SST-read dump to file: \""
+ << yytext << "\"" << endl;)
+ set_data.literal_data_not_file = set_data.random_data = false;
+ }
+ ;
+
+sst_remove_args:
+ SST sst_asset_name {
+ IVM(cout << "SST-remove arguments: \""
+ << yytext << "\"" << endl;)
+ }
+ ;
+
+sst_asset_name:
+ NAME ASSET_IDENTIFIER_LIST {
+ IVM(cout << "SST-asset identifier list: \"" << flush;)
+ random_name = false;
+ asset_name.assign (identifier); /* TODO: Not sure this ultimately has any effect... */
+ random_asset = psa_asset_usage::all; /* don't use random asset */
+ asset_id.id_n_not_name = false;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | NAME STAR {
+ IVM(cout << "SST-asset random identifier: \"" << flush;)
+ random_name = true;
+ rand_data_length = 2 + (rand() % 10);
+ gib.word (false, gib_buff, gib_buff + rand_data_length - 1);
+ aid.assign (gib_buff);
+ asset_id.asset_name_vector.push_back (aid);
+ random_asset = psa_asset_usage::all; /* don't use random asset */
+ asset_id.id_n_not_name = false;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | UID ASSET_NUMBER_LIST {
+ IVM(cout << "SST-asset UID list: \"" << flush;)
+ random_name = false;
+ random_asset = psa_asset_usage::all; /* don't use random asset */
+ asset_id.id_n_not_name = true;
+ asset_id.id_n_specified = true;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | UID STAR {
+ IVM(cout << "SST-asset random UID: \"" << flush;)
+ asset_id.id_n_not_name = true;
+ random_name = false;
+ nid = 100 + (rand() % 10000);
+ asset_id.asset_id_n_vector.push_back (nid);
+ random_asset = psa_asset_usage::all; /* don't use random asset */
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | STAR ACTIVE {
+ IVM(cout << "SST-asset random active: \"" << flush;)
+ random_asset = psa_asset_usage::active;
+ asset_id.id_n_not_name = false;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | STAR DELETED {
+ IVM(cout << "SST-asset random deleted: \"" << flush;)
+ random_asset = psa_asset_usage::deleted;
+ asset_id.id_n_not_name = false;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+sst_asset_set_file_path:
+ FILE_PATH {
+ IVM(cout << "SST-asset-create file path: \"" << flush;)
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+sst_read_args_var_name:
+ IDENTIFIER {
+ IVM(cout << "SST-read-arguments variable name: \"" << flush;)
+ var_name = yytext;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+sst_asset_dump_file_path:
+ FILE_PATH {
+ IVM(cout << "SST-asset dump-file path: \"" << flush;)
+ set_data.file_path = yytext;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+key_set_args:
+ KEY key_id POLICY policy_asset_name {
+ IVM(cout << "Key-create arguments: \""
+ << yytext << "\"" << endl;)
+ }
+ ;
+
+key_remove_args:
+ KEY key_id {
+ IVM(cout << "Key-remove arguments: \""
+ << yytext << "\"" << endl;)
+ }
+ ;
+
+key_read_args:
+ KEY key_id key_read_var_name {
+ IVM(cout << "Key dump to variable: \""
+ << yytext << "\"" << endl;)
+ }
+ ;
+
+key_read_var_name:
+ IDENTIFIER {
+ IVM(cout << "Key-read variable name: \""
+ << yytext << "\"" << endl;)
+ }
+ ;
+
+key_id:
+ IDENTIFIER {
+ IVM(cout << "Key ID: \""
+ << yytext << "\"" << endl;)
+ }
+ ;
+
+policy_set_args:
+ POLICY policy_asset_name {
+ IVM(cout << "Policy-create arguments: \""
+ << yytext << "\"" << endl;)
+ }
+ ;
+
+policy_read_args:
+ POLICY policy_asset_name policy_read_var_name {
+ IVM(cout << "Policy dump to variable: \""
+ << yytext << "\"" << endl;)
+ }
+ ;
+
+policy_asset_name:
+ IDENTIFIER {
+ IVM(cout << "Policy Asset ID: \"" << flush;)
+ asset_name = identifier;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+policy_read_var_name:
+ IDENTIFIER {
+ IVM(cout << "Policy read variable name: \""
+ << yytext << "\"" << endl;)
+ }
+ ;
+
+/* Code structuring: */
+block:
+ SHUFFLE block_content {
+ IVM(cout << "Shuffled block: \"" << flush;)
+ if (nesting_level > 1) {
+ cerr << "\nError: Sorry, currently only one level of { } "
+ << "nesting is allowed." << endl;
+ exit (500);
+ }
+ shuffle_not_pick = true;
+ low_nmbr_lines = high_nmbr_lines = 0; /* not used, but... */
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | exact_sel_count OF block_content {
+ IVM(cout << "Fixed number of lines from block: \"" << flush;)
+ shuffle_not_pick = false;
+ /* low_nmbr_lines and high_nmbr_lines are set below. */
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ | low_sel_count TO high_sel_count OF block_content {
+ IVM(cout << "Range number of lines from block: \"" << flush;)
+ if (nesting_level > 1) {
+ cerr << "\nError: Sorry, currently only one level of { } "
+ << "nesting is allowed." << endl;
+ exit (502);
+ }
+ shuffle_not_pick = false;
+ /* low_nmbr_lines and high_nmbr_lines are set below. */
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+block_content:
+ open_brace lines close_brace {
+ IVM(cout << "Block content: \"" << yytext << "\"" << endl;)
+ }
+ | line {
+ IVM(cout << "Single-line would-be-block content: \"" << flush;)
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+open_brace: OPEN_BRACE {
+ IVM(cout << "Open brace: \"" << flush;)
+ template_block_vector.clear(); // clean slate of template lines
+ nesting_level = 1;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+close_brace: CLOSE_BRACE {
+ IVM(cout << "Close brace: " << flush;)
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+ /* Low-level structures: */
+
+ /* Please see comment before ASSET_IDENTIFIER_LIST, below. */
+ASSET_NUMBER_LIST: ASSET_NUMBER ASSET_NUMBERS; /* at least one number */
+
+ASSET_NUMBERS: /* nothing, or */
+ | ASSET_NUMBER ASSET_NUMBERS;
+
+ASSET_NUMBER: NUMBER_TOK {
+ IVM(cout << "ASSET_NUMBER: \"" << flush;)
+ nid = atol(yytext);
+ asset_id.asset_id_n_vector.push_back (nid);
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+ /* ASSET_IDENTIFIER* are used specifically for lists of assets in a template line.
+ That, as opposed to list of identifers in general. The difference is the need
+ to queue ASSET_IDENTIFIERS up into asset_id.asset_name_vector, and have to do so
+ here before they "vanish." */
+ASSET_IDENTIFIER_LIST: ASSET_IDENTIFIER ASSET_IDENTIFIERS; /* (at least one) */
+
+ASSET_IDENTIFIERS:
+ /* nothing, or */
+ | ASSET_IDENTIFIER ASSET_IDENTIFIERS;
+
+ASSET_IDENTIFIER: IDENTIFIER_TOK {
+ IVM(cout << "ASSET_IDENTIFIER: \"" << flush;)
+ aid = identifier = yytext;
+ asset_id.asset_name_vector.push_back (aid);
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+IDENTIFIER: IDENTIFIER_TOK {
+ IVM(cout << "IDENTIFIER: \"" << flush;)
+ identifier = yytext;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+FILE_PATH: FILE_PATH_TOK {
+ IVM(cout << "FILE_PATH: \"" << flush;)
+ set_data.file_path = yytext;
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+ /* These are related to randomized blocks of template lines: */
+
+exact_sel_count: NUMBER {
+ IVM(cout << "Exact number of random template lines: \"" << flush;)
+ low_nmbr_lines = high_nmbr_lines = exact_nmbr_lines = number;
+ ++nesting_level;
+ IVM(cout << number << "\"" << endl;)
+ }
+ ;
+
+low_sel_count: NUMBER {
+ IVM(cout << "Least number of random template lines: \"" << flush;)
+ low_nmbr_lines = number;
+ IVM(cout << number << "\"" << endl;)
+ }
+ ;
+
+high_sel_count: NUMBER {
+ IVM(cout << "Most number of random template lines: \"" << flush;)
+ high_nmbr_lines = number;
+ ++nesting_level;
+ IVM(cout << number << "\"" << endl;)
+ }
+ ;
+
+
+ /* These are general-case numbers, literals and such: */
+
+NUMBER: NUMBER_TOK {
+ IVM(cout << "NUMBER: \"" << flush;)
+ number = atol(yytext);
+ IVM(cout << yytext << "\"" << endl;)
+ }
+ ;
+
+LITERAL: LITERAL_TOK {
+ IVM(cout << "LITERAL: " << flush;)
+ literal = yytext;
+ IVM(cout << yytext << endl;)
+ }
+ ;
+
+
+%%
+