Need The Full List of PureBASIC Keywords

Just starting out? Need help? Post your questions and find answers here.
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 195
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Need The Full List of PureBASIC Keywords

Post by Tristano »

WHAT — I need the full list of PureBASIC 5.00 keywords (reserved words, commands, directives, etc).

WHY — I need them for maintaining PureBASIC syntax highlighters language definitions.

I’ve created a PureBASIC syntax for two highlighters:
My problem is with the keywords list. In the current definitions, I’ve relied on the keywords list created by Gustavo Julio Fiorenza (@GuShH) for GeSHi — which dates back to 2009, so it’s quite old.

What I’d like to do is maintain an open source project with a database of all PureBAISC 5.x keywords, tracking new keywords, renamings, and deletions. This database could then be used to auto-update syntax definitions for syntax highlighting tools as well as editors.

Ideally, a syntax highlighter should cover all versions of PureBASIC, from 5.00 to the latests (ie: include also deprecated and renamed keywords), so that it might highlight old and new code alike.

I haven’t worked out a way to grab all of PureBASIC’s keywords — ie: all reserved keywords: from If/Then, And/Or, to all commands and built in functions, and compiler directives, eg Debug, CompilerSelect and so on. I’d like to have the full list, including ASM keywords.

I looked into the Syntax highlighter DLL that comes with the PB SDK, and it does contain a full list of tokens (including ASM), except that it not always up to date with the latest PureBASIC version — for example, in version 5.60 the DLL doesn’t cover the new commands like SetImageFrame().

Specifically, I’m looking for the full keywords list of PureBASIC v5.00, and from there on I can simply refere to the History page to apply changes (after all, new commands, renamings and deletions aren’t all that common, and they are always documented therein).

Can anyone help me with this? Can any of the PureBASIC maintainers extract the full tokens list from the sources of PureBASIC v5.00 and publish it somewhere or send it to me? Or does anyone have an idea of how to get hold of the list?

FEATURE REQUEST — I propose that the full list of PureBASIC tokens be added to the SDK. It would help developers of editor’s plugins, syntax highlighters, etc. The SDK seems a reasonable place to put it.
Last edited by Tristano on Sun Apr 30, 2017 10:42 am, edited 2 times in total.
The PureBASIC Archives: FOSS Resources:
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Need The Full List of PureBASIC Keywords

Post by IdeasVacuum »

Hi Tristano

Those of us that use alternative IDEs, such as UltraEdit, would very much like to see a complete list.

I'm sure you are aware of this list: http://www.purebasic.com/documentation/ ... index.html

I think the missing items from PB's Syntax highlighter DLL should be reported as a bug. That DLL must surely be based on a list and updated by Fred or Freak?

Given that top quality syntax highlighting benefits every PB User, I agree that a simple text list distributed with each version would be very very useful.

So, please raise a bug post and a separate feature request post. Since the feature request requires no programming and assuming a list already exists, maybe Fred or Freak can make it available straight away - perhaps for now via http://www.purebasic.com/support.php
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
Bisonte
Addict
Addict
Posts: 1305
Joined: Tue Oct 09, 2007 2:15 am

Re: Need The Full List of PureBASIC Keywords

Post by Bisonte »

For procedures, constants, structures and interfaces I recommended Danilo's GETPBInfo
PureBasic 6.21 (Windows x64) | Windows 11 Pro | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
English is not my native language... (I often use DeepL.)
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: Need The Full List of PureBASIC Keywords

Post by Josh »

Following Keywords are not in your List:

Code: Select all

Align
Array
CompilerElseIf
DeclareModule
EndDeclareModule
EndModule
EnumerationBinary
List
MacroExpandedCount
Map
Module
NewMap
Runtime
Threaded
UndefineMacro
UnuseModule
UseModule
Be careful with 'Align' and 'Extends'. Can be a keyword or not.
sorry for my bad english
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 195
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Re: Need The Full List of PureBASIC Keywords

Post by Tristano »

Hi @IdeasVacuum,

