News:

Let's find out together what makes a PIC Tick!

Main Menu

Using Preprocessor to create constants

Started by JohnB, Mar 13, 2022, 07:19 AM

Previous topic - Next topic

JohnB

This is a question for Les:
 
It is possible to use $define MyIdentifier = 0 to define a constant. 

At present Positron Studio recognises constants from the Symbol or Dim directives.  For the purposes of the Code Explorer and Highlighter, should I be including the preprocessor form of constants as constants rather than preprocessor. 
At present the highlighter will highlight the constant as a preprocessor command.
JohnB

top204

#1
Unfortunately, that is not possible with a preprocessor, because preprocessors work with text replacement.

For example:

    Dim bTemp As Byte
    $define Assign = 10
   
    bTemp Assign

The compiler will actually see "bTemp = 10", because Assign holds the text  " = 10".

As can be seen by the assembler code:

F1_000224 equ $ ; in [E220-LORA.BAS] bTemp = 10
    movlw 10
    movwf bTemp,1

I've looked in the past to try and make a mechanism for an equals character, but it always distorts the preprocessor's operations and will cause problems with user code over time, because it will break the way preprocessors work and some texts in a $define will not be stored correctly.

JohnB

My bad for confusing question I should have left the = sign out which is what I do when I use the preprocessor to define a constant.
So my original question remains when it when I see $define MyConstant 6 should I show it as a constant or a preprocessor in the highlighter and the explorer?

 I would probably only apply that for numbers.
JohnB

top204

Hello John. My bad as well for not reading your question fully. :-)

It is prefereable to have all $define texts as preprocessor highlights, that way a user can see that the text refers to a $define.

Many thanks for your excellent IDE John, it is such a lovely creation, and something you should be very proud of.

I've started up in Delphi again, after a long break from it. It is a good language, but all of those "begin" and "end" statements, and not needed here and needed there do have their annoyance sometimes. LOL I've created a program to make the .ppi and .def files for the new devices, from the Microchip .inf and .PIC files, because they no longer supply the original files that I used. I hate XML files so  much. :-) They are so bulky and wasteful!!!

JohnB

I agree about the XML files.  I have partly developed a PPS Wizard based on the files XML Files generated by mChip.  Everything is so clumsy, its nearly impossible to writ elegant code. 

I got as far a producing a pretty picture of the chip and pin connections which you can allocate to functions.  I stumbled when writing the code generation bit, it partially works for inputs but not for outputs.
JohnB

top204

#5
I gave up creating a parser for XML files, because there are so many differnt types of them now, and some of the headings and sub-headings and sub-sub headings are nonsense in them. Instead I created a simple type of parser to detect texts and extract texts/values, based upon certain leading texts. For example, I extract the PPS output items and values for the .ppi and .def files from the .PIC file with the Delphi code below, which reads a StringList that contains the device's .PIC file data.

//-------------------------------------------------------------------------------------------------------------------------------------------------
// Find_ the PPS list (if there is one) for Peripheral Pin Select
// Input    : None
// Output   : Makes a list of the PPS values in StringList "Global_PPS_List"
// Notes    : Reads the StringList "Global_PIC_List", loaded from the device's .PIC file
//
function Create_PPS_List(): Boolean;
var
    LineOfText: AnsiString;                                                         // Holds the line of text extracted from the StringList
    LineNumber: Integer;                                                            // Holds the line number of the StringList
    PositionOnLine: Integer;                                                        // Holds the position of a particular text in a String
    PPS_Type: AnsiString;                                                           // Holds the PPS type
    PPS_Value: Integer;                                                             // Holds the integer value of the PPS
    PreviousPPS_Value: Integer;                                                     // Holds a previous PPS value, so repeats are not carried out
    PPS_Name: AnsiString;                                                           // Holds the name of the PPS item
    PPS_ValueString: AnsiString;                                                    // Holds the PPS value
begin
    Global_PPS_List.Clear();                                                        // Clear the stringlist before we start
