_ Public Class SearchGrammar Inherits Grammar Public Sub New() MyBase.New(False) Me.GrammarComments = "Google-to-SQL full-text query format converter. Based on original project by Michael Coles." & vbCr & vbLf & "http://www.sqlservercentral.com/articles/Full-Text+Search+(2008)/64248/ " & vbCr & vbLf & "Slightly revised to work with latest version of Irony. " ' Terminals Dim Term = CreateTerm("Term") Dim Phrase = New StringLiteral("Phrase", """") Dim ImpliedAnd = New ImpliedSymbolTerminal("ImpliedAnd") ' NonTerminals Dim BinaryExpression = New NonTerminal("BinaryExpression") Dim BinaryOp = New NonTerminal("BinaryOp") Dim Expression = New NonTerminal("Expression") Dim PrimaryExpression = New NonTerminal("PrimaryExpression") Dim ThesaurusExpression = New NonTerminal("ThesaurusExpression") Dim ThesaurusOperator = New NonTerminal("ThesaurusOperator") Dim ExactExpression = New NonTerminal("ExactExpression") Dim ParenthesizedExpression = New NonTerminal("ParenthesizedExpression") Dim ProximityExpression = New NonTerminal("ProximityExpression") Dim ProximityList = New NonTerminal("ProximityList") Me.Root = Expression Expression.Rule = PrimaryExpression Or BinaryExpression BinaryExpression.Rule = Expression + BinaryOp + Expression BinaryOp.Rule = ImpliedAnd Or "and" Or "&" Or "-" Or "or" Or "|" PrimaryExpression.Rule = Term Or ThesaurusExpression Or ExactExpression Or ParenthesizedExpression Or Phrase Or ProximityExpression ThesaurusExpression.Rule = "~" + Term ExactExpression.Rule = "+" + Term Or "+" + Phrase ParenthesizedExpression.Rule = "(" + Expression + ")" ProximityExpression.Rule = "<" + ProximityList + ">" MakePlusRule(ProximityList, Term) MarkTransient(PrimaryExpression, Expression, ProximityExpression, ParenthesizedExpression, BinaryOp) MarkPunctuation("<", ">", "(", ")") RegisterOperators(10, "or", "|") RegisterOperators(20, "and", "&", "-") RegisterOperators(20, ImpliedAnd) 'Register brace pairs to improve error reporting RegisterBracePair("(", ")") RegisterBracePair("<", ">") 'Do not report ImpliedAnd as expected symbol - it is not really a symbol Me.AddToNoReportGroup(ImpliedAnd) 'also do not report braces as expected Me.AddToNoReportGroup("(", ")", "<", ">") LanguageFlags = LanguageFlags Or LanguageFlags.CanRunSample End Sub 'Creates extended identifier terminal that allows international characters ' Following the pattern used for c# identifier terminal in TerminalFactory.CreateCSharpIdentifier method; Private Function CreateTerm(ByVal name As String) As IdentifierTerminal Dim term As New IdentifierTerminal(name, "!@#$%^*_'.?-", "!@#$%^*_'.?0123456789") 'Ul 'Ll 'Lt 'Lm 'Lo 'Nl 'Nd 'Pc 'Mc 'Mn 'Cf term.CharCategories.AddRange(New Globalization.UnicodeCategory() {Globalization.UnicodeCategory.UppercaseLetter, Globalization.UnicodeCategory.LowercaseLetter, Globalization.UnicodeCategory.TitlecaseLetter, Globalization.UnicodeCategory.ModifierLetter, Globalization.UnicodeCategory.OtherLetter, Globalization.UnicodeCategory.LetterNumber, _ Globalization.UnicodeCategory.DecimalDigitNumber, Globalization.UnicodeCategory.ConnectorPunctuation, Globalization.UnicodeCategory.SpacingCombiningMark, Globalization.UnicodeCategory.NonSpacingMark, Globalization.UnicodeCategory.Format}) 'StartCharCategories are the same term.StartCharCategories.AddRange(term.CharCategories) Return term End Function Public Overrides Function RunSample(ByVal parseTree As ParseTree) As String Dim sql = ConvertQuery(parseTree.Root) Return sql End Function Public Enum TermType Inflectional = 1 Thesaurus = 2 Exact = 3 End Enum Public Shared Function ConvertQuery(ByVal node As ParseTreeNode) As String Return ConvertQuery(node, TermType.Inflectional) End Function Private Shared Function ConvertQuery(ByVal node As ParseTreeNode, ByVal type As TermType) As String Dim result As String = "" ' Note that some NonTerminals don't actually get into the AST tree, ' because of some Irony's optimizations - punctuation stripping and ' transient nodes elimination. For example, ParenthesizedExpression - parentheses ' symbols get stripped off as punctuation, and child expression node ' (parenthesized content) replaces the parent ParenthesizedExpression node Select Case node.Term.Name Case "BinaryExpression" Dim opSym As String = String.Empty Dim op As String = node.ChildNodes(1).FindTokenAndGetText().ToLower() Dim sqlOp As String = "" Select Case op Case "", "&", "and" sqlOp = " AND " type = TermType.Inflectional Exit Select Case "-" sqlOp = " AND NOT " Exit Select Case "|", "or" sqlOp = " OR " Exit Select End Select 'switch result = "(" & ConvertQuery(node.ChildNodes(0), type) & sqlOp & ConvertQuery(node.ChildNodes(2), type) & ")" Exit Select Case "PrimaryExpression" result = "(" & ConvertQuery(node.ChildNodes(0), type) & ")" Exit Select Case "ProximityList" Dim tmp As String() = New String(node.ChildNodes.Count - 1) {} type = TermType.Exact For i As Integer = 0 To node.ChildNodes.Count - 1 tmp(i) = ConvertQuery(node.ChildNodes(i), type) Next result = "(" & String.Join(" NEAR ", tmp) & ")" type = TermType.Inflectional Exit Select Case "Phrase" result = """"c + node.Token.ValueString + """"c Exit Select Case "ThesaurusExpression" result = " FORMSOF (THESAURUS, " + node.ChildNodes(1).Token.ValueString & ") " Exit Select Case "ExactExpression" result = " """ + node.ChildNodes(1).Token.ValueString & """ " Exit Select Case "Term" Select Case type Case TermType.Inflectional result = node.Token.ValueString If result.EndsWith("*") Then result = """" & result & """" Else result = " FORMSOF (INFLECTIONAL, " & result & ") " End If Exit Select Case TermType.Exact result = node.Token.ValueString Exit Select End Select Exit Select Case Else ' This should never happen, even if input string is garbage Throw New ApplicationException("Converter failed: unexpected term: " & Convert.ToString(node.Term.Name) & ". Please investigate.") End Select Return result End Function End Class