2 package com
.interrupt
.bookkeeping
.interpreter
.lexer
;
5 import java
.util
.HashMap
;
6 import java
.util
.Iterator
;
9 import java
.util
.regex
.Matcher
;
10 import java
.util
.regex
.Pattern
;
12 import org
.apache
.log4j
.Logger
;
14 import com
.interrupt
.bob
.base
.BobSystem
;
16 import com
.interrupt
.bob
.util
.Util
;
17 import com
.interrupt
.bookkeeping
.cc
.bkell
.Bkell
;
22 private Logger logger
= Logger
.getLogger(Main
.class);
25 Problem 1: This synax is not recursive. Thus one cannot put commands into commands
26 Problem 2: Extracting raw XML from command line is very difficult to
33 -counterWeight [[a-z]{5,6}]*
34 -amount [[0-9]+\.[0-9]+]*
37 -date [[0-9]{1,2}/[0-9]{1,2}/[0-9]{4}]*
43 create (token -opts(token.literal,...))
44 add ((token) token.literal,...)
45 remove ((token) token.literal,...)
46 reverse ((token) token.literal,...)
55 ** After reading user input, the Lexer must pass the below parameters to the Parser.
56 Each command will be processed iteratively, starting from each leaf node to the root command:
57 i) commad ii) token iii) options iv) token.literals
61 public Map symbolMap
= new HashMap();
62 public Map commandMap
= new HashMap();
65 public static void main(String args
[]) {
67 Logger
.getLogger(Main
.class).debug( "Main Input: "+ args
[0] );
69 String opt_entry
= "-entry [A-Za-z0-9]*"; // opt.entry
70 String opt_account
= "-account [A-Za-z0-9]*"; // opt.account
71 String opt_journal
= "-journal [A-Za-z0-9]*"; // opt.journal
72 String opt_name
= "-name [A-Za-z0-9]*"; // opt.name
73 String opt_type
= "-type [A-Za-z0-9]*"; // opt.type
74 String opt_cweight
= "-counterWeight [[a-z]{5,6}]*"; // opt.cweight
75 String opt_amount
= "-amount ([0-9]+\\.[0-9]+)*"; // opt.amount
76 String opt_id
= "-id [A-Za-z0-9]*"; // opt.id
77 String opt_entrynum
= "-entrynum [0-9]*"; // opt.entrynum
78 String opt_date
= "-date [[0-9]{1,2}/[0-9]{1,2}/[0-9]{4}]*"; // opt.date
79 String opt_file
= "-F [A-Za-z0-9]*"; // opt.file
81 String tok_debit_in
= "(debit[,]?)*"; // token.in.debit
82 String tok_credit_in
= "(credit[,]?)*"; // token.in.credit
83 String tok_entry_in
= "(entry[,]?)*"; // token.in.entry
84 String tok_debit
= "debit"; // token.debit
85 String tok_credit
= "credit"; // token.credit
86 String tok_entry
= "entry"; // token.entry
87 String tok_transaction
= "transaction"; // token.transaction
88 String tok_journal
= "journal"; // token.journal
89 String tok_account
= "account"; // token.account
92 // we also have to represent XML token literals
95 Main main
= new Main();
96 main
.symbolMap
.put("opt.entry", opt_entry
);
97 main
.symbolMap
.put("opt.account", opt_account
);
98 main
.symbolMap
.put("opt.journal", opt_journal
);
99 main
.symbolMap
.put("opt.name", opt_name
);
100 main
.symbolMap
.put("opt.type", opt_type
);
101 main
.symbolMap
.put("opt.cweight", opt_cweight
);
102 main
.symbolMap
.put("opt.amount", opt_amount
);
103 main
.symbolMap
.put("opt.id", opt_id
);
104 main
.symbolMap
.put("opt.entrynum", opt_entrynum
);
105 main
.symbolMap
.put("opt.date", opt_date
);
106 main
.symbolMap
.put("opt.file", opt_file
);
108 main
.symbolMap
.put("token.debit.in", tok_debit_in
);
109 main
.symbolMap
.put("token.credit.in", tok_credit_in
);
110 main
.symbolMap
.put("token.entry.in", tok_entry_in
);
111 main
.symbolMap
.put("token.debit", tok_debit
);
112 main
.symbolMap
.put("token.credit", tok_credit
);
113 main
.symbolMap
.put("token.entry", tok_entry
);
114 main
.symbolMap
.put("token.transaction", tok_transaction
);
115 main
.symbolMap
.put("token.journal", tok_journal
);
116 main
.symbolMap
.put("token.account", tok_account
);
122 String cmd_create_debit
= "create \\((${token.debit}){1} " +
123 "(((${opt.entry} ${opt.account} ${opt.amount}){1}|" +
124 "(${opt.id}){1})\\){1}";
126 String cmd_create_credit
= "create \\((${token.credit}){1} " +
127 "(((${opt.entry} ${opt.account} ${opt.amount}){1}|" +
128 "(${opt.id}){1})\\){1}";
130 String cmd_create_entry
= "create \\((${token.entry}){1} " +
131 "((${opt.entrynum} ${opt.journal} ${opt.date}){1}|" +
132 "(${opt.id}){1}){1} " +
133 "\\(${token.debit.in}|${token.credit.in}\\)\\)";
135 String cmd_create_transaction
= "create \\((${token.transaction}){1} " +
136 "((${opt.name}){1}|" +
137 "(${opt.id}){1}){1} " +
138 "\\(${token.entry.in}\\)\\)";
140 String cmd_create_journal
= "create \\((${token.journal})* " +
141 "((${opt.name}{1}|" +
142 "(${opt.id}){1}){1} " +
143 "\\(${token}[,]?)*\\)\\)";
145 /*String cmd_create_account = "create \\((${token.account})* " +
146 "((${opt.name}{1}|" +
147 "((${opt.type}{1}|" +
148 "(${opt.cweight}){1}){1} " +
149 "\\(${token}[,]?)*\\)\\)";
152 String cmd_create_account
= "create \\(${token.account} "+
153 "((${opt.name}){1} (${opt.type}){1} (${opt.cweight}){1} "+
154 "\\((${token}[,]?)*\\)\\)";
157 String cmd_add
= "add \\(\\(\\$\\{token\\})*\\) \\$\\{token\\}[,]?)*\\)";
158 String cmd_remove
= "remove \\(\\(\\$\\{token\\})*\\) \\$\\{token\\}[,]?)*\\)";
159 String cmd_reverse
= "reverse \\(\\(\\$\\{token\\})*) \\$\\{token\\}[,]?)*\\)";
160 String cmd_find
= "find \\(\\$\\{token\\})* \\$\\{opts\\})*\\)";
161 String cmd_load
= "load \\(\\$\\{token\\})* \\$\\{opts\\})*\\)";
162 String cmd_list
= "list \\(\\$\\{token\\})* \\$\\{opts\\})*\\)";
163 String cmd_login
= "login";
164 String cmd_logout
= "logout";
165 String cmd_exit
= "exit";
167 main
.commandMap
.put("cmd.create.debit", cmd_create_debit
);
168 main
.commandMap
.put("cmd.create.credit", cmd_create_credit
);
169 main
.commandMap
.put("cmd.create.entry", cmd_create_entry
);
170 main
.commandMap
.put("cmd.create.transaction", cmd_create_transaction
);
171 //main.commandMap.put("cmd.create.journal", cmd_create_journal);
172 //main.commandMap.put("cmd.create.account", cmd_create_account);
175 String substitution
= "\\$\\{[A-Z-a-z0-9\\.]+\\}";
177 main
.testCreateDebit(args
[0]);
181 public void testCreateDebit(String input
) {
184 /*String regex = "create \\((${token.debit}){1} " +
185 "((${opt.entry} ${opt.account} ${opt.amount}){1}|" +
186 "(${opt.id}){1})\\){1}";
189 Set keyset
= this.commandMap
.keySet();
190 Iterator keyiterator
= keyset
.iterator();
191 while(keyiterator
.hasNext()) {
193 String rkey
= (String
)keyiterator
.next();
194 regex
= (String
)this.commandMap
.get(rkey
);
197 logger
.debug("NEXT Key["+rkey
+"] Pattern["+regex
+"]");
200 String regex_sub
= "\\$\\{[A-Z-a-z0-9\\.]+\\}";
201 //boolean matches_sub = Pattern.matches( regex_sub, regex );
202 boolean hasMatch
= false;
203 Pattern pattern
= Pattern
.compile(regex_sub
);
204 Matcher matcher
= pattern
.matcher(regex
);
206 // find token & option substitutions
207 //logger.debug( "Substitution Matches / count["+matcher.groupCount()+"]: "+ matches_sub );
209 StringBuffer newRegex
= new StringBuffer();
210 int new_start_index
= -1;
211 int new_end_index
= -1;
212 while(matcher
.find()) {
217 //logger.debug("Next Match / index["+matcher.start()+"]: "+ matcher.group());
219 String interpretable
= regex
.substring(matcher
.start(), matcher
.end());
220 String interpreted
= Util
.getInterpretableName(interpretable
);
221 String interpretedPattern
= (String
)symbolMap
.get(interpreted
);
222 //logger.debug("Interpreted["+interpreted+"] / InterpretedPattern["+interpretedPattern+"]");
224 // match patterns on token & substitutions
225 Pattern pattern_in
= null;
226 Matcher matcher_in
= null;
227 if(interpretedPattern
!= null) {
229 pattern_in
= Pattern
.compile(interpretedPattern
);
230 matcher_in
= pattern_in
.matcher(input
);
232 if(matcher_in
.find()) {
235 logger
.debug(">>> INPUT["+interpretedPattern
+"] / ["+interpretable
+"] > Next Match["+matcher_in
.group()+"]");
236 //logger.debug("Hmmm ["+regex.substring(matcher.start(), matcher.end())+"] / "+ !")*".equals(regex.substring(matcher.end(), matcher.end() + 2)));
237 if( !")*".equals(interpretedPattern
.substring(interpretedPattern
.length() - 2, interpretedPattern
.length()) )){
240 if( '(' == regex
.charAt(matcher
.start() - 1) ) {
241 new_start_index
= matcher
.start() - 1;
244 new_start_index
= matcher
.start();
248 if( "){1}".equals(regex
.substring(matcher
.end(), matcher
.end() + 4))) {
249 new_end_index
= matcher
.end() + 4;
252 new_end_index
= matcher
.end();
258 new_start_index
= matcher
.start();
259 new_end_index
= matcher
.end();
262 newRegex
.append(regex
.substring(lastIndex
, new_start_index
));
263 newRegex
.append(interpretedPattern
);
264 lastIndex
= new_end_index
;
265 //logger.debug(">>> REPLACING in regex["+ newRegex.toString() +"]");
271 logger
.debug(">>> INPUT ["+interpretedPattern
+"] / ["+interpretable
+"] > NO MATCH ");
272 //logger.debug("Hmmm ["+regex.substring(matcher.start(), matcher.end())+"] / "+ !")*".equals(regex.substring(matcher.end(), matcher.end() + 2)));
273 if( !")*".equals(interpretedPattern
.substring(interpretedPattern
.length() - 2, interpretedPattern
.length()) )){
276 if( '(' == regex
.charAt(matcher
.start() - 1) ) {
277 new_start_index
= matcher
.start() - 1;
280 new_start_index
= matcher
.start();
285 "){1}".equals(regex
.substring(matcher
.end(), matcher
.end() + 4))
287 new_end_index
= matcher
.end() + 4;
290 new_end_index
= matcher
.end();
296 new_start_index
= matcher
.start();
297 new_end_index
= matcher
.end();
300 newRegex
.append(regex
.substring(lastIndex
, new_start_index
));
301 newRegex
.append("__no_pattern__");
302 lastIndex
= new_end_index
;
303 //logger.debug(">>> REPLACING in regex["+ newRegex.toString() +"]");
313 newRegex
.append(regex
.substring(new_end_index
));
314 String regexFinal
= newRegex
.toString();
315 logger
.debug(" >>> FINAL regex["+ regexFinal
+"]");
316 logger
.debug(" >>> FINAL input["+input
+"]");
318 Pattern patternFinal
= Pattern
.compile(regexFinal
);
319 Matcher matcherFinal
= patternFinal
.matcher(input
);
320 logger
.debug(" >>> FINAL Matches["+ matcherFinal
.matches()+"]");
325 // now collect i) token ii) options iii) token.literals