I'm not sure about opening a bug report. The way the Syntax DLL work seems to be that it doesn't considers as keywords built-in functions — which is the way PB IDE highlights code: built-in functions that require parenthesis are green but not bold, keyword (ie: don't need parenthesis) are green and bold. Some keyword like Debug (which works with and without parenthesis) are also bold. So, built procedures are treated just like user defined procedures; it is in this sense that it is not "up to date" with PB 5.60. Anyhow, I have notified Fred via PM about his post and the issue.

So far, in my highlighter syntax definitions I've followed the same criteria as above (if you look at the links, you'll notice I've stripped out many keyword from the original GeShi file). But this would not be sufficient for highlighting in editors — they need to know the full list of keywords, and if they come in pairs, take arguments, ecc. Furthermore, some code highlighters also require a full list of keywords — for example, any syntax highlighter that relies on the definitions of a code editor, like Kate, usually imports the full lists.

What PB considers keywords doesn't overlap with what many highlighters define as keywords. "Tokens" might be a better word in this case, or "reserved keywords". Surely, within PureBASIC source code there must be a full list of all the possible tokens the parse might encounter. This is the list needed for maintaining a database like the one I envisages — tokens would be coupled with some tags to further identify them, so that exporting them as lists for third party applications can be automated and produce results specific for certain app needs.

Unfortunately, there is no standard specification for exporting the tokens list for programming languages -- if there was one, porting syntax highlighter would be much easier. Such a specification would have to embrace all the different token categorizations adopted by languages, and build a huge reference table for mapping languages against it, and cover all possible cases --- this would allow to define language-specific schemas that map each language against this ref table, and then map each syntax highlighter against this table too, thus making it easier (if not fully automated) porting definitions from one tool to another (even though 1-to-1 mapping are unlikely, some tag-based reduction rules could be defined for translating).

The commands index you linked unfortunately doesn't all the keywords. I did consider it for extracting the list (each PureBASIC Windows installer comes with that page in the *.chm help files, and the Mac version has is in html format). But I still need a full list of all possible tokens (not only procedures/commands/functions) of the first PB 5.x release, to be sure no tokens are left out. From there on tracking new keywords/commands can be done be hand.

The only bullet-proof way of obtaining such a list is that developers release one with the language --- which would also contain notes about pattern-based tokens, which would translate to a RegEx in a syntax highlighter definition; and other things like the pattern for valid label names, and so on. Such info is in the interest of promoting the language because it makes life easier to developers wishing to contribute resource like highlighter definitions --- mostly being free and open source contributions, which means that having to resort to tedious and complex hacks to gather such basic information is a frustrating deterrent.
The PureBASIC Archives: FOSS Resources:
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 195
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Re: Need The Full List of PureBASIC Keywords

Post by Tristano »

Bisonte wrote:For procedures, constants, structures and interfaces I recommended Danilo's GETPBInfo
Thanks for the link. I've built it and run it (needed commenting out the CompilerIf #PB_Compiler_Unicode part).

I had tried this approach manually before, and stumbled upon a limit: the lists will not contain any procedure not supported by the guest OS! For example, on Windows, you'll not see listed in the procedures CocoaMessage (Mac only) or SvgVectorOutput (Linux only).

This means that to extract a full list you'd need to run it on Windows, Mac and Linux (and since I don't have a Mac I won't be able to get the full list).

Thanks for the missing keywords list @Josh!

PS: I thought it's strange that the documents don't contain a page with a full list of all the reserved keywords -- usually all languages have one, so that you might check you are not trying to use one.
The PureBASIC Archives: FOSS Resources:
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 195
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Re: Need The Full List of PureBASIC Keywords

Post by Tristano »

So far, I've come to the conclusion that the only way to get a full list of all built-in commands and procedure would be to adopt a multi-sided approach:

1) parse commandindex.html via XML and extract all the commands,
2) parse osspecific.html
3) Use GETPBInfo, as suggest by @Bisonte (steps 1-2 would compensate for the missing OS-specific commands)

