1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
/*
* Copyright (C) 2007 Xagasoft, All rights reserved.
*
* This file is part of the libbu++ library and is released under the
* terms of the license contained in the file LICENSE.
*/
#ifndef BU_MINI_MACRO_H
#define BU_MINI_MACRO_H
#include "bu/hash.h"
#include "bu/fstring.h"
namespace Bu
{
/**
* A processor for Libbu++ brand Mini Macros. These are really simple, but
* still fairly flexible. It's mainly text replacement, but with a few
* extras like filter functions and conditional text segments. So far we
* don't support loops or anything, I'm not sure we ever will.
*
* Anatomy of a mini macro:
* - Every macro begins with a two character code, the first character is
* always '{', the second character determines the operation to perform.
* - If the '{' is followed by a character that is not valid it is not
* considered for expansion and the characters are copied to the output.
* - Every macro ends with a closing '}'
* - Macro types:
* - '=': variable replacement. The '=' is immediatley followed by the
* name of the variable to replace, then any number of optional filter
* segments.
* - '?': conditional text. The '?' is immediately followed by the
* variable to test. This works two ways, the variable can be alone, in
* which case it's existance is tested, or it can be followed by a "="
* and a string to compare to. This is then followed by a text segment
* that will be used if the test is true, and an optional text segment
* to be used if the test is false.
* - ':': command. The ':' is immediately followed by a command string,
* of which there's only one right now, but that's ok. These are not
* put into the output stream, but instead mark something for the
* parser. Currently supported:
* - {:end}: end of parsing, stop here, also make note of how many input
* characters were used.
* - Segments:
* - Each segment is seperated by a colon.
* - Filter segments give the name of the filter, followed by
* parenthesies. Parameters may be provided within the parenthesies.
* - Text segments should always be quoted, but may contain any characters
* within the quotes, backslash is used as per C/ANSI/ISO standard.
* You can also quote any text using [' '] instead of quotes, which
* allows for nested strings. The [' token is only recognised within
* a macro.
*
*@verbatim
{=name:tolower()}
{=name:ccsplit("_"):toupper()}
{?name:"name exists and is {=name}"}
{?name:"{=name}":"no name!"}
{?name="bob":"You're named bob!":"Who are you? I only know bob..."}
@endverbatim
*/
typedef Bu::Hash<Bu::FString, Bu::FString> StrHash;
class MiniMacro
{
public:
MiniMacro();
virtual ~MiniMacro();
Bu::FString parse( const Bu::FString &sIn );
void addVar( const Bu::FString &sName, const Bu::FString &sValue );
private:
const char *sCur;
Bu::FString parseRepl();
Bu::FString parseCond();
Bu::FString parseCmd();
Bu::FString callFunc(
const Bu::FString &sIn, const Bu::FString &sFunc );
StrHash hVars;
public:
typedef Bu::List<Bu::FString> StrList;
class Func
{
public:
Func(){}
virtual ~Func(){}
virtual Bu::FString call(
const Bu::FString &sIn, StrList &lsParam )=0;
};
class FuncToUpper : public Func
{
public:
FuncToUpper(){}
virtual ~FuncToUpper(){}
virtual Bu::FString call(
const Bu::FString &sIn, StrList &lsParam )
{
Bu::FString sOut( sIn );
sOut.toUpper();
return sOut;
}
};
class FuncToLower : public Func
{
public:
FuncToLower(){}
virtual ~FuncToLower(){}
virtual Bu::FString call(
const Bu::FString &sIn, StrList &lsParam )
{
Bu::FString sOut( sIn );
sOut.toLower();
return sOut;
}
};
private:
typedef Bu::Hash<Bu::FString,class Func *> FuncHash;
FuncHash hFuncs;
};
};
#endif
|