diff options
Diffstat (limited to 'src/edif/edif-parse.adb')
-rw-r--r-- | src/edif/edif-parse.adb | 1088 |
1 files changed, 1088 insertions, 0 deletions
diff --git a/src/edif/edif-parse.adb b/src/edif/edif-parse.adb new file mode 100644 index 000000000..a3169bd63 --- /dev/null +++ b/src/edif/edif-parse.adb @@ -0,0 +1,1088 @@ +with Types; use Types; +with Std_Names; use Std_Names; +with Errorout; use Errorout; +with Edif.Tokens; use Edif.Tokens; +with Edif.Scans; use Edif.Scans; +with Edif.Nutils; use Edif.Nutils; + +package body Edif.Parse is + Parse_Error : exception; + + procedure Error_Msg_Parse (Msg : String; Args : Earg_Arr := No_Eargs) is + begin + Report_Msg (Msgid_Error, Errorout.Parse, +Get_Token_Location, Msg, Args); + end Error_Msg_Parse; + + procedure Error_Msg_Parse (Msg : String; Arg : Earg_Type) is + begin + Report_Msg (Msgid_Error, Errorout.Parse, +Get_Token_Location, + Msg, (1 => Arg)); + end Error_Msg_Parse; + + procedure Set_Token_Location (N : Node) is + begin + Set_Location (N, Get_Token_Location); + end Set_Token_Location; + + function Parse_Simple return Node; + + procedure Parse_Simple_List_Body (Bod : Node) + is + Last : Node; + El : Node; + begin + Last := Bod; + while Current_Token /= Tok_Right_Paren loop + if Current_Token = Tok_Eof then + Error_Msg_Parse ("missing ')'"); + exit; + end if; + El := Create_Node (N_Chain); + Set_Token_Location (El); + Set_CDR (Last, El); + Set_CAR (El, Parse_Simple); + Last := El; + end loop; + + Set_CDR (Last, Null_Node); + + if Current_Token = Tok_Right_Paren then + -- Skip ')'. + Scan; + end if; + end Parse_Simple_List_Body; + + function Parse_Simple_List return Node + is + Res : Node; + begin + Res := Create_Node (N_Keyword); + Set_Token_Location (Res); + + Set_Keyword (Res, Current_Identifier); + + -- Skip '(' + keyword. + Scan; + + Parse_Simple_List_Body (Res); + + return Res; + end Parse_Simple_List; + + function Parse_Symbol return Node + is + Res : Node; + begin + pragma Assert (Current_Token = Tok_Symbol); + + Res := Create_Node (N_Symbol); + Set_Token_Location (Res); + Set_Symbol (Res, Current_Identifier); + + -- Skip symbol. + Scan; + + return Res; + end Parse_Symbol; + + function Parse_String return Node + is + Res : Node; + begin + Res := Create_Node (N_String); + Set_Token_Location (Res); + Set_String_Id (Res, Current_String); + Set_String_Len (Res, Current_String_Len); + + -- Skip string. + Scan; + + return Res; + end Parse_String; + + function Parse_Number return Node + is + Res : Node; + begin + Res := Create_Node (N_Number); + Set_Token_Location (Res); + Set_Number (Res, Current_Number); + + -- Skip number. + Scan; + + return Res; + end Parse_Number; + + function Parse_Simple return Node is + begin + case Current_Token is + when Tok_Keyword => + return Parse_Simple_List; + + when Tok_Right_Paren => + Error_Msg_Parse ("unexpected ')'"); + + -- Skip it. + Scan; + + return Parse_Simple; + + when Tok_Eof => + Error_Msg_Parse ("unexpected end of file"); + return Null_Node; + + when Tok_Symbol => + return Parse_Symbol; + + when Tok_String => + return Parse_String; + + when Tok_Number => + return Parse_Number; + end case; + end Parse_Simple; + + function Parse_File_Simple return Node + is + Res : Node; + begin + -- Start the scanner. + Scan; + + Res := Parse_Simple; + + return Res; + end Parse_File_Simple; + + procedure Expect_Keyword (Id : Name_Id) is + begin + if Current_Token /= Tok_Keyword + or else Current_Identifier /= Id + then + Error_Msg_Parse ("keyword %i expected here", +Id); + raise Parse_Error; + end if; + end Expect_Keyword; + + procedure Expect_Symbol is + begin + if Current_Token /= Tok_Symbol then + Error_Msg_Parse ("symbol expected here"); + raise Parse_Error; + end if; + end Expect_Symbol; + + procedure Expect_String is + begin + if Current_Token /= Tok_String then + Error_Msg_Parse ("string expected here"); + raise Parse_Error; + end if; + end Expect_String; + + procedure Skip_Right_Paren is + begin + while Current_Token = Tok_Keyword loop + Error_Msg_Parse + ("unexpected %i keyword, skipped", +Current_Identifier); + + declare + Count : Natural; + begin + Count := 1; + loop + -- Skip. + Scan; + + if Current_Token = Tok_Right_Paren then + Count := Count - 1; + exit when Count = 0; + end if; + end loop; + + -- Skip ')'. + Scan; + end; + end loop; + + if Current_Token /= Tok_Right_Paren then + Error_Msg_Parse ("')' expected here"); + else + -- Skip ')'. + Scan; + end if; + end Skip_Right_Paren; + + procedure Expect_Number is + begin + if Current_Token /= Tok_Number then + Error_Msg_Parse ("number expected here"); + raise Parse_Error; + end if; + end Expect_Number; + + procedure Skip_Comments is + begin + while Current_Token = Tok_Keyword + and then Current_Identifier = Name_Comment + loop + -- Skip '(comment'. + Scan; + + if Current_Token = Tok_String then + -- Skip string. + Scan; + else + Error_Msg_Parse ("string expected after comment"); + end if; + + -- Skip ')' (for comment). + Skip_Right_Paren; + end loop; + end Skip_Comments; + + function Parse_Rename return Node + is + Res : Node; + begin + pragma Assert (Current_Token = Tok_Keyword); + + -- Skip 'rename'. + Scan; + + Res := Create_Node (N_Rename); + Expect_Symbol; + Set_Name (Res, Parse_Symbol); + + Expect_String; + Set_String (Res, Parse_String); + + Skip_Right_Paren; + + return Res; + end Parse_Rename; + + function Parse_Name return Node is + begin + if Current_Token = Tok_Symbol then + return Parse_Symbol; + elsif Current_Token = Tok_Keyword then + if Current_Identifier = Name_Rename then + return Parse_Rename; + end if; + end if; + + Error_Msg_Parse ("symbol or rename expected"); + raise Parse_Error; + end Parse_Name; + + function Parse_Boolean return Node + is + Res : Node; + begin + if Current_Token /= Tok_Keyword then + Error_Msg_Parse ("true or false expected"); + raise Parse_Error; + end if; + + Res := Create_Node (N_Boolean); + Set_Token_Location (Res); + + if Current_Identifier = Name_True then + Set_Boolean (Res, True); + elsif Current_Identifier = Name_False then + Set_Boolean (Res, False); + else + Error_Msg_Parse ("true or false expected"); + end if; + + -- Skip keyword. + Scan; + + -- Skip ')' (for true/false). + Skip_Right_Paren; + + return Res; + end Parse_Boolean; + + function Parse_Userdata return Node + is + Res : Node; + begin + Res := Create_Node (N_Userdata); + Set_Token_Location (Res); + + -- Skip '(property' or '(userdata'. + Scan; + + Set_Name (Res, Parse_Name); + + Parse_Simple_List_Body (Res); + + return Res; + end Parse_Userdata; + + function Parse_Property return Node + is + Prop : Node; + Ptype : Name_Id; + begin + Prop := Create_Node (N_Property); + Set_Token_Location (Prop); + + -- Skip '(property' or '(userdata'. + Scan; + + Set_Name (Prop, Parse_Name); + + if Current_Token /= Tok_Keyword then + Error_Msg_Parse ("property value expected"); + raise Parse_Error; + end if; + + Ptype := Current_Identifier; + + -- Skip type keyword. + Scan; + + case Ptype is + when Name_String => + Set_Value (Prop, Parse_String); + + when Name_Integer => + Set_Value (Prop, Parse_Number); + + when Name_Boolean => + Set_Value (Prop, Parse_Boolean); + + when Name_Number => + Set_Value (Prop, Parse_Simple); + + when others => + Error_Msg_Parse ("unknown property type %i", +Ptype); + raise Parse_Error; + end case; + + -- Skip ')' (for value). + Skip_Right_Paren; + + if Current_Token = Tok_Keyword + and then Current_Identifier = Name_Unit + then + -- Skip '(unit'. + Scan; + + Expect_Symbol; + Set_Unit (Prop, Current_Identifier); + Scan; + + -- Skip ')' (for unit). + Skip_Right_Paren; + end if; + + if Current_Token = Tok_Keyword + and then Current_Identifier = Name_Owner + then + -- Skip '(owner'. + Scan; + + Expect_String; + Set_Owner (Prop, Parse_String); + + -- Skip ')' (for owner). + Skip_Right_Paren; + end if; + + -- Skip ')' (for property). + Skip_Right_Paren; + + return Prop; + end Parse_Property; + + procedure Parse_Properties (Constr : in out Constr_Type) + is + El : Node; + begin + while Current_Token = Tok_Keyword loop + case Current_Identifier is + when Name_Property => + El := Parse_Property; + when Name_Userdata => + El := Parse_Userdata; + when others => + exit; + end case; + Append_Node (Constr, El); + end loop; + end Parse_Properties; + + procedure Parse_Properties (N : Node) + is + Constr : Constr_Type; + begin + Init_Constr (Constr); + + Parse_Properties (Constr); + + Set_Properties_Chain (N, Get_Constr_Chain (Constr)); + end Parse_Properties; + + function Parse_Edif_Version return Int32 + is + Res : Int32; + begin + Expect_Keyword (Name_Edifversion); + + -- Skip '(edifversion'. + Scan; + + -- Major + -- FIXME: small number. + Expect_Number; + Res := Current_Number * 100; + Scan; + + -- Minor + Expect_Number; + Res := Res + Current_Number * 10; + Scan; + + -- Revision + Expect_Number; + Res := Res + Current_Number; + Scan; + + -- Skip ')'. + Skip_Right_Paren; + + return Res; + end Parse_Edif_Version; + + function Parse_Edif_Level return Int32 + is + Res : Int32; + begin + Expect_Keyword (Name_Ediflevel); + + -- Skip '(ediflevel'. + Scan; + + Expect_Number; + Res := Current_Number; + + -- Skip number. + Scan; + + -- Skip ')'. + Skip_Right_Paren; + + return Res; + end Parse_Edif_Level; + + function Parse_Technology return Node is + begin + Expect_Keyword (Name_Technology); + + return Parse_Simple_List; + end Parse_Technology; + + procedure Parse_Designator_Opt (N : Node) is + begin + if Current_Token = Tok_Keyword + and then Current_Identifier = Name_Designator + then + -- Skip '(designator'. + Scan; + + Expect_String; + Set_Designator (N, Parse_String); + + -- Skip ')' (for designator). + Skip_Right_Paren; + end if; + end Parse_Designator_Opt; + + function Parse_Array return Node + is + Res : Node; + begin + Res := Create_Node (N_Array); + Set_Token_Location (Res); + + -- Skip '(array'. + Scan; + + Set_Name (Res, Parse_Name); + + Expect_Number; + Set_Array_Length (Res, Current_Number); + + -- Skip number. + Scan; + + -- Skip ')' (for array). + Skip_Right_Paren; + + return Res; + end Parse_Array; + + function Parse_Port return Node + is + -- Constr : Constr_Type; + Res : Node; + Name : Node; + begin + Res := Create_Node (N_Port); + Set_Token_Location (Res); + + -- Skip '(port'. + Scan; + + if Current_Token = Tok_Keyword + and then Current_Identifier = Name_Array + then + Name := Parse_Array; + else + Name := Parse_Name; + end if; + Set_Name (Res, Name); + + Expect_Keyword (Name_Direction); + -- Skip '(direction'. + Scan; + + Expect_Symbol; + case Current_Identifier is + when Name_Input => + Set_Direction (Res, Dir_Input); + when Name_Output => + Set_Direction (Res, Dir_Output); + when Name_Inout => + Set_Direction (Res, Dir_Inout); + when others => + Error_Msg_Parse + ("unhandled port direction %i", +Current_Identifier); + raise Parse_Error; + end case; + + -- Skip symbol. + Scan; + + -- Skip ')' (for direction). + Skip_Right_Paren; + + Parse_Designator_Opt (Res); + + Parse_Properties (Res); + + -- Skip ')' (for port). + Skip_Right_Paren; + + return Res; + end Parse_Port; + + function Parse_Library_Ref_Opt return Node + is + Res : Node; + begin + if Current_Token = Tok_Keyword + and then Current_Identifier = Name_Libraryref + then + -- Skip '(libraryref'. + Scan; + + Expect_Symbol; + Res := Parse_Symbol; + + -- Skip ')' (for libraryref). + Skip_Right_Paren; + else + Res := Null_Node; + end if; + + return Res; + end Parse_Library_Ref_Opt; + + function Parse_Cell_Ref return Node + is + Res : Node; + begin + Res := Create_Node (N_Cell_Ref); + Set_Token_Location (Res); + + -- Skip '(cellref'. + Scan; + + Expect_Symbol; + Set_Name (Res, Parse_Symbol); + + Set_Library_Ref (Res, Parse_Library_Ref_Opt); + + -- Skip ')' (for cellref). + Skip_Right_Paren; + + return Res; + end Parse_Cell_Ref; + + function Parse_View_Ref return Node + is + Res : Node; + begin + Res := Create_Node (N_View_Ref); + Set_Token_Location (Res); + + Expect_Keyword (Name_Viewref); + + -- Skip '(viewref'. + Scan; + + Set_Name (Res, Parse_Name); + + Set_Cell_Ref (Res, Parse_Cell_Ref); + + -- Skip ')' (for viewref). + Skip_Right_Paren; + + return Res; + end Parse_View_Ref; + + procedure Parse_Port_Instances (N : Node) + is + Constr : Constr_Type; + Inst : Node; + begin + Init_Constr (Constr); + + while Current_Token = Tok_Keyword + and then Current_Identifier = Name_Portinstance + loop + Inst := Create_Node (N_Port_Instance); + Set_Token_Location (Inst); + Append_Node (Constr, Inst); + + -- Skip '(portinstance'. + Scan; + + Set_Name (Inst, Parse_Name); + Parse_Properties (Inst); + + -- Skip ')' (for portinstance). + Skip_Right_Paren; + + end loop; + + Set_Port_Instances_Chain (N, Get_Constr_Chain (Constr)); + end Parse_Port_Instances; + + function Parse_Instance return Node + is + Res : Node; + begin + Res := Create_Node (N_Instance); + Set_Token_Location (Res); + + -- Skip '(instance'. + Scan; + + Set_Name (Res, Parse_Name); + Set_Instance_Ref (Res, Parse_View_Ref); + + Parse_Port_Instances (Res); + + Parse_Properties (Res); + + -- Skip ')' (for instance). + Skip_Right_Paren; + + return Res; + end Parse_Instance; + + function Parse_Member return Node + is + Res : Node; + begin + Res := Create_Node (N_Member); + Set_Token_Location (Res); + + -- Skip '(member'. + Scan; + + Set_Name (Res, Parse_Name); + + Expect_Number; + Set_Index (Res, Current_Number); + + -- Skip number. + Scan; + + -- Skip ')' (for member). + Skip_Right_Paren; + + return Res; + end Parse_Member; + + function Parse_Net return Node + is + Constr : Constr_Type; + Res : Node; + Ref : Node; + begin + Res := Create_Node (N_Net); + Set_Token_Location (Res); + + -- Skip '(net'. + Scan; + + Set_Name (Res, Parse_Name); + + if Current_Token = Tok_Keyword + and then Current_Identifier = Name_Joined + then + Init_Constr (Constr); + + -- Skip '(joined'. + Scan; + + while Current_Token = Tok_Keyword + and then Current_Identifier = Name_Portref + loop + Ref := Create_Node (N_Port_Ref); + Set_Token_Location (Ref); + Append_Node (Constr, Ref); + + -- Skip '(portref'. + Scan; + + if Current_Token = Tok_Keyword + and then Current_Identifier = Name_Member + then + Set_Port (Ref, Parse_Member); + else + Set_Port (Ref, Parse_Name); + end if; + + if Current_Token = Tok_Keyword + and then Current_Identifier = Name_Instanceref + then + -- Skip '(instanceref'. + Scan; + + Set_Instance_Ref (Ref, Parse_Name); + + -- Skip ')' (for instanceref). + Skip_Right_Paren; + end if; + + -- Skip ')' (for portref). + Skip_Right_Paren; + end loop; + Set_Joined_Chain (Res, Get_Constr_Chain (Constr)); + + -- Skip ')' (for joined). + Skip_Right_Paren; + end if; + + Parse_Properties (Res); + + -- Skip ')' (for net). + Skip_Right_Paren; + + return Res; + end Parse_Net; + + function Parse_Interface return Node + is + Constr : Constr_Type; + Res : Node; + begin + Res := Create_Node (N_Interface); + Set_Token_Location (Res); + + -- Skip '(interface'. + Scan; + + Parse_Designator_Opt (Res); + + Init_Constr (Constr); + while Current_Token = Tok_Keyword + and then Current_Identifier = Name_Port + loop + Append_Node (Constr, Parse_Port); + end loop; + Set_Ports_Chain (Res, Get_Constr_Chain (Constr)); + + Parse_Designator_Opt (Res); + + Parse_Properties (Res); + + -- Skip ')' (for interface). + Skip_Right_Paren; + + return Res; + end Parse_Interface; + + function Parse_View return Node + is + Constr : Constr_Type; + Prop_Constr : Constr_Type; + Res : Node; + begin + Res := Create_Node (N_View); + Set_Token_Location (Res); + + -- Skip '(view'. + Scan; + + Set_Name (Res, Parse_Name); + + Expect_Keyword (Name_Viewtype); + + -- Skip '(viewtype'. + Scan; + + Expect_Symbol; + Set_View_Type (Res, Current_Identifier); + + -- Skip symbol. + Scan; + + -- Skip ')' (for viewtype). + Skip_Right_Paren; + + Expect_Keyword (Name_Interface); + Set_Interface (Res, Parse_Interface); + + Init_Constr (Prop_Constr); + Parse_Properties (Prop_Constr); + + if Current_Token = Tok_Keyword + and then Current_Identifier = Name_Contents + then + -- Skip '(contents'. + Scan; + + Init_Constr (Constr); + while Current_Token = Tok_Keyword loop + case Current_Identifier is + when Name_Instance => + Append_Node (Constr, Parse_Instance); + when Name_Net => + Append_Node (Constr, Parse_Net); + when Name_Userdata => + Append_Node (Constr, Parse_Userdata); + when others => + Error_Msg_Parse + ("%i not supported in contents", +Current_Identifier); + raise Parse_Error; + end case; + end loop; + Set_Contents_Chain (Res, Get_Constr_Chain (Constr)); + + -- Skip ')' (for contents). + Skip_Right_Paren; + end if; + + Parse_Properties (Prop_Constr); + Set_Properties_Chain (Res, Get_Constr_Chain (Prop_Constr)); + + -- Skip ')' (for view). + Skip_Right_Paren; + + return Res; + end Parse_View; + + function Parse_Cell return Node + is + Res : Node; + Status : Node; + Prop_Constr : Constr_Type; + pragma Unreferenced (Status); + begin + Res := Create_Node (N_Cell); + + -- Skip '(cell'. + Scan; + + Set_Name (Res, Parse_Name); + + Expect_Keyword (Name_Celltype); + + -- Skip '(celltype'. + Scan; + + Expect_Symbol; + Set_Cell_Type (Res, Current_Identifier); + + -- Skip symbol. + Scan; + + -- Skip ')' (for celltype). + Skip_Right_Paren; + + Skip_Comments; + + if Current_Token = Tok_Keyword + and then Current_Identifier = Name_Status + then + Status := Parse_Simple_List; + -- FIXME: free. + end if; + + Init_Constr (Prop_Constr); + Parse_Properties (Prop_Constr); + + Set_View (Res, Parse_View); + + -- Properties can appear at several places... + Parse_Properties (Prop_Constr); + Set_Properties_Chain (Res, Get_Constr_Chain (Prop_Constr)); + + -- Skip ')' (for cell). + Skip_Right_Paren; + + return Res; + end Parse_Cell; + + procedure Parse_Library_Body (Res : Node) + is + Constr : Constr_Type; + begin + -- Skip '(external'. + Scan; + + Set_Name (Res, Parse_Name); + + Set_Edif_Level (Res, Parse_Edif_Level); + Set_Technology (Res, Parse_Technology); + + Init_Constr (Constr); + while Current_Token = Tok_Keyword + and then Current_Identifier = Name_Cell + loop + Append_Node (Constr, Parse_Cell); + end loop; + Set_Cells_Chain (Res, Get_Constr_Chain (Constr)); + + -- Skip ')' (for external). + Skip_Right_Paren; + end Parse_Library_Body; + + function Parse_Library return Node + is + Res : Node; + begin + Expect_Keyword (Name_Library); + + Res := Create_Node (N_Library); + Set_Token_Location (Res); + + Parse_Library_Body (Res); + + return Res; + end Parse_Library; + + function Parse_External return Node + is + Res : Node; + begin + Expect_Keyword (Name_External); + + Res := Create_Node (N_External); + Set_Token_Location (Res); + + Parse_Library_Body (Res); + + return Res; + end Parse_External; + + function Parse_Design return Node + is + Res : Node; + begin + Res := Create_Node (N_Design); + Set_Token_Location (Res); + + -- Skip '(design'. + Scan; + + Set_Name (Res, Parse_Name); + Set_Cell_Ref (Res, Parse_Cell_Ref); + Parse_Properties (Res); + + -- Skip ')' (for design). + Skip_Right_Paren; + + return Res; + end Parse_Design; + + function Parse_Edif200 return Node + is + Res : Node; + Constr : Constr_Type; + begin + -- Start the scanner. + Scan; + + Expect_Keyword (Name_Edif); + + -- Skip '(edif' + Scan; + + Res := Create_Node (N_Edif); + + Set_Name (Res, Parse_Name); + Set_Edif_Version (Res, Parse_Edif_Version); + Set_Edif_Level (Res, Parse_Edif_Level); + + Expect_Keyword (Name_Keywordmap); + -- Skip '(keywordmap'. + Scan; + Set_Keyword_Map (Res, Parse_Simple); + -- Skip ')' (for keywordmap). + Skip_Right_Paren; + + if Current_Token = Tok_Keyword + and then Current_Identifier = Name_Status + then + Set_Status (Res, Parse_Simple); + end if; + + Skip_Comments; + + -- Parse externals. + Init_Constr (Constr); + while Current_Token = Tok_Keyword + and then Current_Identifier = Name_External + loop + Append_Node (Constr, Parse_External); + end loop; + Set_External_Chain (Res, Get_Constr_Chain (Constr)); + + -- Parse libraries. + Init_Constr (Constr); + while Current_Token = Tok_Keyword + and then Current_Identifier = Name_Library + loop + Append_Node (Constr, Parse_Library); + end loop; + Set_Library_Chain (Res, Get_Constr_Chain (Constr)); + + -- Parse design. + if Current_Token = Tok_Keyword + and then Current_Identifier = Name_Design + then + Set_Design (Res, Parse_Design); + end if; + + -- Skip ')' (for edif). + Skip_Right_Paren; + + if Current_Token /= Tok_Eof then + Error_Msg_Parse ("end of file expected"); + end if; + + return Res; + end Parse_Edif200; + +end Edif.Parse; |