... but this would still leave out the basic keywords, which are scattered in separate pages in the "Advanced Keywords" section.

It's a bit of a tour-de-force, really. I personally hate having to resort to twisty hacks to access basic information like this (or trying to see which version of a library module ships with PB, like PCRE version, etc). Being a closed-source language, similar info should be made available by its developers, in the documentation and/or the SDK (or even the website).
The PureBASIC Archives: FOSS Resources:
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 195
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Re: Need The Full List of PureBASIC Keywords

Post by Tristano »

Josh wrote:Following Keywords are not in your List:
Be careful with 'Align' and 'Extends'. Can be a keyword or not.
... could you give me an example of the different usage for both?
The PureBASIC Archives: FOSS Resources:
Marc56us
Addict
Addict
Posts: 1600
Joined: Sat Feb 08, 2014 3:26 pm

Re: Need The Full List of PureBASIC Keywords

Post by Marc56us »

Tristano wrote: 1) parse commandindex.html via XML and extract all the commands,
For this point, no need to parse XML, regular expression can do it with few lines:

Code: Select all

InitNetwork()

*Buffer = ReceiveHTTPMemory("http://www.purebasic.com/documentation/reference/commandindex.html")
If *Buffer
     Taille = MemorySize(*Buffer)
     All_Functions.s = PeekS(*Buffer, Taille, #PB_UTF8|#PB_ByteLength)
     FreeMemory(*Buffer)
Else
     Debug "Download fail"
     End
EndIf

CreateRegularExpression(0, ">(.+)</a><br>") 

If ExamineRegularExpression(0, All_Functions)
     While NextRegularExpressionMatch(0)
          Debug RegularExpressionGroup(0, 1)
     Wend 
EndIf
If help page is up to date, PB have 1746 functions (!)

For constants, changes:

Code: Select all

*Buffer = ReceiveHTTPMemory("http://www.purebasic.com/documentation/reference/pbconstants.html")

CreateRegularExpression(0, "(#PB_[\w\d]+)") 
:wink:
User avatar
Mijikai
Addict
Addict
Posts: 1517
Joined: Sun Sep 11, 2016 2:17 pm

Re: Need The Full List of PureBASIC Keywords

Post by Mijikai »

Some quick code :)
It takes the current Helpfile and extracts Keywords!

Hackish:

Code: Select all

;by mijikai

Procedure.s ListKeywords()
  Protected StringBuffer.s
  Protected Entry.s
  Protected Result.s
  Protected *Zero.Word
  Protected *Position.Byte
  Protected Offset.i, Pos.i
  Protected BufferSize.i = ?EOD - ?Buffer - 2
  If VirtualProtect_(?Buffer,BufferSize,$40,@Pos)
    For Offset = ?Buffer To ?Buffer + BufferSize
      *Position = Offset
      If *Position\b = #Null
        *Position\b = $F
      EndIf
    Next
    *Zero = ?Buffer + BufferSize
    *Zero\w = #Null
    StringBuffer = PeekS(?Buffer,-1,#PB_Ascii)
    Offset = 1
    Entry = StringField(StringBuffer,Offset,"/")
    While Entry
      Pos = FindString(Entry,".html")
      If Pos
        Entry = Left(Entry,Pos-1)
        If Not Entry = "index"
          If Result
            Result + Chr(13)
          EndIf
          Result + Entry
        EndIf
      EndIf
      Offset + 1
      Entry = StringField(StringBuffer,Offset,"/")
    Wend
  EndIf
  ProcedureReturn Result
  Buffer:
  IncludeBinary #PB_Compiler_Home + "PureBasic.chm"
  EOD:
EndProcedure

Debug ListKeywords()
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Need The Full List of PureBASIC Keywords

Post by IdeasVacuum »

Mijikai, that is a very nifty piece of code 8)
It can't grab everything needed for syntax highlighting though and it includes a few anomalies too.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
Mijikai
Addict
Addict
Posts: 1517
Joined: Sun Sep 11, 2016 2:17 pm

