001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.cnd.editor.makefile;
043:
044: import org.netbeans.editor.Syntax;
045: import org.netbeans.editor.TokenID;
046: import java.util.Stack;
047:
048: /**
049: * Syntax analyzes for Makefile files.
050: * Tokens and internal states are given below.
051: */
052:
053: public class MakefileSyntax extends Syntax {
054:
055: //internal analyzer states
056: //numbers assigned to states are not important as long as they are unique
057: private static final int AFTER_COLON = 1; // after ':'
058: private static final int AFTER_DOLLAR = 2; // after '$'
059: private static final int AFTER_BSLASH = 3; // after '\\'
060: private static final int AFTER_PLUS = 4; // after '+'
061: private static final int IN_STRING = 5; // inside string constant
062: private static final int IN_STRING_AFTER_BSLASH = 6; // inside string constant
063: // after backslash
064: private static final int IN_MACRO = 7; // inside macro
065: private static final int IN_MACRO_AFTER_DELIM = 8; // inside macro $() ${}
066: private static final int IN_WHITESPACE = 9; // inside white space
067: private static final int IN_LINE_COMMENT = 10; // inside line comment
068: private static final int IN_IDENTIFIER = 11; // inside identifier
069: private static final int IN_DOT_IDENTIFIER = 12; // inside .identifier
070: private static final int IN_COLON_IDENTIFIER = 13; // inside :identifier
071:
072: private static final char LEFT_PAREN = '(';
073: private static final char RIGHT_PAREN = ')';
074: private static final char LEFT_CURLY = '{';
075: private static final char RIGHT_CURLY = '}';
076:
077: /**
078: * Specifies if the string is defined in double quotes or single quote
079: */
080: private static boolean STRING_IN_DOUBLE_QUOTE = true;
081:
082: /**
083: * Specifies how many macro names has the current macro in it
084: * e.g. the macro $(USER-$(IDE)) is valid and nested_macro_num = 1
085: */
086: private static Integer BRACE_DELIM = new Integer(1);
087: private static Integer PARAN_DELIM = new Integer(2);
088: private Stack macroDelimStack = new Stack();
089:
090: /** constructor */
091: public MakefileSyntax() {
092: tokenContextPath = MakefileTokenContext.contextPath;
093: }
094:
095: /**
096: * This is core function of analyzer and it returns either the token-id
097: * or null to indicate that the end of buffer was found.
098: * The function scans the active character and does one or more
099: * of the following actions:
100: * 1. change internal analyzer state
101: * 2. set the token-context-path and return token-id
102: * 3. adjust current position to signal different end of token;
103: * the character that offset points to is not included in the token
104: */
105: protected TokenID parseToken() {
106: char actChar;
107:
108: while (offset < stopOffset) {
109: actChar = buffer[offset];
110:
111: switch (state) {
112: case INIT:
113: switch (actChar) {
114: case '#': // Makefile comments begin with a # and last to the end of line
115: state = IN_LINE_COMMENT;
116: break;
117:
118: case ':':
119: state = AFTER_COLON;
120: break;
121:
122: case '.':
123: state = IN_DOT_IDENTIFIER;
124: break;
125:
126: case '$':
127: state = AFTER_DOLLAR;
128: break;
129:
130: case '\\':
131: state = AFTER_BSLASH;
132: break;
133:
134: case '"':
135: state = IN_STRING;
136: STRING_IN_DOUBLE_QUOTE = true;
137: break;
138:
139: case '\'':
140: state = IN_STRING;
141: STRING_IN_DOUBLE_QUOTE = false;
142: break;
143:
144: case '+':
145: state = AFTER_PLUS;
146: break;
147:
148: case '-':
149: offset++;
150: return MakefileTokenContext.RULES_MINUS;
151:
152: case '@':
153: offset++;
154: return MakefileTokenContext.RULES_AT;
155:
156: case '?':
157: offset++;
158: return MakefileTokenContext.RULES_QUESTION_MARK;
159:
160: case '!':
161: offset++;
162: return MakefileTokenContext.RULES_EXCLAMATION;
163:
164: case '%':
165: offset++;
166: return MakefileTokenContext.TARGET_PERCENT;
167:
168: case '=':
169: offset++;
170: return MakefileTokenContext.MACRO_OP_EQUALS;
171:
172: case LEFT_PAREN:
173: offset++;
174: return MakefileTokenContext.MACRO_LPAREN;
175:
176: case RIGHT_PAREN:
177: offset++;
178: return MakefileTokenContext.MACRO_RPAREN;
179:
180: case LEFT_CURLY:
181: offset++;
182: return MakefileTokenContext.MACRO_LBRACE;
183:
184: case RIGHT_CURLY:
185: offset++;
186: return MakefileTokenContext.MACRO_RBRACE;
187:
188: default:
189: // Check for whitespace
190: if (Character.isWhitespace(actChar)) {
191: state = IN_WHITESPACE;
192: break;
193: }
194:
195: // Check for identifier
196: // To find out why we're using isJAVAidentifier
197: // here, grep for isJavaIdentifierStart in
198: // CCSyntax.java
199: if (Character.isJavaIdentifierStart(actChar)) {
200: state = IN_IDENTIFIER;
201: break;
202: }
203:
204: //for the sake of the syntax-highlighting
205: //assume non-identifiers and non language specific characters
206: //are identifiers
207: offset++;
208: return MakefileTokenContext.IDENTIFIER;
209:
210: } // switch(actchar)
211: break; // END INIT STATE
212:
213: case IN_WHITESPACE:
214: if (!Character.isWhitespace(actChar)) {
215: state = INIT;
216: return MakefileTokenContext.WHITESPACE;
217: }
218: break;
219:
220: case IN_LINE_COMMENT:
221: switch (actChar) {
222: case '\n':
223: state = INIT;
224: offset++;
225: return MakefileTokenContext.LINE_COMMENT;
226: } // switch IN_LINE_COMMENT
227: break;
228:
229: case AFTER_BSLASH:
230: switch (actChar) {
231: case '$':
232: offset++;
233: state = INIT;
234: return MakefileTokenContext.MACRO_ESCAPED_DOLLAR;
235:
236: default:
237: state = IN_IDENTIFIER;
238: offset--; //go back and evaluate the character
239: break;
240: }//switch AFTER_BSLASH
241: break;
242:
243: case AFTER_DOLLAR:
244: switch (actChar) {
245: case '$':
246: offset++;
247: state = INIT;
248: return MakefileTokenContext.MACRO_DOLAR_REFERENCE;
249:
250: case '*':
251: offset++;
252: state = INIT;
253: return MakefileTokenContext.MACRO_DYN_TARGET_BASENAME;
254:
255: case '<':
256: offset++;
257: state = INIT;
258: return MakefileTokenContext.MACRO_DYN_DEPENDENCY_FILENAME;
259:
260: case '@':
261: offset++;
262: state = INIT;
263: return MakefileTokenContext.MACRO_DYN_CURRENTTARGET;
264:
265: case '?':
266: offset++;
267: state = INIT;
268: return MakefileTokenContext.MACRO_DYN_DEPENDENCY_LIST;
269:
270: case '%':
271: offset++;
272: state = INIT;
273: return MakefileTokenContext.MACRO_DYN_LIBRARYNAME;
274:
275: case LEFT_PAREN:
276: case LEFT_CURLY:
277: offset--; //go back and evaluate the character
278: state = IN_MACRO_AFTER_DELIM;
279: break;
280:
281: default:
282: state = IN_MACRO;
283: break;
284: } //switch AFTER_DOLLAR
285: break;
286:
287: case IN_MACRO:
288: if (!(Character.isJavaIdentifierPart(actChar))) {
289: switch (actChar) {
290: case '.': //allowable macroname characters
291: case '-':
292: break;
293: default:
294: state = INIT;
295: return MakefileTokenContext.MACRO_LITERAL;
296: } //switch IN_MACRO
297: }
298: break;
299:
300: case IN_MACRO_AFTER_DELIM:
301: if (!(Character.isJavaIdentifierPart(actChar))) {
302: switch (actChar) {
303: case '.': //allowable macroname characters
304: case '-':
305: break;
306:
307: case LEFT_PAREN:
308: macroDelimStack.push(PARAN_DELIM);
309: break;
310:
311: case LEFT_CURLY:
312: macroDelimStack.push(BRACE_DELIM);
313: break;
314:
315: case RIGHT_PAREN:
316: case RIGHT_CURLY:
317: Integer delim = (actChar == RIGHT_PAREN) ? PARAN_DELIM
318: : BRACE_DELIM;
319: if (!macroDelimStack.empty()) {
320: if (((Integer) macroDelimStack.pop()) == delim) {
321: if (macroDelimStack.empty()) {
322: state = INIT;
323: offset++;
324: return MakefileTokenContext.MACRO_LITERAL;
325: } else {
326: break;
327: }
328: }
329: }
330:
331: //this statement is reached only if there is an error in macro string
332: state = INIT;
333: offset++;
334: macroDelimStack = new Stack();
335: return MakefileTokenContext.ERR_INCOMPLETE_MACRO_LITERAL;
336:
337: default:
338: if (macroDelimStack.empty()) {
339: state = INIT;
340: return MakefileTokenContext.MACRO_LITERAL;
341: } else {
342: state = INIT;
343: macroDelimStack = new Stack();
344: // Fix for beta13: IZ 86737
345: //return MakefileTokenContext.ERR_INCOMPLETE_MACRO_LITERAL;
346: }
347: } //switch IN_MACRO_AFTER_DELIM
348: }
349: break;
350:
351: case AFTER_PLUS:
352: switch (actChar) {
353: case '=':
354: state = INIT;
355: offset++;
356: return MakefileTokenContext.MACRO_OP_APPEND;
357:
358: default:
359: state = INIT;
360: offset++;
361: return MakefileTokenContext.RULES_PLUS;
362: } // switch AFTER_PLUS
363:
364: case AFTER_COLON:
365: switch (actChar) {
366: case '=':
367: offset++;
368: state = INIT;
369: return MakefileTokenContext.MACRO_OP_CONDITIONAL;
370:
371: case ':':
372: offset++;
373: state = INIT;
374: return MakefileTokenContext.TARGET_DOUBLE_COLON;
375:
376: case 's':
377: case 'S':
378: state = IN_COLON_IDENTIFIER;
379: break;
380:
381: default:
382: state = INIT;
383: return MakefileTokenContext.TARGET_COLON;
384: } //switch AFTER_COLON
385: break;
386:
387: case IN_COLON_IDENTIFIER:
388: if (!Character.isJavaIdentifierPart(actChar)) {
389: state = INIT;
390: TokenID tid = matchKeyword(buffer, tokenOffset,
391: offset - tokenOffset);
392: if (tid != null) {
393: return tid;
394: } else {
395: //highlight the first colon and reevaluate the rest of the string since colon
396: offset = tokenOffset + 1;
397: return MakefileTokenContext.TARGET_COLON;
398: }
399: } // switch IN_COLON_IDENTIFIER
400: break;
401:
402: case IN_DOT_IDENTIFIER:
403: if (!Character.isJavaIdentifierPart(actChar)) {
404: state = INIT;
405: TokenID tid = matchKeyword(buffer, tokenOffset,
406: offset - tokenOffset);
407: if (tid != null)
408: return tid;
409: else {
410: //highlight the first dot and reevaluate the rest of the string since dot
411: offset = tokenOffset + 1;
412: state = INIT;
413: return MakefileTokenContext.IDENTIFIER;
414: }
415: } // switch IN_DOT_IDENTIFIER
416: break;
417:
418: case IN_IDENTIFIER:
419: // To find out why we're using isJAVAidentifier
420: // here, grep for isJavaIdentifierStart in
421: // CCSyntax.java
422: if (!(Character.isJavaIdentifierPart(actChar))) {
423: state = INIT;
424: TokenID tid = matchKeyword(buffer, tokenOffset,
425: offset - tokenOffset);
426: return (tid != null) ? tid
427: : MakefileTokenContext.IDENTIFIER;
428: }
429: break;
430:
431: case IN_STRING:
432: switch (actChar) {
433: case '\\':
434: state = IN_STRING_AFTER_BSLASH;
435: break;
436:
437: case '\n':
438: state = INIT;
439: offset++;
440: supposedTokenID = MakefileTokenContext.STRING_LITERAL;
441: return supposedTokenID;
442:
443: case '"':
444: if (STRING_IN_DOUBLE_QUOTE) {
445: offset++;
446: state = INIT;
447: return MakefileTokenContext.STRING_LITERAL;
448: }
449: break;
450:
451: case '\'':
452: if (!STRING_IN_DOUBLE_QUOTE) {
453: offset++;
454: state = INIT;
455: return MakefileTokenContext.STRING_LITERAL;
456: }
457: break;
458: } //switch IN_STRING
459: break;
460:
461: case IN_STRING_AFTER_BSLASH:
462: switch (actChar) {
463: case '"':
464: case '\'':
465: case '\\':
466: break; //ignore the meaning of these characters
467:
468: default:
469: offset--; //go back and evaluate the character
470: break;
471: } // End switch (actChar)
472: state = IN_STRING;
473: break; // switch IN_STRING_AFTER_BSLASH:
474: } // end of switch(state)
475: // END STATE SWITCH
476: offset++;
477: } // while(offset...)
478:
479: /*
480: * At this stage there's no more text in the scanned buffer.
481: * Scanner first checks whether this is completely the last
482: * available buffer.
483: */
484: if (lastBuffer) {
485: switch (state) {
486: case IN_WHITESPACE:
487: state = INIT;
488: return MakefileTokenContext.WHITESPACE;
489:
490: case IN_DOT_IDENTIFIER:
491: case IN_COLON_IDENTIFIER:
492: case IN_IDENTIFIER:
493: state = INIT;
494: TokenID kwd = matchKeyword(buffer, tokenOffset, offset
495: - tokenOffset);
496: return (kwd != null) ? kwd
497: : MakefileTokenContext.IDENTIFIER;
498:
499: case IN_STRING:
500: case IN_STRING_AFTER_BSLASH:
501: return MakefileTokenContext.STRING_LITERAL; // hold the state
502:
503: case IN_MACRO:
504: case IN_MACRO_AFTER_DELIM:
505: state = INIT;
506: return MakefileTokenContext.MACRO_LITERAL;
507:
508: case AFTER_BSLASH:
509: state = INIT;
510: return MakefileTokenContext.IDENTIFIER;
511:
512: case AFTER_PLUS:
513: state = INIT;
514: return MakefileTokenContext.RULES_PLUS;
515:
516: case AFTER_DOLLAR:
517: state = INIT;
518: return MakefileTokenContext.MACRO_DOLLAR;
519:
520: case AFTER_COLON:
521: state = INIT;
522: return MakefileTokenContext.TARGET_COLON;
523:
524: case IN_LINE_COMMENT:
525: return MakefileTokenContext.LINE_COMMENT; // stay in line-comment state
526: } // switch (state)
527: } // if (lastbuffer)
528:
529: /*
530: * At this stage there's no more text in the scanned buffer, but this buffer
531: * is not the last so the scan will continue on another buffer. The scanner
532: * tries to minimize the amount of characters that will be prescanned in the
533: * next buffer by returning the token where possible.
534: */
535: switch (state) {
536: case IN_WHITESPACE:
537: return MakefileTokenContext.WHITESPACE;
538: }
539:
540: return null; // nothing found
541: }
542:
543: public String getStateName(int stateNumber) {
544: switch (stateNumber) {
545: case AFTER_COLON:
546: return "AFTER_COLON"; //NOI18N
547:
548: case AFTER_DOLLAR:
549: return "AFTER_DOLLAR"; //NOI18N
550:
551: case AFTER_BSLASH:
552: return "AFTER_BSLASH"; //NOI18N
553:
554: case AFTER_PLUS:
555: return "AFTER_PLUS"; //NOI18N
556:
557: case IN_STRING:
558: return "IN_STRING"; //NOI18N
559:
560: case IN_STRING_AFTER_BSLASH:
561: return "IN_STRING_AFTER_BSLASH"; //NOI18N
562:
563: case IN_MACRO:
564: return "IN_MACRO"; //NOI18N
565:
566: case IN_MACRO_AFTER_DELIM:
567: return "IN_MACRO_AFTER_DELIM"; //NOI18N
568:
569: case IN_LINE_COMMENT:
570: return "IN_LINE_COMMENT"; //NOI18N
571:
572: case IN_IDENTIFIER:
573: return "IN_IDENTIFIER"; //NOI18N
574:
575: case IN_DOT_IDENTIFIER:
576: return "IN_DOT_IDENTIFIER"; //NOI18N
577:
578: case IN_COLON_IDENTIFIER:
579: return "IN_COLON_IDENTIFIER"; //NOI18N
580:
581: case IN_WHITESPACE:
582: return "IN_WHITESPACE"; //NOI18N
583:
584: default:
585: return super .getStateName(stateNumber);
586: }
587: }
588:
589: public static TokenID matchKeyword(char[] buffer, int offset,
590: int len) {
591: if (len <= 1 || len > 17) {
592: return null;
593: }
594:
595: //BEGIN MOTHER SWITCH
596: switch (Character.toLowerCase(buffer[offset++])) {
597: //DOT
598: //.DEFAULT .DONE .FAILED .GET_POSIX .IGNORE .INIT .KEEP_STATE
599: //.KEEP_STATE_FILE .MAKE_VERSION .NO_PARALLEL .PARALLEL .POSIX .PRECIOUS
600: //.SCCS_GET .SCCS_GET_POSIX .SILENT .SUFFIXES .WAIT
601: case '.':
602: if ((len < 5) || (len > 16)) {
603: return null;
604: }
605:
606: switch (Character.toLowerCase(buffer[offset++])) {
607: case 'd': // .DEFAULT .DONE
608: switch (Character.toLowerCase(buffer[offset++])) {
609: case 'e': // .DEFAULT
610: return (len == 8
611: && Character.toLowerCase(buffer[offset++]) == 'f'
612: && Character.toLowerCase(buffer[offset++]) == 'a'
613: && Character.toLowerCase(buffer[offset++]) == 'u'
614: && Character.toLowerCase(buffer[offset++]) == 'l' && Character
615: .toLowerCase(buffer[offset++]) == 't') ? MakefileTokenContext.TARGET_DEFAULT
616: : null;
617:
618: case 'o': // .DONE
619: return (len == 5
620: && Character.toLowerCase(buffer[offset++]) == 'n' && Character
621: .toLowerCase(buffer[offset++]) == 'e') ? MakefileTokenContext.TARGET_DONE
622: : null;
623:
624: default:
625: return null;
626: } // switch .d
627:
628: case 'f': //.FAILED
629: return (len == 7
630: && Character.toLowerCase(buffer[offset++]) == 'a'
631: && Character.toLowerCase(buffer[offset++]) == 'i'
632: && Character.toLowerCase(buffer[offset++]) == 'l'
633: && Character.toLowerCase(buffer[offset++]) == 'e' && Character
634: .toLowerCase(buffer[offset++]) == 'd') ? MakefileTokenContext.TARGET_FAILED
635: : null;
636:
637: case 'g': //.GET_POSIX
638: return (len == 10
639: && Character.toLowerCase(buffer[offset++]) == 'e'
640: && Character.toLowerCase(buffer[offset++]) == 't'
641: && Character.toLowerCase(buffer[offset++]) == '_'
642: && Character.toLowerCase(buffer[offset++]) == 'p'
643: && Character.toLowerCase(buffer[offset++]) == 'o'
644: && Character.toLowerCase(buffer[offset++]) == 's'
645: && Character.toLowerCase(buffer[offset++]) == 'i' && Character
646: .toLowerCase(buffer[offset++]) == 'x') ? MakefileTokenContext.TARGET_GETPOSIX
647: : null;
648:
649: case 'i': //.IGNORE .INIT
650: switch (Character.toLowerCase(buffer[offset++])) {
651: case 'g': //.IGNORE
652: return (len == 7
653: && Character.toLowerCase(buffer[offset++]) == 'n'
654: && Character.toLowerCase(buffer[offset++]) == 'o'
655: && Character.toLowerCase(buffer[offset++]) == 'r' && Character
656: .toLowerCase(buffer[offset++]) == 'e') ? MakefileTokenContext.TARGET_IGNORE
657: : null;
658:
659: case 'n': //.INIT
660: return (len == 5
661: && Character.toLowerCase(buffer[offset++]) == 'i' && Character
662: .toLowerCase(buffer[offset++]) == 't') ? MakefileTokenContext.TARGET_INIT
663: : null;
664:
665: default:
666: return null;
667: } // switch .i
668:
669: case 'k': //.KEEP_STATE .KEEP_STATE_FILE
670: if (len >= 11
671: && Character.toLowerCase(buffer[offset++]) == 'e'
672: && Character.toLowerCase(buffer[offset++]) == 'e'
673: && Character.toLowerCase(buffer[offset++]) == 'p'
674: && Character.toLowerCase(buffer[offset++]) == '_'
675: && Character.toLowerCase(buffer[offset++]) == 's'
676: && Character.toLowerCase(buffer[offset++]) == 't'
677: && Character.toLowerCase(buffer[offset++]) == 'a'
678: && Character.toLowerCase(buffer[offset++]) == 't'
679: && Character.toLowerCase(buffer[offset++]) == 'e') {
680: if (len == 11) {
681: return MakefileTokenContext.TARGET_KEEPSTATE;
682: }
683:
684: switch (Character.toLowerCase(buffer[offset++])) {
685: case '_': //.KEEP_STATE_FILE
686: return (len == 16
687: && Character
688: .toLowerCase(buffer[offset++]) == 'f'
689: && Character
690: .toLowerCase(buffer[offset++]) == 'i'
691: && Character
692: .toLowerCase(buffer[offset++]) == 'l' && Character
693: .toLowerCase(buffer[offset++]) == 'e') ? MakefileTokenContext.TARGET_KEEPSTATEFILE
694: : null;
695:
696: default:
697: return null;
698: } // switch .KEEP_STATE
699: } else {
700: return null;
701: }
702:
703: case 'm': //.MAKE_VERSION
704: return (len == 13
705: && Character.toLowerCase(buffer[offset++]) == 'a'
706: && Character.toLowerCase(buffer[offset++]) == 'k'
707: && Character.toLowerCase(buffer[offset++]) == 'e'
708: && Character.toLowerCase(buffer[offset++]) == '_'
709: && Character.toLowerCase(buffer[offset++]) == 'v'
710: && Character.toLowerCase(buffer[offset++]) == 'e'
711: && Character.toLowerCase(buffer[offset++]) == 'r'
712: && Character.toLowerCase(buffer[offset++]) == 's'
713: && Character.toLowerCase(buffer[offset++]) == 'i'
714: && Character.toLowerCase(buffer[offset++]) == 'o' && Character
715: .toLowerCase(buffer[offset++]) == 'n') ? MakefileTokenContext.TARGET_MAKEVERSION
716: : null;
717:
718: case 'n': //.NO_PARALLEL
719: return (len == 12
720: && Character.toLowerCase(buffer[offset++]) == 'o'
721: && Character.toLowerCase(buffer[offset++]) == '_'
722: && Character.toLowerCase(buffer[offset++]) == 'p'
723: && Character.toLowerCase(buffer[offset++]) == 'a'
724: && Character.toLowerCase(buffer[offset++]) == 'r'
725: && Character.toLowerCase(buffer[offset++]) == 'a'
726: && Character.toLowerCase(buffer[offset++]) == 'l'
727: && Character.toLowerCase(buffer[offset++]) == 'l'
728: && Character.toLowerCase(buffer[offset++]) == 'e' && Character
729: .toLowerCase(buffer[offset++]) == 'l') ? MakefileTokenContext.TARGET_NOPARALLEL
730: : null;
731:
732: case 'p': // .PARALLEL .POSIX .PRECIOUS
733: switch (Character.toLowerCase(buffer[offset++])) {
734: case 'a': //.PARALLEL
735: return (len == 9
736: && Character.toLowerCase(buffer[offset++]) == 'r'
737: && Character.toLowerCase(buffer[offset++]) == 'a'
738: && Character.toLowerCase(buffer[offset++]) == 'l'
739: && Character.toLowerCase(buffer[offset++]) == 'l'
740: && Character.toLowerCase(buffer[offset++]) == 'e' && Character
741: .toLowerCase(buffer[offset++]) == 'l') ? MakefileTokenContext.TARGET_PARALLEL
742: : null;
743:
744: case 'o': //.POSIX
745: return (len == 6
746: && Character.toLowerCase(buffer[offset++]) == 's'
747: && Character.toLowerCase(buffer[offset++]) == 'i' && Character
748: .toLowerCase(buffer[offset++]) == 'x') ? MakefileTokenContext.TARGET_POSIX
749: : null;
750:
751: case 'r': //.PRECIOUS
752: return (len == 9
753: && Character.toLowerCase(buffer[offset++]) == 'e'
754: && Character.toLowerCase(buffer[offset++]) == 'c'
755: && Character.toLowerCase(buffer[offset++]) == 'i'
756: && Character.toLowerCase(buffer[offset++]) == 'o'
757: && Character.toLowerCase(buffer[offset++]) == 'u' && Character
758: .toLowerCase(buffer[offset++]) == 's') ? MakefileTokenContext.TARGET_PRECIOUS
759: : null;
760:
761: default:
762: return null;
763: } // switch .p
764:
765: case 's': // .SCCS_GET .SCCS_GET_POSIX .SILENT .SUFFIXES
766: switch (Character.toLowerCase(buffer[offset++])) {
767: case 'c': //.SCCS_GET .SCCS_GET_POSIX
768: if (len >= 9
769: && Character.toLowerCase(buffer[offset++]) == 'c'
770: && Character.toLowerCase(buffer[offset++]) == 's'
771: && Character.toLowerCase(buffer[offset++]) == '_'
772: && Character.toLowerCase(buffer[offset++]) == 'g'
773: && Character.toLowerCase(buffer[offset++]) == 'e'
774: && Character.toLowerCase(buffer[offset++]) == 't') {
775: if (len == 9) {
776: return MakefileTokenContext.TARGET_SCCSGET;
777: }
778:
779: switch (Character.toLowerCase(buffer[offset++])) {
780: case '_': //.SCCS_GET_POSIX
781: return (len == 15
782: && Character
783: .toLowerCase(buffer[offset++]) == 'p'
784: && Character
785: .toLowerCase(buffer[offset++]) == 'o'
786: && Character
787: .toLowerCase(buffer[offset++]) == 's'
788: && Character
789: .toLowerCase(buffer[offset++]) == 'i' && Character
790: .toLowerCase(buffer[offset++]) == 'x') ? MakefileTokenContext.TARGET_SCCSGETPOSIX
791: : null;
792:
793: default:
794: return null;
795: } // switch .SCCS_GET
796: } else {
797: return null;
798: }
799:
800: case 'i': //.SILENT
801: return (len == 7
802: && Character.toLowerCase(buffer[offset++]) == 'l'
803: && Character.toLowerCase(buffer[offset++]) == 'e'
804: && Character.toLowerCase(buffer[offset++]) == 'n' && Character
805: .toLowerCase(buffer[offset++]) == 't') ? MakefileTokenContext.TARGET_SILENT
806: : null;
807:
808: case 'u': //.SUFFIXES
809: return (len == 9
810: && Character.toLowerCase(buffer[offset++]) == 'f'
811: && Character.toLowerCase(buffer[offset++]) == 'f'
812: && Character.toLowerCase(buffer[offset++]) == 'i'
813: && Character.toLowerCase(buffer[offset++]) == 'x'
814: && Character.toLowerCase(buffer[offset++]) == 'e' && Character
815: .toLowerCase(buffer[offset++]) == 's') ? MakefileTokenContext.TARGET_SUFFIXES
816: : null;
817:
818: default:
819: return null;
820: }//switch .s
821:
822: case 'w': //.WAIT
823: return (len == 5
824: && Character.toLowerCase(buffer[offset++]) == 'a'
825: && Character.toLowerCase(buffer[offset++]) == 'i' && Character
826: .toLowerCase(buffer[offset++]) == 't') ? MakefileTokenContext.TARGET_WAIT
827: : null;
828:
829: default:
830: return null;
831: } // switch dot
832:
833: case ':': // ":" and ":sh"
834: return (len == 3
835: && Character.toLowerCase(buffer[offset++]) == 's' && Character
836: .toLowerCase(buffer[offset++]) == 'h') ? MakefileTokenContext.MACRO_COMMAND_SUBSTITUTE
837: : null;
838:
839: case 'i': // "include"
840: return (len == 7
841: && Character.toLowerCase(buffer[offset++]) == 'n'
842: && Character.toLowerCase(buffer[offset++]) == 'c'
843: && Character.toLowerCase(buffer[offset++]) == 'l'
844: && Character.toLowerCase(buffer[offset++]) == 'u'
845: && Character.toLowerCase(buffer[offset++]) == 'd' && Character
846: .toLowerCase(buffer[offset++]) == 'e') ? MakefileTokenContext.GLOBAL_INCLUDE
847: : null;
848:
849: default:
850: return null;
851: } // END MOTHER SWITCH
852: } // matchKeyword
853: }
|