1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * See LICENSE.txt included in this distribution for the specific 9 * language governing permissions and limitations under the License. 10 * 11 * When distributing Covered Code, include this CDDL HEADER in each 12 * file and include the License file at LICENSE.txt. 13 * If applicable, add the following below this CDDL HEADER, with the 14 * fields enclosed by brackets "[]" replaced with your own identifying 15 * information: Portions Copyright [yyyy] [name of copyright owner] 16 * 17 * CDDL HEADER END 18 */ 19 20 /* 21 * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. 22 * Portions Copyright (c) 2017, Chris Fraire <cfraire@me.com>. 23 */ 24 25 /* 26 * Cross reference a Tcl file 27 */ 28 29 package org.opengrok.indexer.analysis.tcl; 30 31 import java.io.IOException; 32 import org.opengrok.indexer.analysis.JFlexSymbolMatcher; 33 import org.opengrok.indexer.web.HtmlConsts; 34 %% 35 %public 36 %class TclXref 37 %extends JFlexSymbolMatcher 38 %unicode 39 %int 40 %char 41 %include ../CommonLexer.lexh 42 %include ../CommonXref.lexh 43 %{ 44 private int braceCount; 45 46 @Override reset()47 public void reset() { 48 super.reset(); 49 braceCount = 0; 50 } 51 52 @Override yypop()53 public void yypop() throws IOException { 54 onDisjointSpanChanged(null, yychar); 55 super.yypop(); 56 } 57 58 /** 59 * Write {@code whsp} to the {@code xref} output -- if the whitespace does 60 * not contain any LFs then the full String is written; otherwise, pre-LF 61 * spaces are condensed as usual. 62 * @param xref the target instance 63 * @param whsp a defined whitespace capture 64 * @throws java.io.IOException if an output error occurs 65 */ writeWhitespace(String whsp)66 private void writeWhitespace(String whsp) throws IOException { 67 int i; 68 if ((i = whsp.indexOf("\n")) == -1) { 69 onNonSymbolMatched(whsp, yychar); 70 } else { 71 int numlf = 1, off = i + 1; 72 while ((i = whsp.indexOf("\n", off)) != -1) { 73 ++numlf; 74 off = i + 1; 75 } 76 while (numlf-- > 0) onEndOfLineMatched("\n", yychar); 77 if (off < whsp.length()) { 78 onNonSymbolMatched(whsp.substring(off), yychar); 79 } 80 } 81 } 82 chkLOC()83 protected void chkLOC() { 84 switch (yystate()) { 85 case COMMENT: 86 case SCOMMENT: 87 break; 88 default: 89 phLOC(); 90 break; 91 } 92 } 93 %} 94 95 File = [a-zA-Z] {FNameChar}+ "." ([a-zA-Z]+) 96 97 %state STRING COMMENT SCOMMENT BRACES VARSUB2 98 99 %include ../Common.lexh 100 %include ../CommonURI.lexh 101 %include ../CommonPath.lexh 102 %include Tcl.lexh 103 %% 104 <YYINITIAL>{ 105 106 [\{] { 107 chkLOC(); 108 onNonSymbolMatched(yytext(), yychar); 109 ++braceCount; 110 yypush(BRACES); 111 } 112 } 113 114 <YYINITIAL, BRACES> { 115 {Number} { 116 chkLOC(); 117 onDisjointSpanChanged(HtmlConsts.NUMBER_CLASS, yychar); 118 onNonSymbolMatched(yytext(), yychar); 119 onDisjointSpanChanged(null, yychar); 120 } 121 \" { 122 chkLOC(); 123 yypush(STRING); 124 onDisjointSpanChanged(HtmlConsts.STRING_CLASS, yychar); 125 onNonSymbolMatched(yytext(), yychar); 126 } 127 "#" { 128 yypush(SCOMMENT); 129 onDisjointSpanChanged(HtmlConsts.COMMENT_CLASS, yychar); 130 onNonSymbolMatched(yytext(), yychar); 131 } 132 {WordOperators} { 133 chkLOC(); 134 onNonSymbolMatched(yytext(), yychar); 135 } 136 } 137 138 <YYINITIAL, STRING, BRACES> { 139 {Backslash_sub} { 140 chkLOC(); 141 onNonSymbolMatched(yytext(), yychar); 142 } 143 {Backslash_nl} { 144 chkLOC(); 145 String capture = yytext(); 146 String esc = capture.substring(0, 1); 147 String whsp = capture.substring(1); 148 onNonSymbolMatched(esc, yychar); 149 writeWhitespace(whsp); 150 } 151 {Varsub1} { 152 chkLOC(); 153 String capture = yytext(); 154 String sigil = capture.substring(0, 1); 155 String name = capture.substring(1); 156 onNonSymbolMatched(sigil, yychar); 157 onFilteredSymbolMatched(name, yychar, Consts.kwd); 158 } 159 {Varsub2} { 160 chkLOC(); 161 // TclXref could get away without VARSUB2 as a state, but for ease in 162 // comparing to TclSymbolTokenizer, it is modeled here too. 163 yypush(VARSUB2); 164 String capture = yytext(); 165 String sigil = capture.substring(0, 1); 166 int lparen_i = capture.indexOf("("); 167 String name1 = capture.substring(1, lparen_i); 168 yypushback(capture.length() - lparen_i - 1); 169 onNonSymbolMatched(sigil, yychar); 170 if (name1.length() > 0) { 171 onFilteredSymbolMatched(name1, yychar, Consts.kwd); 172 } 173 onNonSymbolMatched("(", yychar); 174 } 175 {Varsub3} { 176 chkLOC(); 177 String capture = yytext(); 178 String sigil = capture.substring(0, 2); 179 String name = capture.substring(2, capture.length() - 1); 180 String endtoken = capture.substring(capture.length() - 1); 181 onNonSymbolMatched(sigil, yychar); 182 onFilteredSymbolMatched(name, yychar, Consts.kwd); 183 onNonSymbolMatched(endtoken, yychar); 184 } 185 } 186 187 <VARSUB2> { 188 {name_unit}+ { 189 chkLOC(); 190 String name2 = yytext(); 191 yypop(); 192 onFilteredSymbolMatched(name2, yychar, Consts.kwd); 193 } 194 } 195 196 <YYINITIAL, BRACES> { 197 {OrdinaryWord} { 198 chkLOC(); 199 String id = yytext(); 200 onFilteredSymbolMatched(id, yychar, Consts.kwd); 201 } 202 } 203 204 <STRING> { 205 \" { 206 chkLOC(); 207 onNonSymbolMatched(yytext(), yychar); 208 yypop(); 209 } 210 } 211 212 <BRACES> { 213 [\}] { 214 chkLOC(); 215 if (--braceCount == 0) { 216 yypop(); 217 } 218 onNonSymbolMatched(yytext(), yychar); 219 } 220 [\{] { 221 chkLOC(); 222 ++braceCount; 223 onNonSymbolMatched(yytext(), yychar); 224 } 225 } 226 227 <SCOMMENT> { 228 {WhspChar}*{EOL} { 229 yypop(); 230 onEndOfLineMatched(yytext(), yychar); 231 } 232 } 233 234 <YYINITIAL, STRING, COMMENT, SCOMMENT, BRACES> { 235 {WhspChar}*{EOL} { onEndOfLineMatched(yytext(), yychar); } 236 [[\s]--[\n]] { onNonSymbolMatched(yytext(), yychar); } 237 [^\n] { chkLOC(); onNonSymbolMatched(yytext(), yychar); } 238 } 239 240 <STRING, COMMENT, SCOMMENT> { 241 {FPath} { 242 chkLOC(); 243 onPathlikeMatched(yytext(), '/', false, yychar); 244 } 245 246 {File} 247 { 248 chkLOC(); 249 String path = yytext(); 250 onFilelikeMatched(path, yychar); 251 } 252 253 {BrowseableURI} { 254 chkLOC(); 255 onUriMatched(yytext(), yychar); 256 } 257 258 {FNameChar}+ "@" {FNameChar}+ "." {FNameChar}+ 259 { 260 chkLOC(); 261 onEmailAddressMatched(yytext(), yychar); 262 } 263 } 264