/TypeCobol/Compiler/Preprocessor/ProcessedTokensLine.cs

https://github.com/TypeCobolTeam/TypeCobol · C# · 273 lines · 173 code · 34 blank · 66 comment · 36 complexity · 2851b656d9e322d9080eeb631e8e5a4b MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using TypeCobol.Compiler.Diagnostics;
  4. using TypeCobol.Compiler.Directives;
  5. using TypeCobol.Compiler.Scanner;
  6. using TypeCobol.Compiler.Text;
  7. namespace TypeCobol.Compiler.Preprocessor
  8. {
  9. /// <summary>
  10. /// Line of tokens after preprocessor execution
  11. /// </summary>
  12. public class ProcessedTokensLine : TokensLine, IProcessedTokensLine
  13. {
  14. internal ProcessedTokensLine(ITextLine textLine, ColumnsLayout columnsLayout) : base(textLine, columnsLayout)
  15. {
  16. PreprocessingState = PreprocessorState.NeedsCompilerDirectiveParsing;
  17. }
  18. // --- Computed line properties after preprocessor execution ---
  19. internal enum PreprocessorState
  20. {
  21. NeedsCompilerDirectiveParsing,
  22. NeedsCopyDirectiveProcessing,
  23. Ready
  24. }
  25. /// <summary>
  26. /// True if the preprocessor has not treated this line yet
  27. /// and all the following properties have not been set
  28. /// </summary>
  29. internal PreprocessorState PreprocessingState { get; set; }
  30. /// <summary>
  31. /// Tokens produced after parsing the compiler directives.
  32. /// If a compiler directive is found, several tokens of the source text are grouped
  33. /// into one single CompilerDirectiveToken (which can be continued on several lines).
  34. /// </summary>
  35. public IList<Token> TokensWithCompilerDirectives {
  36. get
  37. {
  38. if (PreprocessingState <= PreprocessorState.NeedsCompilerDirectiveParsing)
  39. {
  40. throw new InvalidOperationException("Compiler directives on this line have not been parsed yet");
  41. }
  42. if (tokensWithCompilerDirectives == null)
  43. {
  44. return SourceTokens;
  45. }
  46. else
  47. {
  48. return tokensWithCompilerDirectives;
  49. }
  50. }
  51. }
  52. // Only needed if several source tokens must be grouped into a single CompilerDirectiveToken
  53. private IList<Token> tokensWithCompilerDirectives;
  54. /// <summary>
  55. /// True if compiler directives have been recognized on the current line
  56. /// (true on each line for multiline compiler directives)
  57. /// </summary>
  58. public bool HasCompilerDirectives { get { return tokensWithCompilerDirectives != null; } }
  59. /// <summary>
  60. /// Compiler listing control directive found on the current line
  61. /// *CBL or *CONTROL, EJECT, SKIP1 or SKIP2 or SKIP3, TITLE
  62. /// (these compiler directives can't span several lines, and you can only write one of them per line)
  63. /// </summary>
  64. public CompilerDirective CompilerListingControlDirective { get; private set; }
  65. /// <summary>
  66. /// Imported compilation documents for each COPY directive found (starting) on this line
  67. /// </summary>
  68. public IDictionary<CopyDirective, ImportedTokensDocument> ImportedDocuments { get; private set; }
  69. /// <summary>
  70. /// Last REPLACE compiler directive found on this this line
  71. /// </summary>
  72. public ReplaceDirective ReplaceDirective { get; private set; }
  73. internal TokensGroup InsertCompilerDirectiveTokenOnFirstLine(IList<Token> tokensOnFirstLineBeforeCompilerDirective, CompilerDirective compilerDirective, bool hasError, IList<Token> compilerDirectiveTokensOnFirstLine, IList<Token> tokensOnFirstLineAfterCompilerDirective, bool hasDirectiveTokenContinuedOnNextLine)
  74. {
  75. // Register compiler listing control directive
  76. if( compilerDirective.Type == CompilerDirectiveType.ASTERISK_CBL ||
  77. compilerDirective.Type == CompilerDirectiveType.ASTERISK_CONTROL ||
  78. compilerDirective.Type == CompilerDirectiveType.EJECT ||
  79. compilerDirective.Type == CompilerDirectiveType.SKIP1 ||
  80. compilerDirective.Type == CompilerDirectiveType.SKIP2 ||
  81. compilerDirective.Type == CompilerDirectiveType.SKIP3 ||
  82. compilerDirective.Type == CompilerDirectiveType.TITLE)
  83. {
  84. CompilerListingControlDirective = compilerDirective;
  85. }
  86. // Register COPY directives
  87. // Prepare dictionary for COPY imported documents
  88. if( compilerDirective.Type == CompilerDirectiveType.COPY ||
  89. compilerDirective.Type == CompilerDirectiveType.EXEC_SQL_INCLUDE)
  90. {
  91. if(ImportedDocuments == null)
  92. {
  93. ImportedDocuments = new Dictionary<CopyDirective, ImportedTokensDocument>(1);
  94. }
  95. ImportedDocuments.Add((CopyDirective)compilerDirective, null);
  96. }
  97. // Register REPLACE compiler directive
  98. if(compilerDirective.Type == CompilerDirectiveType.REPLACE)
  99. {
  100. ReplaceDirective = (ReplaceDirective)compilerDirective;
  101. }
  102. // Initialize tokensWithCompilerDirectives
  103. // (first compiler directive found on this line)
  104. if (!HasCompilerDirectives)
  105. {
  106. // Initialize tokens list
  107. tokensWithCompilerDirectives = new List<Token>();
  108. // Keep tokens before compiler directive
  109. if (tokensOnFirstLineBeforeCompilerDirective != null)
  110. {
  111. foreach (Token token in tokensOnFirstLineBeforeCompilerDirective)
  112. {
  113. tokensWithCompilerDirectives.Add(token);
  114. }
  115. }
  116. }
  117. // Update tokensWithCompilerDirectives
  118. // (several compiler directives on the same line)
  119. else
  120. {
  121. // Reset tokens list
  122. IList<Token> previousTokens = tokensWithCompilerDirectives;
  123. tokensWithCompilerDirectives = new List<Token>();
  124. // Keep tokens before compiler directive
  125. Token firstTokenOfCompilerDirective = compilerDirectiveTokensOnFirstLine[0];
  126. foreach (Token token in previousTokens)
  127. {
  128. if(token == firstTokenOfCompilerDirective)
  129. {
  130. break;
  131. }
  132. tokensWithCompilerDirectives.Add(token);
  133. }
  134. }
  135. // Build a CompilerDirectiveToken wrapping all matched tokens on the first line
  136. CompilerDirectiveToken directiveToken = new CompilerDirectiveToken(
  137. compilerDirective,
  138. compilerDirectiveTokensOnFirstLine,
  139. hasError);
  140. // Add the compilerDirectiveToken
  141. tokensWithCompilerDirectives.Add(directiveToken);
  142. // Keep tokens after compiler directive
  143. if (tokensOnFirstLineAfterCompilerDirective != null)
  144. {
  145. foreach (Token token in tokensOnFirstLineAfterCompilerDirective)
  146. {
  147. tokensWithCompilerDirectives.Add(token);
  148. }
  149. }
  150. // Register line continuation properties
  151. HasDirectiveTokenContinuedOnNextLine = HasDirectiveTokenContinuedOnNextLine || hasDirectiveTokenContinuedOnNextLine;
  152. // Return potentially continued compiler directive token
  153. if (tokensOnFirstLineAfterCompilerDirective == null)
  154. {
  155. return directiveToken;
  156. }
  157. else
  158. {
  159. return null;
  160. }
  161. }
  162. internal TokensGroup InsertCompilerDirectiveTokenOnNextLine(TokensGroup continuedTokensGroupOnPreviousLine, IList<Token> compilerDirectiveTokensOnNextLine, IList<Token> tokensOnFirstLineAfterCompilerDirective, bool hasDirectiveTokenContinuedOnNextLine)
  163. {
  164. // Initialize tokens list
  165. tokensWithCompilerDirectives = new List<Token>();
  166. // Build a ContinuationTokensGroup wrapping all matched tokens on the next line
  167. ContinuationTokensGroup continuationToken = null;
  168. try
  169. {
  170. continuationToken = new ContinuationTokensGroup(
  171. continuedTokensGroupOnPreviousLine,
  172. compilerDirectiveTokensOnNextLine);
  173. }
  174. catch(Exception e)
  175. {
  176. string error = e.Message;
  177. }
  178. // Add the ContinuationTokensGroup
  179. tokensWithCompilerDirectives.Add(continuationToken);
  180. // Keep tokens after compiler directive
  181. if (tokensOnFirstLineAfterCompilerDirective != null)
  182. {
  183. foreach (Token token in tokensOnFirstLineAfterCompilerDirective)
  184. {
  185. tokensWithCompilerDirectives.Add(token);
  186. }
  187. }
  188. // Register line continuation properties
  189. HasDirectiveTokenContinuationFromPreviousLine = true;
  190. HasDirectiveTokenContinuedOnNextLine = HasDirectiveTokenContinuedOnNextLine || hasDirectiveTokenContinuedOnNextLine;
  191. // Return potentially continued compiler directive token
  192. if (tokensOnFirstLineAfterCompilerDirective == null)
  193. {
  194. return continuationToken;
  195. }
  196. else
  197. {
  198. return null;
  199. }
  200. }
  201. /// <summary>
  202. /// True if the first compiler directive token on the next line continues the last compiler directive token of this line
  203. /// </summary>
  204. public bool HasDirectiveTokenContinuedOnNextLine { get; private set; }
  205. /// <summary>
  206. /// True if the first compiler directive token on this line continues the last compiler directive token of the previous line
  207. /// </summary>
  208. public bool HasDirectiveTokenContinuationFromPreviousLine { get; private set; }
  209. /// <summary>
  210. /// Error and warning messages produced while scanning the raw source text line
  211. /// (before text manipulation phase)
  212. /// </summary>
  213. public IList<Diagnostic> PreprocessorDiagnostics { get; private set; }
  214. /// <summary>
  215. /// Lazy initialization of diagnostics list
  216. /// </summary>
  217. internal void AddDiagnostic(Diagnostic diag)
  218. {
  219. if(PreprocessorDiagnostics == null)
  220. {
  221. PreprocessorDiagnostics = new List<Diagnostic>();
  222. }
  223. PreprocessorDiagnostics.Add(diag);
  224. }
  225. // --- Incremental compilation process ---
  226. protected void CopyProcessedTokensLineProperties(ProcessedTokensLine previousLineVersion)
  227. {
  228. this.CompilerListingControlDirective = previousLineVersion.CompilerListingControlDirective;
  229. this.ImportedDocuments = previousLineVersion.ImportedDocuments;
  230. this.HasDirectiveTokenContinuationFromPreviousLine = previousLineVersion.HasDirectiveTokenContinuationFromPreviousLine;
  231. this.HasDirectiveTokenContinuedOnNextLine = previousLineVersion.HasDirectiveTokenContinuedOnNextLine;
  232. this.PreprocessorDiagnostics = previousLineVersion.PreprocessorDiagnostics;
  233. this.PreprocessingState = previousLineVersion.PreprocessingState;
  234. this.ReplaceDirective = previousLineVersion.ReplaceDirective;
  235. this.tokensWithCompilerDirectives = previousLineVersion.tokensWithCompilerDirectives;
  236. CompilationStep = Concurrency.CompilationStep.Preprocessor;
  237. }
  238. }
  239. }