ir_reader: Add a pattern matching system and use it everywhere.

Previously, the IR reader was riddled with code that:
1. Checked for the right number of list elements (via a linked list walk)
2. Retrieved references to each component (via ->next->next pointers)
3. Downcasted as necessary to make sure that each sub-component was the
   right type (i.e. symbol, int, list).
4. Checking that the tag (i.e. "declare") was correct.

This was all very ad-hoc and a bit ugly.  Error checking had to be done
at both steps 1, 3, and 4.  Most code didn't even check the tag, relying
on the caller to do so.  Not all callers did.

The new pattern matching module performs the whole process in a single
straightforward function call, resulting in shorter, more readable code.

Unfortunately, MSVC does not support C99-style anonymous arrays, so the
pattern must be declared outside of the match call.
This commit is contained in:
Kenneth Graunke
2010-11-03 12:47:06 -07:00
parent 407184fe08
commit daeb0c646e
3 changed files with 297 additions and 311 deletions

View File

@@ -26,9 +26,11 @@
#ifndef S_EXPRESSION_H
#define S_EXPRESSION_H
#include "main/core.h" /* for Elements */
#include "strtod.h"
#include "list.h"
/* Type-safe downcasting macros (also safe to pass NULL) */
#define SX_AS_(t,x) ((x) && ((s_expression*) x)->is_##t()) ? ((s_##t*) (x)) \
: NULL
#define SX_AS_LIST(x) SX_AS_(list, x)
@@ -36,6 +38,10 @@
#define SX_AS_NUMBER(x) SX_AS_(number, x)
#define SX_AS_INT(x) SX_AS_(int, x)
/* Pattern matching macros */
#define MATCH(list, pat) s_match(list, Elements(pat), pat, false)
#define PARTIAL_MATCH(list, pat) s_match(list, Elements(pat), pat, true)
/* For our purposes, S-Expressions are:
* - <int>
* - <float>
@@ -140,4 +146,36 @@ public:
exec_list subexpressions;
};
// ------------------------------------------------------------
/**
* Part of a pattern to match - essentially a record holding a pointer to the
* storage for the component to match, along with the appropriate type.
*/
class s_pattern {
public:
s_pattern(s_expression *&s) : p_expr(&s), type(EXPR) { }
s_pattern(s_list *&s) : p_list(&s), type(LIST) { }
s_pattern(s_symbol *&s) : p_symbol(&s), type(SYMBOL) { }
s_pattern(s_number *&s) : p_number(&s), type(NUMBER) { }
s_pattern(s_int *&s) : p_int(&s), type(INT) { }
s_pattern(const char *str) : literal(str), type(STRING) { }
bool match(s_expression *expr);
private:
union {
s_expression **p_expr;
s_list **p_list;
s_symbol **p_symbol;
s_number **p_number;
s_int **p_int;
const char *literal;
};
enum { EXPR, LIST, SYMBOL, NUMBER, INT, STRING } type;
};
bool
s_match(s_expression *top, unsigned n, s_pattern *pattern, bool partial);
#endif /* S_EXPRESSION_H */