Re: Need The Full List of PureBASIC Keywords

Post by Mijikai »

IdeasVacuum wrote:Mijikai, that is a very nifty piece of code 8)
It can't grab everything needed for syntax highlighting though and it includes a few anomalies too.
Thanks for pointing it out :)
Didn't double check - seems like its not that usefull then.
User_Russian
Addict
Addict
Posts: 1520
Joined: Wed Nov 12, 2008 5:01 pm
Location: Russia

Re: Need The Full List of PureBASIC Keywords

Post by User_Russian »

New version file purebasic.php for GeSHi.

Code: Select all

<?php

$language_data = array (
    'LANG_NAME' => 'PureBasic',
    'COMMENT_SINGLE' => array( 1 => ";"),
    'COMMENT_MULTI' => array( ),
    'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE,
    'QUOTEMARKS' => array('"', "'"),
    'ESCAPE_CHAR' => '',
    'KEYWORDS' => array(
        1 => array(
            // Keywords
            'And', 'Array', 'As', 'Align', 'Break', 'CallDebugger', 'Case', 'CompilerCase', 'CompilerDefault', 'CompilerElse', 'CompilerElseIf', 'CompilerEndIf', 'CompilerEndSelect',
            'CompilerError', 'CompilerIf', 'CompilerSelect', 'Continue', 'Data', 'DataSection', 'EndDataSection', 'Debug', 'DebugLevel', 'Declare', 'DeclareC',
            'DeclareCDLL', 'DeclareDLL', 'Default', 'Define', 'Dim', 'DisableASM', 'DisableDebugger', 'DisableExplicit', 'DeclareModule', 'Else', 'ElseIf', 'EnableASM',
            'EnableDebugger', 'EnableExplicit', 'End', 'EndEnumeration', 'EndIf', 'EndImport', 'EndInterface', 'EndMacro', 'EndProcedure', 'EndDeclareModule', 'EndModule',
            'EndSelect', 'EndStructure', 'EndStructureUnion', 'EndWith', 'Enumeration', 'Extends', 'FakeReturn', 'For', 'Next', 'ForEach',
            'ForEver', 'Global', 'Gosub', 'Goto', 'If', 'Import', 'ImportC', 'IncludeBinary', 'IncludeFile', 'IncludePath', 'Interface', 'List', 'Macro', 'Map', 'MacroExpandedCount',
            'Module', 'NewList', 'Not', 'Or', 'Procedure', 'ProcedureC', 'ProcedureCDLL', 'ProcedureDLL', 'ProcedureReturn', 'Protected', 'Prototype',
            'PrototypeC', 'Read', 'ReDim', 'Repeat', 'Until', 'Restore', 'Return', 'Runtime', 'Select','Shared', 'Static', 'Step', 'Structure', 'StructureUnion',
            'Swap', 'To', 'Wend', 'While', 'With', 'XIncludeFile', 'XOr','UseModule', 'UnuseModule', 'UndefineMacro'
            ),
 
        2 => array(
            // some ASM instructions
            'AAA', 'AAD', 'AAM', 'AAS', 'ADC', 'ADD', 'AND', 'ARPL', 'BOUND', 'BSF', 'BSR', 'BSWAP', 'BT', 'BTC', 'BTR',
            'BTS', 'CALL ', 'CBW', 'CDQ', 'CLC', 'CLD', 'CLI', 'CLTS', 'CMC', 'CMP', 'CMPS', 'CMPXCHG', 'CWD', 'CWDE',
            'DAA', 'DAS', 'DB', 'DD', 'DEC', 'DIV', 'DW', 'ENTER', 'ESC', 'F2XM1', 'FABS', 'FADD', 'FCHS', 'FCLEX',
            'FCOM', 'FDIV', 'FDIVR', 'FFREE', 'FINCSTP', 'FINIT', 'FLD', 'FLD1', 'FLDCW', 'FMUL', 'FNOP', 'FPATAN',
            'FPREM', 'FRNDINT', 'FSAVE', 'FSCALE', 'FSETPM', 'FSIN', 'FSQRT', 'FST', 'FSTENV', 'FSTSW', 'FSUB',
            'FSUBR', 'FTST', 'FUCOM', 'FWAIT', 'FXAM', 'FXCH', 'FXTRACT', 'FYL2X', 'FYL2XP1', 'HLT', 'IDIV', 'IMUL',
            'IN ', 'INC ', 'INS', 'INT ', 'INTO', 'INVLPG', 'IRET', 'IRETD', 'JA', 'JAE', 'JB', 'JBE', 'JC', 'JCXZ', 'JE', 'JECXZ',
            'JG', 'JGE', 'JL', 'JLE', 'JMP', 'JNA', 'JNAE', 'JNB', 'JNBE', 'JNC', 'JNE', 'JNG', 'JNGE', 'JNL', 'JNLE', 'JNO', 'JNP',
            'JNS', 'JNZ', 'JO', 'JP', 'JPE', 'JPO', 'JS', 'JZ', 'LAHF', 'LAR', 'LDS', 'LEA', 'LEAVE', 'LES', 'LFS', 'LGDT', 'LGS',
            'LIDT', 'LLDT', 'LMSW', 'LOCK', 'LODS', 'LOOP', 'LOOPE', 'LOOPNE', 'LOOPNZ', 'LOOPZ', 'LSL', 'LSS', 'LTR',
            'MOV', 'MOVS', 'MOVSX', 'MOVZX', 'MUL', 'NEG', 'NOP', 'NOT', 'OR', 'OUT', 'OUTS', 'POP', 'POPA', 'POPAD',
            'POPF', 'POPFD', 'PUSH', 'PUSHA', 'PUSHAD', 'PUSHF', 'PUSHFD', 'RCL', 'RCR', 'REP', 'REPE', 'REPNE',
            'REPNZ', 'REPZ', 'RET', 'RETF', 'ROL', 'ROR', 'SAHF', 'SAL', 'SAR', 'SBB', 'SCAS', 'SETAE', 'SETB', 'SETBE',
            'SETC', 'SETE', 'SETG', 'SETGE', 'SETL', 'SETLE', 'SETNA', 'SETNAE', 'SETNB', 'SETNC', 'SETNE', 'SETNG',
            'SETNGE', 'SETNL', 'SETNLE', 'SETNO', 'SETNP', 'SETNS', 'SETNZ', 'SETO', 'SETP', 'SETPE', 'SETPO',
            'SETS', 'SETZ', 'SGDT', 'SHL', 'SHLD', 'SHR ', 'SHRD', 'SIDT', 'SLDT', 'SMSW', 'STC', 'STD', 'STI',
            'STOS', 'STR ', 'SUB', 'TEST ', 'VERR', 'VERW', 'WAIT', 'WBINVD', 'XCHG', 'XLAT', 'XLATB', 'XOR '
            )
        ),
    'SYMBOLS' => array(
        '(', ')', '+', '-', '*', '/', '>', '<', '=', '<=', '>=', '&', '|', '!', '~', '<>', '>>', '<<', '%', '[', ']', ":", '?', '@', '\\', '.', ','
        ),
    'CASE_SENSITIVE' => array(
        GESHI_COMMENTS => false,
        1 => false,
        2 => false,
        ),
    'STYLES' => array(
        'KEYWORDS' => array(
            1 => 'color: #006666; font-weight: bold;',
            2 => 'color: #904070; font-weight: bold;'
            ),
        'COMMENTS' => array(
            1 => 'color: #00AAAA; font-style: italic;'
            ),
        'ESCAPE_CHAR' => array(
            0 => 'color: #000000;'
            ),
        'BRACKETS' => array(
            0 => 'color: #4040B0;'
            ),
        'STRINGS' => array(
            0 => 'color: #800080;'
            ),
        'NUMBERS' => array(
            0 => 'color: #0061C1;'
            ),
        'METHODS' => array(
            1 => 'color: #000000;'
            ),
        'SYMBOLS' => array(
            0 => 'color: #2020B0;'
            ),
        'REGEXPS' => array(
	      0 => 'color: #0061C1;',
			1 => 'color: #0061C1;',
			2 => 'color: #924B72;',
			3 => 'color: #006868;',
			4 => 'color: #0000FF;',
			5 => 'color: #400080;',
			6 => 'color: #FF8040;',
			7 => 'color: #FF0080;'
            ),
        'SCRIPT' => array(
            0 => '',
            1 => '',
            )
        ),
    'URLS' => array(
        0 => '',
        ),
    'OOLANG' => false,
    'OBJECT_SPLITTERS' => array(
        1 => '\\'
        ),
    'REGEXPS' => array(
	    // Hex numbers.
              0 => '\$[0-9a-fA-F]+',
		// Bin numbers.
		1 => '\%[0-1]+',
		// Constant.
		2 => '\#\w+\$?',
		// Funct.
		3 => '([\.]?\w\w+\s*\()|(\w+(?=\.\w*:?:?\w*\s*\())',
		// Module name.
		4 => '\w+(?=::)',
		// Point.
		5 => '((@?\*|\?)[^0-9]\w*)|(@[^0-9]\w*\s*\()',
		// Structure.
		6 => '(\w*\.[^abcdfilsqwuABCDFILSQWU]?[^\s]\w+\(?)|(\w+(?=\\\))|((?<=\\\)\w+(?=\\\))|((?<=\\\)\w+\$?)',
		// Label.
		7 => '\w+\:\s'
        ),
    'STRICT_MODE_APPLIES' => GESHI_NEVER,
    'SCRIPT_DELIMITERS' => array(),
    'HIGHLIGHT_STRICT_BLOCK' => array(),
    'TAB_WIDTH' => 4
);

