diff options
Diffstat (limited to 'tools/d2c/rules')
-rw-r--r-- | tools/d2c/rules/Makefile.am | 31 | ||||
-rw-r--r-- | tools/d2c/rules/decl.h | 37 | ||||
-rw-r--r-- | tools/d2c/rules/grammar.y | 162 | ||||
-rw-r--r-- | tools/d2c/rules/manager.c | 531 | ||||
-rw-r--r-- | tools/d2c/rules/manager.h | 120 | ||||
-rw-r--r-- | tools/d2c/rules/tokens.l | 57 |
6 files changed, 938 insertions, 0 deletions
diff --git a/tools/d2c/rules/Makefile.am b/tools/d2c/rules/Makefile.am new file mode 100644 index 0000000..c2d9d96 --- /dev/null +++ b/tools/d2c/rules/Makefile.am @@ -0,0 +1,31 @@ + +BUILT_SOURCES = grammar.h + + +# On évite d'utiliser les variables personnalisées de type *_la_[YL]FLAGS +# afin de conserver des noms de fichiers simples, ie sans le nom de la +# bibliothèque de sortie en préfixe. + +AM_YFLAGS = -v -d -p rules_ + +AM_LFLAGS = -P rules_ -o lex.yy.c --header-file=tokens.h \ + -Dyylval=rules_lval -Dyyget_lineno=rules_get_lineno \ + -Dyy_scan_string=rules__scan_string \ + -Dyy_delete_buffer=rules__delete_buffer + +AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) + + +noinst_LTLIBRARIES = libd2crules.la + +.NOTPARALLEL: $(noinst_LTLIBRARIES) + +libd2crules_la_SOURCES = \ + decl.h \ + manager.h manager.c \ + tokens.l \ + grammar.y + + +# Automake fait les choses à moitié +CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h diff --git a/tools/d2c/rules/decl.h b/tools/d2c/rules/decl.h new file mode 100644 index 0000000..f7d7960 --- /dev/null +++ b/tools/d2c/rules/decl.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * decl.h - déclarations de prototypes utiles + * + * Copyright (C) 2016 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA 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 3 of the License, or + * (at your option) any later version. + * + * OpenIDA 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _TOOLS_D2C_RULES_DECL_H +#define _TOOLS_D2C_RULES_DECL_H + + +#include "manager.h" + + + +/* Interprête des données relatives à un bloc règles. */ +bool load_rules_from_raw_block(decoding_rules *, const char *); + + + +#endif /* _TOOLS_D2C_RULES_DECL_H */ diff --git a/tools/d2c/rules/grammar.y b/tools/d2c/rules/grammar.y new file mode 100644 index 0000000..effd4b3 --- /dev/null +++ b/tools/d2c/rules/grammar.y @@ -0,0 +1,162 @@ + +%{ + +#include "tokens.h" +#include "../helpers.h" + + +/* Affiche un message d'erreur suite à l'analyse en échec. */ +static int yyerror(decoding_rules *, char *); + +%} + + +%code requires { + +#include "decl.h" +#include "../args/decl.h" + +} + + +%union { + + char *string; /* Chaîne de caractères #1 */ + const char *cstring; /* Chaîne de caractères #2 */ + + cond_expr *expr; /* Expression de déclenchement */ + rule_action raction; /* Action et éléments associés */ +} + + +%define api.pure full + +%parse-param { decoding_rules *rules } + +%code provides { + +#define YY_DECL \ + int rules_lex(YYSTYPE *yylvalp) + +YY_DECL; + +} + + +%token IF EXPR_START EXPR_END THEN + +%token SEE CALL CHK_CALL UNPREDICTABLE + +%token NAME + +%token EQUAL BINVAL HEXVAL + +%token AND AND_LOG + +%token RAW_LINE + + +%type <string> NAME + +%type <cstring> RAW_LINE + +%type <expr> rule_cond +%type <string> BINVAL HEXVAL +%type <raction> action + + +%% + + +rules_list : /* empty */ + | rules_list rule + +rule : IF EXPR_START rule_cond EXPR_END THEN action { register_conditional_rule(rules, $3, &$6); } + | action { register_conditional_rule(rules, NULL, &$1); } + +rule_cond : NAME EQUAL BINVAL { $$ = build_simple_cond_expression($1, CCT_EQUAL, $3, true); } + | NAME EQUAL HEXVAL { $$ = build_simple_cond_expression($1, CCT_EQUAL, $3, false); } + | NAME AND_LOG BINVAL { $$ = build_simple_cond_expression($1, CCT_AND, $3, true); } + | NAME AND_LOG HEXVAL { $$ = build_simple_cond_expression($1, CCT_AND, $3, false); } + | EXPR_START rule_cond EXPR_END AND EXPR_START rule_cond EXPR_END + { $$ = build_composed_cond_expression($2, COT_AND, $6); } + +action : SEE RAW_LINE { $$.type = CAT_SEE; $$.details = make_callable($2, false); } + | UNPREDICTABLE { $$.type = CAT_UNPREDICTABLE; } + | CALL RAW_LINE { + right_op_t rop; + bool status; + + status = load_call_from_raw_line(&rop, $2); + if (!status) YYABORT; + + $$.type = CAT_CALL; $$.callee = rop.func; $$.args = rop.args; + + } + | CHK_CALL RAW_LINE { + right_op_t rop; + bool status; + + status = load_call_from_raw_line(&rop, $2); + if (!status) YYABORT; + + $$.type = CAT_CHECKED_CALL; $$.callee = rop.func; $$.args = rop.args; + + } + + +%% + + +/****************************************************************************** +* * +* Paramètres : rules = structure impliquée dans le processus. * +* msg = message d'erreur. * +* * +* Description : Affiche un message d'erreur suite à l'analyse en échec. * +* * +* Retour : 0 * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int yyerror(decoding_rules *rules, char *msg) +{ + printf("yyerror line %d: %s\n", yyget_lineno(), msg); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : rules = structure à constituer à partir de données lues. * +* raw = données brutes à analyser. * +* * +* Description : Interprête des données relatives à un bloc règles. * +* * +* Retour : true si l'opération s'est bien déroulée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool load_rules_from_raw_block(decoding_rules *rules, const char *raw) +{ + bool result; /* Bilan à faire remonter */ + YY_BUFFER_STATE state; /* Support d'analyse */ + int status; /* Bilan de l'analyse */ + + state = yy_scan_string(raw); + + status = yyparse(rules); + + result = (status == 0); + + yy_delete_buffer(state); + + return result; + +} diff --git a/tools/d2c/rules/manager.c b/tools/d2c/rules/manager.c new file mode 100644 index 0000000..f30559e --- /dev/null +++ b/tools/d2c/rules/manager.c @@ -0,0 +1,531 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * manager.h - prototypes pour les variations de décodage selon certaines conditions + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA 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 3 of the License, or + * (at your option) any later version. + * + * OpenIDA 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "manager.h" + + +#include <malloc.h> +#include <stdbool.h> +#include <string.h> + + +#include "../helpers.h" +#include "../qckcall.h" + + + +/* -------------------------- CONDITIONS DE DECLENCHEMENTS -------------------------- */ + + +/* Expression d'une condition */ +struct _cond_expr +{ + bool is_simple; /* Sélection de champ */ + + union + { + struct + { + char *variable; /* Variable manipulée */ + CondCompType comp; /* Type de comparaison */ + char *value; /* Valeur binaire comparée */ + + bool is_binary; /* Binaire ou hexadécimal */ + + } simple; + + struct + { + cond_expr *a; /* Première sous-expression */ + CondOpType operator; /* Relation entre expressions */ + cond_expr *b; /* Seconde sous-expression */ + + } composed; + + }; + +}; + + +/* Libère de la mémoire une expression conditionnelle. */ +static void delete_cond_expr(cond_expr *); + +/* Traduit en code une expression de condition. */ +static bool write_cond_expr(const cond_expr *, int, const coding_bits *); + + + +/* ------------------------- REGLES ET ACTIONS CONSEQUENTES ------------------------- */ + + +/* Règle particulière */ +typedef struct _extra_rule +{ + cond_expr *expr; /* Expression de déclenchement */ + rule_action action; /* Conséquence d'une validation*/ + +} extra_rule; + +/* Règles de décodage supplémentaires */ +struct _decoding_rules +{ + extra_rule *extra; /* Règles conditionnelles */ + size_t extra_count; /* Nombre de ces règles */ + +}; + + + +/* ---------------------------------------------------------------------------------- */ +/* CONDITIONS DE DECLENCHEMENTS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : variable = désignation de la variable à manipuler. * +* comp = type de comparaison à utiliser. * +* value = valeur binaire à comparer. * +* is_binary = indique la nature de la valeur transmise. * +* * +* Description : Crée une expression conditionnelle simple. * +* * +* Retour : Structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +cond_expr *build_simple_cond_expression(char *variable, CondCompType comp, char *value, bool is_binary) +{ + cond_expr *result; /* Structure à retourner */ + + result = (cond_expr *)calloc(1, sizeof(cond_expr)); + + result->is_simple = true; + + result->simple.variable = make_string_lower(variable); + result->simple.comp = comp; + result->simple.value = value; + + result->simple.is_binary = is_binary; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : a = première expression à intégrer. * +* operator = type de comparaison à utiliser. * +* b = second expression à intégrer. * +* * +* Description : Crée une expression conditionnelle composée. * +* * +* Retour : Structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +cond_expr *build_composed_cond_expression(cond_expr *a, CondOpType operator, cond_expr *b) +{ + cond_expr *result; /* Structure à retourner */ + + result = (cond_expr *)calloc(1, sizeof(cond_expr)); + + result->is_simple = false; + + result->composed.a = a; + result->composed.operator = operator; + result->composed.b = b; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = représentation d'expression à traiter. * +* * +* Description : Libère de la mémoire une expression conditionnelle. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void delete_cond_expr(cond_expr *expr) +{ + if (expr->is_simple) + { + free(expr->simple.variable); + free(expr->simple.value); + } + else + { + delete_cond_expr(expr->composed.a); + delete_cond_expr(expr->composed.b); + } + + free(expr); + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression simple ou composée à transposer. * +* fd = descripteur d'un flux ouvert en écriture. * +* bits = gestionnaire des bits d'encodage. * +* * +* Description : Traduit en code une expression de condition. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool write_cond_expr(const cond_expr *expr, int fd, const coding_bits *bits) +{ + bool result; /* Bilan à renvoyer */ + const raw_bitfield *bf; /* Champ de bits de définition */ + unsigned int provided; /* Nombre de bits fournis */ + + result = true; + + dprintf(fd, "("); + + if (expr->is_simple) + { + bf = find_named_field_in_bits(bits, expr->simple.variable); + if (bf == NULL) + { + fprintf(stderr, "Error: no bitfield defined the requested variable '%s'.\n", expr->simple.variable); + result = false; + goto wce_exit; + } + + if (expr->simple.is_binary) + provided = strlen(expr->simple.value); + else + provided = 4 * strlen(expr->simple.value); + + if (get_raw_bitfield_length(bf) != provided) + { + fprintf(stderr, "Error: variable '%s' and provided value sizes do not match (%u vs %u).\n", + expr->simple.variable, get_raw_bitfield_length(bf), provided); + result = false; + goto wce_exit; + } + + dprintf(fd, "raw_%s", expr->simple.variable); + + switch (expr->simple.comp) + { + case CCT_EQUAL: + dprintf(fd, " == "); + break; + case CCT_DIFF: + dprintf(fd, " != "); + break; + case CCT_AND: + dprintf(fd, " & "); + break; + } + + if (expr->simple.is_binary) + dprintf(fd, "b%s", expr->simple.value); + else + dprintf(fd, "0x%s", expr->simple.value); + + } + else + { + result = write_cond_expr(expr->composed.a, fd, bits); + if (!result) goto wce_exit; + + switch (expr->composed.operator) + { + case COT_AND: + dprintf(fd, " && "); + break; + case COT_OR: + dprintf(fd, " || "); + break; + } + + result = write_cond_expr(expr->composed.b, fd, bits); + if (!result) goto wce_exit; + + } + + dprintf(fd, ")"); + + wce_exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* REGLES ET ACTIONS CONSEQUENTES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un nouveau rassemblement de règles de décodage. * +* * +* Retour : Nouvelle structure prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +decoding_rules *create_decoding_rules(void) +{ + decoding_rules *result; /* Définition vierge à renvoyer*/ + + result = (decoding_rules *)calloc(1, sizeof(decoding_rules)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rules = ensemble de règles de décodage à supprimer. * +* * +* Description : Supprime de la mémoire un ensemble de règles supplémentaires.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_decoding_rules(decoding_rules *rules) +{ + size_t i; /* Boucle de parcours */ + extra_rule *rule; /* Règle à traiter */ + + for (i = 0; i < rules->extra_count; i++) + { + rule = &rules->extra[i]; + + if (rule->expr != NULL) + delete_cond_expr(rule->expr); + + switch (rule->action.type) + { + case CAT_SEE: + free(rule->action.details); + break; + + case CAT_UNPREDICTABLE: + break; + + case CAT_CALL: + case CAT_CHECKED_CALL: + free(rule->action.callee); + delete_arg_list(rule->action.args); + break; + + } + + } + + if (rules->extra != NULL) + free(rules->extra); + + free(rules); + +} + + +/****************************************************************************** +* * +* Paramètres : rules = ensemble de règles à compléter. * +* expr = représentation d'expression à conserver. * +* action = conséquence associée à la règle. * +* * +* Description : Ajoute une règle complète à la définition d'un codage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void register_conditional_rule(decoding_rules *rules, cond_expr *expr, const rule_action *action) +{ + extra_rule *rule; /* Nouvelle prise en compte */ + + rules->extra = (extra_rule *)realloc(rules->extra, ++rules->extra_count * sizeof(extra_rule)); + + rule = &rules->extra[rules->extra_count - 1]; + + rule->expr = expr; + rule->action = *action; + +} + + +/****************************************************************************** +* * +* Paramètres : rules = ensemble de règles à consulter. * +* filter = filtre sur les règles à effectivement imprimer. * +* fd = descripteur d'un flux ouvert en écriture. * +* arch = architecture visée par l'opération. * +* subarch = sous-catégorie de cette même architecture. * +* bits = gestionnaire des bits d'encodage. * +* list = liste de l'ensemble des fonctions de conversion. * +* pp = pré-processeur pour les échanges de chaînes. * +* exit = exprime le besoin d'une voie de sortie. [OUT] * +* * +* Description : Traduit en code les éventuelles règles présentes. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool write_decoding_rules(decoding_rules *rules, CondActionType filter, int fd, const char *arch, const char *subarch, const coding_bits *bits, const conv_list *list, const pre_processor *pp, bool *exit) +{ + bool result; /* Bilan à remonter */ + size_t i; /* Boucle de parcours */ + const extra_rule *rule; /* Règle en cours d'écriture */ + bool multi_lines; /* Nécessite des accolades */ + const char *callable; /* Fonction à appeler */ + + result = true; + + for (i = 0; i < rules->extra_count; i++) + { + rule = &rules->extra[i]; + + if (rule->action.type != filter) + continue; + + switch (rule->action.type) + { + case CAT_CALL: + multi_lines = false; + break; + + default: + multi_lines = true; + break; + + } + + if (rule->expr != NULL) + { + dprintf(fd, "\t\tif "); + + result = write_cond_expr(rule->expr, fd, bits); + if (!result) break; + + dprintf(fd, "\n"); + + if (multi_lines) + dprintf(fd, "\t\t{\n"); + + } + + switch (rule->action.type) + { + case CAT_SEE: + +#if 0 + dprintf(fd, "\t\t\tinstr = %s_read_%sinstr_%s", arch, subarch, rule->action.details); + + /* TODO : adapter les paramètres d'appel selon le 'coder' */ + dprintf(fd, "(_raw);\n"); + + dprintf(fd, "\t\t\tgoto quick_exit;\n"); + + *exit = true; +#endif + break; + + case CAT_UNPREDICTABLE: + break; + + case CAT_CALL: + + callable = find_macro(pp, rule->action.callee); + + if (callable == NULL) + callable = rule->action.callee; + + if (rule->expr != NULL) + dprintf(fd, "\t"); + + result = call_instr_func(callable, rule->action.args, fd, bits, list, pp); + + break; + + case CAT_CHECKED_CALL: + + callable = find_macro(pp, rule->action.callee); + + if (callable == NULL) + callable = rule->action.callee; + + if (rule->expr != NULL) + dprintf(fd, "\t"); + + result = checked_call_instr_func(callable, rule->action.args, fd, bits, list, pp); + + if (rule->expr != NULL) + dprintf(fd, "\t"); + + dprintf(fd, "\t\t\tgoto quick_exit;\n"); + + *exit = true; + break; + + } + + if (rule->expr != NULL && multi_lines) + dprintf(fd, "\t\t}\n"); + + dprintf(fd, "\n"); + + } + + return result; + +} diff --git a/tools/d2c/rules/manager.h b/tools/d2c/rules/manager.h new file mode 100644 index 0000000..f8ff2d6 --- /dev/null +++ b/tools/d2c/rules/manager.h @@ -0,0 +1,120 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * manager.h - prototypes pour les variations de décodage selon certaines conditions + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA 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 3 of the License, or + * (at your option) any later version. + * + * OpenIDA 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _TOOLS_D2C_RULES_MANAGER_H +#define _TOOLS_D2C_RULES_MANAGER_H + + +#include "../pproc.h" +#include "../args/manager.h" +#include "../bits/manager.h" +#include "../conv/manager.h" + + + +/* -------------------------- CONDITIONS DE DECLENCHEMENTS -------------------------- */ + + +/* Types de comparaison */ +typedef enum _CondCompType +{ + CCT_EQUAL, /* Egalité '==' */ + CCT_DIFF, /* Différence '!=' */ + CCT_AND /* Et logique '&' */ + +} CondCompType; + +/* Types de combinaison d'expressions */ +typedef enum _CondOpType +{ + COT_AND, /* Combinaison ET ('&&') */ + COT_OR /* Combinaison OU ('||') */ + +} CondOpType; + +/* Expression d'une condition */ +typedef struct _cond_expr cond_expr; + + +/* Crée une expression conditionnelle simple. */ +cond_expr *build_simple_cond_expression(char *, CondCompType, char *, bool); + +/* Crée une expression conditionnelle composée. */ +cond_expr *build_composed_cond_expression(cond_expr *, CondOpType, cond_expr *); + + + +/* ------------------------- REGLES ET ACTIONS CONSEQUENTES ------------------------- */ + + +/* Conséquence en cas de condition remplie */ +typedef enum _CondActionType +{ + CAT_SEE, /* Renvoi vers une instruction */ + CAT_UNPREDICTABLE, /* Cas de figure improbable */ + CAT_CALL, /* Appel à une fonction C */ + CAT_CHECKED_CALL /* Appel à une fonction C */ + +} CondActionType; + +/* Définition d'une action de règle */ +typedef struct _rule_action +{ + CondActionType type; /* Conséquence d'une validation*/ + + union + { + /* CAT_SEE */ + char *details; /* Eventuel complément d'info. */ + + /* CAT_CALL */ + struct + { + char *callee; /* Fonction appelée */ + arg_list_t *args; /* Arguments à fournir */ + + }; + + }; + +} rule_action; + +/* Règles de décodage supplémentaires */ +typedef struct _decoding_rules decoding_rules; + + +/* Crée un nouveau rassemblement de règles de décodage. */ +decoding_rules *create_decoding_rules(void); + +/* Supprime de la mémoire un ensemble de règles supplémentaires. */ +void delete_decoding_rules(decoding_rules *); + +/* Ajoute une règle complète à la définition d'un codage. */ +void register_conditional_rule(decoding_rules *, cond_expr *, const rule_action *); + +/* Traduit en code les éventuelles règles présentes. */ +bool write_decoding_rules(decoding_rules *, CondActionType, int, const char *, const char *, const coding_bits *, const conv_list *, const pre_processor *, bool *); + + + +#endif /* _TOOLS_D2C_RULES_MANAGER_H */ diff --git a/tools/d2c/rules/tokens.l b/tools/d2c/rules/tokens.l new file mode 100644 index 0000000..36d6c4a --- /dev/null +++ b/tools/d2c/rules/tokens.l @@ -0,0 +1,57 @@ + +%top { + +#include "grammar.h" + +} + + +%option noyywrap +%option nounput +%option noinput +%option yylineno +%option stack +%option noyy_top_state + +%x cond +%x cond_binval +%x cond_hexval +%x action +%x raw_line + + +%% + + +\/\/[^\n]+ { printf("SKIP '%s'\n", yytext); } + +"if" { yy_push_state(cond); return IF; } +<cond>[ ]+ { } +<cond>"(" { return EXPR_START; } +<cond>[A-Za-z_][A-Za-z0-9_]* { yylvalp->string = strdup(yytext); return NAME; } +<cond>"==" { return EQUAL; } +<cond>"'" { yy_push_state(cond_binval); } +<cond_binval>[01][01]* { yylvalp->string = strdup(yytext); return BINVAL; } +<cond_binval>"'" { yy_pop_state(); } +<cond>"0x" { yy_push_state(cond_hexval); } +<cond_hexval>[0-9a-f][0-9a-f]* { yylvalp->string = strdup(yytext); yy_pop_state(); return HEXVAL; } +<cond>")" { return EXPR_END; } +<cond>"&&" { return AND; } +<cond>"&" { return AND_LOG; } + +<cond>";" { yy_pop_state(); return THEN; } + +[ ] { } + +"see " { yy_push_state(raw_line); return SEE; } + +"unpredictable" { return UNPREDICTABLE; } + +"call" { yy_push_state(raw_line); return CALL; } +"chk_call" { yy_push_state(raw_line); return CHK_CALL; } + +<raw_line>[^\n]+ { yylvalp->cstring = yytext; return RAW_LINE; } +<raw_line>"\n" { yy_pop_state(); } + + +%% |