Synergy/DE Documentation Reimagined
April 9, 2018Taking Aim at the Credit Card Security Target
June 19, 2018If you have large (and I mean LARGE) blocks of code in single source files – and by large I mean 20k lines plus – then you may be having compiler issue with “SEGBIG” errors: “Segment too big”. This issue arises because your code segment is just too big for the compiler to handle and is usually the result of many man years of development to a single routine that has just grown over time.
If you encounter SEGBIG issues, as a customer I have recently worked with did, then this quick blog will give you some practical ideas of how to manage the issue and modify the code to allow for future development and expansion, without having to rewrite the world.
First off, it’s not the physical number of lines of code in the source file that’s the issue, it’s the lines of code and data definitions within each routine block: subroutine or function. Developers have encountered the problem for many years and the resolution has previously been to chop out a section of code, make it into a subroutine or function, and somehow pass all the appropriate data to it – usually by large numbers of arguments or common/global data blocks.
The “today” way is not too dissimilar but is a little more refined: turn the code block into a class. The first major advantage is class-based data. This removes the need to create subroutines or functions that accept large numbers of arguments, or to create large common or global data blocks. As an example:
subroutine BigRoutine
endparams
.include ‘AppCommonData.inc’
record localData
localRoutineData ,a10
endrecord
proc
call doSomeLogic
call doOtherLogic
xreturn
doSomeLogic,
return
doOtherLogic,
return
end
Obviously this code will not give us a SEGBIG issue, but its an example of the structure of the code. The routine has a common data include and private data. In the routine body we make multiple local label calls. When there is too much data and too many lines of code added we will encounter a SEGBIG error.
So to address this, in the same source file, we can create a class with class-level data (the routine level data) and methods for the local call labels. So, for example:
namespace CompanyName
public class BigRoutineClass
private record localData
localRoutineData ,a10
endrecord
public method Execute, void
endparams
proc
doSomeLogic()
doOtherLogic()
mreturn
endmethod
method doSomeLogic, void
.include ‘AppCommonData.inc’
proc
mreturn
endmethod
method doOtherLogic, void
.include ‘AppCommonData.inc’
proc
mreturn
endmethod
endclass
endnamespace
In this code, the Execute method becomes the entry point. All the existing code that made the label calls is moved into this routine and the calls changed to method invocations;
doSomeLogic()
doOtherLogic()
Then we can change the existing BigRoutine code;
subroutine BigRoutine
endparams
record
routineInstance ,@CompanyName.BigRoutineClass
endrecord
proc
routineInstance = new BigRoutineClass()
routineInstance.Execute()
xreturn
end
Simple!
Although the code changes I’ve described here sound monumental, if you use Visual Studio to develop your Traditional Synergy code the process is actually quite simple. Once you have created the scaffolding routine and defined the base class with class level data (which really is a case of cutting and pasting the data definition code), there are a few simple regex commands we can use that will basically do the work for us.
To change all the call references to class method invocations you can use:
Find: ([\t ]+)(call )([\w\d]+)
Replace: $1$3()
To change the actual labels into class methods, simply use the following regex:
Find: ^([\t ]+)([a-zA-z0-9_]+)[,]
Replace: $1endmethod\n$1method $2, void\n$1proc
And to change the return statements to method returns, use:
Find: \breturn
Replace: mreturn
These simple steps will allow you to take your large code routines and make manageable classes from them which can be extended as required.
If you have any questions or would like assistance in addressing your SEGBIG issues, please let me know.
2 Comments
Great info! Wouldn’t replacing Execute with a class constructor simplify the code slightly? You include AppCommonData at the method level, to more closely resemble the original subroutine, wouldn’t you want to include it at the class level?
Hi Kish,
The Execute method is used so that if required you could return a status/error condition. A constructor method works just as well if you don’t want to be able to return any information.
The AppCommonData include is at the method level and not the class level because it contains “common” and/or “global” data which you can’t define at the class level. Record data is defined at the class level.