?>
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: Need The Full List of PureBASIC Keywords

Post by Josh »

Tristano wrote:
Josh wrote:Following Keywords are not in your List:
Be careful with 'Align' and 'Extends'. Can be a keyword or not.
... could you give me an example of the different usage for both?

Code: Select all

Structure MyStruc1
EndStructure

Structure MyStruc2 Extends MyStruc1 Align #PB_Structure_AlignC
EndStructure

Debug Extends
Debug Align

Code: Select all

Interface MyIface1
EndInterface

Interface MyIface2 Extends MyIface1
EndInterface

Debug Extends

There are other keywords that can be used elsewhere in Pb, but they are also highlighted in Pb.

E.g. Array, List, Map
sorry for my bad english
User avatar
Tristano
Enthusiast
Enthusiast
Posts: 195
Joined: Thu Nov 26, 2015 6:52 pm
Location: Italy
Contact:

Re: Need The Full List of PureBASIC Keywords

Post by Tristano »

Thanks a lot, you've provided lots of useful information and codes to approach the problem at hand.

@Marc56us code to extract from commandindex.htm is a very neat solution — all I need to do is to extract the commandindex page from the different chm help files that come with each PB release, and I can quickly get the all the commands history and merge them together so it can track what was introduced/removed when.

The bare keywords can be extracted from SyntaxHilighting.dll with some smart HexEditor (from v5.50 upward the strings are in Unicode, before that they are in Ascii). I've done some more checking against the keywords list pasted here by @Josh and @User_Russian and it looks like the 5.50 dell does contain all the keywords.

These two lists should be enough to cover the needs of most syntax highlighters, constants, types and structures are not usually needed (not sure about code editors though, some require more info for autocompletion).

I'll update my two highlighters definitions, and will also create a folder in my PureBASIC Archives repo linking back here and resuming what has been said so far, and attempt to create a reusable list of some kind. I'll update this thread when things are ready.

@Mijikai, I'm quite impressed by your code approach, it's really cool the idea of working directly on the chm without unpacking the files first. I can foresee that your code is going to be reused at some point, it's really handy.

@User_Russian, where can I find the updated GeSHi file you pasted? I'd link to update my links to point to it.
The PureBASIC Archives: FOSS Resources:
Post Reply