Try
    LineOfText := Find_ExactText(Global_PIC_List, '<edc:PinList');                  // Find the beginning of the PPS list (if available)
    If(LineOfText <> '') Then                                                       // Was a PPS list found?
        begin                                                                       // Yes. So...
            //Display('Found A PPS List');
            PPS_Type := GetTextAfter('ppsflavor=', LineOfText);
            //Display('PPS_Type is ' + PPS_Type);
            If((PPS_Type = 'complex-port') Or (PPS_Type = 'complex'))Then
                begin
                    Result := True;                                                 // Indicate that we have found the PPS list within the .PIC file
                    //Display('Found Complex PPS List');
                    //
                    // Create a loop to scan the PPS list and extract the values
                    //
                    LineNumber := Global_LineNumber + 1;                            // Move to the next line down from where it was found
                    Repeat
                        LineOfText := GetTextFromALine(Global_PIC_List, LineNumber);// Extract a line from the stringlist
                        //Display(LineOfText);
                        PositionOnLine := AnsiPos('</edc:PinList>', LineOfText);    // Look for the end of the PPS list
                        If(PositionOnLine > 0) Then                                 // Have we found the end of the list?
                            begin                                                   // Yes. So...
                                Break;                                              // Exit the loop
                            end;
                        PositionOnLine := AnsiPos('ppsval=', LineOfText);           // Look for the value of the PPS
                        If(PositionOnLine > 0) Then                                 // Have we found the PPS value?
                            begin                                                   // Yes. So..
                                //Display(LineOfText);
                                PPS_Name := GetTextAfter('name=', LineOfText);      // Get the name of the PPS
                                PPS_ValueString := GetTextAfter('ppsval=', LineOfText);
                                //
                                // Convert a (sometimes hex) value into a decimal value
                                //
                                PPS_ValueString := UpperCase(PPS_ValueString);
                                PPS_ValueString := AnsiReplaceStr(PPS_ValueString, '0X', '$');
                                PPS_Value := StrToInt(PPS_ValueString);
                                PPS_ValueString := IntToStr(PPS_Value);

                                Global_PPS_List.Add('_PPS_Fn_' + PPS_Name + ' EQU ' + PPS_ValueString);
                                //Display('_PPS_Fn_' + PPS_Name + ' EQU ' + PPS_ValueString);
                            end;
                        Inc(LineNumber);
                    Until(LineNumber >= Global_PIC_List.Count);            // Exit the loop if we come to the end of the stringlist
                end
            else
                begin
                    Result := False;
                end;
        end
    else
        begin
            Result := False;
        end;
Except
    DisplayError('******** Exception in Create_PPS_List');
    Result := False;
end;
end;

Clumsy and inefficient, but it works nicely for that particular task. Notice the exception handling? :-) I always do that type of thing when I am dealing with String parsing and StringList parsing etc, because Windows goes potty with them if an overflow or underflow occurs, which I have always found extremely annoying!!! Why can't it simply do nothing or give a value back if using a function, instead of giving a global "Exception Occured" message window on the desktop???

JohnB

#6
Where are the .PIC files located?
Had a look at your code, I guess  you are using some utilities because it makes calls to Find_ExactText and GetTextFrinALine

Are the .PIC files part of MPLAB/MPLABX?
JohnB

top204

#7
Install the dreadfful MplabX version 6.0 and they are in its directory: "C:\Program Files\Microchip\MPLABX\v6.00\packs\Microchip", but inside many other directories that are required for unbelievably bad and bloated Java programs. :-)

For example: "C:\Program Files\Microchip\MPLABX\v6.00\packs\Microchip\PIC18F-Q_DFP\1.13.211\edc"

The *.PIC files are a version of XML, but do not seem to be a standard version for some reason, so I had problems with standard XML parsers with it, because they were not listing some items within it. I tried some XML parser programs, so I could, maybe, extract the bits and pieces I needed for the compiler's files more quickly, but Oh No!!! Not with Sun or Microchip stuff (MplabX is the Sun Netbeans IDE, which is why it is so bloated, slow, and riddled with anomalies). Microchip create nothing of their own anymore. LOL

So I had to create a few rudimentary parsers in my .ppi and .def file creator program.

top204

#8
The procedures are simple extraction types that I created for the original .PPI creator, some 17 years ago, but they do their job well. :-)

They are listed below:

//-------------------------------------------------------------------------------------------------------
// Search a StringList for a specific piece of text that matches exactly
// Input    : pSourceList holds the StringList to search
//          : pTextToFind holds the text to find in the StringList
// Output   : Returns the line of text where the substring was found
//            Otherwise returns with an empty String
//            Also returns the line number within the StringList where it was found in the Global variable "Global_LineNumber"
// Notes    : None
//
function Find_ExactText(pSourceList: TStrings; pTextToFind: AnsiString): AnsiString;
var
    ReturnString: AnsiString;
    LineIndex: Integer;
    LineOfText: AnsiString;
    PositionOnLine: Integer;
begin
Try
    ReturnString := '';
    LineIndex := 0;
    Repeat
        PositionOnLine := AnsiPos(pTextToFind, pSourceList[LineIndex]);
        If(PositionOnLine > 0) Then
            begin
                //
                // Make sure it is the text and not just a fragment of it
                //
                LineOfText := GetNextFrom(pSourceList[LineIndex], PositionOnLine);
                If(LineOfText = pTextToFind) Then
                    begin
                        ReturnString := pSourceList[LineIndex];
                        Global_LineNumber := LineIndex;
                        Break;
                    end;
            end;
        Inc(LineIndex);
    Until(LineIndex >= pSourceList.Count);
    Result := ReturnString;
