class EXTERNAL_LANG_AS inherit AST_EIFFEL redefine is_equivalent end LEAF_AS EXTERNAL_CONSTANTS COMPILER_EXPORTER SHARED_EIFFEL_PARSER export {NONE} all end SHARED_ERROR_HANDLER export {NONE} all end SHARED_WORKBENCH export {NONE} all end create initialize feature {NONE} -- Initialization initialize (l: like language_name) is -- Create a new EXTERNAL_LANGUAGE AST node. require l_not_void: l /= Void do language_name := l parse ensure language_name_set: language_name = l end feature -- Visitor process (v: AST_VISITOR) is -- process current element. do v.process_external_lang_as (Current) end feature -- Attributes language_name: STRING_AS -- Language name -- might be replaced by external_declaration or external_definition extension: EXTERNAL_EXTENSION_AS -- Parsed external extension feature -- Comparison is_equivalent (other: like Current): BOOLEAN is -- Is `other' equivalent to the current object ? do -- It is enough to just compare `language_name' since it stores -- full external specification. And if it is the same specification -- then it is the same external. Result := language_name.is_equivalent (other.language_name) end feature -- Properties extension_i: EXTERNAL_EXT_I is -- EXTERNAL_EXT_I corresponding to current extension do Result := extension.extension_i ensure extension_i_not_void: Result /= Void end feature {NONE} -- Implementation parse is -- Parse external declaration local parser: like external_parser is_yacc_parsing_successful: BOOLEAN do parser := External_parser parser.parse_external (Eiffel_parser.line, Eiffel_parser.filename, language_name.value) extension := parser.root_node is_yacc_parsing_successful := not parser.has_error and then extension /= Void if not is_yacc_parsing_successful then extension := Void old_parse end ensure extension_set: extension /= Void end old_parse is -- Parse external declaration require extension_not_yet_set: extension = Void local source, image: STRING ext_language_name: STRING special_part: STRING special_type: STRING signature_part: STRING dll_ext: DLL_EXTENSION_AS start_special_part, end_special_part: INTEGER valid_language_name: BOOLEAN done, is_cpp_extension: BOOLEAN pos: INTEGER index_pos: INTEGER dll_index: INTEGER nb: INTEGER do source := language_name.value debug io.error.put_string ("Parsing ") io.error.put_string (source) io.error.put_new_line end -- getting rid of extra blanks image := source.twin image.left_adjust image.right_adjust -- extracting language name from nb := image.count pos := 1 until pos > nb or else done loop inspect image.item (pos) when '%T', ' ','[','(',':','|' then done := True else pos := pos + 1 end end pos := pos - 1 -- The external name goes from 1 to `pos' if pos > 0 then ext_language_name := image.substring (1, pos) ext_language_name.to_upper -- Validity check on language name if ext_language_name.is_equal ("C") then valid_language_name := True elseif ext_language_name.is_equal ("C++") then valid_language_name := True end end if not valid_language_name then if ext_language_name = Void then debug io.error.put_string ("Void%N") end raise_external_error ("Unrecognized external language", 1) else debug io.error.put_string (ext_language_name) io.error.put_new_line end pos := source.substring_index (ext_language_name,1) raise_external_error ("Unrecognized external language", pos) end else -- cleaning string for next operation image.remove_head (pos) image.left_adjust -- Extracting the special part if image.count /= 0 and then image.item (1) = '[' then start_special_part := source.index_of ('[', 1) end_special_part := source.index_of (']', 1) if end_special_part = 0 then raise_external_error ("Missing closing bracket ']'", start_special_part) elseif end_special_part = start_special_part + 1 then raise_external_error ("Empty brackets" , start_special_part) else special_part := source.substring (start_special_part + 1, end_special_part - 1) special_part.right_adjust special_part.left_adjust -- Only unprocessed part is kept in `image' image.remove_head (image.index_of (']', 1)) image.left_adjust -- Checking the type of special part pos := special_part.index_of (' ', 1) if pos = 0 then -- Case where the is no spaces, possibly just tabs. pos := special_part.index_of ('%T', 1) else -- Case where we might have both spaces and tabs, find out -- which one comes first. index_pos := special_part.index_of ('%T', 1) if index_pos /= 0 then pos := index_pos.min (pos) end end if pos = 0 then -- Only one word in brackets raise_external_error ("Only one word between brackets", source.index_of ('[', 1) + 1) else -- Is it a C++ external? is_cpp_extension := ext_language_name.is_equal ("C++") -- C special_type := special_part.substring (1, pos - 1) special_type.to_lower dll_index := -1 from done :=false nb := special_type.count index_pos := 1 until index_pos > nb or else done loop inspect special_type.item (index_pos) when '@' then done := True dll_index := special_type.substring(index_pos + 1,special_type.count).to_integer else index_pos := index_pos + 1 end end special_type := special_type.substring (1, index_pos-1) if special_type.is_equal (macro_string) then create {MACRO_EXTENSION_AS} extension.make (is_cpp_extension) -- Even if used in a C++ context it is not a -- CPP extension. is_cpp_extension := False elseif special_type.is_equal (struct_string) then create {STRUCT_EXTENSION_AS} extension.make (is_cpp_extension) -- Even if used in a C++ context it is not a -- CPP extension. is_cpp_extension := False elseif special_type.is_equal (dll32_string) then create dll_ext dll_ext.set_type (dll32_type) dll_ext.set_index (dll_index) extension := dll_ext elseif special_type.is_equal (dllwin32_string) then create dll_ext dll_ext.set_type (dllwin32_type) dll_ext.set_index (dll_index) extension := dll_ext elseif is_cpp_extension then create {CPP_EXTENSION_AS} extension else create {C_EXTENSION_AS} extension end if not is_cpp_extension then -- Remove special type from special_part special_part := special_part.substring (pos + 1, special_part.count) special_part.left_adjust end extension.set_special_part (special_part) end end end -- Extracting the signature if image.count /= 0 and then image.item (1) = '(' then pos := image.index_of (')',2) if pos = 0 then raise_external_error ("Missing closing parenthesis ) in signature clause", source.index_of ('(', 1)) else signature_part := image.substring (1, pos) -- Only unprocessed part is kept in `image' image.remove_head (pos) image.left_adjust end end -- Return type if image.count /= 0 and then image.item (1) = ':' then if signature_part = Void then create signature_part.make (0) end pos := image.index_of ('|', 1) if pos = 0 then -- No include part signature_part.append (image) image.wipe_out else signature_part.append (image.substring (1, pos - 1)) signature_part.right_adjust -- Only unprocessed part is kept in `image' image.remove_head (pos - 1) end end if signature_part /= Void or else image.count /= 0 then if extension = Void then if ext_language_name.is_equal ("C++") then raise_external_error ("Missing special part", 1) else create {C_EXTENSION_AS} extension end end end if signature_part /= Void then extension.set_signature (signature_part) end debug if extension /= Void then io.error.put_string ("Extension: ") io.error.put_string (extension.generator) io.error.put_new_line end end if image.count /= 0 then -- Extracting the include part if image.item (1) = '|' then extension.set_include_files (image.substring (2, image.count)) else debug io.error.put_string (image) end raise_external_error ("Extra text at end of external language specification", source.substring_index (image,1)) end end if extension = Void and ext_language_name.is_equal ("C++") then raise_external_error ("Missing special part", 1) end if extension /= Void then extension.parse end -- For old external we generate a syntax warning if option is turned on. raise_external_warning end end raise_external_warning is -- Raises warning when parsing an old external syntax. local l_warning: SYNTAX_WARNING do -- FIXME: Manu 10/09/2003. We do not yet raise a warning for 5.4 -- as new external syntax is not clearly specified. if False and then System.has_syntax_warning then create l_warning.make ( eiffel_parser.line, eiffel_parser.column, eiffel_parser.filename, "Use new external syntax instead.") Error_handler.insert_warning (l_warning) end end raise_external_error (msg: STRING; start_p: INTEGER) is -- Raises error occurred while parsing local ext_error: EXTERNAL_SYNTAX_ERROR do create ext_error.init ext_error.set_column (start_p) ext_error.set_external_error_message (msg) Error_handler.insert_error (ext_error) Error_handler.raise_error end invariant language_name_not_void: language_name /= Void extension_not_void: extension /= Void end -- class EXTERNAL_LANG_AS