Recently in an app, instead of supporting the bare minimum I wanted to support a bit more sophisticated search expression, like embedded commands and compounded conditional expression. I just hand-rolled the lexical tokenizer and the parser, and stopped without going the full mile. The tokenizer used simple regex to break up the terms and tagged them with token types. Came up with a grammar for the mini language. The parser used the standard recursive descent parsing technique on the grammar production. It's simple to handle errors and do auto-completion of the missing syntax because the parser knew what to expect at the point of error and could fill in the default nodes in the tree as needed. The generated AST was enough to implement the search tree and the embedded commands. The whole thing was only couple files and done in couple days, but it's very useful for the app.