Except
    Global_LineNumber := 0;
    Result := '';
end;
end;

//-------------------------------------------------------------------------------------------------------
// Return the text from the line number given
// Input    : pSourceList holds the StringList to search
//          : pLineNumber holds the line number of pSourceList to extract the line of text from
// Output   : Returns the text from the line number given
//            Otherwise returns with an empty string
// Notes    : None
//
function GetTextFromALine(pSourceList: TStrings; pLineNumber: Integer): AnsiString;
var
    ReturnString: AnsiString;
    LineIndex: Integer;
    PositionOnLine: Integer;
begin
Try
    LineIndex := pLineNumber;
    Repeat
        Inc(LineIndex);
    Until(LineIndex >= pLineNumber) Or (LineIndex >= pSourceList.Count);
    Result := pSourceList[LineIndex - 1];
Except
    Result := '';
end;
end;

//-------------------------------------------------------------------------------------------------------
// Extract the text from the line, terminating at line end or a whitespace or a '-' or a '+'
// Input    : pLineOfText holds the text to search
//          : pLinePosition holds the position within pLineOfText to extract the text from
// Output   : Returns the text from the position
// Notes    : None
//
function GetTextFromLine(pLineOfText: AnsiString; pLinePosition: Integer): AnsiString;
var
    Index: Integer;
    Character: AnsiString;
    ReturnString: AnsiString;
begin
Try
    ReturnString := '';
    Index := pLinePosition;
    Repeat
        Character := pLineOfText[Index];
        If((Character = ' ') Or (Character <= #13) Or (Character = ')') Or (Character = '\t')) Or (Character = '-') Or (Character = '+') Then Break;
        ReturnString := ReturnString + Character;
        Inc(Index);
    Until(Index > Length(pLineOfText));
    Result := ReturnString;
Except
    Result := '';
end;
end;

//-------------------------------------------------------------------------------------------------------
// Return the next Text entry from the AnsiString passed
// Input    : pLineOfText holds the String to search
//          : pPositionOnLine holds the position to search
// Output   : Returns the text found
// Notes    : None
//
function GetNextFrom(pLineOfText: AnsiString; pPositionOnLine: Integer): AnsiString;
var
    ReturnString: AnsiString;
    Character: Char;
begin
Try
    Repeat
        Character := pLineOfText[pPositionOnLine];
        If((Character = ' ') Or (Character <= #13)) Then Break;                 // Exit the loop when a terminator is located
        If((Character = ';') Or (Character <= '''') Or (Character = '=')) Then Break;   // Exit the loop when a terminator is located
        ReturnString := ReturnString + Character;
        Inc(pPositionOnLine);
    Until(pPositionOnLine > Length(pLineOfText));                               // Until all the line is scanned
    Result := ReturnString;
Except
    Result := '';
end;
end;

JohnB

I had MPLABX installed when I was developing the PPSWIzard, and use similar if not the same files.  I used the XML library that comes with Delphi but I could not extract the information I need for to generate the PPS code.

Here is a screen shot of the app now abandoned.
JohnB

top204

#10
That looks excellent John.

I know what you mean about the values in the, nearly an XML, file. :-) I can extract the names and the values associated with the names, but there is no explanation texts as to what the PPS is for within its section?

I've looked in most of the files and cannot find any details concerning the PPS names and values, so I could add them as comments in the .ppi and .def files. Have you come across any more details in any of the microchip data files John? I may need to go deeper into the Java and Class files for them. I wish they would create a program that dissasembles the library files that they have for the devices, but they are now hidden in compressed .a files, and the compilers and programs they create are no longer "real" open source or shared. :-(

JohnB

It started of off as an academic exercise to see if I could build a graphical component and it developed from there.

I haven't pursued it further but at the time of the project, I could find no explanatory text at all. 
The other thing which made it difficult for me was the dependencies, i.e. some combinations of Pin/Peripheral are legal and others not.
JohnB

top204

#12
Quotesome combinations of Pin/Peripheral are legal and others not.

I have found that out the hard way John. Microchip cannot make their mind up how PPS works on different devices, and there are 3 versions of it. That's why I had to add a new directive in the compiler's .ppi files, i.e. "PPS_Type", so the compiler knows what to do on a particular device when auto setting PPS for some commands. With the PIC24 and dsPIC33 devices, there are also different mechanisms for different device families!!!

Get the sequence incorrect on certain devices, and it simply does not work. I also set the default config fuses on the compiler for PPS to be changed at any time, once the unlock sequence has been used.

Within the .PPI files, the last texts in a PPS sub-header informs you what ports are suitable for the PPS in question. i.e. <A, C>