private void endComment() { if (!fInComment) { return; } fInComment = false; String comment = fCommentBuffer.toString(); String title = fDocCommentParser.isDocComment(comment); if (title != null) { SVPreProc2InputData in = fInputCurr; SVDBDocComment doc_comment = new SVDBDocComment(title, comment); SVDBLocation loc = new SVDBLocation( fCommentStart.getFileId(), fCommentStart.getLineNo(), fCommentStart.getLinePos()); doc_comment.setLocation(loc); if (in.getFileTree() != null) { in.getFileTree().getSVDBFile().addChildItem(doc_comment); } } }
private void cleanup_preproc_leftovers() { int file_id = fInputCurr.getFileId(); while (fPreProcLoc.size() > 0 && fPreProcLoc.peek().getFileId() == file_id) { // Leftovers indicates unbalanced directives ScanLocation loc = fPreProcLoc.pop(); fPreProcEn.pop(); SVDBLocation location = new SVDBLocation(loc.getFileId(), loc.getLineNo(), loc.getLinePos()); SVDBMarker m = new SVDBMarker( MarkerType.Error, MarkerKind.UnbalancedDirective, "Unbalanced pre-processor directive"); if (fDebugEn) { fLog.debug("Cleanup pre-proc leftover @ " + loc.getLineNo()); } m.setLocation(location); if (fInputCurr.getFileTree() != null) { fInputCurr.getFileTree().fMarkers.add(m); } } }
private void leave_ifdef(ScanLocation scan_loc) { boolean enabled_pre = ifdef_enabled(); if (fPreProcEn.size() > 0) { fPreProcEn.pop(); fPreProcLoc.pop(); } if (fDebugEn) { fLog.debug( "leave_ifdef: " + scan_loc.getLineNo() + " pre=" + enabled_pre + " post=" + ifdef_enabled()); } update_unprocessed_region(scan_loc, enabled_pre); }
private void enter_else(ScanLocation scan_loc) { boolean enabled_pre = ifdef_enabled(); if (fPreProcEn.size() > 0) { int e = fPreProcEn.pop(); fPreProcLoc.pop(); // Invert only if we're in an enabled scope and // we haven't already 'taken' a branch in the // ifdef/elsif/else structure if ((e & PP_CARRY) == 0) { if ((e & PP_THIS_LEVEL_EN_BLOCK) != 0) { // Disable any blocks beyond the 'taken' block e &= ~PP_ENABLED; } else { // Enable this branch and set the BLOCK_ENABLED flag e |= PP_ENABLED; } } // Flip to 'true' only if we aren't fPreProcEn.push(e); fPreProcLoc.push(scan_loc); } else { fLog.debug("Warning: encountered `else with empty PreProcEn stack"); } if (fDebugEn) { fLog.debug( "enter_else: " + scan_loc.getLineNo() + " pre=" + enabled_pre + " post=" + ifdef_enabled()); } update_unprocessed_region(scan_loc, enabled_pre); }
private void enter_ifdef(ScanLocation scan_loc, boolean enabled) { boolean enabled_pre = ifdef_enabled(); int e = (enabled) ? PP_ENABLED : PP_DISABLED; if (fPreProcEn.size() > 0) { int e_t = fPreProcEn.peek(); if ((e_t & PP_ENABLED) == 0) { // Anything beneath a disabled section is also disabled e = PP_DISABLED; e |= PP_CARRY; } } // Mark that we've taken one branch if ((e & PP_ENABLED) == 1) { e |= PP_THIS_LEVEL_EN_BLOCK; } fPreProcEn.push(e); fPreProcLoc.push(scan_loc); if (fDebugEn) { fLog.debug( "enter_ifdef: " + scan_loc.getLineNo() + " enabled=" + enabled + " pre=" + enabled_pre + " post=" + ifdef_enabled() + " sz=" + fPreProcEn.size()); } update_unprocessed_region(scan_loc, enabled_pre); }
private void handle_preproc_directive() { int ch = -1; while ((ch = get_ch()) != -1 && Character.isWhitespace(ch)) {} ScanLocation scan_loc = getLocation(); String type; if (ch == -1) { type = ""; } else { type = readPreProcIdentifier(ch); if (type == null) { type = ""; } } if (type.equals("ifdef") || type.equals("ifndef") || type.equals("elsif")) { // TODO: line number tracking ch = skipWhite(get_ch()); // TODO: evaluate the expression? String remainder = readPreProcIdentifier(ch); if (remainder != null) { remainder = remainder.trim(); } else { remainder = ""; } // Add a new entry to the referenced macros add_macro_reference(remainder); if (type.equals("ifdef")) { if (fDebugEn) { fLog.debug("ifdef \"" + remainder + "\": " + fDefineProvider.isDefined(remainder, -1)); } boolean active = fDefineProvider.isDefined(remainder, -1); enter_ifdef(scan_loc, active); } else if (type.equals("ifndef")) { boolean active = !fDefineProvider.isDefined(remainder, -1); if (fDebugEn) { fLog.debug("ifndef \"" + remainder + "\": " + active); } enter_ifdef(scan_loc, active); } else { // elsif boolean active = fDefineProvider.isDefined(remainder, -1); enter_elsif(scan_loc, active); } } else if (type.equals("else")) { enter_else(scan_loc); } else if (type.equals("endif")) { leave_ifdef(scan_loc); } else if (fIgnoredDirectives.contains(type)) { // Skip entire line readLine(get_ch()); } else if (type.equals("define")) { SVDBLocation location = new SVDBLocation(scan_loc.getFileId(), scan_loc.getLineNo(), scan_loc.getLinePos()); SVDBMacroDef m = new SVDBMacroDef(); // TODO: save file? // TODO: line numbers ch = skipWhite(get_ch()); m.setName(readIdentifier(ch)); m.setLocation(location); fParamList.clear(); ch = get_ch(); if (ch == '(') { // Has parameters List<SVDBMacroDefParam> param_list = new ArrayList<SVDBMacroDefParam>(); do { ch = skipWhite(get_ch()); if (!(Character.isJavaIdentifierPart(ch))) { break; } else { String p = readIdentifier(ch); String dflt = null; ch = skipWhite(get_ch()); if (ch == '=') { // Read default value ch = skipWhite(get_ch()); if (ch == '"') { // String dflt = readString(ch); dflt = "\"" + dflt + "\""; } else { // Read up to comma or close bracket startCapture(ch); while ((ch = get_ch()) != -1 && ch != ',' && ch != ')') {} unget_ch(ch); dflt = endCapture(); } } else { unget_ch(ch); } param_list.add(new SVDBMacroDefParam(p, dflt)); } ch = skipWhite(get_ch()); } while (ch == ','); m.setParameters(param_list); if (ch == ')') { ch = get_ch(); } } // Now, read the remainder of the definition String define = readLine(ch); if (define == null) { define = ""; // define this macro as existing } /* We should carry-through the single-line comments. However, this is only * true in the case of a single-line macro. Multi-line macros get to keep * their single-line comments */ int last_comment; if ((last_comment = define.lastIndexOf("//")) != -1) { int lr = define.indexOf('\n', last_comment); if (lr == -1) { // Nothing beyond this comment define = define.substring(0, define.indexOf("//")); } } m.setDef(define); // TODO: need to warn on re-definition? if (ifdef_enabled()) { addMacro(m); SVPreProc2InputData in = currentRealFile(); // Add the macro to the pre-processor version of the file if (in != null && in.getFileTree() != null && in.getFileTree().getSVDBFile() != null) { in.getFileTree().getSVDBFile().addChildItem(m); in.getFileTree().addToMacroSet(m); } } } else if (type.equals("include")) { ch = skipWhite(get_ch()); if (ch == '"') { String inc = readString(ch); if (inc.length() > 2 && ifdef_enabled()) { // TODO: need to save the include statement in the pre-proc view? // Process include and switch to new file if (fIncFileProvider != null) { Tuple<String, List<SVDBFileTreeMacroList>> defs; Tuple<String, InputStream> in; // TODO: for now, assuming accumulated pre-processor state // doesn't change file content. This isn't precisely correct. defs = fIncFileProvider.findCachedIncFile(inc); SVPreProc2InputData curr_in = fInputCurr; if (defs != null) { // Add in the macros from the included file for (SVDBFileTreeMacroList l : defs.second()) { for (SVDBMacroDef m : l.getMacroList()) { addMacro(m); } } // TODO: Need to mark as a 'virtual' include? SVDBInclude svdb_inc = new SVDBInclude(inc); svdb_inc.setLocation( new SVDBLocation( scan_loc.getFileId(), scan_loc.getLineNo(), scan_loc.getLinePos())); curr_in.getFileTree().getSVDBFile().addChildItem(svdb_inc); SVDBFileTree ft_i = new SVDBFileTree(defs.first()); ft_i.setParent(curr_in.getFileTree()); curr_in.getFileTree().addIncludedFileTree(ft_i); for (SVDBFileTreeMacroList ml : defs.second()) { for (SVDBMacroDef m : ml.getMacroList()) { ft_i.addToMacroSet(m); } } } else if ((in = fIncFileProvider.findIncFile(inc)) != null && in.second() != null) { if (fDebugEn) { fLog.debug("Switching from file " + curr_in.getFileName() + " to " + in.first()); } // TODO: Add tracking data for new file // Find the root file path String rootfile = fInputStack.get(0).getFileName(); fIncFileProvider.addCachedIncFile(in.first(), rootfile); SVDBInclude svdb_inc = new SVDBInclude(inc); svdb_inc.setLocation( new SVDBLocation( scan_loc.getFileId(), scan_loc.getLineNo(), scan_loc.getLinePos())); curr_in.getFileTree().getSVDBFile().addChildItem(svdb_inc); enter_file(in.first(), in.second()); } else { SVDBLocation location = new SVDBLocation( scan_loc.getFileId(), scan_loc.getLineNo(), scan_loc.getLinePos()); SVDBMarker m = new SVDBMarker( MarkerType.Error, MarkerKind.MissingInclude, "Failed to find include file " + inc); m.setLocation(location); // SVPreProc2InputData curr_in = fInputCurr; curr_in.getFileTree().fMarkers.add(m); // TODO: add missing-include error if (fDebugEn) { fLog.debug("Failed to find include file " + inc); } } } } else { inc = ""; } } } else if (type.equals("__LINE__")) { if (ifdef_enabled()) { output("" + fInputCurr.getLineNo()); } } else if (type.equals("__FILE__")) { if (ifdef_enabled()) { output("\"" + fInputCurr.getFileName() + "\""); } } else if (type.equals("pragma")) { ch = skipWhite(get_ch()); String id = readIdentifier(ch); if (id != null) { // Ignore everything in the 'protected' region. // Not much we can meaningfully show... if (id.equals("protect")) { ch = skipWhite(get_ch()); id = readIdentifier(ch); if (id != null) { if (id.equals("begin_protected")) { enter_ifdef(scan_loc, false); } else if (id.equals("end_protected")) { leave_ifdef(scan_loc); } } } } } else if (type.equals("protected")) { enter_ifdef(scan_loc, false); } else if (type.equals("endprotected")) { leave_ifdef(scan_loc); } else if (!type.equals("")) { // Note: type="" occurs when no identifier followed the tick // macro expansion. // TODO: is TmpBuffer available? fTmpBuffer.setLength(0); fTmpBuffer.append('`'); fTmpBuffer.append(type); // If we're in a disabled section, don't try to expand if (ifdef_enabled()) { // Read the full string // Add a reference for this macro add_macro_reference(type); boolean is_defined = fDefineProvider.isDefined(type, -1); if (!is_defined) { SVDBLocation location = new SVDBLocation(scan_loc.getFileId(), scan_loc.getLineNo(), scan_loc.getLinePos()); SVDBMarker m = new SVDBMarker( MarkerType.Error, MarkerKind.UndefinedMacro, "Macro " + type + " undefined"); m.setLocation(location); fInputCurr.getFileTree().fMarkers.add(m); } if (fDefineProvider.hasParameters(type, fInputCurr.getLineNo()) || !is_defined) { // Try to read the parameter list ch = get_ch(); // skip up to new-line or non-whitespace if (!is_defined) { // For undefined macros, only search up to end-of-line while (ch != -1 && Character.isWhitespace(ch) && ch != '\n') { ch = get_ch(); } } else { // For defined macros, skip all whitespace while (ch != -1 && Character.isWhitespace(ch)) { ch = get_ch(); } } if (ch == '(') { fTmpBuffer.append((char) ch); // Read the parameter list int matchLevel = 1, last_ch = -1; boolean in_string = false; do { ch = get_ch(); if (!in_string) { if (ch == '(') { matchLevel++; } else if (ch == ')') { matchLevel--; } else if (ch == '\"' && last_ch != '\\') { in_string = true; } } else if (ch == '\"' && last_ch != '\\') { in_string = false; } if (ch != -1) { fTmpBuffer.append((char) ch); } } while (ch != -1 && matchLevel > 0); } else if (is_defined) { unget_ch(ch); } else { unget_ch(ch); } } if (!is_defined) { // Leave a breadcrumb for the lexer output("`undefined"); } else if (fDefineProvider != null) { try { String exp = fDefineProvider.expandMacro( fTmpBuffer.toString(), fInputCurr.getFileName(), fInputCurr.getLineNo()); if (fDebugEn) { fLog.debug("Expansion of \"" + fTmpBuffer.toString() + "\" == " + exp); } SVPreProc2InputData in = new SVPreProc2InputData( this, new StringInputStream(exp), "ANONYMOUS", fInputCurr.getFileId(), false); fInputStack.push(in); fInputCurr = in; } catch (Exception e) { /* System.out.println("Exception while expanding \"" + fTmpBuffer.toString() + "\" @ " + getLocation().getFileName() + ":" + getLocation().getLineNo()); */ e.printStackTrace(); } } } } }